ilyachalov (ilyachalov) wrote,
ilyachalov
ilyachalov

Category:

JavaScript: расставить героев на поле, постановка задачи

Решил задачу «Расставить супергероев по полю» к подразделу 3.3 «Drag'n'Drop с событиями мыши» второй части учебника по JavaScript.

Задача интересная и, можно сказать, демонстрационная (в хороших учебниках такие задачи используют, чтобы ученику стало интересно). На первый взгляд выглядит сложной, но, на самом деле, она не слишком сложная.

Дана тестовая HTML-страница со схемой футбольного поля. Рядом с этим полем расположено 7 объектов, которые пользователь может разместить на футбольном поле. Пять из этих объектов представляют собой разных супергероев из американских комиксов, шестой объект — Винни-Пух из советского мультфильма 1969 года, а седьмой объект — знакомый нам по предыдущим задачам мяч.

Если ширины HTML-страницы хватает, то объекты будут расположены справа от футбольного поля. В противном случае они появятся снизу от футбольного поля.

Изначально пользователь может лишь навести курсор мыши на эти объекты, в результате чего курсор мыши изменит свой вид со стрелки на руку с указующим пальцем.

Задача состоит в том, чтобы с помощью скрипта на языке JavaScript обеспечить пользователю возможность перетаскивать (с помощью механизма «Drag’n’Drop»: то есть пользователь нажимает кнопку мыши на выбранном объекте, затем, не отпуская нажатой кнопки мыши, перетаскивает объект в выбранное место и отпускает кнопку мыши, оставляя объект на новом месте) заданные на HTML-страницы объекты туда, куда он пожелает.

Предполагается, что пользователь захочет перетаскивать объекты на схему футбольного поля, но условия задачи не ставят такого ограничения, поэтому в итоге пользователь должен иметь возможность перетащить выбранный объект в любое место тестовой HTML-страницы. Действующий пример с решением задачи от авторов задачи можно посмотреть на отдельной странице.

Выше футбольного поля на тестовой HTML-странице есть текст с заголовком, в котором программисту, который будет писать скрипт, даны дополнительные инструкции. Либо это можно считать памяткой с главными условиями, которые должны быть учтены при работе скрипта.

Вот как выглядит тестовая HTML-страница изначально в моём браузере (картинка):



Тонкая серая линия сверху и слева на картинке — это край окна браузера. Я оставил ее на картинке, чтобы можно было понять, где в области просмотра браузера относительно края области просмотра находится содержимое тестовой HTML-страницы.

* * *

Рассмотрим, как заданная тестовая HTML-страница сделана с точки зрения языков HTML и CSS. В принципе, у меня это всегда первый этап при решении задач в обсуждаемом учебнике.

Тут, кстати, можно представить, как примерно работают команды по созданию веб-сайтов: художник рисует нужные картинки заданных верстальщиком размеров (общая ширина и высота), верстальщик пишет код HTML-страницы на языке HTML и стили для элементов HTML-страницы на языке CSS, а затем программист придает HTML-странице интерактивность с помощью скриптов на языке JavaScript.

Как в коде HTML тут представлено футбольное поле? Оно представлено HTML-элементом div с идентификатором field. Для этого элемента в файле soccer.css описан стиль #field. В этом стиле заданы ширина и высота HTML-элемента (800 × 600 пикселей), а также загружается картинка того же размера в формате PNG, которая будет фоном данного HTML-элемента div. На этой картинке и изображена схема футбольного поля, которую в итоге видит пользователь в браузере. Надписи на схеме являются частью картинки футбольного поля.

В стиле #field стоит обратить внимание на указание float: left;, которое смещает футбольное поле к левой стороне контейнера (в данном случае контейнером является тело тестовой HTML-страницы), позволяя тексту и строковым HTML-элементам обтекать себя справа. Именно поэтому 7 объектов, которые пользователь сможет перетаскивать, располагаются справа от футбольного поля (если позволяет ширина тестовой HTML-страницы) или снизу от футбольного поля (если ширина тестовой HTML-страницы настолько маленькая, что объектам не остается места справа от футбольного поля).

Как в коде HTML тут представлены 7 перетаскиваемых (по-английски «draggable») объектов? Мяч и 6 объектов-героев представлены по-разному.

Мяч, так же, как и в предыдущих задачах из обсуждаемого учебника, представлен HTML-элементом img, в который загружается файл в формате SVG (напомню, это не картинка, а текстовый файл на языке разметки SVG, похожем на язык разметки HTML; с помощью формата SVG браузер может отображать изображения масштабируемой векторной графики). Размеры мяча заданы в файле SVG — 40 × 40 пикселей.

6 объектов-героев представлены шестью HTML-элементами div с идентификаторами от hero1 до hero6. Для этих шести HTML-элементов в файле soccer.css описаны CSS-класс .hero и шесть индивидуальных стилей от #hero1 до #hero6. Размер (ширина и высота) содержимого каждого HTML-элемента div из шести задан в 130 × 128 пикселей. Здесь же (в стиле) загружается картинка формата PNG, которая будет фоном каждого из шести HTML-элементов div.

Как может одна картинка давать разный фон для каждого из шести HTML-элементов div? Рисунки всех шести героев содержатся на одной картинке размером (ширина и высота) в 380 × 260 пикселей. С помощью CSS-свойства background-position в индивидуальных стилях шести HTML-элементов div, изображающих героев, указывается расстояние в пикселях, на которое браузер сдвинет фоновое изображение относительно левого верхнего угла клиентской части конкретного HTML-элемента div. Используется два числа: сдвиг по горизонтали, сдвиг по вертикали. Если сдвиг фонового изображения происходит за пределы клиентской части HTML-элемента div влево или вверх, то расстояние соответствующего сдвига указывается отрицательным числом.

