[Перевод] tween.js Руководство пользователя на китайском языке

внешний интерфейс JavaScript CSS three.js
[Перевод] tween.js Руководство пользователя на китайском языке

tween.js Руководство пользователя на английском языке
Сначала посмотрите на пример:hello,tween.js

Что такое твин? как использовать? почему вы хотите его использовать?

твин (анимация) (изin-between) — это концепция, позволяющая плавно изменять свойства объекта. Вы просто сообщаете ему, какие свойства изменить, какие окончательные значения они должны иметь, когда анимация завершится, и сколько времени это займет, а движок анимации позаботится о вычислении значений от начальной точки до конечной точки. .

Например,positionобъект владеетxа такжеyДве координаты:

var position = { x: 100, y: 0 }

если вы хотитеxЗначения координат из100стали200, ты должен сделать:

// 首先为位置创建一个补间(tween)
var tween = new TWEEN.Tween(position);

// 然后告诉 tween 我们想要在1000毫秒内以动画的形式移动 x 的位置
tween.to({ x: 200 }, 1000);

В общем этого мало, твин создан, но не активирован (используется), нужно запустить так:

// 启动
tween.start();

Наконец, чтобы успешно выполнить этот эффект, вам нужно вызвать основную функциюTWEEN.update, используется следующим образом:

animate();

function animate() {
    requestAnimationFrame(animate);
    // [...]
    TWEEN.update();
    // [...]
}

Это будет запускать анимацию при каждом обновлении кадра; через 1 секунду (1000 мс)position.xстанет200.

если вы не печатаете в консолиxзначение, иначе вы не увидите его изменения. вы можете использоватьonUpdateПерезвоните:

tween.onUpdate(function(object) {
    console.log(object.x);
});

Советы: вы можете не получить его здесьobject.x, см. тот, который я упомянул для деталейissue

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

До сих пор мы использовали только анимацию движения для вывода значений на консоль, но вы можете комбинировать это с объектом three.js:

var tween = new TWEEN.Tween(cube.position)
        .to({ x: 100, y: 100, z: 100 }, 10000)
        .start();

animate();

function animate() {
    requestAnimationFrame(animate);
    TWEEN.update();

    threeRenderer.render(scene, camera);
}

В этом случае, поскольку рендерер three.js будет смотреть на положение объекта перед рендерингом, поэтому не используйте явноеonUpdateПерезвоните.

Возможно, вы также заметили нечто другое: tween.js можно связать! каждыйtweenфункция вернетсяtweeninstance, поэтому вы можете переписать следующий код:

var tween = new TWEEN.Tween(position);
tween.to({ x: 200 }, 1000);
tween.start();

Измените его на это:

var tween = new TWEEN.Tween(position)
    .to({ x: 200 }, 1000)
    .start();

Здесь вы увидите множество примеров, так что хорошо бы ознакомиться с ним! Например04-simplestэтот пример.

анимация tween.js

Tween.js не запускается сам по себе. вам нужно явно вызватьupdateметод, чтобы сказать ему, когда бежать. Рекомендуемый способ — сделать это в основном цикле анимации. использоватьrequestAnimationFrameВызовите этот цикл для лучшей производительности графики.

Как и в предыдущем примере:

animate();

function animate() {
    requestAnimationFrame(animate);
    // [...]
    TWEEN.update();
    // [...]
}

Если при вызове не передаются никакие параметры,updateТекущий момент времени будет оцениваться, чтобы определить, сколько времени прошло с момента последнего запуска.

Конечно, вы также можете передать явный параметр времени вupdate

TWEEN.update(100);

Означает «время обновления = 100 мс». Вы можете использовать это, чтобы убедиться, что все связанные со временем функции в вашем коде используют одно и то же значение времени. Например, предположим, что у вас есть проигрыватель, и вы хотите синхронно запустить анимацию движения. твойanimateФункция может выглядеть так:

var currentTime = player.currentTime;
TWEEN.update(currentTime);

Мы используем явные значения времени для модульного тестирования. ты можешь взглянутьtests.jsэтот пример, чтобы увидеть, как мы можем вызывать с разными значениямиTWEEN.update()для имитации течения времени.

контролировать твин

начать и остановить

