LeCodesdocs

animate

Одноразовый твин значения на кадровых часах хоста: интерполирует from → to за duration и вызывает onUpdate с текущим значением каждый кадр. Он анимирует значения, а не объекты — значение ты применяешь сам в onUpdate. Для бесконечного покадрового движения используй setLoop (Глобалы хоста).

Обзор

TypeScript
const id = animate({
  from: 0,
  to: 1,
  duration: 400,                     // миллисекунды
  easing: easeOut,
  onUpdate: v => { ghost.opacity = v },
  onComplete: () => console.log('faded in'),
})

Запуск твина

TypeScript
animate({
  from: T,                  // начальное значение
  to: T,                    // конечное значение — его форма выбирает интерполяцию (см. ниже)
  duration: number,         // МИЛЛИСЕКУНДЫ
  onUpdate(val: T): void,   // вызывается каждый кадр с интерполированным значением
  onComplete?(): void,      // вызывается один раз, после финального onUpdate
  easing?: Easing,          // отображает линейный прогресс 0..1; по умолчанию линейный
}): number                  // id анимации для stop/pause/resume
Note

durationмиллисекунды (кадровый dt — секунды; длительности UI .animateTo() тоже в мс). См. Соглашения.

easing получает сырой линейный прогресс 0..1 и возвращает сглаженный — см. Функции сглаживания. onComplete срабатывает, когда прогресс достигает 1; твин, остановленный раньше, его не вызывает.

Виды значений

Форма to выбирает интерполяцию:

to Интерполяция onUpdate получает
number lerp number
массив длины 2 (как Vec2) покомпонентный lerp Float32Array (переиспользуется)
массив длины 3 (как Vec3) покомпонентный lerp Float32Array (переиспользуется)
массив длины 4 (как Quat) slerp кватерниона Float32Array (переиспользуется)
Note

для массивных видов onUpdate получает один и тот же Float32Array каждый кадр — он перезаписывается на месте. Не храни ссылку; копируй ([...v]), если нужно сохранить значение кадра.

Note

массивы длины 4 всегда трактуются как кватернионы (slerp с переворотом полушария) — не анимируй RGBA-кортеж как массив длины 4.

Not implemented

строковые значения (цвета). Ветка цвета в исходнике — мёртвый код (сравнивает значение, а не тип), поэтому строковый to проваливается в проверки длины массива и не даёт ничего полезного — NaN на строках из 2/3/4 символов, полный no-op в остальных случаях. Исключение не бросается. Анимируй цвет, твиня число 0..1 и смешивая два цвета сам в onUpdate.

Управление запущенным твином

TypeScript
stopAnimation(id: number): void     // остановить навсегда — больше нет onUpdate, нет onComplete
pauseAnimation(id: number): void    // заморозить прогресс
resumeAnimation(id: number): void   // продолжить приостановленный твин

animateMat4 — твин матрицы трансформа

TypeScript
animateMat4({
  from: Mat4Like,           // Float32Array | number[], 16 элементов
  to: Mat4Like,
  duration: number,         // миллисекунды
  onUpdate(m: Float32Array): void,
  onComplete?(): void,
  easing?: Easing,
}): number

Поэлементный lerp матрицы дал бы скос; animateMat4 вместо этого раскладывает обе матрицы один раз в момент вызова на позицию / поворот / масштаб, lerp'ит позицию и масштаб, slerp'ит поворот и пересобирает каждый кадр. onUpdate получает переиспользуемый Float32Array из 16 элементов — то же правило «не храни ссылку», что и у векторных видов.

Подводные камни

TypeScript
// ✗ duration в секундах — твин завершится меньше чем за кадр
animate({ from: 0, to: 100, duration: 0.5, onUpdate: v => { node.x = v } })
// ✓ миллисекунды
animate({ from: 0, to: 100, duration: 500, onUpdate: v => { node.x = v } })

// ✗ хранение vec-значения — все записи окажутся одним (финальным) массивом
animate({ from: [0, 0], to: [10, 10], duration: 300, onUpdate: v => path.push(v) })
// ✓ копируй значение кадра
animate({ from: [0, 0], to: [10, 10], duration: 300, onUpdate: v => path.push([...v]) })

Смотрите также