UNPKG

bodymovin

Version:

After Effects plugin for exporting animations to SVG + JavaScript or canvas + JavaScript

253 lines (233 loc) 10 kB
function bezFunction(){ var easingFunctions = []; var math = Math; function pointOnLine2D(x1,y1, x2,y2, x3,y3){ var det1 = (x1*y2) + (y1*x3) + (x2*y3) - (x3*y2) - (y3*x1) - (x2*y1); return det1 > -0.0001 && det1 < 0.0001; } function pointOnLine3D(x1,y1,z1, x2,y2,z2, x3,y3,z3){ if(z1 === 0 && z2 === 0 && z3 === 0) { return pointOnLine2D(x1,y1, x2,y2, x3,y3); } var dist1 = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2) + Math.pow(z2 - z1, 2)); var dist2 = Math.sqrt(Math.pow(x3 - x1, 2) + Math.pow(y3 - y1, 2) + Math.pow(z3 - z1, 2)); var dist3 = Math.sqrt(Math.pow(x3 - x2, 2) + Math.pow(y3 - y2, 2) + Math.pow(z3 - z2, 2)); var diffDist; if(dist1 > dist2){ if(dist1 > dist3){ diffDist = dist1 - dist2 - dist3; } else { diffDist = dist3 - dist2 - dist1; } } else if(dist3 > dist2){ diffDist = dist3 - dist2 - dist1; } else { diffDist = dist2 - dist1 - dist3; } return diffDist > -0.0001 && diffDist < 0.0001; } /*function getEasingCurve(aa,bb,cc,dd,encodedFuncName) { if(!encodedFuncName){ encodedFuncName = ('bez_' + aa+'_'+bb+'_'+cc+'_'+dd).replace(/\./g, 'p'); } if(easingFunctions[encodedFuncName]){ return easingFunctions[encodedFuncName]; } var A0, B0, C0; var A1, B1, C1; easingFunctions[encodedFuncName] = function(tt) { var x = tt; var i = 0, z; while (++i < 20) { C0 = 3 * aa; B0 = 3 * (cc - aa) - C0; A0 = 1 - C0 - B0; z = (x * (C0 + x * (B0 + x * A0))) - tt; if (bm_abs(z) < 1e-3) break; x -= z / (C0 + x * (2 * B0 + 3 * A0 * x)); } C1 = 3 * bb; B1 = 3 * (dd - bb) - C1; A1 = 1 - C1 - B1; var polyB = x * (C1 + x * (B1 + x * A1)); //return c * polyB + b; return polyB; }; return easingFunctions[encodedFuncName]; }*/ var getBezierLength = (function(){ function Segment(l,p){ this.l = l; this.p = p; } return function(pt1,pt2,pt3,pt4){ var curveSegments = defaultCurveSegments; var k; var i, len; var ptCoord,perc,addedLength = 0; var ptDistance; var point = [],lastPoint = []; var lengthData = { addedLength: 0, segments: [] }; len = pt3.length; for(k=0;k<curveSegments;k+=1){ perc = k/(curveSegments-1); ptDistance = 0; for(i=0;i<len;i+=1){ ptCoord = bm_pow(1-perc,3)*pt1[i]+3*bm_pow(1-perc,2)*perc*pt3[i]+3*(1-perc)*bm_pow(perc,2)*pt4[i]+bm_pow(perc,3)*pt2[i]; point[i] = ptCoord; if(lastPoint[i] !== null){ ptDistance += bm_pow(point[i] - lastPoint[i],2); } lastPoint[i] = point[i]; } if(ptDistance){ ptDistance = bm_sqrt(ptDistance); addedLength += ptDistance; } lengthData.segments.push(new Segment(addedLength,perc)); } lengthData.addedLength = addedLength; return lengthData; }; }()); function getSegmentsLength(shapeData) { var closed = shapeData.c; var pathV = shapeData.v; var pathO = shapeData.o; var pathI = shapeData.i; var i, len = shapeData._length; var lengths = []; var totalLength = 0; for(i=0;i<len-1;i+=1){ lengths[i] = getBezierLength(pathV[i],pathV[i+1],pathO[i],pathI[i+1]); totalLength += lengths[i].addedLength; } if(closed){ lengths[i] = getBezierLength(pathV[i],pathV[0],pathO[i],pathI[0]); totalLength += lengths[i].addedLength; } return {lengths:lengths,totalLength:totalLength}; } function BezierData(length){ this.segmentLength = 0; this.points = new Array(length); } function PointData(partial,point){ this.partialLength = partial; this.point = point; } var buildBezierData = (function(){ var storedData = {}; return function (keyData){ var pt1 = keyData.s; var pt2 = keyData.e; var pt3 = keyData.to; var pt4 = keyData.ti; var bezierName = (pt1.join('_')+'_'+pt2.join('_')+'_'+pt3.join('_')+'_'+pt4.join('_')).replace(/\./g, 'p'); if(storedData[bezierName]){ keyData.bezierData = storedData[bezierName]; return; } var curveSegments = defaultCurveSegments; var k, i, len; var ptCoord,perc,addedLength = 0; var ptDistance; var point,lastPoint = null; if(pt1.length === 2 && (pt1[0] != pt2[0] || pt1[1] != pt2[1]) && pointOnLine2D(pt1[0],pt1[1],pt2[0],pt2[1],pt1[0]+pt3[0],pt1[1]+pt3[1]) && pointOnLine2D(pt1[0],pt1[1],pt2[0],pt2[1],pt2[0]+pt4[0],pt2[1]+pt4[1])){ curveSegments = 2; } var bezierData = new BezierData(curveSegments); len = pt3.length; for(k=0;k<curveSegments;k+=1){ point = new Array(len); perc = k/(curveSegments-1); ptDistance = 0; for(i=0;i<len;i+=1){ ptCoord = bm_pow(1-perc,3)*pt1[i]+3*bm_pow(1-perc,2)*perc*(pt1[i] + pt3[i])+3*(1-perc)*bm_pow(perc,2)*(pt2[i] + pt4[i])+bm_pow(perc,3)*pt2[i]; point[i] = ptCoord; if(lastPoint !== null){ ptDistance += bm_pow(point[i] - lastPoint[i],2); } } ptDistance = bm_sqrt(ptDistance); addedLength += ptDistance; bezierData.points[k] = new PointData(ptDistance,point); lastPoint = point; } bezierData.segmentLength = addedLength; keyData.bezierData = bezierData; storedData[bezierName] = bezierData; } }()); function getDistancePerc(perc,bezierData){ var segments = bezierData.segments; var len = segments.length; var initPos = bm_floor((len-1)*perc); var lengthPos = perc*bezierData.addedLength; var lPerc = 0; if(lengthPos == segments[initPos].l){ return segments[initPos].p; }else{ var dir = segments[initPos].l > lengthPos ? -1 : 1; var flag = true; while(flag){ if(segments[initPos].l <= lengthPos && segments[initPos+1].l > lengthPos){ lPerc = (lengthPos - segments[initPos].l)/(segments[initPos+1].l-segments[initPos].l); flag = false; }else{ initPos += dir; } if(initPos < 0 || initPos >= len - 1){ flag = false; } } return segments[initPos].p + (segments[initPos+1].p - segments[initPos].p)*lPerc; } } function SegmentPoints(){ this.pt1 = new Array(2); this.pt2 = new Array(2); this.pt3 = new Array(2); this.pt4 = new Array(2); } function getPointInSegment(pt1, pt2, pt3, pt4, percent, bezierData) { var t1 = getDistancePerc(percent,bezierData); var u0 = 1; var u1 = 1 - t1; var ptX = Math.round((u1*u1*u1* pt1[0] + (t1*u1*u1 + u1*t1*u1 + u1*u1*t1)* pt3[0] + (t1*t1*u1 + u1*t1*t1 + t1*u1*t1)*pt4[0] + t1*t1*t1* pt2[0])* 1000) / 1000; var ptY = Math.round((u1*u1*u1* pt1[1] + (t1*u1*u1 + u1*t1*u1 + u1*u1*t1)* pt3[1] + (t1*t1*u1 + u1*t1*t1 + t1*u1*t1)*pt4[1] + t1*t1*t1* pt2[1])* 1000) / 1000; return [ptX, ptY]; } function getNewSegment(pt1,pt2,pt3,pt4,startPerc,endPerc, bezierData){ var pts = new SegmentPoints(); startPerc = startPerc < 0 ? 0 : startPerc > 1 ? 1 : startPerc; var t0 = getDistancePerc(startPerc,bezierData); endPerc = endPerc > 1 ? 1 : endPerc; var t1 = getDistancePerc(endPerc,bezierData); var i, len = pt1.length; var u0 = 1 - t0; var u1 = 1 - t1; //Math.round(num * 100) / 100 for(i=0;i<len;i+=1){ pts.pt1[i] = Math.round((u0*u0*u0* pt1[i] + (t0*u0*u0 + u0*t0*u0 + u0*u0*t0) * pt3[i] + (t0*t0*u0 + u0*t0*t0 + t0*u0*t0)* pt4[i] + t0*t0*t0* pt2[i])* 1000) / 1000; pts.pt3[i] = Math.round((u0*u0*u1*pt1[i] + (t0*u0*u1 + u0*t0*u1 + u0*u0*t1)* pt3[i] + (t0*t0*u1 + u0*t0*t1 + t0*u0*t1)* pt4[i] + t0*t0*t1* pt2[i])* 1000) / 1000; pts.pt4[i] = Math.round((u0*u1*u1* pt1[i] + (t0*u1*u1 + u0*t1*u1 + u0*u1*t1)* pt3[i] + (t0*t1*u1 + u0*t1*t1 + t0*u1*t1)* pt4[i] + t0*t1*t1* pt2[i])* 1000) / 1000; pts.pt2[i] = Math.round((u1*u1*u1* pt1[i] + (t1*u1*u1 + u1*t1*u1 + u1*u1*t1)* pt3[i] + (t1*t1*u1 + u1*t1*t1 + t1*u1*t1)*pt4[i] + t1*t1*t1* pt2[i])* 1000) / 1000; } return pts; } return { //getEasingCurve : getEasingCurve, getBezierLength : getBezierLength, getSegmentsLength : getSegmentsLength, getNewSegment : getNewSegment, getPointInSegment : getPointInSegment, buildBezierData : buildBezierData, pointOnLine2D : pointOnLine2D, pointOnLine3D : pointOnLine3D }; } var bez = bezFunction();