До сих пор мы узналиTween.startметод, но есть много других способов управления одной анимацией. Пожалуй, самый важный из нихstarСоответствующий метод:停止. Если вы хотите отменить анимацию, просто вызовите этот метод с отдельной анимацией:

tween.stop();

Остановка анимации, которая никогда не запускалась или уже остановилась, не имеет никакого эффекта. Никаких ошибок не выдает.

startметод принимает один параметрtime. Если вы используете его, то твин не запускается сразу до определенного момента, в противном случае он запускается как можно скорее (т.е. при следующем вызовеTWEEN.update).

update

У подростков также есть обновленный метод --- который на самом деле выполняетсяTWEEN.updateназывается. Обычно вам не нужно вызывать его напрямую, если вы не сумасшедший хакер.

chain

Все становится интереснее, когда вы упорядочиваете разные анимации движения, например, начинаете новую анимацию сразу после окончания предыдущей. Мы называем это цепной анимацией, в которой используетсяchainспособ сделать это. Поэтому, чтобы сделатьtweenBсуществуетtewwnAзапускать:

tweenA.chain(tweenB);

Или, для бесконечной цепочки, установите tweenA для запуска, как только tweenB завершится:

tweenA.chain(tweenB);
tweenB.chain(tweenA);

О неограниченном количестве связанных просмотровHello world.

В других случаях может потребоваться связать несколько твинов с другим, чтобы они (связанные твины) начинали анимацию одновременно:

tweenA.chain(tweenB,tweenC);

предупреждение: звонюtweenA.chain(tweenB)На самом деле изменен tweenA, поэтому tweenA всегда запускается после завершения tweenA.chainВозвращаемое значение — просто tweenA, а не новая анимация.

repeat

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

tween.repeat(10); // 循环10次
tween.repeat(Infinity); // 无限循环

Общее количество раз, когда анимация будет повторяться, плюс одна начальная анимация. ПроверитьRepeat.

yoyo

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

delay

Для более сложных расписаний может потребоваться задержка анимации движения перед ее фактическим запуском. вы можете использоватьdelayспособ сделать это

tween.delay(1000);
tween.start();

Начнет выполняться через 1 секунду после вызова метода запуска.

Контролируйте всех подростков

В глобальном объекте TWEEN можно найти следующие методы, кромеupdateКроме того, большинство из этих объектов вообще не требуется использовать.

TWEEN.update(time)

Мы уже обсуждали этот метод. Он используется для обновления всех активных твинов.
еслиtimeЕсли не указано, будет использоваться текущее время.

TWEEN.getAll and TWEEN.removeAll

Используется для получения пар действийtweensссылки на массив и удалить их все из массива всего за один вызов каждый

TWEEN.add(tween) and TWEEN.remove(tween)

Используется для добавления твинов в список активных твинов или для удаления определенных твинов из списка по отдельности.

Эти методы обычно используются только внутри, но раскрываются, если вы хотите сделать что-то интересное.

Группа анимации движения

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

Пример: межкомпонентный конфликт

При использованииTWEENС несколькими компонентами, каждый из которых хочет управлять своим собственным набором твинов, могут возникнуть конфликты. Если компонент вызываетTWEEN.update()илиTWEEN.removeAll(), анимация других компонентов также будет обновлена ​​или удалена.

Создайте свою собственную группу твинов

Для решения этой проблемы каждый компонент может создать свой собственныйTWEEN.Groupэкземпляр (это глобальныйTWEENобъект, используемый для внутреннего использования). При создании новой анимации эти группы можно передать в качестве второго необязательного параметра:

var groupA = new TWEEN.Group();
var groupB = new TWEEN.Group();

var tweenA = new TWEEN.Tween({ x: 1 }, groupA)
    .to({ x: 10 }, 100)
    .start();

var tweenB = new TWEEN.Tween({ x: 1 }, groupB)
    .to({ x: 10 }, 100)
    .start();

var tweenC = new TWEEN.Tween({ x: 1 })
    .to({ x: 10 }, 100)
    .start();

groupA.update(); // 只更新tweenA
groupB.update(); // 只更新tweenB
TWEEN.update(); // 只更新tweenC

groupA.removeAll(); // 只移除tweenA
groupB.removeAll(); // 只移除tweenB
TWEEN.removeAll(); // 只移除tweenC

Таким образом, каждый компонент может создавать, обновлять и уничтожать собственный набор твинов.

