Анимация и эффекты в javascript с помощью mootools

Эта статья начнет небольшую серию материалов, посвященных анимации в javascript. Тема статьи подсказана вами, уважаемые читатели. В последнее время мне пришло несколько писем с вопросами, как сделать с помощью javascript так, чтобы "блестело, вертелось, двигалось". По-правде говоря, javascript для этого совсем не предназначен, но если подумать, то…

Подтверждаю: да, исторически javascript не имеет поддержки анимации, эффектов. В то время, когда javascript начали использовать внутри html- страниц (а было это добрых лет пятнадцать назад), его сфера применения сводилась к приданию html-страницам хоть какой-нибудь динамичности. Например, вверху страницы могла выводиться фраза "доброе утро" или "добрый день" в зависимости от времени часов пользователя, еще на javascript делались бегущие строки и подобные им "глупости". Для серьезной анимации планировалось использовать java-апплеты. И у них были изначально все возможности: до ссоры с microsoft исполняющая среда java-апплетов была практически на каждом компьютере с windows. Плюс развитый язык программирования, возможности рисовать, работа с визуальными компонентами (текстовые поля, кнопки, падающие списки), — все это даже на самых начальных этапах java. Но не сложилось: рынок был захвачен macromedia flash. Так же бездарно прошла жизнь ряда подобных технологий — они поставлялись в виде отдельных программ (плагинов), которые надо было скачать и установить на своем компьютере для просмотра веб-страниц, использующих некие особые возможности анимации. Например, 3dml (время ее расцвета — лет десять назад) считалась вместе с vrml основой для построения трехмерных веб-приложений: интерактивные музеи, модели городов, интернет-игры и прочее. Для тех, кто знаком с vrml, надо сказать, что 3dml ориентировался на моделирование 3d-окружения (ландшафт, интерьеры помещений), и для создания такого трехмерного мирка достаточно было блокнота и небольшого справочника по командам языка — он был действительно очень прост. Но хватит о делах давно ушедших дней — разберем, что у нас есть на текущий момент.

Стандартных средств для рисования в javascript до сих пор нет, и эмулировать их… Пару лет назад я пролистывал книжку одного российского автора, посвященную javascript. Название ее я не помню, да это и не важно: книжка была достаточно посредственного качества. Одна из глав ее была посвящена рисованию с помощью javascript. Автор рассказывал, как рисовать линию — график какой-то функции. Для этого он программно создал в цикле множество объектов-картинок размером в 1 пиксель, затем, используя css-свойства (position: absolute; left: 100px, top: 200px;), выполнил их позиционирование на странице так, чтобы создавалась иллюзия сплошной линии. Я не поленился набрать этот фрагмент кода и понял, что мои предчувствия оправдались: это было очень медленно и совершенно неприменимо для рисования чего-то, кроме пары линий. Закраска, градиенты, кривые Безье, прозрачность, — все это требовало других инструментов. Есть вариант рисования с помощью тега canvas. В настоящий момент его поддерживают только opera и firefox, а самый "популярный" браузер нуждается в дополнительной библиотеке — файле javascript, который занимается эмуляцией canvas с помощью vrml (и эмуляция не стопроцентная), либо установке дополнительного плагина. Этим явно не будет заниматься типовой посетитель вашего сайта. Так что canvas я откладываю на полку до тех пор, пока этот новый тег не войдет в очередной стандарт html, и — самое главное — его не "забудут" реализовать программисты microsoft в одной из следующих версий internet explorer. Еще вариант — рисование с помощью svg. SVG расшифровывается как scalable vector graphics. Это изображение, которое можно создать буквально с помощью блокнота. Ведь файл с картинкой — это текстовой документ (в формате xml), содержимое которого — команды рисования линий, эллипсов, прямоугольников, кривых Безье, закраски, градиенты и прочее и прочее. Разумеется, создавать только с помощью блокнота что-то сложнее пары красиво раскрашенных квадратов нельзя. Так, для svg есть замечательный редактор Inkscape (это open source программа, и ее домашний сайт ). Не стоит полагать, что Inkscape одна на весь мир: и CorelDRAW, и Adobe Illustrator, и Microsoft Visio, и OpenOffice, — все они имеют худо-бедно работать с svg хотя бы на уровне экспорта/импорта. Яркий недостаток svg — повышенный размер файлов (даже после сжатия zip) и скорость отрисовки: она заметно ниже, чем для gif или jpeg. С другой стороны, не забывайте, что и png, и jpg, и gif — это все не векторная, а растровая графика, и при масштабировании изображения будут возникать артефакты. Возможности Svg не ограничиваются только яркими статическими картинками. Так как изображение — набор тегов, и это изображение встроено в страницу html, то вы можете с помощью javascript манипулировать этими узлами и создавать ту самую анимацию и эффекты, которые вынесены в заголовок статьи. Предусмотрены также и специальные теги анимации, позволяющие изменять некоторые свойства (координаты, заливку, прозрачность) по определенным законам во времени. Предусмотрена в svg и поддержка Events: мы можем "поймать" событие: навели мышь на фрагмент изображения — например, прямоугольник — и поменяли, цвет или координаты этого объекта. Найдется в svg и поддержка фильтров. Взгляните на следующий фрагмент кода. В нем изображено движение желтого эллипса сверху вниз внутри родительского прямоугольника, обозначенного зеленой рамкой, как показано на рис. 1:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="400" height="400" xmlns="http://www.w3.org/2000/svg" version="1.1">
<title>Ellipse anime</title>
<rect x ="5" y="5" width="395" height="395" stroke="green" stroke-width="2" fill="none" />
<ellipse cx="200" cy="50" rx="100" ry="80" fill="yellow" stroke="orange" stroke-width="2">
<animate attributeName="cy" from="0" to="300" dur="5s" repeatCount="indefinite"/>
</ellipse>
</svg>