Фрагмент файла soccer.css:
#hero1 {
  background-position: 0 0;
}

#hero2 {
  background-position: 0 -128px;
}

#hero3 {
  background-position: -120px 0;
}

#hero4 {
  background-position: -125px -128px;
}

#hero5 {
  background-position: -248px -128px;
}

#hero6 {
  background-position: -244px 0;
}

Чтобы ситуация стала еще более ясной, я взял картинку с героями и выделил на ней области, которые оказываются фоном для каждого из шести HTML-элементов div, изображающих героев:



Вставляя эту картинку в данный пост, я задал ей в стиле синюю границу толщиной в 1 пиксель. Надеюсь, ЖЖ ее отображает. У меня в браузере она видна. Я ее добавил, чтобы было видно, где заканчивается картинка с героями (это здесь, в посте, не видно, потому что у картинки в оригинале прозрачный фон). Сама эта синяя граница не входит в картинку.

Области фона каждого из шести HTML-элементов div я выделил красной границей. Эти красные границы являются частью каждого из шести прямоугольников фона размером 130 × 128 пикселей (этот размер, как уже было сказано ранее, указан в стиле .hero). Еще я добавил красные цифры на картинке — это номера индивидуальных стилей объектов-героев от #hero1 до #hero6.

(Тут, кстати, нужно отметить, что на тестовую HTML-страницу герои выводятся по порядку в строку, а строка в браузере может иметь переносы на следующую строку, если она не помещается в область просмотра браузера по ширине. А на картинке выше герои нумеруются по другому принципу. Эта разница может запутать программиста. Чтобы увидеть эту разницу, можно сравнить картинку из начала поста и данную картинку с героями.)

На картинке видно, что некоторые соседние области фона накладываются (залезают) друг на друга. Пространства, в котором происходят такие наложения, я заполнил красной штриховкой. Снизу и справа, кстати, осталось небольшое узкое пространство, которое не попадает в фон ни к одному из шести HTML-элементов div, изображающих героев.

Видно, как верстальщик в паре с художником здесь накосячили.

Например, у изображений героев 1, 2, 3 и 4 с боков есть довольно большое пустое пространство. Это скажется, когда мы решим задачу. По условиям задачи, при поднесении объекта-героя к левому или правому краю области просмотра браузера, герой не должен вылезать за границу области просмотра. В итоге мы не сможем поднести изображение героя вплотную к границе области просмотра браузера из-за пустого пространства на самой картинке.

У героя 1 художник отрезал часть тени слева. У героя 2 верстальщик отрезал часть тени снизу. У героев 2 и 4 над головой остается ощутимо разное расстояние до верхней границы области фона.

Художник по всей картинке оставил кучу каких-то сероватых точек (не тени), которые на тестовой HTML-странице кажутся грязью на дисплее. Я долго тёр дисплей, прежде, чем сообразил, что это не грязь, а косяки художника.

В стиле .hero следует обратить внимание на указание float: left;. Если бы у нас в теле тестовой HTML-страницы был бы только один HTML-элемент с таким указанием, то он был бы прижат к левой стороне контейнера (в данном случае контейнером, как уже было указано выше, является тело тестовой HTML-страницы). Но у нас таких HTML-элементов восемь (футбольное поле и семь перетаскиваемых объектов). В такой ситуации к левой стороне контейнера оказалось прижато футбольное поле, потому что оно в коде HTML-страницы идет первым. Следующий HTML-элемент с таким указанием обтекает предыдущий HTML-элемент с таким указанием и так далее. (Если это указание убрать из указанного стиля, объекты-герои окажутся под футбольным полем, они его как бы не заметят.)

Все перетаскиваемые объекты (их семь штук: герои и мяч) помечены CSS-классом .draggable. Это можно будет использовать, если в скрипте понадобится обратиться сразу ко всем этим объектам (по общему CSS-классу легко сделать выборку).

И, наконец, последним в теле тестовой HTML-страницы (если не учитывать HTML-элемент script) идет еще один HTML-элемент div. Зачем он нужен? Дело в том, что в его стиле есть указание clear:both. Такую конструкцию применяют, если нужно очистить (по-английски «clear») имеющуюся у браузера информацию о ранее установленном в стилях предыдущих HTML-элементов выравнивании и обтекании (в данном случае нужно очистить действие CSS-свойства float: left;).

В нашем случае, если эту конструкцию убрать, то ничего не изменится, не сломается и не нарушится. Однако, если в будущем кто-то захочет добавить в конец тела HTML-страницы текст или некие строковые HTML-элементы, то они сначала будут заполнять свободное пространство справа от футбольного поля и только то, что там не поместится, уже будет отображаться снизу футбольного поля. Но, предположим, мы хотим, чтобы текст (или строчные HTML-элементы) начали размещаться сразу под футбольным полем? Вот как раз ради этого и производится очистка информации об обтекании. То есть эта конструкция рассчитана на возможные будущие добавления к данной HTML-странице, как я понимаю.

На этом разбор постановки задачи заканчиваю. Разбор решения — в следующем посте.
Tags: Образование, Программирование
Subscribe

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 0 comments