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

January 14, 2008

Эта статья начнет небольшую серию материалов посвященных “анимации” в 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 программа и ее домашний сайт www.inkscape.org). Не стоит полагать что Inkscape – одна на весь мир, так и CorelDRAW и Adobe Illustrator и Microsoft Visio и OpenOffice – все они имеют худо-бедно работать с svg хотя бы на уровне экспорта/импорта. Яркий недостаток svg – повышенный размер файлов (даже после сжатия zip) и скорость отрисовки: она заметно ниже, чем для gif или jpeg. С другой стороны не забывайте что и png, и jpg, и gif – все это не векторная, а растровая графика и при масштабировании изображения будут возникать артефакты. Возможности Svg не ограничиваются только яркими статическими картинками. Так как изображение – набор тегов и это изображение встроено в страницу html то вы можете с помощью javascript манипулировать этими узлами и создавать ту самую анимацию и эффекты, которые вынесены в заголовок статьи. Предусмотрены также и специальные теги анимации позволяющие изменять некоторые свойства (координаты, заливку, прозрачность) по определенным законам во времени. Предусмотрена в svg и поддержка Events: мы можем “поймать” событие “навели мышь на фрагмент изображения”, например прямоугольник, и поменять, цвет или координаты этого объекта. Найдется в svg и поддержка фильтров. Гляньте, на следующий фрагмент кода. В нем изображено движение желтого эллипса сверху вниз внутри родительского прямоугольника обозначенного зеленой рамкой, как показано на рис. 1.
  1. <?xml version="1.0" encoding="UTF-8" standalone="no"?>
  2. <!DOCTYPE svg PUBLIC "-W3CDTD SVG 1.1EN"
  3.  "www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
  4. <svg width="400" height="400" xmlns="www.w3.org/2000/svg" version="1.1">
  5.   <title>Ellipse anime</title>
  6.   <rect x ="5" y="5" width="395" height="395" stroke="green" stroke-width="2" fill="none" />
  7.   <ellipse cx="200" cy="50" rx="100" ry="80"  fill="yellow" stroke="orange" stroke-width="2">
  8.      <animate attributeName="cy" from="0" to="300" dur="5s" repeatCount="indefinite"/>
  9.   </ellipse>
  10. </svg>
Существует несколько версий стандарта svg (1.0, 1.1, 1.2), которые в свою очередь делятся на подмножества: tiny, basic, full. В различных версиях браузеров поддержка svg реализована по разному, так лучше всего она реализована в opera 9.5, затем firefox, safari, KDE Konqueror. Заметили, какого браузера нет в списке? Конечно же, разработчики самого популярного в мире браузера снова решили не напрягаться. Желание написать серию статей посвященных svg зреет у меня с прошлой весны, но всякий раз я нахожу более интересную тему для статей, да и опасность “потерять” почти половину посетителей сайта не радует. Хотя если количество заявок будет достаточно велико, почему бы и нет.

Фильтры в 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 для второй картинки – именно там и задается эффект.


  1. <html>
  2.  <body>
  3.   <img src="pic_1.png" style="float: left;"/>
  4.   <img src="pic_1.png" 
  5.     style="float: right;filter:progid:DXImageTransform.Microsoft.MotionBlur(strength=80)
  6.     progid:DXImageTransform.Microsoft.BasicImage(mirror=1)"/> 
  7.  </body>
  8. </html>
Что же фильтры штука неплохая, но опять таки это только для internet explorer, не говоря о том средств svg и больше и лучше. Неужели, нет выхода, кроме как использовать flash, чтобы не терять какую-либо часть посетителей сайта? Увы да. Если вам нужно рисовать произвольные картинки, эффекты переходов или фильтры, то flash именно то, что нужно. С другой стороны делать сайты только на flash не слишком хорошая идея и причин тому множество. Что делать, если всего лишь хотите разместить на своем сайте, например, форму обратной связи, плавно выезжающую из-за края страницы, когда посетитель жмет на ссылку “написать отзыв”? Как сделать так, чтобы при наведении мыши на некоторый элемент появилась всплывающая подсказка? Как дать возможность перетаскивать товары из таблицы прайса прямо в корзину с помощью мыши? Как скрыть или показать некоторый элемент не резко, а постепенно изменяя его прозрачность? Вот этому я посвящу данный материал, а если вас интересует произвольная анимация, то flash, canvas, svg ждут вас.

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

