Опубликован: 01.07.2011 | Уровень: для всех | Доступ: платный
Лекция 12:

Анимация в JavaScript

< Лекция 11 || Лекция 12 || Лекция 13 >
Аннотация: Простой пример: метод угасания желтого цвета. Анимация с помощью библиотек JavaScript. Более сложный пример: перемещение и изменение размера. Переходы CSS.

Введение

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

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

Лекция имеет следующее содержание:

  • Простой пример: метод угасания желтого цвета
  • Анимация с помощью библиотек JavaScript
  • Более сложный пример: перемещение и изменение размера
  • Переходы CSS
  • Заключение
  • Контрольные вопросы

Простой пример: метод угасания желтого цвета

Одним из распространенных применений анимации является метод угасания желтого цвета (http://www.37signals.com/svn/archives/000558.php), когда для измененной области на странице задается желтый цвет фона, который затем постепенно снова возвращается к исходному цвету. Это хороший, ненавязчивый способ показать, что что-то изменилось (например, появился дополнительный контент, или какие-то сообщения обратной связи формы), не мешая тому, что делает пользователь. Посмотрите на пример угасания желтого цвета в действии (http://dev.opera.com/articles/view/javascript-animation/yft_pure_js.html).

Принцип в основе угасания состоит в том, что задается желтый цвет фона элемента угасания, а затем, за некоторую последовательность шагов его цвет возвращается к исходному. Поэтому, если исходный цвет фона был красный, то затем цвет задается желтым, затем оранжево-желтым, затем оранжевым, затем красно-оранжевым, и затем красным. Число использованных шагов определяет, насколько плавно происходит изменение цвета, а время между шагами определяет, как долго продолжается изменение цвета. При изменении цвета можно использовать полезный факт из CSS: цвет можно определить как тройку обычных чисел или как шестнадцатеричную строку. Поэтому #FF0000 (красный цвет) можно определить также как rgb(255,0,0). Изменение от желтого цвета до красного за пять шагов означает, поэтому, переход от rgb(255,255,0) (желтый) к rgb(255,0,0) за пять следующих шагов:

rgb(255,255,0)
rgb(255,192,0)
rgb(255,128,0)
rgb(255,64,0)
rgb(255,0,0)

Вы задаете цвет фона элемента как rgb(255,255,0), затем через какое-то время (предположим, 100 миллисекунд), изменяете цвет фона на rgb(255,192,0), а затем через 100 мс задаете цвет фона как rgb(255,128,0), и т.д.:

Цвет Время
rgb(255,255,0)
rgb(255,192,0) 100 мс
rgb(255,128,0) 200 мс
rgb(255,64,0) 300 мс
rgb(255,0,0) 400 мс

Весь процесс занимает 400 мс (меньше чем половина секунды), и получается плавный переход между желтым и красным цветом. Удобно то, что мы изменяем только одну часть цвета (зеленый канал; три части цвета rgb составляют красный, зеленый и синий каналы), но вполне возможно изменение более одного канала. В этом примере значение зеленого канала изменяется от 255 до 0 за четыре шага, что означает изменение его на 64 единицы за каждый шаг.

Включение действия через определенный период времени делается в JavaScript с помощью функций setTimeout и setInterval. Функция setTimeout выполняет действие один раз после определенной временной задержки, setInterval выполняет действие снова и снова через определенную временную задержку, что будет идеально для анимации. По существу тогда, чтобы выполнить это угасание, необходимо определить каждый из шагов, и затем использовать setInterval для их вызова один за другим. Функция setInterval получает два параметра: функцию для вызова в качестве действия, и временную задержку в миллисекундах.

Очевидно, что не всегда требуется изменение от желтого цвета к красному, поэтому функция должна иметь общий вид. Если известны начальный и конечный цвета и число шагов, то изменение цвета на каждом шаге будет определяться обычной математикой. Если определить массив startcolour как список из трех чисел ( [255,255,0] ), а endcolour как аналогичный список ( [255,0,0] ), тогда величина изменения каждого цвета на шаге будет:

var red_change = (startcolour[0] - endcolour[0]) / steps;
var green_change = (startcolour[1] - endcolour[1]) / steps;
var blue_change = (startcolour[2] - endcolour[2]) / steps;

Затем мы используем setInterval для изменения цвета фона элемента на шаге:

var currentcolour = [255,255,0];
var timer = setInterval(function(){
    currentcolour[0] = parseInt(currentcolour[0] - red_change);
    currentcolour[1] = parseInt(currentcolour[1] - green_change);
    currentcolour[2] = parseInt(currentcolour[2] - blue_change);
    element.style.backgroundColor = 'rgb(' + currentcolour.toString() + ')';
}, 50);

На каждом шаге берем currentcolour и изменяем красный канал на величину red_change, зеленый канал на величину green_change, и синий канал на величину blue_change. Затем задаем для реального цвета фона элемента новый цвет: [255,255,0].toString() будет "255,255,0", поэтому мы используем toString() для создания rgb(255,255,0), и задаем это как цвет фона элемента.

Однако функция setInterval будет вызывать функцию действия бесконечно; она не остановится, когда будет достигнут заданный цвет. Чтобы остановить ее, используйте функцию clearInterval() ; следующий код подсчитывает, сколько раз было вызвано действие, и очищает интервал вызова через заданное количество шагов:

var currentcolour = startcolour;
var stepcount = 0;
var timer = setInterval(function(){
    currentcolour[0] = parseInt(currentcolour[0] - red_change);
    currentcolour[1] = parseInt(currentcolour[1] - green_change);
    currentcolour[2] = parseInt(currentcolour[2] - blue_change);
    element.style.backgroundColor = 'rgb(' + currentcolour.toString() + ')';
    stepcount += 1;
    if (stepcount >= steps) {
        element.style.backgroundColor = 'rgb(' + endcolour.toString() + ')';
        clearInterval(timer);
    }
}, 50);

Так и делается анимация: небольшие изменения на одном шаге.

Как задать startcolour и endcolour? Один простой способ состоит в размещении приведенного выше кода в функции fade:

fade: function(element, startcolour, endcolour, time_elapsed) {
   ...приведенный выше код ...
}

а затем можно запускать угасание желтого цвета на элементе с помощью вызова функции следующего вида:

fade(document.getElementById("yft"), [255,255,60], [0,0,255], 750);

или "угасание красного цвета", которое задает для элемента красный цвет и затем угасает до синего (цвет фона элемента), следующим образом:

fade(document.getElementById("yft"), [255,0,0], [0,0,255], 750);

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

Анимация с помощью библиотек JavaScript

Анимация является широко используемым эффектом, и поэтому большинство библиотек JavaScript имеют для нее некоторую поддержку, включая встроенную поддержку для широко распространенной анимации. Например, jQuery (http://jquery.com/) имеет встроенную поддержку для анимации, делающей элемент прозрачным:

$("#myelement").fadeOut();

и функцию animate() для более сложной специальной работы:

$("#block").animate({ 
    width: "70%",
}, 1500 );

Это вполне интуитивно понятно - берется элемент и изменяется атрибут CSS width, в течение 1500 миллисекунд, из исходного текущего состояния до 70% - функция animate описана здесь (http://docs.jquery.com/Effects).

Среда разработки Prototype's scriptaculous (http://script.aculo.us/) предлагает аналогичные средства, такие как Effect.Fade('id_of_element'), и много, много других. Библиотека Yahoo UI (http://developer.yahoo.com/yui/3/animation/) также может создавать аналогичные эффекты:

new Y.Anim({ node: '#demo', to: { width: 70%, }}).run();

Если вы уже использовали в своем коде библиотеки JavaScript, то знаете, что они предлагают значительно более простые средства анимации, чем самостоятельное управление анимацией с помощью setInterval. Однако, я думаю, что важно понимать, что происходит в реальности - это значительно улучшает навыки создания сценариев в долгосрочной перспективе.

Именно поэтому мы рассмотрели пример, начиная с самых первых принципов, прежде чем обращаться к библиотекам.

Дополнительные ресурсы об использовании различных библиотек JavaScript можно найти на сайте dev.opera.com (http://dev.opera.com/articles/view/introduction-to-javascript-toolkits/).

Более сложный пример: перемещение и изменение размера

Хотя метод угасания желтого цвета демонстрирует анимацию, он несколько скучен. Когда большинство людей представляют себе анимацию, они обычно имеют в виду движение. Интересный прием предупреждения пользователя о том, что что-то произошло, не прерывая его рабочего процесса, состоит в немодальном сообщении. Вместо вывода диалогового окна alert(), которое требует от пользователя щелчка на OK, прежде чем он сможет продолжить, поместите сообщение просто в плавающий div на странице, который ненавязчиво остается там, пока не получит подтверждение. Второй достаточно интересной вещью затем может быть предоставление пользователю возможности вернуться к сообщению, для которого он подтвердил желание прочитать его еще раз. Поэтому давайте реализуем плавающее сообщение, которое, после щелчка на нем, "схлопывается" в угол экрана, и затем по щелчку может быть снова восстановлено. Вы можете посмотреть небольшую демонстрацию такого "схлопывающегося сообщения" (http://dev.opera.com/articles/view/javascript-animation/moving_messages_jq.html), чтобы понять общую идею.

Если вы делаете какую-то серьезную анимационную работу, или какую-то серьезную работу с JavaScript, почти всегда стоит использовать библиотеку JavaScript. Это позволит создать требуемое представление для пользователей, не беспокоясь о математических тонкостях, требуемых для выполнения анимации. (Познакомившись с представленным выше первым примером, вы знаете теперь, как выполнить математические вычисления и как использовать setInterval, но вы сохраните время и собственные силы, используя готовые решения.)

Приведенный выше демонстрационный пример использует для работы библиотеку jQuery (http://jquery.com/), но как упоминалось, большинство библиотек предоставляют достаточно похожую концепцию анимации, и поэтому вы сможете реализовать принципиальную часть, используя предпочитаемую библиотеку. По существу, необходимо сделать следующее:

  1. Показать плавающее сообщение в центре экрана
  2. Когда на нем производится щелчок:
    1. Переместить его горизонтальную позицию в крайнее правое положение
    2. Переместить его вертикальную позицию вверх
    3. Задать его ширину равной 20px
    4. Задать его высоту равной 20px
    5. Сделать его плотность равной 20%, так что оно становится почти прозрачно и скрыть в нем текст
  3. Когда выполняется щелчок на этой "мини"-версии сообщения, восстановить его в центре экрана (т.е., обратное тому, что мы делали для его сжатия) и чтобы пользователь получил четкую картину того, что произошло с его сообщением, переход от полноразмерного сообщения к мини-сообщению должен быть анимирован (чтобы они видели, что сообщение "сжалось" в угол окна).

Выполнить анимацию с помощью jQuery очень легко: используйте просто функцию .animate() и предоставьте желательный конечный результат анимации (и как долго она должна выполняться):

$(ourObject).animate({
    width: "20px", height: "20px", top: "20px",
    right: "20px", marginRight: "0px", opacity: "0.2"
  }, 300);

функция получает ourObject и, за 300 миллисекунд, заменяет его ширину и высоту на 20px, его верхнюю и правую позиции на 20px, его свойство стиля margin-right на 0px, и его плотность (в браузерах, которые поддерживают плотность изображения) на 20%. Затем это просто вопрос программирования в стиле jQuery, чтобы получить требуемую анимацию, когда происходит щелчок на сообщении:

$(ourObject.click, function(){
  $(this).animate({
    width: "20px", height: "20px", top: "20px",
    right: "20px", marginRight: "0px", opacity: "0.2"
  }, 300)
});

Для восстановления сообщения, когда на нем снова происходит щелчок, потребуется просто еще один вызов .animate():

$(ourObject).animate({
    width: "400px", height: "75px", top: "50px",
    right: "50%", marginRight: "-200px", opacity: "0.9"
  }, 300);

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

Переходы CSS

Наконец, некоторые (не все) анимации можно в действительности создавать вообще без JavaScript! Safari и другие браузеры на основе Webkit, и Firefox 3.1, могут плавно выполнять переходы от одного значения CSS к другому, не используя JavaScript. Следующий код:

div { opacity: 1; -webkit-transition: opacity 1s linear; }
div:hover { opacity: 0; }

заставит div плавно исчезнуть в течение одной секунды в поддерживающем браузере, когда над ним находится указатель мыши. Однако эти переходы CSS являются очень новыми, и поддерживаются только в самых современных браузерах, поэтому, если требуется, чтобы анимация работала для большей части пользователей, то для этого потребуется использовать сценарии DOM.

Заключение

На этом завершается наш обзор анимации web-страниц с помощью JavaScript - были рассмотрены несколько примеров анимации, созданных, исходя из основных принципов, с помощью функций setTimeout и setInterval, а затем мы рассмотрели, как можно использовать библиотеки JavaScript для более быстрого создания анимации.

Контрольные вопросы

  1. В чем различие между setTimeout и setInterval?
  2. Если бы функция setInterval не существовала, как можно было бы ее эмулировать?
  3. Как можно сделать элемент исчезающим от полной видимости до полной невидимости за 20 шагов в течение 1.5 секунд?
  4. Как можно сделать элемент исчезающим от полной видимости до полной невидимости и затем снова к видимости за 20 шагов в течение 1.5 секунд?

Об авторе


Стюарт Лэнгридж вполне возможно единственный человек в мире, который имеет степень бакалавра по программированию и философии. Когда он не занят с компьютерами, он программист на JavaScript, Django, и Python в компании Canonical (http://www.canonical.com/), автор книги DHTML Utopia (http://www.sitepoint.com/books/dhtml1/) издательства SitePoint, или пьет приличное пиво. Он также составляет одну четвертую команды LugRadio (http://lugradio.org/presenters/), первого в мире радио-шоу, посвященного Free and Open Source Software. Результаты его разносторонних интересов в web, программировании сценариев, создании программного обеспечения с открытым кодом, и всего остального, что проплывает за окном, можно найти по адресу kryogenix.org (http://kryogenix.org/); Стюарта можно встретить на улице в поисках места для курения.

< Лекция 11 || Лекция 12 || Лекция 13 >
Сергей Крупко
Сергей Крупко
Как оплатить курс?
Галина Башкирова
Галина Башкирова
Темы Вкр для проф. переподготовки Профессиональное веб-программирование
Наталья Алмаева
Наталья Алмаева
Россия
Роман Паранин
Роман Паранин
Россия, Ярославль