Изменить функцию смягчения

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

tween.easing(TWEEN.Easing.Quadratic.In);

Это приведет к тому, что изменение начнется медленно к конечному значению, ускорится к середине, а затем быстро достигнет своего конечного значения, и наоборот,TWEEN.Easing.Quadratic.OutСначала он ускоряется, но в конечном итоге замедляется по мере приближения значения.

Доступные функции плавности: TWEEN.Easing

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

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

Эти функции получены из уравнения Роберта Пеннера, которое служит исходным уравнением, предоставленным в качестве бесплатного программного обеспечения несколько лет назад, но оптимизированным для работы с JavaScript.

Использовать пользовательское смягчение

Вы можете не только использовать любую существующую функцию, но также можете предоставить свою собственную, если вы следуете некоторым соглашениям:

  • Он должен принимать один параметр:
    • k: процесс смягчения или как долго длится наша анимация. Допустимые значения находятся в диапазоне [0, 1].
  • Он должен возвращать значение на основе входного параметра.

Функция смягчения вызывается только один раз для каждого обновления, независимо от того, сколько свойств изменяется. Затем используйте результат с начальным значением и дельтой между этим значением и окончательным значением, как этот псевдокод:

easedElapsed = easing(k);
for each property:
    newPropertyValue = initialPropertyValue + propertyDelta * easedElapsed;

Для тех, кто больше заботится о производительности: вызовите только tweenstart()Значение приращения рассчитывается только при .

Итак, допустим, вы хотите использовать пользовательскую функцию плавности, которая уменьшает значение, но применяет Math.floor к выходным данным, поэтому возвращается только целая часть, что приводит к своего рода цепочке вывода:

function tenStepEasing(k) {
    return Math.floor(k * 10) / 10;
}

Вы можете использовать его, просто вызвав его метод смягчения, как мы видели ранее:

tween.easing(tenStepEasing);

Проверитьgraphs for custom easing functionsпример, чтобы увидеть это в действии (и немного метапрограммирования для генерации пошаговых функций).

Перезвоните

Еще одна мощная функция — возможность запуска собственных функций в определенное время в жизненном цикле каждой анимации. Это часто требуется, когда изменения свойств недостаточно.

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

var trickyObjTween = new TWEEN.Tween({
    propertyA: trickyObj.getPropertyA(),
    propertyB: trickyObj.getPropertyB()
})
    .to({ propertyA: 100, propertyB: 200 })
    .onUpdate(function(object) {
        object.setA( object.propertyA );
        object.setB( object.propertyB );
    });

Или представьте, что вы хотите воспроизвести звук при запуске анимации. вы можете использоватьstartПерезвоните:

var tween = new TWEEN.Tween(obj)
    .to({ x: 100 })
    .onStart(function() {
        sound.play();
    });

Областью действия каждого обратного вызова является объект анимации, в данном случаеobj.

onStart

Выполнить перед запуском твина -- т.е. перед вычислением. Каждая анимация может быть выполнена только один раз, т.е. при передачеrepeat()Когда анимация повторяется, она не запускается.

Замечательно синхронизироваться с другими событиями или инициировать действия, которые вы хотите выполнить при запуске анимации.

Объект tween передается в качестве первого аргумента.

onStop

когда прошелstop()Явно останавливает выполнение анимации во время, но выполняет анимацию, когда она завершается нормально и до остановки любых возможных анимаций цепочки.

Объект tween передается в качестве первого аргумента.

onUpdate

Выполняется каждый раз, когда обновляется анимация, фактическое обновленное значение.

Объект tween передается в качестве первого аргумента.

onComplete

Выполняется, когда анимация завершается нормально (т. е. не останавливается).

Объект tween передается в качестве первого аргумента.

Расширенный твин

относительное значение

использоватьtoметод, вы также можете использовать относительные значения. Когда tween запускается, Tween.js считывает текущее значение свойства и применяет относительное значение для определения нового конечного значения.
Но вам нужно использовать кавычки, иначе значения будут считаться абсолютными. Давайте посмотрим на пример:

// This will make the `x` property be 100, always
var absoluteTween = new TWEEN.Tween(absoluteObj).to({ x: 100 });

// Suppose absoluteObj.x is 0 now
absoluteTween.start(); // Makes x go to 100