Существует несколько версий стандарта svg (1.0, 1.1, 1.2), которые, в свою очередь, делятся на подмножества: tiny, basic, full. В различных версиях браузеров поддержка svg реализована по-разному: лучше всего это сделано в opera 9.5, затем firefox, safari, KDE Konqueror. Заметили, какого браузера нет в списке? Конечно же, разработчики самого популярного в мире браузера снова решили не напрягаться. Фильтры в internet explorer. Четвертая версия internet explorer (выпущена она была лет десять назад) принесла с собой действительно много значимых улучшений и новых возможностей. Именно эта версия победила в отшумевшей "войне браузеров" и захватила ту огромную долю рынка, которую до сегодняшнего дня держит за собой microsoft. Так вот, именно в этой версии появились фильтры. Это нестандартная возможность только для internet explorer (поддержки в opera или firefox нет) заключалась в возможности внедрить в страницы html эффекты (например, Alpha, BasicImage, Blur, Chroma, Compositor, Wave, Shadow, MotionBlur, Matrix, MaskFilter, Light, ICMFilter, Glow, Engrave, Emboss, DropShadow), накладываемые на произвольные элементы. Согласитесь, что их много, а я ведь перечислил только так называемые статические эффекты, кроме того, есть и эффекты перехода. Их применяют тогда, когда вы хотите одно изображение сменить другим — например, при наведении мыши на изображение оно меняется, но не резко: раз — и новая картинка, — а создается иллюзия плавного перехода, растворения или изображение будто проявилось из-за жалюзи. Словами описать эти примеры достаточно тяжело, так что посмотрите примеры в MSDN и непосредственно на сайте microsoft. В примере ниже изображены две картинки- звезды, и на вторую из них наложен фильтр MotionBlur (см. рис. 2). Обратите внимание в примере на значение атрибута style для второй картинки — именно там и задается эффект.

<html><body>
<img src="pic_1.png" style="float: left;"/>
<img src="pic_1.png" style="float: right;filter:progid:DXImageTransform.Microsoft.MotionBlur(strength=80)
progid:DXImageTransform.Microsoft.BasicImage(mirror=1)"/>
</body></html>

