Автор: black-zorro
Сайт: © компьютерная газета
Сегодня я продолжу рассказ о библиотеке mootols. Это одна из наиболее известных javascript-библиотек, позволяющих внедрить на веб-страницу немножко эффектов и чуть-чуть анимации. Сегодня мы завершим знакомство с обязательной частью mootols и попробуем создавать всплывающие подсказки, управлять перемещением элементов, эффектами перехода одного изображения в другое. В прошлый раз мы остановились на изучении методов поиска html-элементов на странице. “Страшное” чередование вызовов getElementsByTagName и getElementById осталось в далеком прошлом: все современные javascript-библиотеки имеют средства для того, чтобы выполнить поиск элемента на странице, записав его характеристики: id, класс css, имя тега или их комбинацию. Честно говоря, в этом плане mootools слабее jquery (об этой библиотеке я писал в серии статей летом 2007), но сегодня разговор прежде всего об анимации.
Начнем с простенького задания: при наведении мыши на некоторое изображение оно должно смениться другим. Сложность не в том, чтобы создать обработчик события omouseover и onmouseout, а в сущей безделице: в том, чтобы запустить процесс анимации именно тогда, когда все нужные для нее ресурсы будут загружены браузером. Т.е. мы навели мышь на картинку, и она должна тут же смениться новой, а не так: сначала исчезает старая картинка, и только через несколько секунд появляется новая. Даже самый начинающий javascript-разработчик знает, что можно предварительно загрузить нужные картинки, но не показывая их до поры до времени — например, так:
<img src="1.png" onmouseover="this.src='2.png'" onmouseout="this.src='1.png'"/>
var imgHover = new Image ();
imgHover.src = '2.png';
И все было бы хорошо, если бы веб-страница не содержала множество изображений, css- и javascript-файлов, загружающихся в хаотичном порядке. Вовсе не факт, что к тому времени, как пользователь наведет мышь на изображение, то, второе, изображение будет уже загружено. В составе mootols есть класс Asset, его назначение — динамическая загрузка css- и js-файлов, изображений. Для картинок (к сожалению, только для них) можно установить обработчик события “все картинки были загружены”. Вот первый пример:
new Asset.javascript('js/logic.js', {id: 'js_logic});
new Asset.css('css/for_ie.css', {id: 'css_ie_fix'});
Первый параметр вызова функции css или javascript — имя загружаемого файла, затем идет перечисление атрибутов, которые будут назначены для динамически созданных тегов “<script>” и “<link>”. Можно загрузить одну картинку, а в обработчике события “загрузка завершена” назначить, в свою очередь, обработку событий mouseover и mouseout для изображения (предполагается, что на странице есть картинка с id, равным “roll”): function onLoadComplete (){
$('roll').onmouseover = function(){this.src = '2.png'};
$('roll').onmouseout = function(){this.src = '1.png'}; }
new Asset.image('2.png', {onload: onLoadComplete});
Если вы хотите динамически загрузить несколько картинок, удобнее будет воспользоваться функцией images. Ей в качестве параметра передается не только массив с именами картинок, но и две функции (хотя они и не обязательны). Первая функция onComplete вызывается тогда, когда все картинки были загружены, вторая — onProgress — вызывается каждый раз, как загрузится очередное изображение.
new Asset.images(['1.png', '2.png'], {
onComplete: function(){alert('all images loaded');},
onProgress: function(){alert ('next pic was loaded'); } });
Загруженную картинку можно автоматически переместить в определенное место страницы. Для этого к результату вызова “new Asset.image” следует применить функцию injectInside, а ей в качестве параметра указать id того элемента страницы, внутрь которого будет помещена эта картинка. В примере предполагается, что на странице существует некоторый тег div с id, равным “block”. Картинка не затрет старое содержимое элемента “block”, а добавит изображение к этому содержимому в самый конец.
window.addEvent('domready', function(){
new Asset.image('2.png', {alt : 'pic', title : 'info' }).injectInside ('block'); });
Если вам хочется вставить картинку внутрь block, но не в конце, а в самом начале — используйте вызов injectTop. Найдется и еще пара функций: injectAfter — изображение будет помещено после тега div, injectBefore — до блока div. Естественно, использовать injectInside, injectBefore, injectTop можно не только для динамически создаваемых картинок, но и для существующих тегов:
$('friend').injectTop ('block');
Здесь предполагается, что friend и block — два блока div, размещенных в тексте страницы. Общая рекомендация: не забывайте весь код mootols помещать внутрь функции, обрабатывающей событие domready. В противном случае код может и не работать — возможно, на момент выполнения js-кода, перемещающего один div внутрь другого, сами эти div’ы еще не существуют. Разумеется, тема динамического изменения содержимого веб-страницы — добавление новых узлов DOM, их перемещение и удаление — не так проста. Одно дело если вы разрабатываете простенькие сайты, где подобных операций не много, но как только количество операций начинает увеличиваться, вам следует подумать, как сделать так, чтобы браузер не слишком сильно тормозил. Все же и javascript, и DOM — не самые быстрые вещи. Я несколько раз сталкивался с тем, что брался некоторый javascript-framework, начиналась разработка с его помощью, и… И спустя какое-то время понимали, что удобство разработки — это, конечно, хорошо, но почему же код работает так медленно? По этой теме полезным будет почитать комментарии к статье сайт Показанный выше прием с назначением обработчика события “('roll').onmouseover = …” не самый лучший. Возможно так привязать к некоторому элементу страницы функцию-обработчик, чтобы в качестве параметра ей из mootols был передан особый объект Event, внутри которого найдется парочка интересных свойств и методов. В следующем примере я использую специальную функцию window.addEvent, которая добавляет событие для тега div c id, равным “block”, но так, что внутри этой функции я могу использовать объект event. Он содержит сведения о произошедшем событии (не только координаты мыши в виде переменной event.client.x и event.client.y, но и сведения о нажатых клавишах, что также позволит вам управлять обработкой события):
1. Нажаты ли клавиши shift (переменная event.shift), клавиши ctrl и alt (переменные event.control и event.alt).
2. Если на клавиатуре нажата какая-то из клавиш, то сведения об этом хранятся в переменных (event.key и event.code). А сведения о скроллинге найдутся в переменной event.wheel.
3. Для того, чтобы отменить распространение события, используйте метод stopPropagation, а для того, чтобы отменить действие по умолчанию — preventDefault. Например, по нажатию на кнопку “отправить форму” вы проверили корректность заполнения полей и решили, что форму отправлять нельзя — данные были введены с ошибкой.
function over(event){ alert(event.client.x);};
window.addEvent('domready', function(){
$('block').addEvent('mouseover', over.bindWithEvent(block));});
Теперь, вооружившись теорией, перейдем собственно к эффектам в mootols. Для работы с ними нам потребуется объект Fx.Base, на базе которого построены объекты Fx.CSS, Fx.Style и Fx.Styles. Именно с помощью них мы сделаем первый пример: блок div будет плавно менять свой цвет при наведении на него мыши. Методы работы с Fx всегда сходны: сначала нужно создать объект, хранящий сведения о преобразовании некоторого css- атрибута для элемента.
var bgColor = new Fx.Style('block', 'backgroundColor', {duration:500});
Здесь я создал объект bgColor, позволяющий управлять для элемента с id, равным block, значением css-свойства backgroundColor. Третий параметр функции Fx.Style — это объект, содержащий параметры будущей анимации. Кроме параметра duration — длительности в миллисекундах выполняемой анимации, можно указать также transition — параметр, управляющий тем, как именно (по какому математическому закону) будет выполняться изменение атрибута backgroundColor от некоторого начального значения до конечного. Параметр unit служит для указания того, в каких единицах измерения задается начальное и конечное значение анимируемого параметра (px, %). Параметр fps (значение по умолчанию равно 50) влияет на то, с какой частотой будет обновляться значение анимируемого параметра. Также можно указать обработчик события, который будет вызван тогда, когда анимация будет запущена — onStart, и обработчик для ситуации onComplete — когда анимация будет завершена. После создания объекта анимации необходимо выполнить его запуск, используя функцию start. Первый ее параметр — начальное значение атрибута, второй — конечное:
bgColor.start('#ff00ff', '#ffffff');
Запущенную анимацию можно остановить с помощью stop (параметров у функции нет) или же быстро перемотать в нужную точку — set.
// делаем элемент прозрачным
new Fx.Style('block', 'opacity').set(0);
Изменять можно любой атрибут css. Например, меняя left и top, можно создать анимацию выезжающей из-за границы экрана (например, при нажатии на кнопку) формы регистрации.
var posLeft = new Fx.Style('block', 'left', {duration:5000});
posLeft.set (-400);// вначале прячем форму за границу экрана
// а по нажатию на кнопку "показать форму" запускаем анимацию:
posLeft.start(-400, 400);
Вам может понравиться еще и такой вариант, когда содержимое некоторого блока медленно уезжает за его верхний край или, наоборот, выезжает из-за него.
var shower = new Fx.Slide('block', {duration: 5000});
$('button').addEvent ('click', function () {shower.toggle();})
Здесь я создал два блока div: первый из них — block — будет попеременно прятаться и показываться (для этого используется функция toggle). Ее, в свою очередь, вызывает обработчик события “нажатие мыши” на втором блоке div (его id равен button). По умолчанию содержимое блока будет прятаться за границами блока, уезжая вверх. Но если вы хотите это переопределить так, чтобы блок уезжал влево, то при создании объекта Fx.Slide следует указать атрибут mode равным значению 'horizontal':
new Fx.Slide('block', {mode: 'horizontal' , duration: 5000}).slideIn();
// функция slideIn прячет элемент, а функция slideOut его показывает.
Есть альтернативный вариант синтаксиса, чтобы задать анимацию css-свойств с помощью функции effect, но практической разницы с ранее показанными приемами нет:
$('block').effect('backgroundColor', {duration: 2000}).start('#00ff00','#ff00ff');
Гораздо интереснее разобраться с тем, как именно mootools будет вычислять промежуточные значения цветов фона между '#00ff00' и '#ff00ff'. Если вы думаете, что используется линейный подход с увеличением от меньшего к большему с шагом, равным длина_интервала/время, то это не совсем так. В составе mootools есть специальный объект Fx.Transitions, представляющий собой коллекцию различных алгоритмов изменения анимируемого параметра. Далее я приведу пару формул таких преобразований, но сначала разберемся, как это работает внутри. Например, вы хотите плавно переместить некоторый элемент, т.е. изменить его атрибут left с начального значения 100 до 1000. Анимация начинается в некоторый момент 0, тут же запускается таймер, который каждые 1000 / fps миллисекунд вызывает функцию расчета нового значения атрибута left. В ней берется время, прошедшее с момента запуска анимации до текущего момента, и делится на duration — получается число от 0 до 1. Затем это значение поступает на вход функции transition, которая, например, берет и вычисляет значение по формуле (это, кстати, формула transition-преобразования по умолчанию): -(Math.cos(Math.PI * p) — 1) / 2. Здесь p — то самое входное значение (число от 0 до 1). Полученное значение обозначим как delta. Оно поступает на вход по следующей формуле: now = (to — from) * delta + from. Очевидно, что from — начальное значение анимируемого параметра, а to — конечное. Полученное значение now присваивается атрибуту left — и… фигурка движется. К некоторым из видов законов изменения добавляются вариации:
1. easeIn — формула transition остается без изменения.
2. easeOut — формула расчета delta меняется на следующую: 1 — transition(1 — p). Визуально этот эффект похож на зеркальное отражение easeIn.
3. easeInOut — формула будет такой: если значение p еще не дошло до 0.5, т.е. мы не прошли еще половины всего времени анимации, то значение delta считается по формуле:
transition(2 * p) / 2.
А после того, как p превысило половину расчетного времени, формула меняется на (2 — transition(2 * (1 — p))) / 2.
1. Linear — самый простой вариант, когда параметр изменяется линейно с одинаковым шагом на каждом из этапов (y=x).
2. Quad — зависимость задается в виде квадрата (y=x*x).
3. Cubic — зависимость в виде куба (y = x*x*x).
4. Quart — здесь x возводится в четвертую степень.
5. Quint — здесь пятая степень.
6. Pow — а это универсальная формула, основанная на возведении числа в произвольную степень. Ранее описанные Quad, Cubic, Quart, Quint построены на основе общего transition-закона Pow.
7. Circ — формула изменения следующая: 1 — Math.sin(Math.acos(p)).
8. Sine — закон движения похож на график синусоиды: 1 — Math.sin((1 — p) * Math.PI / 2).
9. Back — формулу не привожу, но визуально кажется, как сначала медленно убывает и даже выходит за границы начального, но затем резкий скачок, и параметр начинает быстро приближаться к конечному значению анимируемого параметра.
10. Bounce — представьте, как мяч отскакивает от пола, только его движения не только затухают, а могут и расти, небольшими шажками двигаясь от начального значения к конечному.
11. Elastic — вспомните из курса математики график любой асимптотической функции. Так вот, это тот самый закон.
Конечно, вот так “на слух” воспринять и представить, как может изменяться цвет или координаты элемента страницы, довольно тяжело. Поэтому предлагаю посетить следующие две страницы на официальном сайте библиотеки: сайт и сайт . На первой странице вы найдете картинки с нарисованными графиками изменения transition для каждой из формул, а вторая страница представляет собой интерактивный учебник. Там вы увидите форму, где в падающем списке можно выбрать интересующий вас закон движения, указать время, в течение которого будет длиться анимация, а затем понаблюдать за перемещением анимируемого кубика. Естественно, разработчики mootols не открыли Америки, и подобных библиотек, содержащих “пачку” законов анимации, очень много. Есть такие библиотеки и для flash, и для javascript. Может оказаться полезным и следующая ссылка: сайт . Там вы найдете еще одну интересную библиотечку tween’ов для javascript. Для flash 8/9 подобная функциональность сосредоточена в пакетах fl.motion, mx.transitions. Интерес представляет и следующий пример: сайт . В нем показано, как можно выполнить преобразование одного элемента (его стили, размеры, шрифты) в другой так, чтобы за счет одновременного и плавного изменения этих характеристик создавался эффект морфинга. Хотя код примера достаточно велик, но в основе его лежат уже знакомые вам приемы — попробуйте разобраться в нем самостоятельно.
Теперь рассмотрим, как можно создать всплывающую подсказку для некоторых элементов. Стандартом html для каждого из элементов предусмотрен атрибут title — стандартная подсказка, но мы хотим большего — задать анимацию появления и исчезновения подсказки, управлять ее внешним видом: шрифты, фоновый цвет, иконка в углу — и все это нам позволит mootools. Внешний вид подсказок зависит от того тега, которому она назначена. Так, для тегов “a” будет добавлена строка заголовка, содержащая ссылку, на которую указывает тег “a”. Результат показан на рис. 1.
<a href=”http://grav.ru”
id="grav" title="Изучает гравитационное поле Земли">ГРАВИМЕТРИЯ</span>
<span class="hclass" title="Рыхлая крупнообломочная осадочная горная порода">ГРАВИЙ</span>
И код, создающий tooltips:
new Tips($('grav'));
new Tips($$('.hclass'));
В первом случае я явно указал id элемента, для которого будет создана всплывающая подсказка, а во втором подсказка была добавлена ко всем элемента с классом, равным “hclass” (обратите внимание: я использую функцию $ и $$). При создании объекта Tips можно указать также следующие параметры:
1. maxTitleChars — максимальная длина заголовка tooltip’а (количество символов).
2. showDelay — задает время, через которое после наведения мыши на элемент подсказка должна появиться (задается в миллисекундах).
3. hideDelay — время, через которое подсказка исчезнет.
4. offsets — можно указать смещение, на котором относительно позиции мыши будет показан tooltip (задавать значение нужно так: {x: 100, y: 100}).
5. fixed — булева переменная — признак того, будет ли при перемещении курсора мыши подсказка следовать вслед за ним или останется на месте.
6. className — префикс css-классов, используемых для оформления tooltip’а. Всего есть три класса, которые для этого используются: tool-tip, tool- title, tool-text. Служат они соответственно для оформления всего блока tooltip’а, его заголовка и зоны размещения основного текста. Имя этих классов должно начинаться с префикса, заданного className’ом.
Конечно, это не все возможности mootools. Еще интересно рассказать о поддержке DnD и нескольких элементах управления (accordion, scroller). Но, наверное, это будет гораздо позже и в другой серии статей, посвященных библиотекам, ориентированным именно на проектирование сложного пользовательского интерфейса.
Обсудить
в форуме...>>>>