// Suppose absoluteObj.x is -100 now
absoluteTween.start(); // Makes x go to 100

// In contrast...

// This will make the `x` property be 100 units more,
// relative to the actual value when it starts
var relativeTween = new TWEEN.Tween(relativeObj).to({ x: "+100" });

// Suppose relativeObj.x is 0 now
relativeTween.start(); // Makes x go to 0 +100 = 100

// Suppose relativeObj.x is -100 now
relativeTween.start(); // Makes x go to -100 +100 = 0

Проверить09_relative_valuesПример.

массив значений анимации

В дополнение к тому, что tween может быть абсолютным или относительным, также возможно изменение свойств Tween.js в диапазоне значений. Для этого вам просто нужно указать массив значений, а не одно значение для свойства. Например:

var tween = new TWEEN.Tween(relativeObj).to({ x: [0, -100, 100] });

сделаюxИзмените исходное значение на 0, -100 и 100.

Эти значения рассчитываются следующим образом:

  • Во-первых, прогресс анимации рассчитывается как обычно.
  • Прогресс (от 0 до 1) используется в качестве входных данных для функции интерполяции.
  • Генерировать интерполированные значения на основе массива прогресса и значений

Например, когда анимация только началась (прогресс равен 0), функция интерполяции вернет первое значение в массиве. Когда анимация будет наполовину выполнена, функция интерполяции вернет значение, которое находится примерно в середине массива, а когда анимация закончится, функция интерполяции вернет последнее значение.

Вы можете использовать метод интерполяции, чтобы изменить функцию интерполяции. Например:

tween.interpolation( TWEEN.Interpolation.Bezier );

Доступны следующие значения:

  • TWEEN.Interpolation.Linear
  • TWEEN.Interpolation.Bezier
  • TWEEN.Interpolation.CatmullRom

По умолчаниюLinear.

Обратите внимание, что функция интерполяции является глобальной для всех свойств анимации движения с массивом в той же анимации движения. Вы не можете использовать массив и линейную функцию для изменения свойства A, а также использовать одну и ту же анимацию для внесения изменений в свойство B массива B и функцию Безье; вы должны использовать два объекта с анимацией, которые работают с одним и тем же объектом, но изменяют разные свойства и использовать другую функцию интерполяции.

Проверить06_array_interpolationПример.

Получите лучшую производительность

Пока Tween.js пытается реализовать себя, ничто не мешает вам использовать его непродуктивным образом. Вот несколько способов избежать замедления вашего проекта при использовании Tween.js (или при анимации на веб-странице).

Используйте высокопроизводительный CSS

Когда вы пытаетесь установить положение элемента на странице, самым простым решением являетсяtopа такжеleftСвойство анимируется следующим образом:

var element = document.getElementById('myElement');
var tween = new TWEEN.Tween({ top: 0, left: 0 })
    .to({ top: 100, left: 100 }, 1000)
    .onUpdate(function(object) {
        element.style.top = object.top + 'px';
        element.style.left = object.left + 'px';
    });

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

var element = document.getElementById('myElement');
var tween = new TWEEN.Tween({ top: 0, left: 0 })
    .to({ top: 100, left: 100 }, 1000)
    .onUpdate(function(object) {
        element.style.transform = 'translate(' + object.left + 'px, ' + object.top + 'px);';
    });

Если вы хотите узнать об этом больше, заглянитеэта статья.

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

против сборщика мусора (псевдоним GC)

Если вы используете функцию обратного вызова onUpdate, вам нужно использовать ее очень осторожно. Поскольку эта функция вызывается много раз в секунду, вы можете заблокировать основной поток с ужасными результатами, если каждое обновление стоит дорого или если ваша операция включает выделение памяти, сборку мусора. Устройство работает слишком часто, что также приводит к результатам. Так что просто не делайте ни одной из этих вещей. Держите свои обратные вызовы onUpdate очень легкими и обязательно используйте профилировщик памяти при разработке.

сумасшедший подросток

Это то, что вы можете не использовать очень часто, но вы можете использовать формулы анимации вне Tween.js. В конце концов, это всего лишь функции. Таким образом, вы можете использовать их для вычисления гладких кривых в качестве входных данных.
Например, они используются вэтот экспериментдля создания аудиоданных.