Что же, фильтры — штука неплохая, но, опять-таки, это только для internet explorer, не говоря о том, что средств svg и больше, и лучше. Неужели нет выхода, кроме как использовать flash, чтобы не терять какую-либо часть посетителей сайта? Увы, да. Если вам нужно рисовать произвольные картинки, эффекты переходов или фильтры, то flash — именно то, что нужно. С другой стороны, делать сайты только на flash — не слишком хорошая идея, и причин тому множество. Что делать, если вы всего лишь хотите разместить на своем сайте, например, форму обратной связи, плавно выезжающую из-за края страницы, когда посетитель жмет на ссылку "написать отзыв"? Как сделать так, чтобы при наведении мыши на некоторый элемент появилась всплывающая подсказка? Как дать возможность перетаскивать товары из таблицы прайса прямо в корзину с помощью мыши? Как скрыть или показать некоторый элемент, не резко, а постепенно изменяя его прозрачность? Вот этому я посвящу данный материал, а если вас интересует произвольная анимация, то flash, canvas, svg ждут вас.

Javascript-библиотек (framework'ов), решающих описанные выше задачи, много, очень много. Летом я написал серию статей, посвященных jquery. Тогда основной упор делался на возможности css/xpath-подобной адресации элементов, возможности управлять css-параметрами, обработке событий и работе с ajax. Собственно, внимание анимации движения или переходов было уделено очень мало. Особенность jquery в крайне небольшом размере (порядка 10 Кб) и развитой архитектуре плагинов. Если чего-то нет в базовой поставке jquery, то наверняка есть плагин, который делает то, что вам нужно. Но сегодня разговор пойдет о другой библиотеке — mootools. Мне она показалась более ориентированной на анимацию и эффекты, чем jquery. В своих проектах я использую три-четыре javascript-библиотеки: наилегчайшую и наибыстрейшую jquery, наикрасивейшую mootools и yahoo controls или extjs (когда мне нужны сложные элементы управления, падающие меню, деревья, таблицы…). Хотя возможности этих библиотек пересекаются, не стоит зацикливаться на одной из них. Нужно комбинировать, выбирать для каждого проекта ту, которая лучше всего подходит (помните: серебряной пули нет).

Домашний сайт библиотеки: сайт Там вы можете скачать документацию, примеры и собственно библиотеку. Приятно, что возможности mootools разделены на несколько модулей (работа с окнами, эффекты, поддержка DnD, ajax, элементы управления), и вы можете на странице сайт выбрать, какие именно вам нужны компоненты, указать способ сжатия js-файла (будут ли включены в js-файл комментарии, будут ли убраны или оставлены пробелы, знаки табуляции и т.д). Рекомендации стандартны: для разработки используем полную версию библиотеки (так, чтобы иметь возможность подсмотреть, как "это" работает внутри), а на стадии размещения в интернет — режим максимального сжатия. Начнем с простого примера, определяющего версию браузера и выводящего некоторое сообщение пользователю. Для этого подключим js-файл библиотеки и обратимся к объекту window. Да-да, к тому самому стандартному для любого браузера объекту window. Дело в том, что mootools идет немного по другому пути, чем jquery, и не создает некий объект "$", от имени которого будут вызываться все функции или обращаться ко всем свойствам. К части функций в mootools обращаемся через "$", к части через "$$", а часть функций являются глобальными и не вложены в состав какого-либо объекта.

<html><head>
<script src="getmootools_js.js"> </script>
</head> <body><script>
if (window.ie) alert ('ie');
if (window.ie6) alert ('ie 6');
if (window.ie7) alert ('ie 7');
if (window.gecko) alert ('firefox | flock | seamonkey ...');
if (window.opera) alert ('opera');
</script> </body></html>

В примере к объекту window были добавлены свойства-флажки (ie, ie6, ie7, opera, gecko). Кроме того, был добавлен ряд функций, которые являются надстройкой над уже предусмотренными изначально в javascript механизмами и не представляют особого интереса, кроме функции $type — ее назначение — определить тип переменной, переданной как параметр.

alert ($type ('vasyano'));// строка
alert ($type ('12'));// строка
alert ($type (12));// число
alert ($type (function () {} ));// функция
alert ($type (true));// логический тип
alert ($type (new Date ()));// объект
alert ($type (document.body));// элемент DOM страницы
alert ($type (/vasya/i));// регулярное выражение

Не совсем понятно, зачем была выполнена замена привычных для javascript функий setTimeout и setInterval на следующий вариант синтаксиса, ну да ладно.

function foo (){ alert ('hello'); }
var myTimer = foo.delay(1000);// замена setTimeout
var myTimer = foo.periodical(1000);// замена setInterval
myTimer = $clear(myTimer);// замена clearTimeout

Прежде чем мы сделаем какую-либо модификацию html-наполнения страницы с помощью mootools, вспомните понятие DOM Ready. Я про него говорил еще тогда, когда писал про jquery. Дело в том, что мы не можем выполнять модификацию дерева DOM страницы до тех пор, пока все его части не будут загружены. В интернете возможна ситуация, когда у вас успеет загрузиться весь javascript-код, но пока еще не вся страница, и при попытке обратиться к какому-либо из узлов, которых еще нет, возникнет ошибка. Чтобы этого избежать, в состав jquery был введен специальный механизм ожидания domReady — когда все содержимое страницы загрузилось, но не дожидаясь загрузки собственно содержимого картинок. Есть подобный прием и в mootools (еще в примере ниже используется функция $time — она возвращает величину текущего времени timestamp):

<body><script>
// запомнили время начала загрузки страницы
var old_time = $time();
// обработчик события полностью страница была загружена
window.onload = function (){ alert('full load time is ' + ($time() — old_time)); }
// обработка события загружено только дерево DOM
window.addEvent('domready', function(){
alert('the dom is ready in ' + ($time() — old_time));
});
</script>

Именно здесь размещена огромнейшая картинка, занимающая до пары минут загрузки

<img src="big.png" />
</body>

Внутри функции обработчика события domready мы обращаемся к произвольным элементам страницы и меняем их css-параметры. Для поиска узлов DOM используется функция "$" или "$$". В первом случае необходимо передать id элемента, который нужно найти. Во втором же случае возвращается список найденных узлов, а в качестве условия поиска можно указать цепочку узлов, через которые следует пройти.

$('test') // ищем один элемент на основании его id
var dv = document.getElementById('test');// аналог команды выше

Найденный с помощью "getElementById" элемент "dv" можно "обернуть" mootools так, чтобы использовать специализированные приемы изменения свойств узла $(dv).функция_или_свойство. В примере ниже выполняется поиск узлов по заданным условиям:

$$('span') //найти все теги span на странице
$$('span', 'div') //найти как все теги span, так и теги div
$$('#test') //найти элемент, у которого идентификатор равен слову test
$$('#test p.marked') //найти внутри тега с идентификатором test все абзацы, у которых класс равен marked

Теперь попробуем изменять визуальное оформление найденного тега и указать для него новый css-класс. Есть три базовые функции: addClass — добавляет класс к элементу, removeClass — удаляет класс с заданным именем от элемента, и toggleClass — чередует класс: если у элемента есть уже класс с указанным именем, то он удаляется, а иначе назначается.

<style>// стили
.user_a {color: red;}
.user_b {font-size: 14px;}
</style>
<script>// назначаем стили
window.addEvent('domready', function(){
// сначала всем абзацам в странице
$$('p').addClass ('user_a');
// только одному, у которого id = spec
$('spec').addClass ('user_b');
});
</script>

Для смены css-атрибутов используются две функции: setStyle и setStyles. Отличие в том, что первая из них получает в качестве параметра два значения: имя css-атрибута и его значение; вторая же получает целый массив, состоящий из пар "атрибут-значение".

$$('p').setStyle ('border', '1px solid red');
$('spec').setStyles ({fontWeight: 'bold', fontSize: '30px'});
Найдутся и две парные функции getStyle и getStyles, назначение которых — получить те css-стили, которые привязаны к элементу сейчас. alert ( $('spec').getStyle('text-decoration') );
alert ( $('spec').getStyles('text-decoration', 'width') );
Даже в случае, когда запрошенный параметр не был явно назначен элементу, он будет вычислен и возвращен из функций getStyle и getStyles. Последнее на сегодня — как выполнить полную замену содержимого некоторого элемента новой информацией.
$('spec').setHTML('<i>new text</i>');

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

black-zorro@tut.by, black-zorro.com


Компьютерная газета. Статья была опубликована в номере 01 за 2008 год в рубрике программирование

©1997-2024 Компьютерная газета