Merge branch 'master' of github.com:airbnb/lottie-web
diff --git a/player/js/module_worker.js b/player/js/module_worker.js
deleted file mode 100644
index fc4faa9..0000000
--- a/player/js/module_worker.js
+++ /dev/null
@@ -1,696 +0,0 @@
-import {
- setDefaultCurveSegments,
- getDefaultCurveSegments,
- roundValues,
- setIdPrefix,
-} from './utils/common';
-import animationManager from './animation/AnimationManager';
-
-function workerContent() {
- var localIdCounter = 0;
- var animations = {};
-
- var styleProperties = ['width', 'height', 'display', 'transform', 'opacity', 'contentVisibility', 'mix-blend-mode'];
- function createElement(namespace, type) {
- var style = {
- serialize: function () {
- var obj = {};
- for (var i = 0; i < styleProperties.length; i += 1) {
- var propertyKey = styleProperties[i];
- var keyName = '_' + propertyKey;
- if (keyName in this) {
- obj[propertyKey] = this[keyName];
- }
- }
- return obj;
- },
- };
- styleProperties.forEach(function (propertyKey) {
- Object.defineProperty(style, propertyKey, {
- set: function (value) {
- if (!element._isDirty) {
- element._isDirty = true;
- }
- element._changedStyles.push(propertyKey);
- var keyName = '_' + propertyKey;
- this[keyName] = value;
- },
- get: function () {
- var keyName = '_' + propertyKey;
- return this[keyName];
- },
- });
- });
- localIdCounter += 1;
- var element = {
- _state: 'init',
- _isDirty: false,
- _changedStyles: [],
- _changedAttributes: [],
- _changedElements: [],
- type: type,
- namespace: namespace,
- children: [],
- attributes: {
- id: 'l_d_' + localIdCounter,
- },
- style: style,
- appendChild: function (child) {
- child.parentNode = this;
- this.children.push(child);
- this._isDirty = true;
- this._changedElements.push([child, this.attributes.id]);
- },
- insertBefore: function (newElement, nextElement) {
- var children = this.children;
- for (var i = 0; i < children.length; i += 1) {
- if (children[i] === nextElement) {
- children.splice(i, 0, newElement);
- this._isDirty = true;
- this._changedElements.push([newElement, this.attributes.id, nextElement.attributes.id]);
- return;
- }
- }
- children.push(nextElement);
- },
- setAttribute: function (attribute, value) {
- this.attributes[attribute] = value;
- if (!element._isDirty) {
- element._isDirty = true;
- }
- element._changedAttributes.push(attribute);
- },
- serialize: function () {
- return {
- type: this.type,
- namespace: this.namespace,
- style: this.style.serialize(),
- attributes: this.attributes,
- children: this.children.map(function (child) { return child.serialize(); }),
- };
- },
- getContext: function () { return { fillRect: function () {} }; },
- addEventListener: function (_, callback) {
- setTimeout(callback, 1);
- },
- setAttributeNS: function (_, attribute, value) {
- this.attributes[attribute] = value;
- if (!element._isDirty) {
- element._isDirty = true;
- }
- element._changedAttributes.push(attribute);
- },
- };
- element.style = style;
- return element;
- }
-
- var window = self; // eslint-disable-line no-redeclare, no-unused-vars
-
- var document = { // eslint-disable-line no-redeclare
- createElementNS: function (namespace, type) {
- return createElement(namespace, type);
- },
- createElement: function (type) {
- return createElement('', type);
- },
- };
- /* eslint-enable */
- var lottieInternal = (function () {
- 'use strict';
-
- /* <%= contents %> */
- var lottiejs = {};
-
- function addElementToList(element, list) {
- list.push(element);
- element._isDirty = false;
- element._changedStyles.length = 0;
- element._changedAttributes.length = 0;
- element._changedElements.length = 0;
- element.children.forEach(function (child) {
- addElementToList(child, list);
- });
- }
-
- function addChangedAttributes(element) {
- var changedAttributes = element._changedAttributes;
- var attributes = [];
- var attribute;
- for (var i = 0; i < changedAttributes.length; i += 1) {
- attribute = changedAttributes[i];
- attributes.push([attribute, element.attributes[attribute]]);
- }
- return attributes;
- }
-
- function addChangedStyles(element) {
- var changedStyles = element._changedStyles;
- var styles = [];
- var style;
- for (var i = 0; i < changedStyles.length; i += 1) {
- style = changedStyles[i];
- styles.push([style, element.style[style]]);
- }
- return styles;
- }
-
- function addChangedElements(element, elements) {
- var changedElements = element._changedElements;
- var elementsList = [];
- var elementData;
- for (var i = 0; i < changedElements.length; i += 1) {
- elementData = changedElements[i];
- elementsList.push([elementData[0].serialize(), elementData[1], elementData[2]]);
- addElementToList(elementData[0], elements);
- }
- return elementsList;
- }
-
- function loadAnimation(payload) {
- var params = payload.params;
- var wrapper;
- var animation;
- var elements = [];
- if (params.renderer === 'svg') {
- wrapper = document.createElement('div');
- params.container = wrapper;
- } else {
- var canvas = params.rendererSettings.canvas;
- var ctx = canvas.getContext('2d');
- params.rendererSettings.context = ctx;
- }
- animation = animationManager.loadAnimation(params);
- animation.addEventListener('error', function (error) {
- console.log(error); // eslint-disable-line
- });
- animation.onError = function (error) {
- console.log('ERRORO', error); // eslint-disable-line
- };
- if (params.renderer === 'svg') {
- animation.addEventListener('DOMLoaded', function () {
- var serialized = wrapper.serialize();
- addElementToList(wrapper, elements);
- self.postMessage({
- type: 'loaded',
- payload: {
- id: payload.id,
- tree: serialized.children[0],
- totalFrames: animation.totalFrames,
- frameRate: animation.frameRate,
- },
- });
- });
- animation.addEventListener('drawnFrame', function (event) {
- var changedElements = [];
- var element;
- for (var i = 0; i < elements.length; i += 1) {
- element = elements[i];
- if (element._isDirty) {
- var changedElement = {
- id: element.attributes.id,
- styles: addChangedStyles(element),
- attributes: addChangedAttributes(element),
- elements: addChangedElements(element, elements),
- };
- changedElements.push(changedElement);
- element._isDirty = false;
- element._changedAttributes.length = 0;
- element._changedStyles.length = 0;
- element._changedElements.length = 0;
- }
- }
- self.postMessage({
- type: 'updated',
- payload: {
- elements: changedElements,
- id: payload.id,
- currentTime: event.currentTime,
- },
- });
- });
- }
- animations[payload.id] = animation;
- }
-
- function setQuality(value) {
- if (typeof value === 'string') {
- switch (value) {
- case 'high':
- setDefaultCurveSegments(200);
- break;
- case 'medium':
- setDefaultCurveSegments(50);
- break;
- case 'low':
- default:
- setDefaultCurveSegments(10);
- break;
- }
- } else if (!isNaN(value) && value > 1) {
- setDefaultCurveSegments(value);
- }
- if (getDefaultCurveSegments() >= 50) {
- roundValues(false);
- } else {
- roundValues(true);
- }
- }
-
- function setIDPrefix(prefix) {
- setIdPrefix(prefix);
- }
-
- lottiejs.play = animationManager.play;
- lottiejs.pause = animationManager.pause;
- lottiejs.togglePause = animationManager.togglePause;
- lottiejs.setSpeed = animationManager.setSpeed;
- lottiejs.setDirection = animationManager.setDirection;
- lottiejs.stop = animationManager.stop;
- lottiejs.registerAnimation = animationManager.registerAnimation;
- lottiejs.loadAnimation = loadAnimation;
- lottiejs.resize = animationManager.resize;
- lottiejs.goToAndStop = animationManager.goToAndStop;
- lottiejs.destroy = animationManager.destroy;
- lottiejs.setQuality = setQuality;
- lottiejs.freeze = animationManager.freeze;
- lottiejs.unfreeze = animationManager.unfreeze;
- lottiejs.setVolume = animationManager.setVolume;
- lottiejs.mute = animationManager.mute;
- lottiejs.unmute = animationManager.unmute;
- lottiejs.getRegisteredAnimations = animationManager.getRegisteredAnimations;
- lottiejs.setIDPrefix = setIDPrefix;
- lottiejs.version = '[[BM_VERSION]]';
-
- return lottiejs;
- }({}));
- onmessage = function (evt) {
- var data = evt.data;
- var type = data.type;
- var payload = data.payload;
- if (type === 'load') {
- lottieInternal.loadAnimation(payload);
- } else if (type === 'pause') {
- if (animations[payload.id]) {
- animations[payload.id].pause();
- }
- } else if (type === 'play') {
- if (animations[payload.id]) {
- animations[payload.id].play();
- }
- } else if (type === 'stop') {
- if (animations[payload.id]) {
- animations[payload.id].stop();
- }
- } else if (type === 'setSpeed') {
- if (animations[payload.id]) {
- animations[payload.id].setSpeed(payload.value);
- }
- } else if (type === 'setDirection') {
- if (animations[payload.id]) {
- animations[payload.id].setDirection(payload.value);
- }
- } else if (type === 'setDirection') {
- if (animations[payload.id]) {
- animations[payload.id].setDirection(payload.value);
- }
- } else if (type === 'goToAndPlay') {
- if (animations[payload.id]) {
- animations[payload.id].goToAndPlay(payload.value, payload.isFrame);
- }
- } else if (type === 'goToAndStop') {
- if (animations[payload.id]) {
- animations[payload.id].goToAndStop(payload.value, payload.isFrame);
- }
- } else if (type === 'setSubframe') {
- if (animations[payload.id]) {
- animations[payload.id].setSubframe(payload.value);
- }
- } else if (type === 'addEventListener') {
- if (animations[payload.id]) {
- animations[payload.id].addEventListener(payload.eventName, function () {
- self.postMessage({
- type: 'event',
- payload: {
- id: payload.id,
- callbackId: payload.callbackId,
- argument: arguments[0],
- },
- });
- });
- }
- } else if (type === 'destroy') {
- if (animations[payload.id]) {
- animations[payload.id].destroy();
- animations[payload.id] = null;
- }
- } else if (type === 'resize') {
- if (animations[payload.id]) {
- animations[payload.id].resize();
- }
- } else if (type === 'playSegments') {
- if (animations[payload.id]) {
- animations[payload.id].playSegments(payload.arr, payload.forceFlag);
- }
- }
- };
-}
-
-function createWorker(fn) {
- var blob = new Blob(['(' + fn.toString() + '())'], { type: 'text/javascript' });
- var url = URL.createObjectURL(blob);
- return new Worker(url);
-}
-// eslint-disable-next-line no-unused-vars
-var lottie = (function () {
- 'use strict';
-
- var workerInstance = createWorker(workerContent);
- var animationIdCounter = 0;
- var eventsIdCounter = 0;
- var animations = {};
- var defaultSettings = {
- rendererSettings: {},
- };
-
- function createTree(data, container, map, afterElement) {
- var elem;
- if (data.type === 'div') {
- elem = document.createElement('div');
- } else {
- elem = document.createElementNS(data.namespace, data.type);
- }
- for (var attr in data.attributes) {
- if (Object.prototype.hasOwnProperty.call(data.attributes, attr)) {
- if (attr === 'href') {
- elem.setAttributeNS('http://www.w3.org/1999/xlink', attr, data.attributes[attr]);
- } else {
- elem.setAttribute(attr, data.attributes[attr]);
- }
- if (attr === 'id') {
- map[data.attributes[attr]] = elem;
- }
- }
- }
- for (var style in data.style) {
- if (Object.prototype.hasOwnProperty.call(data.style, style)) {
- elem.style[style] = data.style[style];
- }
- }
- data.children.forEach(function (element) {
- createTree(element, elem, map);
- });
- if (!afterElement) {
- container.appendChild(elem);
- } else {
- container.insertBefore(elem, afterElement);
- }
- }
-
- var handleAnimationLoaded = (function () {
- return function (payload) {
- var animation = animations[payload.id];
- animation._loaded = true;
- // if callbacks have been added before the animation has loaded
- animation.pendingCallbacks.forEach(function (callbackData) {
- animation.animInstance.addEventListener(callbackData.eventName, callbackData.callback);
- if (callbackData.eventName === 'DOMLoaded') {
- callbackData.callback();
- }
- });
- animation.animInstance.totalFrames = payload.totalFrames;
- animation.animInstance.frameRate = payload.frameRate;
- var container = animation.container;
- var elements = animation.elements;
- createTree(payload.tree, container, elements);
- };
- }());
-
- function addNewElements(newElements, elements) {
- var element;
- for (var i = 0; i < newElements.length; i += 1) {
- element = newElements[i];
- var parent = elements[element[1]];
- if (parent) {
- var sibling;
- if (element[2]) {
- sibling = elements[element[2]];
- }
- createTree(element[0], parent, elements, sibling);
- newElements.splice(i, 1);
- i -= 1;
- }
- }
- }
-
- function updateElementStyles(element, styles) {
- var style;
- for (var i = 0; i < styles.length; i += 1) {
- style = styles[i];
- element.style[style[0]] = style[1];
- }
- }
-
- function updateElementAttributes(element, attributes) {
- var attribute;
- for (var i = 0; i < attributes.length; i += 1) {
- attribute = attributes[i];
- element.setAttribute(attribute[0], attribute[1]);
- }
- }
-
- function handleAnimationUpdate(payload) {
- var changedElements = payload.elements;
- var animation = animations[payload.id];
- if (animation) {
- var elements = animation.elements;
- var elementData;
- for (var i = 0; i < changedElements.length; i += 1) {
- elementData = changedElements[i];
- var element = elements[elementData.id];
- addNewElements(elementData.elements, elements);
- updateElementStyles(element, elementData.styles);
- updateElementAttributes(element, elementData.attributes);
- }
- animation.animInstance.currentFrame = payload.currentTime;
- }
- }
-
- function handleEvent(payload) {
- var animation = animations[payload.id];
- if (animation) {
- var callbacks = animation.callbacks;
- if (callbacks[payload.callbackId]) {
- callbacks[payload.callbackId](payload.argument);
- }
- }
- }
-
- workerInstance.onmessage = function (event) {
- if (event.data.type === 'loaded') {
- handleAnimationLoaded(event.data.payload);
- } else if (event.data.type === 'updated') {
- handleAnimationUpdate(event.data.payload);
- } else if (event.data.type === 'event') {
- handleEvent(event.data.payload);
- }
- };
-
- function resolveAnimationData(params) {
- return new Promise(function (resolve, reject) {
- var paramsCopy = Object.assign({}, defaultSettings, params);
- if (paramsCopy.animType && !paramsCopy.renderer) {
- paramsCopy.renderer = paramsCopy.animType;
- }
- if (paramsCopy.wrapper) {
- if (!paramsCopy.container) {
- paramsCopy.container = paramsCopy.wrapper;
- }
- delete paramsCopy.wrapper;
- }
- if (paramsCopy.animationData) {
- resolve(paramsCopy);
- } else if (paramsCopy.path) {
- fetch(paramsCopy.path)
- .then(function (response) {
- return response.json();
- })
- .then(function (animationData) {
- paramsCopy.animationData = animationData;
- delete paramsCopy.path;
- resolve(paramsCopy);
- });
- } else {
- reject();
- }
- });
- }
-
- function loadAnimation(params) {
- animationIdCounter += 1;
- var animationId = 'lottie_animationId_' + animationIdCounter;
- var animation = {
- elements: {},
- callbacks: {},
- pendingCallbacks: [],
- };
- var animInstance = {
- id: animationId,
- pause: function () {
- workerInstance.postMessage({
- type: 'pause',
- payload: {
- id: animationId,
- },
- });
- },
- play: function () {
- workerInstance.postMessage({
- type: 'play',
- payload: {
- id: animationId,
- },
- });
- },
- stop: function () {
- workerInstance.postMessage({
- type: 'stop',
- payload: {
- id: animationId,
- },
- });
- },
- setSpeed: function (value) {
- workerInstance.postMessage({
- type: 'setSpeed',
- payload: {
- id: animationId,
- value: value,
- },
- });
- },
- setDirection: function (value) {
- workerInstance.postMessage({
- type: 'setDirection',
- payload: {
- id: animationId,
- value: value,
- },
- });
- },
- goToAndStop: function (value, isFrame) {
- workerInstance.postMessage({
- type: 'goToAndStop',
- payload: {
- id: animationId,
- value: value,
- isFrame: isFrame,
- },
- });
- },
- goToAndPlay: function (value, isFrame) {
- workerInstance.postMessage({
- type: 'goToAndPlay',
- payload: {
- id: animationId,
- value: value,
- isFrame: isFrame,
- },
- });
- },
- playSegments: function (arr, forceFlag) {
- workerInstance.postMessage({
- type: 'playSegments',
- payload: {
- id: animationId,
- arr: arr,
- forceFlag: forceFlag,
- },
- });
- },
- setSubframe: function (value) {
- workerInstance.postMessage({
- type: 'setSubframe',
- payload: {
- id: animationId,
- value: value,
- },
- });
- },
- addEventListener: function (eventName, callback) {
- if (!animation._loaded) {
- animation.pendingCallbacks.push({
- eventName: eventName,
- callback: callback,
- });
- } else {
- eventsIdCounter += 1;
- var callbackId = 'callback_' + eventsIdCounter;
- animation.callbacks[callbackId] = callback;
- workerInstance.postMessage({
- type: 'addEventListener',
- payload: {
- id: animationId,
- callbackId: callbackId,
- eventName: eventName,
- },
- });
- }
- },
- destroy: function () {
- animations[animationId] = null;
- if (animation.container) {
- animation.container.innerHTML = '';
- }
- workerInstance.postMessage({
- type: 'destroy',
- payload: {
- id: animationId,
- },
- });
- },
- resize: function () {
- workerInstance.postMessage({
- type: 'resize',
- payload: {
- id: animationId,
- },
- });
- },
- };
- animation.animInstance = animInstance;
- resolveAnimationData(params)
- .then(function (animationParams) {
- var transferedObjects = [];
- if (animationParams.container) {
- animation.container = animationParams.container;
- delete animationParams.container;
- }
- if (animationParams.renderer === 'canvas' && !animationParams.rendererSettings.canvas) {
- var canvas = document.createElement('canvas');
- animation.container.appendChild(canvas);
- canvas.width = animationParams.animationData.w;
- canvas.height = animationParams.animationData.h;
- canvas.style.width = '100%';
- canvas.style.height = '100%';
- var offscreen = canvas.transferControlToOffscreen();
- transferedObjects.push(offscreen);
- animationParams.rendererSettings.canvas = offscreen;
- }
- animations[animationId] = animation;
- workerInstance.postMessage({
- type: 'load',
- payload: {
- params: animationParams,
- id: animationId,
- },
- }, transferedObjects);
- });
- return animInstance;
- }
-
- var lottiejs = {
- loadAnimation: loadAnimation,
- };
- return lottiejs;
-}());
diff --git a/player/js/worker_wrapper.js b/player/js/worker_wrapper.js
index 710a0cd..63c41a9 100644
--- a/player/js/worker_wrapper.js
+++ b/player/js/worker_wrapper.js
@@ -549,6 +549,7 @@
elements: {},
callbacks: {},
pendingCallbacks: [],
+ status: 'init',
};
var animInstance = {
id: animationId,
@@ -675,16 +676,21 @@
});
},
destroy: function () {
- animations[animationId] = null;
- if (animation.container) {
- animation.container.innerHTML = '';
+ if (animation.status === 'init') {
+ animation.status = 'destroyable';
+ } else {
+ animation.status = 'destroyed';
+ animations[animationId] = null;
+ if (animation.container) {
+ animation.container.innerHTML = '';
+ }
+ workerInstance.postMessage({
+ type: 'destroy',
+ payload: {
+ id: animationId,
+ },
+ });
}
- workerInstance.postMessage({
- type: 'destroy',
- payload: {
- id: animationId,
- },
- });
},
resize: function () {
workerInstance.postMessage({
@@ -709,6 +715,11 @@
animation.animInstance = animInstance;
resolveAnimationData(params)
.then(function (animationParams) {
+ if (animation.status === 'destroyable') {
+ animation.animInstance.destroy();
+ return;
+ }
+ animation.status = 'loaded';
var transferedObjects = [];
if (animationParams.container) {
animation.container = animationParams.container;