blob: f3ee34344c935a7f3d0aaad176699f3f609fe9ef [file] [log] [blame]
var AnimationItem = function (options) {
if (!options) {
options = {};
}
this.element = options.element;
this.src = options.src;
this.data = options.data;
this.autoplay = options.autoplay;
this.loop = options.loop;
this.engine = options.engine;
this.prerender = options.prerender;
this._init();
}
// -------------------------------------------------------------------o Public
AnimationItem.prototype.trigger = function(eventName, args){
if (!this.callbacks){
this.callbacks = [];
}
var delay = (this.callbacks.length === 0) ? true : false;
var that = this;
if (this.callbacks[eventName]) {
if (delay){
setTimeout(function(){
for (var i = 0; i < that.callbacks[eventName].length; i++){
that.callbacks[eventName][i](args);
}
}, 0);
}
else {
for (var i = 0; i < this.callbacks[eventName].length; i++){
this.callbacks[eventName][i](args);
}
}
}
};
AnimationItem.prototype.addEventListener = function(eventName, callback){
if (!this.callbacks){
this.callbacks = [];
}
if (!this.callbacks[eventName]){
this.callbacks[eventName] = [];
}
this.callbacks[eventName].push(callback);
};
// -------------------------------------------------------------------o Init
AnimationItem.prototype._init = function () {
this.animationID = randomString(10);
this.renderer = null;
this.path = '';
this.animationData = {};
this.layers = [];
this.assets = [];
this.scaleMode = 'fit';
this.currentFrame = 0;
this.currentRawFrame = 0;
this.totalFrames = 0;
this.frameRate = 0;
this.frameMult = 0;
this.playSpeed = 1;
this.playDirection = 1;
this.pendingElements = 0;
this.playCount = 0;
this.renderedFrameCount = 0;
this.isLoaded = false;
this.isPaused = true;
this.initParams();
if (this.autoplay === true) {
this.play();
}
}
AnimationItem.prototype._initEvents = function () {
}
// -------------------------------------------------------------------o Private
// -------------------------------------------------------------------o Public
AnimationItem.prototype.play = function () {
this._changeState(BodyMovin.PLAYING);
}
AnimationItem.prototype.pause = function () {
this._changeState(BodyMovin.PLAYING);
}
AnimationItem.prototype.pause = function () {
this._changeState(BodyMovin.PAUSED);
}
AnimationItem.prototype.seek = function (frame) {
}
AnimationItem.prototype.timeUpdate = function (frame) {
this.trigger(BodyMovin.TIMEUPDATE);
}
// -------------------------------------------------------------------o Getters
AnimationItem.prototype.getDuration = function () {
return this.duration;
}
AnimationItem.prototype.getCurrentFrame = function () {
return this.currentFrame;
}
// -------------------------------------------------------------------o Setters
AnimationItem.prototype.setData = function (data) {
this.data = data;
}
AnimationItem.prototype.initParams = function () {
var params = {
wrapper: this.element
};
var wrapperAttributes = this.element.attributes;
params.path = this.path || this.element.getAttribute('data-animation-path') || this.element.getAttribute('data-bm-path') || '';
params.engine = this.engine || this.element.getAttribute('data-animation-engine') || this.element.getAttribute('data-anim-engine') || this.element.getAttribute('data-bm-engine') || 'svg';
params.loop = this.loop || this.element.getAttribute('data-animation-loop') || this.element.getAttribute('data-bm-loop') || true;
params.name = this.name || this.element.getAttribute('data-animation-name') || this.element.getAttribute('data-bm-name') || '';
params.path = this.src;
params.prerender = this.prerender || this.element.getAttribute('data-animation-prerender') || this.element.getAttribute('data-bm-prerender') || true;
this.setParams(params);
}
AnimationItem.prototype.setParams = function (params) {
var self = this;
if (params.context) {
this.context = params.context;
}
if (params.wrapper) {
this.wrapper = params.wrapper;
}
if (this.engine == 'canvas') {
this.renderer = new CanvasRenderer(this, params.renderer);
}
else {
this.renderer = new SVGRenderer(this, params.renderer);
}
if (this.data) {
self.configAnimation(this.data);
} else if (params.path) {
if (params.path.substr(-4) != 'json') {
if (params.path.substr(-1, 1) != '/') {
params.path += '/';
}
params.path += 'data.json';
}
var xhr = new XMLHttpRequest();
this.path = params.path.substr(0,params.path.lastIndexOf('/')+1);
xhr.open('GET', params.path, true);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
self.configAnimation(JSON.parse(xhr.responseText));
} else {
try {
var response = JSON.parse(xhr.responseText);
self.configAnimation(response);
}
catch(err) {
}
}
}
};
}
}
AnimationItem.prototype.configAnimation = function (animData) {
this.renderer.configAnimation(animData);
this.animationData = animData;
this.animationData._id = this.animationID;
this.animationData._animType = this.engine;
this.layers = this.animationData.animation.layers;
this.assets = this.animationData.assets;
this.totalFrames = this.animationData.animation.totalFrames;
this.frameRate = this.animationData.animation.frameRate;
this.firstFrame = Math.round(this.animationData.animation.ff*this.frameRate);
/*this.firstFrame = 38;
this.totalFrames = 2;*/
this.frameMult = this.animationData.animation.frameRate / 1000;
dataManager.completeData(this.animationData);
this.renderer.buildItems(this.animationData.animation.layers);
this.updaFrameModifier();
this.checkLoaded();
}
AnimationItem.prototype.elementLoaded = function () {
this.pendingElements--;
this.checkLoaded();
}
AnimationItem.prototype.checkLoaded = function () {
if (this.pendingElements === 0) {
this.renderer.buildStage(this.container, this.layers);
if (this.prerender) {
this.prerenderFrames(0);
dataManager.renderFrame(this.animationID,this.currentFrame + this.firstFrame);
this.renderer.renderFrame(this.currentFrame + this.firstFrame);
} else {
this.isLoaded = true;
this.gotoFrame(0);
// autoplayed
}
}
};
/*AnimationItem.prototype.prerenderFrames = function (count) {
console.log(count);
if (!count) {
count = 0;
}
if (this.renderedFrameCount === Math.floor(this.totalFrames)) {
//TODO Need polyfill for ios 5.1
this.isLoaded = true;
this.gotoFrame(0);
// autoplayed
} else {
dataManager.renderFrame(this.animationID, this.renderedFrameCount + this.firstFrame);
this.renderedFrameCount += 1;
if (count > 10) {
setTimeout(this.prerenderFrames.bind(this),0);
} else {
count += 1;
this.prerenderFrames(count);
}
}
};*/
AnimationItem.prototype.resize = function () {
this.renderer.updateContainerSize();
};
AnimationItem.prototype.play = function (name) {
if (this.isPaused === true) {
this.isPaused = false;
}
};
AnimationItem.prototype.pause = function (name) {
if (this.isPaused === false) {
this.isPaused = true;
}
this.trigger(BodyMovin.PAUSED);
};
AnimationItem.prototype.togglePause = function (name) {
if (this.isPaused === true) {
this.isPaused = false;
this.play();
} else {
this.isPaused = true;
this.pause();
}
};
AnimationItem.prototype.stop = function (name) {
this.isPaused = true;
this.currentFrame = this.currentRawFrame = 0;
this.playCount = 0;
this.gotoFrame(0);
};
AnimationItem.prototype.goToAndStop = function (value, isFrame, name) {
if (isFrame) {
this.setCurrentRawFrameValue(value);
} else {
this.setCurrentRawFrameValue(value * this.frameModifier);
}
this.isPaused = true;
};
// ----------------------------------------------o Animating frames
AnimationItem.prototype.update = function (value) {
this.currentRawFrame = this.currentRawFrame + value * this.frameModifier;
this.currentFrame = this.currentRawFrame % this.totalFrames;
if (this.isPaused === false && this.currentFrame > this.totalFrames - 1) {
this.resetFrame();
if (this.loop === false){
this.pause();
}
}
else if (this.isPaused === true) {
return;
}
this.gotoFrame(this.currentRawFrame);
//this.updateCurrentRawFrameValue(currentRawFrame);
};
/*AnimationItem.prototype.updateCurrentRawFrameValue = function(value){
this.currentRawFrame = value;
/*if (this.currentRawFrame >= this.totalFrames) {
if(this.loop === false){
this.currentRawFrame = this.totalFrames - 1;
this.gotoFrame();
this.pause();
return;
} else {
this.playCount += 1;
if (this.loop !== true) {
if(this.playCount == this.loop){
this.currentRawFrame = this.totalFrames - 1;
this.gotoFrame();
this.pause();
return;
}
}
}
} else if (this.currentRawFrame < 0) {
this.playCount -= 1;
if (this.playCount < 0) {
this.playCount = 0;
}
if (this.loop === false) {
this.currentRawFrame = 0;
this.gotoFrame();
this.pause();
return;
} else {
this.currentRawFrame = this.totalFrames + this.currentRawFrame;
this.gotoFrame();
return;
}
}
this.currentRawFrame = this.currentRawFrame % this.totalFrames;
this.gotoFrame(this.currentRawFrame);
};*/
AnimationItem.prototype.gotoFrame = function (frame) {
frame = this.getFrame(frame);
this.currentFrame = frame;
if (frame > this.totalFrames - 1) {
this.resetFrame();
}
this.renderFrame();
};
AnimationItem.prototype.getFrame = function (rawFrame) {
if (subframeEnabled){
frame = Math.round(rawFrame * 100) / 100;
} else {
frame = Math.floor(rawFrame);
}
return frame;
};
AnimationItem.prototype.resetFrame = function (rawFrame) {
this.currentRawFrame = 0;
this.currentFrame = 0;
};
AnimationItem.prototype.renderFrame = function () {
if(this.isLoaded === false){
return;
}
dataManager.renderFrame(this.animationID,this.currentFrame + this.firstFrame);
this.renderer.renderFrame(this.currentFrame + this.firstFrame);
};
AnimationItem.prototype.setSpeed = function (val) {
this.playSpeed = val;
this.updaFrameModifier();
};
AnimationItem.prototype.setDirection = function (val) {
this.playDirection = val < 0 ? -1 : 1;
this.updaFrameModifier();
};
AnimationItem.prototype.updaFrameModifier = function () {
this.frameModifier = this.frameMult * this.playSpeed * this.playDirection;
};
AnimationItem.prototype.getPath = function () {
return this.path;
};
AnimationItem.prototype.getAssets = function () {
return this.assets;
};