optimizations
diff --git a/player/index.html b/player/index.html
index a9cffd2..cb5f4c1 100644
--- a/player/index.html
+++ b/player/index.html
@@ -10,6 +10,7 @@
<script src="js/utils/canvasPolyFill.js"></script>
<script src="js/utils/functionExtensions.js"></script>
<script src="js/utils/DataManager.js"></script>
+ <script src="js/utils/bez.js"></script>
<script src="js/renderers/SVGRenderer.js"></script>
<script src="js/renderers/CanvasRenderer.js"></script>
<script src="js/effects.js"></script>
@@ -39,6 +40,6 @@
</head>
<body style="background-color:#666; margin: 10px;height: 100%; font-family: sans-serif;font-size: 10px">
<div id="loader"></div>
-<div style="width:800px;height:800px;background-color:#cccccc" class="bodymovin" data-animation-path="exports/shapes" data-bm-player="0" data-anim-type="canvas" data-anim-loop="false"></div>
+<div style="width:800px;height:800px;background-color:#cccccc" class="bodymovin" data-animation-path="exports/ninja" data-bm-player="0" data-anim-type="canvas" data-anim-loop="true"></div>
</body>
</html>
diff --git a/player/js/animation/AnimationItem.js b/player/js/animation/AnimationItem.js
index d861b2e..f11c8b8 100644
--- a/player/js/animation/AnimationItem.js
+++ b/player/js/animation/AnimationItem.js
@@ -104,7 +104,7 @@
AnimationItem.prototype.gotoFrame = function () {
if(subframeEnabled){
this.renderedFrames = [];
- this.currentFrame = this.currentRawFrame;
+ this.currentFrame = Math.round(this.currentRawFrame*100)/100;
}else{
this.currentFrame = Math.floor(this.currentRawFrame);
}
@@ -120,7 +120,7 @@
}
if(!this.renderedFrames[this.currentFrame]){
this.renderedFrames[this.currentFrame] = true;
- dataManager.renderFrame(this.layers,this.currentFrame);
+ dataManager.renderFrame(this.layers,this.currentFrame,this.animType);
}
this.renderer.renderFrame(this.currentFrame);
};
diff --git a/player/js/elements/canvasElements/CVMaskElement.js b/player/js/elements/canvasElements/CVMaskElement.js
index 417d88c..218c2e1 100644
--- a/player/js/elements/canvasElements/CVMaskElement.js
+++ b/player/js/elements/canvasElements/CVMaskElement.js
@@ -36,12 +36,9 @@
ctx.lineTo(-this.layerSize.w/2,this.layerSize.h-this.layerSize.h/2);
ctx.lineTo(-this.layerSize.w/2,-this.layerSize.h/2);*/
var j, jLen = data.v.length;
- for (j = 0; j < jLen; j++) {
- if (j == 0) {
- ctx.moveTo(data.v[j][0], data.v[j][1]);
- } else {
- ctx.bezierCurveTo(data.o[j - 1][0] + data.v[j - 1][0], data.o[j - 1][1] + data.v[j - 1][1], data.i[j][0] + data.v[j][0], data.i[j][1] + data.v[j][1], data.v[j][0], data.v[j][1]);
- }
+ ctx.moveTo(data.v[0][0], data.v[0][1]);
+ for (j = 1; j < jLen; j++) {
+ ctx.bezierCurveTo(data.o[j - 1][0] + data.v[j - 1][0], data.o[j - 1][1] + data.v[j - 1][1], data.i[j][0] + data.v[j][0], data.i[j][1] + data.v[j][1], data.v[j][0], data.v[j][1]);
}
ctx.bezierCurveTo(data.o[j - 1][0] + data.v[j - 1][0], data.o[j - 1][1] + data.v[j - 1][1], data.i[0][0] + data.v[0][0], data.i[0][1] + data.v[0][1], data.v[0][0], data.v[0][1]);
ctx.closePath();
diff --git a/player/js/elements/canvasElements/CVShapeItemElement.js b/player/js/elements/canvasElements/CVShapeItemElement.js
index 1e1015c..7f6b162 100644
--- a/player/js/elements/canvasElements/CVShapeItemElement.js
+++ b/player/js/elements/canvasElements/CVShapeItemElement.js
@@ -48,6 +48,7 @@
this.renderer.canvasContext.fill();
this.renderer.canvasContext.stroke();
}
+ delete this.renderedPaths[num];
ctx.restore();
};
@@ -76,11 +77,10 @@
if(trimData.e == trimData.s){
return;
}
- var ctx = this.renderer.canvasContext;
- var path2d = new Path2D();
if(this.renderedPaths[num]){
return;
}
+ var path2d = new Path2D();
var animData = this.data.an;
var path = animData.path[animData.path[num].forwardFrame];
var pathNodes = path.pathNodes;
@@ -116,7 +116,6 @@
})
}
var addedLength = 0;
- //ctx.beginPath();
var j, jLen,perc,flag, ended = false;
var k, kLen = trims.length;
@@ -144,16 +143,12 @@
for(k = 0; k < kLen; k+=1){
if(trims[k].s >= addedLength && trims[k].s < addedLength + segments[i].points[j+1].partialLength){
perc = ( trims[k].s - addedLength)/segments[i].points[j+1].partialLength;
- /*path2d.moveTo(segments[i].points[j].point[0]+(segments[i].points[j+1].point[0] - segments[i].points[j].point[0])*perc
- ,segments[i].points[j].point[1]+(segments[i].points[j+1].point[1] - segments[i].points[j].point[1])*perc);*/
- ctx.moveTo(segments[i].points[j].point[0]+(segments[i].points[j+1].point[0] - segments[i].points[j].point[0])*perc
+ path2d.moveTo(segments[i].points[j].point[0]+(segments[i].points[j+1].point[0] - segments[i].points[j].point[0])*perc
,segments[i].points[j].point[1]+(segments[i].points[j+1].point[1] - segments[i].points[j].point[1])*perc);
}
if(trims[k].e > addedLength && trims[k].e <= addedLength + segments[i].points[j+1].partialLength){
perc = ( trims[k].e - addedLength)/segments[i].points[j+1].partialLength;
- /*path2d.lineTo(segments[i].points[j].point[0]+(segments[i].points[j+1].point[0] - segments[i].points[j].point[0])*perc
- ,segments[i].points[j].point[1]+(segments[i].points[j+1].point[1] - segments[i].points[j].point[1])*perc);*/
- ctx.lineTo(segments[i].points[j].point[0]+(segments[i].points[j+1].point[0] - segments[i].points[j].point[0])*perc
+ path2d.lineTo(segments[i].points[j].point[0]+(segments[i].points[j+1].point[0] - segments[i].points[j].point[0])*perc
,segments[i].points[j].point[1]+(segments[i].points[j+1].point[1] - segments[i].points[j].point[1])*perc);
trims.splice(k,1);
k -= 1;
@@ -163,12 +158,11 @@
break;
}
}else if(addedLength > trims[k].s && addedLength < trims[k].e){
- //path2d.lineTo(segments[i].points[j].point[0],segments[i].points[j].point[1]);
- ctx.lineTo(segments[i].points[j].point[0],segments[i].points[j].point[1]);
+ path2d.lineTo(segments[i].points[j].point[0],segments[i].points[j].point[1]);
}
}
}
- //this.renderedPaths[num] = path2d;
+ this.renderedPaths[num] = path2d;
}
};
@@ -176,6 +170,11 @@
var animData = this.data.an;
var path = animData.path[animData.path[num].forwardFrame];
+ if(this.renderedPaths[num]){
+ return;
+ }
+ var path2d = new Path2D();
+
animData.renderedFrame.path = path.pathString;
var ctx = this.renderer.canvasContext;
@@ -187,19 +186,19 @@
ctx.beginPath();
for(i=0;i<len;i+=1){
if(i == 0){
- ctx.moveTo(pathNodes.v[i][0],pathNodes.v[i][1]);
+ path2d.moveTo(pathNodes.v[i][0],pathNodes.v[i][1]);
}else{
- ctx.bezierCurveTo(pathNodes.o[i-1][0]+pathNodes.v[i-1][0],pathNodes.o[i-1][1]+pathNodes.v[i-1][1]
+ path2d.bezierCurveTo(pathNodes.o[i-1][0]+pathNodes.v[i-1][0],pathNodes.o[i-1][1]+pathNodes.v[i-1][1]
,pathNodes.i[i][0]+pathNodes.v[i][0],pathNodes.i[i][1]+pathNodes.v[i][1]
,pathNodes.v[i][0],pathNodes.v[i][1]);
}
}
if(path.closed){
- ctx.bezierCurveTo(pathNodes.o[i-1][0]+pathNodes.v[i-1][0],pathNodes.o[i-1][1]+pathNodes.v[i-1][1]
+ path2d.bezierCurveTo(pathNodes.o[i-1][0]+pathNodes.v[i-1][0],pathNodes.o[i-1][1]+pathNodes.v[i-1][1]
,pathNodes.i[0][0]+pathNodes.v[0][0],pathNodes.i[0][1]+pathNodes.v[0][1]
,pathNodes.v[0][0],pathNodes.v[0][1]);
}
- ctx.closePath();
+ this.renderedPaths[num] = path2d;
};
CVShapeItemElement.prototype.renderEllipse = function(num){
diff --git a/player/js/utils/DataManager.js b/player/js/utils/DataManager.js
index e47a010..30089cc 100644
--- a/player/js/utils/DataManager.js
+++ b/player/js/utils/DataManager.js
@@ -1,6 +1,5 @@
var dataManager = (function(){
var frameRate = 0;
- var easingFunctions = {};
var matrixInstance = new MatrixManager();
var storedBezierCurves = {};
@@ -48,40 +47,6 @@
return string;
}
- function bez(encodedFuncName, coOrdArray) {
- coOrdArray = encodedFuncName;
- encodedFuncName = 'bez_' + coOrdArray.join('_').replace(/\./g, 'p');
- if(easingFunctions[encodedFuncName]){
- return encodedFuncName;
- }
- var polyBez = function(p1, p2) {
- var A = [null, null], B = [null, null], C = [null, null],
- bezCoOrd = function(t, ax) {
- C[ax] = 3 * p1[ax], B[ax] = 3 * (p2[ax] - p1[ax]) - C[ax], A[ax] = 1 - C[ax] - B[ax];
- return t * (C[ax] + t * (B[ax] + t * A[ax]));
- },
- xDeriv = function(t) {
- return C[0] + t * (2 * B[0] + 3 * A[0] * t);
- },
- xForT = function(t) {
- var x = t, i = 0, z;
- while (++i < 14) {
- z = bezCoOrd(x, 0) - t;
- if (Math.abs(z) < 1e-3) break;
- x -= z / xDeriv(x);
- }
- return x;
- };
- return function(t) {
- return bezCoOrd(xForT(t), 1);
- }
- };
- easingFunctions[encodedFuncName] = function(x, t, b, c, d) {
- return c * polyBez([coOrdArray[0], coOrdArray[1]], [coOrdArray[2], coOrdArray[3]])(t/d) + b;
- };
- return encodedFuncName;
- }
-
function getInterpolatedValues(keyframes, frameCount, offsetTime){
var i ,len;
var valuesArray = [];
@@ -94,7 +59,6 @@
var count;
var propertyArray = [];
var j, jLen;
- var easingFnName;
len = keyframes.length;
var perc;
var curveSegments = 1000;
@@ -166,8 +130,7 @@
}else if(i>=keyData.t && i<nextKeyData.t){
propertyArray = [];
if(keyData.to){
- easingFnName = bez([keyData.o.x,keyData.o.y,keyData.i.x,keyData.i.y]);
- perc = easingFunctions[easingFnName]('',i-keyData.t,0,1,nextKeyData.t-keyData.t);
+ perc = bez.getCurve([keyData.o.x,keyData.o.y,keyData.i.x,keyData.i.y])('',i-keyData.t,0,1,nextKeyData.t-keyData.t);
var bezierData = keyData.bezierData;
var distanceInLine = bezierData.segmentLength*perc;
var k, kLen, segmentPerc;
@@ -206,8 +169,7 @@
inX = keyData.i.x;
inY = keyData.i.y;
}
- easingFnName = bez([outX,outY,inX,inY]);
- perc = easingFunctions[easingFnName]('',i-keyData.t,0,1,nextKeyData.t-keyData.t);
+ perc = bez.getCurve([outX,outY,inX,inY])('',i-keyData.t,0,1,nextKeyData.t-keyData.t);
}
// for shapes
if(startItem.i){
@@ -373,6 +335,8 @@
bezierData.segmentLength = addedLength;
}
+ var keyData, nextKeyData,propertyArray,bezierData;
+
function getInterpolatedValue(keyframes, frameNum, offsetTime){
//Todo save on each frame the point found. pass to this function the previous frame to iterate points from last point.
@@ -380,7 +344,7 @@
if(!(keyframes instanceof Array) || keyframes[0].t == null){
return keyframes;
}
- var i = 0, len = keyframes.length-1, keyData, nextKeyData;
+ var i = 0, len = keyframes.length-1;
while(i<len){
keyData = keyframes[i];
nextKeyData = keyframes[i+1];
@@ -394,16 +358,16 @@
buildBezierData(keyData);
}
var k, kLen;
- var easingFnName, perc, j = 0, propertyArray = [];
+ var easingFnName, perc, j = 0;
+ propertyArray = [];
if(keyData.to){
- var bezierData = keyData.bezierData;
+ bezierData = keyData.bezierData;
if(frameNum >= nextKeyData.t-offsetTime){
return bezierData.points[bezierData.points.length - 1].point;
}else if(frameNum < keyData.t-offsetTime){
return bezierData.points[0].point;
}
- easingFnName = bez([keyData.o.x,keyData.o.y,keyData.i.x,keyData.i.y]);
- perc = easingFunctions[easingFnName]('',(frameNum)-(keyData.t-offsetTime),0,1,(nextKeyData.t-offsetTime)-(keyData.t-offsetTime));
+ perc = bez.getCurve([keyData.o.x,keyData.o.y,keyData.i.x,keyData.i.y])('',(frameNum)-(keyData.t-offsetTime),0,1,(nextKeyData.t-offsetTime)-(keyData.t-offsetTime));
var distanceInLine = bezierData.segmentLength*perc;
var segmentPerc;
while(j<bezierData.points.length){
@@ -439,8 +403,7 @@
inX = keyData.i.x;
inY = keyData.i.y;
}
- easingFnName = bez([outX,outY,inX,inY]);
- perc = easingFunctions[easingFnName]('',(frameNum)-(keyData.t-offsetTime),0,1,(nextKeyData.t-offsetTime)-(keyData.t-offsetTime));
+ perc = bez.getCurve([outX,outY,inX,inY])('',(frameNum)-(keyData.t-offsetTime),0,1,(nextKeyData.t-offsetTime)-(keyData.t-offsetTime));
if(frameNum >= nextKeyData.t-offsetTime){
perc = 1;
}else if(frameNum < keyData.t-offsetTime){
@@ -489,6 +452,8 @@
}
var pathV,pathO,pathI;
+ var pathString = '';
+ var pathData;
function createPathString(paths,closed){
if(!(paths instanceof Array)){
@@ -496,43 +461,20 @@
}
var l,lLen = paths.length;
var k, kLen;
- var pathString = '';
- var pathData;
+ pathString = '';
for(l = 0;l<lLen;l+=1){
pathData = paths[l];
pathV = pathData.v;
pathO = pathData.o;
pathI = pathData.i;
kLen = pathV.length;
- for(k=0;k<kLen;k++){
- if(k==0){
- pathString += "M"+pathV[k][0]+","+pathV[k][1];
- }else{
- pathString += " C"+(pathO[k-1][0]+pathV[k-1][0])+","+(pathO[k-1][1]+pathV[k-1][1]);
- pathString += " "+(pathI[k][0]+pathV[k][0])+","+(pathI[k][1]+pathV[k][1]);
- pathString += " "+pathV[k][0]+","+pathV[k][1];
- }
+ pathString += "M"+pathV[0][0]+","+pathV[0][1];
+ for(k=1;k<kLen;k++){
+ pathString += " C"+(pathO[k-1][0]+pathV[k-1][0])+","+(pathO[k-1][1]+pathV[k-1][1]) + " "+(pathI[k][0]+pathV[k][0])+","+(pathI[k][1]+pathV[k][1]) + " "+pathV[k][0]+","+pathV[k][1];
}
if(closed !== false){
- pathString += " C"+(pathO[k-1][0]+pathV[k-1][0])+","+(pathO[k-1][1]+pathV[k-1][1]);
- pathString += " "+(pathI[0][0]+pathV[0][0])+","+(pathI[0][1]+pathV[0][1]);
- pathString += " "+pathV[0][0]+","+(pathV[0][1]);
+ pathString += " C"+(pathO[k-1][0]+pathV[k-1][0])+","+(pathO[k-1][1]+pathV[k-1][1]) + " "+(pathI[0][0]+pathV[0][0])+","+(pathI[0][1]+pathV[0][1]) + " "+pathV[0][0]+","+(pathV[0][1]);
}
- /*
- for(k=0;k<kLen;k++){
- if(k==0){
- pathString += "M"+Math.round(10*(pathV[k][0]))/10+","+Math.round(10*(pathV[k][1]))/10;
- }else{
- pathString += " C"+Math.round(10*(pathO[k-1][0]+pathV[k-1][0]))/10+","+Math.round(10*(pathO[k-1][1]+pathV[k-1][1]))/10;
- pathString += " "+Math.round(10*(pathI[k][0]+pathV[k][0]))/10+","+Math.round(10*(pathI[k][1]+pathV[k][1]))/10;
- pathString += " "+Math.round(10*(pathV[k][0]))/10+","+Math.round(10*(pathV[k][1]))/10;
- }
- }
- if(closed !== false){
- pathString += " C"+Math.round(10*(pathO[k-1][0]+pathV[k-1][0]))/10+","+Math.round(10*(pathO[k-1][1]+pathV[k-1][1]))/10;
- pathString += " "+Math.round(10*(pathI[0][0]+pathV[0][0]))/10+","+Math.round(10*(pathI[0][1]+pathV[0][1]))/10;
- pathString += " "+Math.round(10*(pathV[0][0]))/10+","+Math.round(10*(pathV[0][1]))/10;
- }*/
}
return pathString;
}
@@ -542,8 +484,9 @@
var timeRemapped;
var shapeItem;
var fillOpacity,fillColor, shape, strokeColor, strokeOpacity, strokeWidth, elmPos, elmSize, elmRound;
+ var shapeTrOb = {};
- function iterateLayers(layers, frameNum){
+ function iterateLayers(layers, frameNum,renderType){
var offsettedFrameNum, i, len;
var j, jLen = layers.length, item;
@@ -587,7 +530,9 @@
}
maskValue = getInterpolatedValue(maskProps[i].pt,offsettedFrameNum, item.startTime);
maskProps[i].pathVertices[offsettedFrameNum] = maskValue instanceof Array ? maskValue : [maskValue];
- maskProps[i].pathStrings[offsettedFrameNum] = createPathString(maskValue,maskProps[i].cl);
+ if(renderType == 'svg'){
+ maskProps[i].pathStrings[offsettedFrameNum] = createPathString(maskValue,maskProps[i].cl);
+ }
maskProps[i].opacity[offsettedFrameNum] = getInterpolatedValue(maskProps[i].o,offsettedFrameNum, item.startTime);
maskProps[i].opacity[offsettedFrameNum] = maskProps[i].opacity[offsettedFrameNum] instanceof Array ? maskProps[i].opacity[offsettedFrameNum][0]/100 : maskProps[i].opacity[offsettedFrameNum]/100;
}
@@ -631,11 +576,13 @@
if(shapeItem.ks){
shape = getInterpolatedValue(shapeItem.ks,offsettedFrameNum, item.startTime);
shapeItem.an.path[offsettedFrameNum] = {
- pathString : createPathString(shape,shapeItem.closed),
pathNodes: shape,
closed: shapeItem.closed,
forwardFrame : offsettedFrameNum
};
+ if(renderType == 'svg'){
+ shapeItem.an.path[offsettedFrameNum].pathString = createPathString(shape,shapeItem.closed);
+ }
}else if(shapeItem.el){
elmPos = getInterpolatedValue(shapeItem.el.p,offsettedFrameNum, item.startTime);
elmSize = getInterpolatedValue(shapeItem.el.s,offsettedFrameNum, item.startTime);
@@ -666,7 +613,7 @@
forwardFrame : offsettedFrameNum
};
}
- var shapeTrOb = {};
+ shapeTrOb = {};
//var shapeDataOb = {};
shapeTrOb.a = getInterpolatedValue(shapeItem.tr.a,offsettedFrameNum, item.startTime);
shapeTrOb.o = getInterpolatedValue(shapeItem.tr.o,offsettedFrameNum, item.startTime);
@@ -700,8 +647,8 @@
}
}
- function renderFrame(layers,num){
- iterateLayers(layers, num);
+ function renderFrame(layers,num, renderType){
+ iterateLayers(layers, num, renderType);
}
var moduleOb = {};
diff --git a/player/js/utils/canvasPolyFill.js b/player/js/utils/canvasPolyFill.js
index a03f530..1762ce5 100644
--- a/player/js/utils/canvasPolyFill.js
+++ b/player/js/utils/canvasPolyFill.js
@@ -10,7 +10,6 @@
}
}
if(!supportsPath2D){
- console.log('supportsPath2D: ',supportsPath2D);
function Path2D_(){
this.commandArrays = [];
}
@@ -21,8 +20,8 @@
this.commandArrays.push({type:'line',coord:[x,y]})
};
- Path2D_.prototype.bezierCurveTo = function(cx,cy,x,y){
- this.commandArrays.push({type:'bezierCurve',coord:[cx,cy,x,y]})
+ Path2D_.prototype.bezierCurveTo = function(cx,cy,cx2,cy2,x,y){
+ this.commandArrays.push({type:'bezierCurve',coord:[cx,cy,cx2,cy2,x,y]})
};
Path2D_.prototype.drawToContext = function(ctx){
@@ -38,11 +37,10 @@
ctx.lineTo(command.coord[0],command.coord[1]);
break;
case "bezierCurve":
- ctx.bezierCurveTo(command.coord[0],command.coord[1],command.coord[2],command.coord[3]);
+ ctx.bezierCurveTo(command.coord[0],command.coord[1],command.coord[2],command.coord[3],command.coord[4],command.coord[5]);
break;
}
}
- ctx.closePath();
};
Path2D = Path2D_;
}
diff --git a/player/js/utils/common.js b/player/js/utils/common.js
index f6bb0da..bf7d32d 100644
--- a/player/js/utils/common.js
+++ b/player/js/utils/common.js
@@ -1,12 +1,8 @@
var subframeEnabled = false;
-var svgElement = document.createElementNS(svgNS,'svg');
-var shapeHelper = document.createElementNS(svgNS,'path');
var supportsPath2D = typeof Path2D === 'function';
supportsPath2D = false;
var body;
-svgElement.appendChild(shapeHelper);
-
function styleDiv(element){
element.style.position = "absolute";
element.style.top = 0;
@@ -52,13 +48,4 @@
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
-}
-
-function getPathSize(path){
- if(!body){
- body = document.getElementsByTagName('body')[0];
- body.appendChild(svgElement);
- }
- shapeHelper.setAttribute('d',path);
- return svgElement.getBBox();
-}
+}
\ No newline at end of file