Домашний сайт библиотеки - mootools.net/. Там вы можете скачать документацию, примеры и собственно библиотеку. Приятно, что возможности mootools разделены на несколько модулей (работа с окнами, эффекты, поддержка DnD, ajax, элементы управления) и вы может на странице mootools.net/download выбрать какие именно вам нужны компоненты, указать способ сжатия js-файла (будут ли включены в js-файл комментарии, будут ли убраны или оставлены пробелы, знаки табуляции и т.д). Рекомендации стандартны: для разработки используем полную версию библиотеки (так чтобы иметь возможность подсмотреть как “это” работает внутри), а на стадии размещения в Интернет – режим максимального сжатия.

Начнем с простого примера определяющего версию браузера и выводящего некоторое сообщение пользователю. Для этого подключим js-файл библиотеки и обратимся к объекту window. Да, да, к тому самому стандартному для любого браузера объекту window. Дело в том, что mootools идет немного по другому пути, чем jquery и не создает некий объект “$”, от имени которого будут вызываться все функции или обращаться ко всем свойствам. К части функций в mootools обращаемся через “$”, к части через “?, ? ????? ??????? ???????? ??????????? ? ?? ??????? ? ?????? ??????-???? ???????.
<br />

<div class='source-highlight'><div class=
  1. <html>
  2.   <head>
  3.     <script src="getmootools_js.js"> </script>
  4.   </head>
  5.   <body>
  6.     <script>
  7.       if (window.ie) 
  8.          alert ('ie');
  9.       if (window.ie6) 
  10.          alert ('ie 6');
  11.       if (window.ie7) 
  12.          alert ('ie 7');
  13.       if (window.gecko) 
  14.          alert ('firefox | flock | seamonkey ...');
  15.       if (window.opera) 
  16.          alert ('opera');
  17.    </script>
  18.   </body>
  19. </html>
? ??????? ? ??????? window ???? ????????? ????????-?????? (ie, ie6, ie7, opera, gecko). ????? ????, ???? ???????? ??? ???????, ??????? ???????? ??????????? ??? ??? ???????????????? ?????????? ? javascript ??????????? ? ?? ???????????? ??????? ???????? ????? ??????? $type ? ?? ?????????? ?????????? ??? ?????????? ?????????? ??? ???????? (?? ???? ??? ?????? ?????????? ? js typeof).
  1. alert ($type ('vasyano')); ??????
  2.  alert ($type ('12')); ??????
  3.  alert ($type (12)); ?????
  4.  alert ($type (function () {} )); ???????
  5.  alert ($type (true)); ?????????? ???
  6.  alert ($type (new Date ())); ??????
  7.  alert ($type (document.body)); ??????? DOM ????????
  8.  alert ($type (/vasya/i)); ?????????? ?????????
?? ?????? ??????? ????? ???? ????????? ?????? ????????? ??? javascript ?????? setTimeout ? setInterval ?? ????????? ??????? ??????????, ?? ?? ?????.
  1. function foo (){ 
  2.    alert ('hello'); 
  3.  }
  4.  var myTimer = foo.delay(1000); ?????? setTimeout
  5.  var myTimer = foo.periodical(1000); ?????? setInterval
  6.  myTimer = $clear(myTimer); ?????? clearTimeout
