Источник изображения:aescripts.com/bodymovin/
Автор этой статьи:Цинчжоу
предисловие
LottieЭто решение для сложной покадровой анимации, которое обеспечивает поток инструментов от дизайнеров, использующих AE (Adobe After Effects), до разработчиков на всех концах для достижения анимации. После того, как дизайнер завершит анимацию через AE, можно использовать расширение для AEBodymovinЭкспортируйте данные анимации в формате JSON, а затем разработчики могут преобразовать сгенерированные данные JSON в анимацию через Lottie.
1. Как реализовать анимацию Lottie
- Дизайнеры используют AE для создания анимации.
- Анимация экспортируется в файл данных JSON через подключаемый модуль AE Bodymovin, предоставленный Lottie.
- Загрузка библиотеки Lottie в сочетании с файлом JSON и следующими строками кода может реализовать анимацию Lottie.
import lottie from 'lottie-web';
import animationJsonData from 'xxx-demo.json'; // json 文件
const lot = lottie.loadAnimation({
container: document.getElementById('lottie'),
renderer: 'svg',
loop: true,
autoplay: false,
animationData: animationJsonData,
});
// 开始播放动画
lot.play();
Другие анимированные шаблоны JSON можно посмотретьlottiefiles.com/
2. Интерпретация формата данных файла JSON
Я сам сделал Lottie Demo ->нажмите на меня, чтобы просмотреть
- от 0 до 3 с,
scale
Значение атрибута изменено со 100% до 50%. - от 3с до 6с,
scale
Значение свойства меняется с 50% на 100% для завершения анимации.
Структура данных JSON, экспортированная через плагин Bodymovin, показана на следующем рисунке:
Подробную информацию в формате JSON можно просмотреть в разделе Демонстрация. Названия информации в формате JSON относительно лаконичны, и с первого взгляда их может быть трудно понять. Далее я буду интерпретировать его в сочетании с демонстрацией, которую сделал сам.
2.1 Глобальная информация
Слева находится информация, которую необходимо заполнить для создания новой композиции анимации с использованием AE, которая соответствует первому слою информации JSON справа следующим образом:
-
w
а такжеh
: ширина 200, высота 200 -
v
: Плагин Bodymovin версии 4.5.4 -
fr
:частота кадров 30fps -
ip
а такжеop
: начальный кадр 0, конечный кадр 180 -
assets
: Статическая информация о ресурсах (например, изображения) -
layers
: информация о слое (каждый слой и информация о действии в анимации). -
ddd
: Это 3D -
comps
: Синтетический слой
вfr
,ip
,op
Это особенно важно в процессе анимации Lottie.Как упоминалось ранее, наша демонстрационная анимация составляет 0–6 с, но Lottie рассчитывает время анимации по частоте кадров. Частота кадров, установленная в демонстрации, составляет 30 кадров в секунду, поэтому 0–6 с эквивалентны 0–180 кадрам.
2.2 Информация, относящаяся к уровню
Поняв внешнюю информацию JSON, давайте расширим и посмотрим на JSON.layers
конкретная информация, сначалаdemoДетали анимации следующие:
В основном это 3 направления:
- Область содержимого, которая содержит такую информацию, как размер, положение и округлость слоя формы.
- Область изменения, содержит 5 свойств изменения (точка привязки, положение, масштаб, вращение, непрозрачность).
- Увеличьте 3 кадра (зеленая область на картинке) и измените свойства масштабирования на кадры 0, 90 и 180. На картинке показан 90-й кадр, а слой увеличен до 50%.
В соответствии с информацией о производстве анимации на рисунке выше, это может соответствоватьlayers
. Как показано ниже:
2.3 Информация об изменении атрибута
см. далееks
(изменить свойство) вs
Развернуть, то есть увеличить информацию.
в:
-
t
Представляет количество ключевых кадров -
s
Представляет до изменения (слой двумерный, поэтому третье значение зафиксировано на 100). -
e
После изменения представления (слой двумерный, поэтому третье значение фиксируется равным 100).
3. Как Lottie перемещает данные JSON
Значение данных в формате JSON было кратко рассмотрено ранее, так как же Lottie перемещает данные JSON? Затем прочитайте исходный код демо-версии Lottie, будет отображаться только часть исходного кода, ключ в том, чтобы прояснить идею, не придерживаться исходного кода.
Следующее введение в исходный код в основном разделено на 2 части:
- Инициализация анимации (разделы 3.1 - 3.3)
- Воспроизведение анимации (раздел 3.4)
3.1 Инициализация средства визуализации
Такие какDemoпоказано, Лотти проходитloadAnimation
метод для инициализации анимации. Процесс инициализации рендерера выглядит следующим образом:
function loadAnimation(params){
// 生成当前动画实例
var animItem = new AnimationItem();
// 注册动画
setupAnimation(animItem, null);
// 初始化动画实例参数
animItem.setParams(params);
return animItem;
}
function setupAnimation(animItem, element) {
// 监听事件
animItem.addEventListener('destroy', removeElement);
animItem.addEventListener('_active', addPlayingCount);
animItem.addEventListener('_idle', subtractPlayingCount);
// 注册动画
registeredAnimations.push({elem: element, animation:animItem});
len += 1;
}
-
AnimationItem
Этот класс является базовым классом для анимации Lottie.loadAnimation
метод сначала сгенерируетAnimationItem
Экземпляр и возврат, разработчик используетПараметры и методы конфигурациииз этого класса. -
генерировать
animItem
После экземпляра позвонитеsetupAnimation
метод. Этот метод сначала прослушиваетdestroy
,_active
,_idle
Три события ожидают запуска. Поскольку несколько анимаций могут быть распараллелены, определяется глобальная переменнаяlen
,registeredAnimations
и т. д., для оценки и кэширования зарегистрированных экземпляров анимации. -
Следующий звонок
animItem
примерsetParams
метод для инициализации параметров анимации, кроме initializeloop
,autoplay
Помимо прочих параметров, самое главное — выбрать рендерер. следующим образом:
AnimationItem.prototype.setParams = function(params) {
// 根据开发者配置选择渲染器
switch(animType) {
case 'canvas':
this.renderer = new CanvasRenderer(this, params.rendererSettings);
break;
case 'svg':
this.renderer = new SVGRenderer(this, params.rendererSettings);
break;
default:
// html 类型
this.renderer = new HybridRenderer(this, params.rendererSettings);
break;
}
// 渲染器初始化参数
if (params.animationData) {
this.configAnimation(params.animationData);
}
}
Lottie предоставляет три режима рендеринга: SVG, Canvas и HTML, обычно используя первый или второй.
-
Средство визуализации SVG поддерживает большинство функций и является наиболее часто используемым методом визуализации. И SVG масштабируется, без искажений при любом разрешении.
-
Визуализатор Canvas непрерывно перерисовывает объекты каждого кадра в соответствии с данными анимации.
-
Визуализатор HTML ограничен своими функциями и поддерживает наименьшее количество функций: он может отображать только очень простую графику или текст и не поддерживает эффекты фильтров.
Каждый рендерер имеет свою реализацию и сложность, но чем сложнее анимация, тем выше потребление производительности, что зависит от реальной ситуации. Исходный код рендерера находится вplayer/js/renderers/Демонстрация в этой статье под папкой анализирует только реализацию анимации рендеринга SVG. Поскольку три рендерера основаны наBaseRenderer
класс, поэтому следующее, кромеSVGRenderer
также появляютсяBaseRenderer
метод класса.
3.2 Инициализация свойств анимации и загрузка статических ресурсов
Убедившись, что средство визуализации SVG используется, вызовитеconfigAnimation
метод для инициализации рендерера.
AnimationItem.prototype.configAnimation = function (animData) {
if(!this.renderer) {
return;
}
// 总帧数
this.totalFrames = Math.floor(this.animationData.op - this.animationData.ip);
this.firstFrame = Math.round(this.animationData.ip);
// 渲染器初始化参数
this.renderer.configAnimation(animData);
// 帧率
this.frameRate = this.animationData.fr;
this.frameMult = this.animationData.fr / 1000;
this.trigger('config_ready');
// 加载静态资源
this.preloadImages();
this.loadSegments();
this.updaFrameModifier();
// 等待静态资源加载完毕
this.waitForFontsLoaded();
};
В этом методе будут инициализированы дополнительные свойства объекта анимации, такие как общее количество кадров.totalFrames
, частота кадровframeMult
Ждать. Затем загрузите некоторые другие ресурсы, такие как изображения, шрифты и т. д. Как показано ниже:
в то же времяwaitForFontsLoaded
В методе дождитесь загрузки статического ресурса, а затем вызовите средство визуализации SVG.initItems
Метод отрисовывает слой анимации, то есть анимация отрисовывается.
AnimationItem.prototype.waitForFontsLoaded = function(){
if(!this.renderer) {
return;
}
// 检查加载完毕
this.checkLoaded();
}
AnimationItem.prototype.checkLoaded = function () {
this.isLoaded = true;
// 初始化所有元素
this.renderer.initItems();
setTimeout(function() {
this.trigger('DOMLoaded');
}.bind(this), 0);
// 渲染第一帧
this.gotoFrame();
// 自动播放
if(this.autoplay){
this.play();
}
};
существуетcheckLoaded
Как видно из метода, поinitItems
После того, как все элементы инициализированы, перейдитеgotoFrame
Рендеринг первого кадра, если он настроен разработчикомautoplay
дляtrue
, он будет напрямую вызыватьplay
способ играть. Здесь хорошо иметь впечатление, и я расскажу об этом подробно позже. посмотрим дальшеinitItems
Детали реализации.
3.3 Отрисовка начального слоя анимации
initItems
Метод в основном заключается в вызовеbuildAllItems
Создайте все слои.buildItem
метод будет вызван сноваcreateItem
Определите конкретный тип слоя. Исходный код метода здесь разделен на более мелкие детали. В этой статье сохранены толькоcreateItem
метод, другие заинтересованные могут просмотреть детали исходного кода.
При создании анимации дизайнеры манипулируют множеством элементов слоев, таких как изображения, фигуры, текст и т. д. такlayers
Там будет поле для каждого слоя вty
различать. комбинироватьcreateItem
С точки зрения методов, существует в общей сложности следующие 8 типов.
BaseRenderer.prototype.createItem = function(layer) {
// 根据图层类型,创建相应的 svg 元素类的实例
switch(layer.ty){
case 0:
// 合成
return this.createComp(layer);
case 1:
// 固态
return this.createSolid(layer);
case 2:
// 图片
return this.createImage(layer);
case 3:
// 兜底空元素
return this.createNull(layer);
case 4:
// 形状
return this.createShape(layer);
case 5:
// 文字
return this.createText(layer);
case 6:
// 音频
return this.createAudio(layer);
case 13:
// 摄像机
return this.createCamera(layer);
}
return this.createNull(layer);
};
Поскольку автор и большинство разработчиков не являются профессиональными игроками в AE, не нужно беспокоиться о том, что представляет собой каждый тип, просто уточните основные идеи. В сочетании с авторской демонстрацией есть только один слой, а слойty
4 . ЯвляетсяShape
слой формы, поэтому во время инициализации слоя выполняется толькоcreateShape
метод.
Логика рендеринга для других типов слоев, таких какImage
,Text
,Audio
И так далее, логика отрисовки каждого элемента реализована в исходном кодеplayer/js/elements/Под папкой конкретная логика реализации здесь не будет развернута, и заинтересованные учащиеся могут просмотреть ее самостоятельно.
Следующим шагом является выполнениеcreateShape
метод для инициализации свойств, связанных с элементом.
Помимо некоторых деталей метода инициализации, стоит отметить, чтоinitTransform
метод.
initTransform: function() {
this.finalTransform = {
mProp: this.data.ks
? TransformPropertyFactory.getTransformProperty(this, this.data.ks, this)
: {o:0},
_matMdf: false,
_opMdf: false,
mat: new Matrix()
};
},
использоватьTransformPropertyFactory
правильноtransform
Инициализация в сочетании с 0-м кадром Demo соответствует следующему:
- Непрозрачность 100%
- Масштаб 100%
transform: scale(1);
opacity: 1;
Итак, почему вам нужно инициализировать при инициализации слоя рендеринга?transform
а такжеopacity
Шерстяная ткань? Ответ на этот вопрос будет дан в разделе 3.4.
3.4 Воспроизведение анимации Lottie
Прежде чем анализировать воспроизведение анимации исходного кода Lottie, давайте вспомним ее. Настройки анимации авторской Демо:
- от 0 до 3 с,
scale
Значение атрибута изменено со 100% до 50%. - от 3с до 6с,
scale
Значение атрибута изменено с 50% на 100%.
Если вы сделаете изменение в 3 с в соответствии с этой настройкой, анимация будет слишком жесткой. Поэтому дизайнер установил частоту кадров 30 кадров в секунду, что означает каждые 33,3 мс.РазнообразиеСделайте анимацию не слишком жесткими. Так как добиться этогоРазнообразие, который упоминается в разделе 3.3transform
а такжеopacity
.
5 свойств изменения, упомянутых в разделе 2.2 (точка привязки, положение, масштаб, вращение, непрозрачность). где непрозрачность передается через CSSopacity
контролировать остальные 4 (точка привязки, положение, масштаб, вращение) черезtransform
изmatrix
контролировать. Фактические начальные значения в Демо автора следующие:
transform: matrix(1, 0, 0, 1, 100, 100);
/* 上文的 transform: scale(1); 只是为了方便理解*/
opacity: 1;
Это связано с тем, что такие свойства, как вращение или масштабирование, в основном применяютсяtransform
изmatrix()
метод, поэтому Лотти использует его единообразноmatrix
иметь дело с. Обычно разработчики используют что-то вродеtransform: scale
Эта форма выражения просто потому, что ее легче понять, запомнить и начать.matrix
Соответствующие знания можно получить у г-на Чжан Синьсюя.Понимание Matrix в преобразованиях CSS3.
Таким образом, процесс воспроизведения анимации Lottie может бытьвременныйРезюме:
- Рендеринг слоев, инициализация всех слоев
transform
а такжеopacity
- Рассчитать каждый кадр (33,3 мс на 33 мс) в соответствии с частотой кадров 30 кадров в секунду
transform
а такжеopacity
и изменить DOM
Но как Lottie контролирует интервал 30 кадров в секунду? Что если дизайнер установит 20 кадров в секунду или 40 кадров в секунду? в состоянии пройтиsetTimeout
,setInterval
Пойми? Возьмите эту задачу, чтобы увидеть, как обрабатывается исходный код и как реализовать общее решение.
Воспроизведение анимации Lottie в основном используетAnimationItem
примерplay
метод.如果开发者配置了autoplay
дляtrue
, после того как вся работа по инициализации подготовлена (упомянутая в Разделе 3.2), вызовите напрямуюplay
способ играть. В противном случае он активно вызывается разработчикомplay
способ играть.
Далее изplay
Метод Узнайте подробности всего процесса воспроизведения:
AnimationItem.prototype.play = function (name) {
this.trigger('_active');
};
удалить лишний код,play
Метод в основном запускается_active
событие, это_active
События регистрируются при инициализации в разделе 3.1.
animItem.addEventListener('_active', addPlayingCount);
function addPlayingCount(){
activate();
}
function activate(){
// 触发第一帧渲染
window.requestAnimationFrame(first);
}
После срабатывания вызовомrequestAnimationFrameметод, который вызывается непрерывноresume
способ управления анимацией.
function first(nowTime){
initTime = nowTime;
// requestAnimationFrame 每次都进行计算修改 DOM
window.requestAnimationFrame(resume);
}
Параметры анимации, упомянутые выше:
- начальный кадр с 0
- конечный кадр 180
- Частота кадров 30 кадров в секунду
requestAnimationFrame
60 кадров в секунду в нормальных условиях (каждые 16,7 мс или около того). Так как же Lottie обеспечивает плавную работу анимации со скоростью 30 кадров в секунду (каждые 33,3 мс). В настоящее время нам нужно изменить наше мышление.Дизайнер надеется вычислять изменение каждые 33,3 мс.requestAnimationFrame
метод, он рассчитывается каждые 16,7 мс, а также могут быть рассчитаны изменения анимации. Просто расчет более детальный, и он сделает анимацию более плавной, чтобы ее можно было обрабатывать будь то 20фпс или 40фпс, посмотрим как обрабатывается исходный код.
постоянно звонюresume
В методе основная логика следующая:
function resume(nowTime) {
// 两次 requestAnimationFrame 间隔时间
var elapsedTime = nowTime - initTime;
// 下一次计算帧数 = 上一次执行的帧数 + 本次间隔的帧数
// frameModifier 为帧率( fr / 1000 = 0.03)
var nextValue = this.currentRawFrame + value * this.frameModifier;
this.setCurrentRawFrameValue(nextValue);
initTime = nowTime;
if(playingAnimationsNum && !_isFrozen) {
window.requestAnimationFrame(resume);
} else {
_stopped = true;
}
}
AnimationItem.prototype.setCurrentRawFrameValue = function(value){
this.currentRawFrame = value;
// 渲染当前帧
this.renderFrame();
};
resume
метод:
-
Сначала вычисляется текущее время и последнее время
diff
время. -
Затем вычислите текущий номер кадра времени от начала анимации до настоящего времени. Обратите внимание здесьномер кадраПросто единица расчета относительно настройки AE, которая может иметь десятичные дроби.
-
наконец прошло
renderFrame()
Метод обновляет изменения DOM, соответствующие текущему кадру.
Например:
Предполагая, что предыдущий кадр равен 70,25 кадра, на этот разrequestAnimationFrame
Интервал равен 16,78 мс, тогда:
当前帧数:70.25 + 16.78 * 0.03 = 70.7534帧
Поскольку 70,7534 кадра находится в диапазоне анимации от 0 до 90 кадров в демонстрации, масштаб кадра (который представляет собой процент времени, в течение которого выполняется анимация) рассчитывается следующим образом:
帧比例:70.7534 / 90 = 0.786148889
Анимация для кадров 0 - 90 масштабирует слой от 100% до 50%, так как рассчитывается только 50% изменение, поэтому масштаб выглядит следующим образом:
缩放比例: 100 - (50 * 0.781666)= 60.69255555%
Соответствующий код расчета находится вTransformPropertyFactory
В классе:
// 计算百分比
perc = fnc((frameNum - keyTime) / (nextKeyTime - keyTime ));
endValue = nextKeyData.s || keyData.e;
// 计算值
keyValue = keyData.s[i] + (endValue[i] - keyData.s[i]) * perc;
вfnc
Для функции расчета, если задана функция кривой движения Безье, тоfnc
Правила расчета также изменены соответствующим образом. Текущая демонстрация использует линейные изменения для простоты понимания. Учащиеся, заинтересованные в конкретном исходном коде, могут просмотреть его самостоятельно.
Рассчитать текущийscale
значение, затем используйтеTransformPropertyFactory
Рассчитать текущий соответствующийtransform
изmatrix
значение, а затем измените свойство CSS соответствующего элемента DOM. так черезrequestAnimationFrame
Постоянно подсчитывая количество кадров, а затем вычисляя соответствующие изменения CSS, анимация реализуется в течение определенного периода времени. Процесс воспроизведения выглядит следующим образом:
Рассчитанное здесь количество кадров нужно помнить всегда,В Lottie количество кадров, заданное AE как единица расчета, Лотти вносит все изменения не в соответствии с заданными дизайнером 30 кадрами в секунду (каждые 33,3 мс), а в соответствии сrequestAnimationFrame
Интервал (каждые 16,7 мс или около того) рассчитывает более подробные изменения, чтобы обеспечить плавную работу анимации.
не прошелsetTimeout
,setInterval
Это реализовано, потому что все они имеют свои недостатки, поэтому я не буду их здесь распространять, и каждый может ознакомиться с информацией самостоятельно.requestAnimationFrame
Системный временной интервал используется для поддержания наилучшей эффективности прорисовки, чтобы анимация могла иметь унифицированный механизм обновления, тем самым экономя системные ресурсы, повышая производительность системы и улучшая визуальные эффекты.
4. Резюме
Хотя мы понимаем принцип реализации Lottie, в практических приложениях есть некоторые преимущества и недостатки, которые следует выбирать в соответствии с реальной ситуацией.
4.1 Преимущества Лотти
- Дизайнеры делают анимацию через AE, а фронтенд можно напрямую восстановить, и не будет ситуации, когда покупатели хвастаются, а продавцы хвастаются.
- SVG масштабируется и не будет искажаться при любом разрешении.
- Файл JSON, который можно повторно использовать в нескольких терминалах (веб, Android, iOS, React Native).
- Размер файла JSON будет намного меньше, чем файлы GIF и APNG, а производительность будет лучше.
4.2 Недостатки Лотти
- Сам Lottie-Web-файл по-прежнему относительно большой, при 513 тыс. Несбежавших, 144K сжал в световой версии и 39K после GZIP. Таким образом, вам нужно обратить внимание на загрузку Lottie-Web.
- Ненужные кадры последовательности. Основная идея анимации Lottie заключается в том, чтобы рисовать определенный слой и постоянно менять свойства CSS.Если дизайнер ленив и использует некоторые плагины для достижения эффекта анимации, это может привести к тому, что каждый кадр будет картинкой, как показано на рисунке. На следующем рисунке это приведет к тому, что этот файл JSON будет очень большим, обратите внимание на то, чтобы заранее связаться с дизайнером.
- Некоторые эффекты автоэкспозиции не поддерживаются. Есть небольшое количество анимационных эффектов автоэкспозиции, которые Лотти не может реализовать. Некоторые из них связаны с проблемами производительности, а некоторые не реализованы. Пожалуйста, свяжитесь с дизайнером заранее.нажмите на меня, чтобы посмотреть.
5. Ссылки
- GitHub.com/air не NB/Lott…
- airbnb.io/lottie/#/
- Понимание Matrix в преобразованиях CSS3
- window.requestAnimationFrame
Эта статья была опубликована сКоманда внешнего интерфейса NetEase Cloud Music, Любое несанкционированное воспроизведение статьи запрещено. Мы набираем front-end, iOS и Android круглый год.Если вы готовы сменить работу и любите облачную музыку, присоединяйтесь к нам на grp.music-fe(at)corp.netease.com!