|
Documentation
Описание библиотеки и принципов работы с ней
Featured Зачем это нужноВ интернете сейчас существует много готовых фреймворков для анимации: практически все современные JavaScript-библиотеки (jQuery, prototype/script.aculo.us, dojo, Ext и т.д.) умеют с ней работать. Почему же потребовалось создавать еще один? Во-первых, практически все существующие библиотеки направлены на анимацию только HTML-элементов. Во-вторых, большинство из них принудительно выставляют некоторые CSS-свойства (overflow, display) у элементов, что может привести к непредсказуемым последствиям. Ну и, наконец, зачастую с этими анимациями нельзя нормально работать (например, в jQuery нельзя запустить одновременно несколько анимаций одного и того же объекта). Это неудивительно: все они создавались с учетом того, что пользователю будет предоставлено несколько заготовленных эффектов (например, раздвинуть блок под размер контента) и что этот самый пользователь не захочет вникать в тонкости работы эффектов. Поэтому у меня и возникла мысль написать свою библиотеку — jTweener, которая будет такой же простой в использовании, как и современные JavaScript-библиотеки, но в то же время даст разработчику полный контроль над анимациями. Первая анимацияСоздадим нашу первую анимацию на jTweener: переместим элемент с id="sample" вправо в значение 300px и вниз в значение 200px: jTweener.addTween(
document.getElementById(‘sample’),
{
left: 300,
top: 200
}
);Как видно из примера, существует объект jTweener, в котором определен ряд методов, один из которых — addTween(). Это самый главный метод для создания анимаций. Он принимает два аргумента. Первый — это объект (или массив объектов), который нужно анимировать. Это может быть как обычный JavaScript объект, так и HTML-элемент (в последнем случае будут изменяться CSS-свойства элемента). Второй аргумент — это объект (хэш), который содержит параметры анимации: свойства объекта, которые нужно анимировать, и настройки самой анимации. В версии 0.2 был добавлен специальный «фасад» $t, который предназначен для удобства работы с анимациями. При использовании фасада пример выглядел бы так:
Глядя на этот пример, может возникнуть вопрос: мы указали конечные значения свойств, а где указывать начальные? Их указывать совсем необязательно: jTweener сам попытается их определить. В случае с HTML-элементом он попытается определить текущие CSS-свойства. Однако он не всегда сделает это правильно (особенно когда свойства указываются в единицах, отличных от пикселей). Поэтому иногда рекомендуется выставлять начальные свойства принудительно: var elem = document.getElementById(‘sample’);
// ставим начальное значение анимируемого свойства
elem.style.left = '100px';
// запускаем анимацию
jTweener.addTween(elem, {left: 400});Объект переместится вправо из точки 100px в точку 400px. Итак, мы научились создавать простую анимацию, теперь попробуем изменить ее свойства: скорость, закон изменения параметра, задержка перед началом и т.д. За эти настройки отвечает ряд предопределенных свойств в хэше параметров:
По умолчанию все анимации длятся одну секунду и свойства объекта меняются с замедлением по экспоненте ('easeoutexpo'). Давайте сделаем так, чтобы анимация длилась три с половиной секунды, свойства объекта менялись с кубическим ускорением, а само действие запустилось только через одну секунду: jTweener.addTween(
document.getElementById('sample'),
{
left: 300,
top: 200,
time: 3.5,
transition: 'easeincubic',
delay: 1
}
);Хочу сразу обратить внимание на параметр delay — это довольно мощное и удобное средство для создания последовательностей анимаций. Давайте заставим наш объект двигаться вдоль квадрата: var elem = document.getElementById(‘sample’);
jTweener.addTween(elem, {left: 200, time: 2});
jTweener.addTween(elem, {top: 200, time: 2, delay: 2});
jTweener.addTween(elem, {left: 0, time: 1, delay: 4});
jTweener.addTween(elem, {top: 0, time: 2, delay: 5});В этом примере значение параметра delay равно сумме параметров time предыдущих анимаций. Меняя парамтры time и delay можно очень легко добиваться интересных эффектов. Анимация цветаПри анимации HTML-элемента следующие свойства воспринимаются как цветовые: backgroundColor, borderColor, borderBottomColor, borderLeftColor, borderRightColor, borderTopColor, color, outlineColor. То есть при анимации одного из этих CSS-свойств jTweener ожидает в качестве конечного значения именно цвет, который может быть в одном из следующих форматов: rgb(100, 230, 50), rgb(100%, 45%, 99%), #ffcc00, #fc0. jTweener.addTween(
document.getElementById(‘sample’),
{
backgroundColor: ‘#00cf00’
}
);Анимация прозрачностиС помощью jTweener можно анимировать прозрачность элемента, за это отвечает свойство opacity, значение которого может быть от 0 до 1. Для IE автоматически будет использован фильтр Alpha, а также принудительно выставлено CSS-свойство zoom. jTweener.addTween(
document.getElementById('sample'),
{
opacity: 0.3
}
);Getter/setterКак было упомянуто вначале, jTweener может анимировать не только HTML-элементы, но и обычные JavaScript объекты. Как правило, от простого изменения свойства объекта толку мало: нужно как-то визуально отразить это изменение, для чего необходимо вызвать какую-нибудь функцию. К сожалению, в JavaScript нет возможности объявить getter/setter функции для свойств объекта (это такие функции, которые автоматически вызываются при получении/установке значения свойства объекта). В jTweener для этих целей можно воспользоваться параметром onUpdate, но есть более изящное решение. В jTweener используется следующее соглашение: если анимируемое свойство объекта является функцией, то вызов этой функции без аргументов должен работать как getter, а вызов функции с одним аргументом — как setter. Рассмотрим пример. Предположим, нам необходимо двигать какой-то элемент с ускорением и замедлением по окружности. Для этого нам нужно одновременно менять top и left свойства HTML-элемента. Можно написать специальную анимационную функцию для каждой координаты и запустить параллельно две анимации. Но это довольно сложно и требует хорошей математической подготовки. Есть более элегантное решение этой задачи: мы создадим объект, в котором будем менять угловую скорость, а при изменении этого параметра будем считать left и top координаты элемента. var circle = {
obj: document.getElementById(‘sample’),
r: 100, //радиус окружности
a: 0, // текущий угол
/** угловая скорость */
angle: function(){
if (!arguments.length) {
// нет аргументов — работаем как getter
return this.a;
} else {
// есть аргумент — работаем как setter
this.a = arguments[0];
// переводим угол из градусов в радианы
var a = this.a / 180 * Math.PI;
// считаем новые координаты
this.obj.style.left = Math.sin(a) * this.r;
this.obj.style.top = Math.cos(a) * this.r;
}
}
};
jTweener.addTween(circle, {
angle: 360, // полный оборот
transition: 'easeintoutexpo'
});Процентная анимацияЭто особый вид уличной магии анимации, когда анимируемое свойство является функцией. Чем-то похоже на Getter/setter, только функция всегда используется как setter. Это очень удобное упрощение getter/setter соглашения:
Добавить такую анимацию можно двумя способами:
var from_x = 100, to_x = 250;
jTweener.addTween(
document.getElementById('sample'),
{
time: 2,
transition: 'easeoutcubic',
top: 100,
moveX: function(value){
// значение переменной value в диапазоне от 0 до 1
this.style.left = (from_x + (to_x - from_x) * value) + 'px'
}
}
);
var from_x = 100, to_x = 250;
var obj = document.getElementById('sample');
jTweener.addPercent(
{
time: 2,
transition: 'easeoutcubic',
moveX: function(value){
// значение переменной value в диапазоне от 0 до 1
obj.style.left = (from_x + (to_x - from_x) * value) + 'px'
}
}
);Процентная анимация используется, как правило, в сложных ситуациях, например, движение вдоль кривой Безье: // определяем конечные и контрольные точки кривой Безье
var from_x = 100, from_y = 340;
var to_x = 280, to_y = 340;
var cp1_x = 390, cp1_y = 75;
var cp2_x = 30, cp2_y = 75;
// объект, который будем анимировать
var obj = document.getElementById('sample');
jTweener.addPercent(
{
bezier: function(t){
// у jTweener есть встроенные функции для работы с кривыми Безье
var x = jTweener.Utils.bezier3(t, from_x, cp1_x, cp2_x, to_x);
var y = jTweener.Utils.bezier3(t, from_y, cp1_y, cp2_y, to_y);
obj.style.left = x + 'px';
obj.style.top = y + 'px';
},
time: 2,
transition: 'easeinoutcubic'
}
);
Относительное изменение свойствИногда необходимо делать не абсолютное, а относительное изменение свойств анимируемых объектов, то есть делать изменение относительно текущего значения свойства. Для этого перед значением свойства нужно поставить '+=' или '-=': jTweener.addTween(
document.getElementById(‘sample’),
{
left: '+=100'
}
);Тем самым мы скажем: «переместись вправо на 100 пикселей относительно текущего положения». Анимация групп объектовСобственно, это то, ради чего писалась эта библиотека. Рассмотрим следующую ситуацию. Предположим, мы решили использовать canvas для того, чтобы рисовать какие-то элементы на странице, и нам нужно использовать анимацию: необходимо перемещать 5 прямоугольников на холсте. Canvas работает по следующему принципу: для показа нового изображения нужно сначала очистить весь холст, а потом отрисовать все элементы. Если мы будем использовать параметр onUpdate, изображение будет перерисовываться столько раз, сколько у нас анимируемых объектов (в нашем случае — 5), что крайне негативно скажется на производительности. В идеале нужно сначала изменить координаты всех прямоугольников, после чего один раз все перерисовать. В библиотеке JSTweener, которую я взял за основу, эта задача решалась следующим образом: перекрывался основной метод eventLoop, который отвечал за один проход анимации всех объектов. Но тут возникает другая проблема: если на текущей странице библиотека используется для анимации других объектов, не связанных с canvas, изображение все равно будет постоянно перерисовываться, хотя там не происходит никаких изменений. Что, опять же, приведет к снижению производительности. Для решения этой проблемы в jTweener было введено такое понятие, как пространство имен (namespace). По умолчанию все анимации работают в пространстве имен default, но при необходимости его можно переопределить для каждой анимации в помощью параметра namespace. А затрем с помощью метода addNSAction() указать функции, который будут выполняться за один проход анимации всех объектов из указанного пространства имен (свойство onUpdate) либо после завершения всех анимаций из этого пространства (свойство onComplete). Если рассматривать наш пример с canvas, то нам всего лишь необходимо выделить все анимации прямоугольников в отдельное пространство имен, а затем добавить действие по перерисовке этих прямоугольников за каждый проход анимации. // описываем прямоугольники
var rects = [
{x: 0, y: 0, width: 10, height: 10, color: '#c279ff'},
...
];
// Функция рисования
function draw(){
...
}
// регистрируем функцию перерисовки в пространстве имен
jTweener.addNSAction({onUpdate: draw}, 'canvas');
// анимируем объекты
for (var i = 0; i < rects.length; i++) {
jTweener.addTween(rects[i], {
x: Math.random() * 200,
y: Math.random() * 200,
namespace: 'canvas'
});
}Удаление анимацийАнимации удаляются с помощью функции removeTween(), которая имеет несколько вариантов использования:
var obj = document.getElementById('anim_item');
jTweener.addTween(obj, {left: 200});
document.getElementById('stop_button').onclick = function(){
jTweener.removeTween(obj);
}Более подробное описание методов jTweener вы можете найти в jsdoc-файле с документацией. |
надо разобратся на досуге...
Офигенная библиотека, спасибо авторам!
Очень интересно, в чем преимущество перед тем же scriptaculous?
почему oncomplete срабатывает также и при старте анимации?
можете прислать пример?
neolord.tmb >> Очевидно же...
Круто конечно, только редко нужно (:
Сергей, огромное спасибо вам за библиотеку!