?????? ??? ?? ??????? ????? ???? ??????????? html-?????????? ???????? ? ??????? mootools, ????????? ??????? DOM Ready. ? ??? ???? ??????? ??? ????? ????? ????? ??? jquery. ???? ? ???, ??? ?? ?? ????? ????????? ??????????? ?????? DOM ???????? ?? ??? ???, ???? ??? ??? ????? ?? ????? ?????????. ? ????????? ???????? ???????? ??? ? ??? ?????? ??????????? ???? javascript-???, ?? ???? ??? ?? ??? ????????. ? ??? ??????? ?????????? ? ??????-???? ?? ?????, ??????? ??? ???, ????????? ??????. ????? ????? ???????? ? ?????? jquery ??? ?????? ??????????? ???????? ???????? domReady ? ????? ??? ?????????? ???????? ???????????, ?? ?? ????????? ???????? ?????????? ??????????? ????????. ???? ???????? ????? ? ? mootools (??? ? ??????? ???? ???????????? ??????? $time ? ??? ?????????? ???????? ???????? ??????? timestamp):
  1. <body>
  2.   <script>
  3.     ????????? ????? ?????? ???????? ????????
  4.    var old_time = $time();
  5.     ?????????? ??????? ????????? ???????? ???? ?????????
  6.    window.onload = function (){ 
  7.         alert('full load time is ' + ($time() - old_time)); 
  8.    }
  9.     ????????? ??????? ????????? ?????? ?????? DOM
  10.    window.addEvent('domready', function(){
  11.        alert('the dom is ready in ' + ($time() - old_time));
  12.    });
  13.   </script>
  14.    -----------
  15.    ?????? ????? ????????? ??????????? ????????, ?????????? ?? ???? ????? ????????
  16.    <img src="big.png" />
  17. </body>
?????? ??????? ??????????? ??????? domready ?? ?????????? ? ???????????? ????????? ???????? ? ?????? ?? css ?????????. ??? ?????? ????? DOM ???????????? ??????? ?$? ??? ?" />”. В первом случае необходимо передать id элемента, который нужно найти. Во втором же случае возвращается список найденных узлов, а в качестве условия поиска можно указать цепочку узлов, через которые следует пройти.
  1. $('test')  ищем один элемент на основании его id
  2.  var dv = document.getElementById('test’); аналог команды выше
Найденный с помощью “getElementById” элемент “dv” можно “обернуть” mootools так чтобы использовать специализированные приемы изменения свойств узла $(dv).фукция_или_свойство. В примере ниже выполняется поиск узлов по заданным условиям:
  1. <span class=('span') ????? ??? ???? span ?? ????????
  2.  " />('span', 'div') найти как все теги span так и теги div
  3.  <span class=('#test') ????? ??????? ? ???????? ????????????? ????? ????? test
  4.  " />('#test p.marked') найти внутри тега с идентификатором test все абзацы у которых класс равен marked
Теперь попробуем изменять визуальное оформление найденного тега и указать для него новый css класс. Есть три базовые функции: addClass – добавляет класс к элементу, removeClass – удаляет класс с заданным именем от элемента, и toggleClass – чередует класс, если у элемента есть уже класс с указанным именем, то он удаляется, а иначе назначается.
  1. <style> стили
  2.  .user_a {color: red;}
  3.  .user_b {font-size: 14px;}
  4. </style>
  5. <script> назначаем стили
  6.   window.addEvent('domready', function(){
  7.      сначала всем абзацам в странице
  8.     ('p').addClass ('user_a');</pre></li><li class=
         ?????? ?????? ? ???????? id = spec
  9.     $('spec').addClass ('user_b');
  10.   });
  11. </script>
??? ????? css ????????? ???????????? ??? ??????? setStyle ? setStyles. ??????? ? ???, ??? ?????? ?? ??? ???????? ? ???????? ????????? ??? ????????: ??? css-???????? ? ??? ????????, ?????? ?? ??????? ???????? ????? ??????, ????????? ?? ??? ????????-?????????.
  1. " />('p').setStyle ('border', '1px solid red');
  2. $('spec').setStyles (
  3.   {fontWeight: 'bold', fontSize: '30px'}
  4. );
Найдутся и две парные функции getStyle и getStyles – назначение которых получить те css стили, которые привязаны к элементу сейчас.
  1. alert ( $('spec').getStyle('text-decoration')  );
  2. alert ( $('spec').getStyles('text-decoration', 'width')  );
Даже в случае, когда запрошенный параметр не был явно назначен элементу, то он будет вычислен и возвращен из функций getStyle и getStyles. Последнее на сегодня - это как выполнить полную замену содержимого некоторого элемента новой информацией.
  1. $('spec').setHTML('<i>new text</i>');
В следующий раз мы закончим с обязательной программой знакомства с mootools и попробуем создавать всплывающие подсказки, заставим элементы перемещаться и менять свои стилевые параметры в зависимости от времени.