| (function addPropertyDecorator() { |
| function loopOut(type, duration, durationFlag) { |
| if (!this.k || !this.keyframes) { |
| return this.pv; |
| } |
| type = type ? type.toLowerCase() : ''; |
| var currentFrame = this.comp.renderedFrame; |
| var keyframes = this.keyframes; |
| var lastKeyFrame = keyframes[keyframes.length - 1].t; |
| if (currentFrame <= lastKeyFrame) { |
| return this.pv; |
| } else { |
| var cycleDuration, firstKeyFrame; |
| if (!durationFlag) { |
| if (!duration || duration > keyframes.length - 1) { |
| duration = keyframes.length - 1; |
| } |
| firstKeyFrame = keyframes[keyframes.length - 1 - duration].t; |
| cycleDuration = lastKeyFrame - firstKeyFrame; |
| } else { |
| if (!duration) { |
| cycleDuration = Math.max(0, lastKeyFrame - this.elem.data.ip); |
| } else { |
| cycleDuration = Math.abs(lastKeyFrame - elem.comp.globalData.frameRate * duration); |
| } |
| firstKeyFrame = lastKeyFrame - cycleDuration; |
| } |
| var i, len, ret; |
| if (type === 'pingpong') { |
| var iterations = Math.floor((currentFrame - firstKeyFrame) / cycleDuration); |
| if (iterations % 2 !== 0) { |
| return this.getValueAtTime(((cycleDuration - (currentFrame - firstKeyFrame) % cycleDuration + firstKeyFrame)) / this.comp.globalData.frameRate, 0); // eslint-disable-line |
| } |
| } else if (type === 'offset') { |
| var initV = this.getValueAtTime(firstKeyFrame / this.comp.globalData.frameRate, 0); |
| var endV = this.getValueAtTime(lastKeyFrame / this.comp.globalData.frameRate, 0); |
| var current = this.getValueAtTime(((currentFrame - firstKeyFrame) % cycleDuration + firstKeyFrame) / this.comp.globalData.frameRate, 0); // eslint-disable-line |
| var repeats = Math.floor((currentFrame - firstKeyFrame) / cycleDuration); |
| if (this.pv.length) { |
| ret = new Array(initV.length); |
| len = ret.length; |
| for (i = 0; i < len; i += 1) { |
| ret[i] = (endV[i] - initV[i]) * repeats + current[i]; |
| } |
| return ret; |
| } |
| return (endV - initV) * repeats + current; |
| } else if (type === 'continue') { |
| var lastValue = this.getValueAtTime(lastKeyFrame / this.comp.globalData.frameRate, 0); |
| var nextLastValue = this.getValueAtTime((lastKeyFrame - 0.001) / this.comp.globalData.frameRate, 0); |
| if (this.pv.length) { |
| ret = new Array(lastValue.length); |
| len = ret.length; |
| for (i = 0; i < len; i += 1) { |
| ret[i] = lastValue[i] + (lastValue[i] - nextLastValue[i]) * ((currentFrame - lastKeyFrame) / this.comp.globalData.frameRate) / 0.0005; // eslint-disable-line |
| } |
| return ret; |
| } |
| return lastValue + (lastValue - nextLastValue) * (((currentFrame - lastKeyFrame)) / 0.001); |
| } |
| return this.getValueAtTime((((currentFrame - firstKeyFrame) % cycleDuration + firstKeyFrame)) / this.comp.globalData.frameRate, 0); // eslint-disable-line |
| } |
| } |
| |
| function loopIn(type, duration, durationFlag) { |
| if (!this.k) { |
| return this.pv; |
| } |
| type = type ? type.toLowerCase() : ''; |
| var currentFrame = this.comp.renderedFrame; |
| var keyframes = this.keyframes; |
| var firstKeyFrame = keyframes[0].t; |
| if (currentFrame >= firstKeyFrame) { |
| return this.pv; |
| } else { |
| var cycleDuration, lastKeyFrame; |
| if (!durationFlag) { |
| if (!duration || duration > keyframes.length - 1) { |
| duration = keyframes.length - 1; |
| } |
| lastKeyFrame = keyframes[duration].t; |
| cycleDuration = lastKeyFrame - firstKeyFrame; |
| } else { |
| if (!duration) { |
| cycleDuration = Math.max(0, this.elem.data.op - firstKeyFrame); |
| } else { |
| cycleDuration = Math.abs(elem.comp.globalData.frameRate * duration); |
| } |
| lastKeyFrame = firstKeyFrame + cycleDuration; |
| } |
| var i, len, ret; |
| if (type === 'pingpong') { |
| var iterations = Math.floor((firstKeyFrame - currentFrame) / cycleDuration); |
| if (iterations % 2 === 0) { |
| return this.getValueAtTime((((firstKeyFrame - currentFrame) % cycleDuration + firstKeyFrame)) / this.comp.globalData.frameRate, 0); // eslint-disable-line |
| } |
| } else if (type === 'offset') { |
| var initV = this.getValueAtTime(firstKeyFrame / this.comp.globalData.frameRate, 0); |
| var endV = this.getValueAtTime(lastKeyFrame / this.comp.globalData.frameRate, 0); |
| var current = this.getValueAtTime((cycleDuration - ((firstKeyFrame - currentFrame) % cycleDuration) + firstKeyFrame) / this.comp.globalData.frameRate, 0); |
| var repeats = Math.floor((firstKeyFrame - currentFrame) / cycleDuration) + 1; |
| if (this.pv.length) { |
| ret = new Array(initV.length); |
| len = ret.length; |
| for (i = 0; i < len; i += 1) { |
| ret[i] = current[i] - (endV[i] - initV[i]) * repeats; |
| } |
| return ret; |
| } |
| return current - (endV - initV) * repeats; |
| } else if (type === 'continue') { |
| var firstValue = this.getValueAtTime(firstKeyFrame / this.comp.globalData.frameRate, 0); |
| var nextFirstValue = this.getValueAtTime((firstKeyFrame + 0.001) / this.comp.globalData.frameRate, 0); |
| if (this.pv.length) { |
| ret = new Array(firstValue.length); |
| len = ret.length; |
| for (i = 0; i < len; i += 1) { |
| ret[i] = firstValue[i] + ((firstValue[i] - nextFirstValue[i]) * (firstKeyFrame - currentFrame)) / 0.001; |
| } |
| return ret; |
| } |
| return firstValue + ((firstValue - nextFirstValue) * (firstKeyFrame - currentFrame)) / 0.001; |
| } |
| return this.getValueAtTime(((cycleDuration - ((firstKeyFrame - currentFrame) % cycleDuration + firstKeyFrame))) / this.comp.globalData.frameRate, 0); // eslint-disable-line |
| } |
| } |
| |
| function smooth(width, samples) { |
| if (!this.k) { |
| return this.pv; |
| } |
| width = (width || 0.4) * 0.5; |
| samples = Math.floor(samples || 5); |
| if (samples <= 1) { |
| return this.pv; |
| } |
| var currentTime = this.comp.renderedFrame / this.comp.globalData.frameRate; |
| var initFrame = currentTime - width; |
| var endFrame = currentTime + width; |
| var sampleFrequency = samples > 1 ? (endFrame - initFrame) / (samples - 1) : 1; |
| var i = 0, j = 0; |
| var value; |
| if (this.pv.length) { |
| value = createTypedArray('float32', this.pv.length); |
| } else { |
| value = 0; |
| } |
| var sampleValue; |
| while (i < samples) { |
| sampleValue = this.getValueAtTime(initFrame + i * sampleFrequency); |
| if (this.pv.length) { |
| for (j = 0; j < this.pv.length; j += 1) { |
| value[j] += sampleValue[j]; |
| } |
| } else { |
| value += sampleValue; |
| } |
| i += 1; |
| } |
| if (this.pv.length) { |
| for (j = 0; j < this.pv.length; j += 1) { |
| value[j] /= samples; |
| } |
| } else { |
| value /= samples; |
| } |
| return value; |
| } |
| |
| function getValueAtTime(frameNum) { |
| frameNum *= this.elem.globalData.frameRate; |
| frameNum -= this.offsetTime; |
| if (frameNum !== this._cachingAtTime.lastFrame) { |
| this._cachingAtTime.lastIndex = this._cachingAtTime.lastFrame < frameNum ? this._cachingAtTime.lastIndex : 0; |
| this._cachingAtTime.value = this.interpolateValue(frameNum, this._cachingAtTime); |
| this._cachingAtTime.lastFrame = frameNum; |
| } |
| return this._cachingAtTime.value; |
| } |
| |
| function getTransformValueAtTime(time) { |
| if (!this._transformCachingAtTime) { |
| this._transformCachingAtTime = { |
| v: new Matrix(), |
| }; |
| } |
| /// / |
| var matrix = this._transformCachingAtTime.v; |
| matrix.cloneFromProps(this.pre.props); |
| if (this.appliedTransformations < 1) { |
| var anchor = this.a.getValueAtTime(time); |
| matrix.translate( |
| -anchor[0] * this.a.mult, |
| -anchor[1] * this.a.mult, |
| anchor[2] * this.a.mult |
| ); |
| } |
| if (this.appliedTransformations < 2) { |
| var scale = this.s.getValueAtTime(time); |
| matrix.scale( |
| scale[0] * this.s.mult, |
| scale[1] * this.s.mult, |
| scale[2] * this.s.mult |
| ); |
| } |
| if (this.sk && this.appliedTransformations < 3) { |
| var skew = this.sk.getValueAtTime(time); |
| var skewAxis = this.sa.getValueAtTime(time); |
| matrix.skewFromAxis(-skew * this.sk.mult, skewAxis * this.sa.mult); |
| } |
| if (this.r && this.appliedTransformations < 4) { |
| var rotation = this.r.getValueAtTime(time); |
| matrix.rotate(-rotation * this.r.mult); |
| } else if (!this.r && this.appliedTransformations < 4) { |
| var rotationZ = this.rz.getValueAtTime(time); |
| var rotationY = this.ry.getValueAtTime(time); |
| var rotationX = this.rx.getValueAtTime(time); |
| var orientation = this.or.getValueAtTime(time); |
| matrix.rotateZ(-rotationZ * this.rz.mult) |
| .rotateY(rotationY * this.ry.mult) |
| .rotateX(rotationX * this.rx.mult) |
| .rotateZ(-orientation[2] * this.or.mult) |
| .rotateY(orientation[1] * this.or.mult) |
| .rotateX(orientation[0] * this.or.mult); |
| } |
| if (this.data.p && this.data.p.s) { |
| var positionX = this.px.getValueAtTime(time); |
| var positionY = this.py.getValueAtTime(time); |
| if (this.data.p.z) { |
| var positionZ = this.pz.getValueAtTime(time); |
| matrix.translate( |
| positionX * this.px.mult, |
| positionY * this.py.mult, |
| -positionZ * this.pz.mult |
| ); |
| } else { |
| matrix.translate(positionX * this.px.mult, positionY * this.py.mult, 0); |
| } |
| } else { |
| var position = this.p.getValueAtTime(time); |
| matrix.translate( |
| position[0] * this.p.mult, |
| position[1] * this.p.mult, |
| -position[2] * this.p.mult |
| ); |
| } |
| return matrix; |
| /// / |
| } |
| |
| function getTransformStaticValueAtTime(time) { |
| return this.v.clone(new Matrix()); |
| } |
| |
| var getTransformProperty = TransformPropertyFactory.getTransformProperty; |
| TransformPropertyFactory.getTransformProperty = function (elem, data, container) { |
| var prop = getTransformProperty(elem, data, container); |
| if (prop.dynamicProperties.length) { |
| prop.getValueAtTime = getTransformValueAtTime.bind(prop); |
| } else { |
| prop.getValueAtTime = getTransformStaticValueAtTime.bind(prop); |
| } |
| prop.setGroupProperty = expressionHelpers.setGroupProperty; |
| return prop; |
| }; |
| |
| var propertyGetProp = PropertyFactory.getProp; |
| PropertyFactory.getProp = function (elem, data, type, mult, container) { |
| var prop = propertyGetProp(elem, data, type, mult, container); |
| // prop.getVelocityAtTime = getVelocityAtTime; |
| // prop.loopOut = loopOut; |
| // prop.loopIn = loopIn; |
| if (prop.kf) { |
| prop.getValueAtTime = expressionHelpers.getValueAtTime.bind(prop); |
| } else { |
| prop.getValueAtTime = expressionHelpers.getStaticValueAtTime.bind(prop); |
| } |
| prop.setGroupProperty = expressionHelpers.setGroupProperty; |
| prop.loopOut = loopOut; |
| prop.loopIn = loopIn; |
| prop.smooth = smooth; |
| prop.getVelocityAtTime = expressionHelpers.getVelocityAtTime.bind(prop); |
| prop.getSpeedAtTime = expressionHelpers.getSpeedAtTime.bind(prop); |
| prop.numKeys = data.a === 1 ? data.k.length : 0; |
| prop.propertyIndex = data.ix; |
| var value = 0; |
| if (type !== 0) { |
| value = createTypedArray('float32', data.a === 1 ? data.k[0].s.length : data.k.length); |
| } |
| prop._cachingAtTime = { |
| lastFrame: initialDefaultFrame, |
| lastIndex: 0, |
| value: value, |
| }; |
| expressionHelpers.searchExpressions(elem, data, prop); |
| if (prop.k) { |
| container.addDynamicProperty(prop); |
| } |
| |
| return prop; |
| }; |
| |
| function getShapeValueAtTime(frameNum) { |
| // For now this caching object is created only when needed instead of creating it when the shape is initialized. |
| if (!this._cachingAtTime) { |
| this._cachingAtTime = { |
| shapeValue: shape_pool.clone(this.pv), |
| lastIndex: 0, |
| lastTime: initialDefaultFrame, |
| }; |
| } |
| |
| frameNum *= this.elem.globalData.frameRate; |
| frameNum -= this.offsetTime; |
| if (frameNum !== this._cachingAtTime.lastTime) { |
| this._cachingAtTime.lastIndex = this._cachingAtTime.lastTime < frameNum ? this._caching.lastIndex : 0; |
| this._cachingAtTime.lastTime = frameNum; |
| this.interpolateShape(frameNum, this._cachingAtTime.shapeValue, this._cachingAtTime); |
| } |
| return this._cachingAtTime.shapeValue; |
| } |
| |
| var ShapePropertyConstructorFunction = ShapePropertyFactory.getConstructorFunction(); |
| var KeyframedShapePropertyConstructorFunction = ShapePropertyFactory.getKeyframedConstructorFunction(); |
| |
| function ShapeExpressions() {} |
| ShapeExpressions.prototype = { |
| vertices: function (prop, time) { |
| if (this.k) { |
| this.getValue(); |
| } |
| var shapePath = this.v; |
| if (time !== undefined) { |
| shapePath = this.getValueAtTime(time, 0); |
| } |
| var i, len = shapePath._length; |
| var vertices = shapePath[prop]; |
| var points = shapePath.v; |
| var arr = createSizedArray(len); |
| for (i = 0; i < len; i += 1) { |
| if (prop === 'i' || prop === 'o') { |
| arr[i] = [vertices[i][0] - points[i][0], vertices[i][1] - points[i][1]]; |
| } else { |
| arr[i] = [vertices[i][0], vertices[i][1]]; |
| } |
| } |
| return arr; |
| }, |
| points: function (time) { |
| return this.vertices('v', time); |
| }, |
| inTangents: function (time) { |
| return this.vertices('i', time); |
| }, |
| outTangents: function (time) { |
| return this.vertices('o', time); |
| }, |
| isClosed: function () { |
| return this.v.c; |
| }, |
| pointOnPath: function (perc, time) { |
| var shapePath = this.v; |
| if (time !== undefined) { |
| shapePath = this.getValueAtTime(time, 0); |
| } |
| if (!this._segmentsLength) { |
| this._segmentsLength = bez.getSegmentsLength(shapePath); |
| } |
| |
| var segmentsLength = this._segmentsLength; |
| var lengths = segmentsLength.lengths; |
| var lengthPos = segmentsLength.totalLength * perc; |
| var i = 0, len = lengths.length; |
| var j = 0, jLen; |
| var accumulatedLength = 0, pt; |
| while (i < len) { |
| if (accumulatedLength + lengths[i].addedLength > lengthPos) { |
| var initIndex = i; |
| var endIndex = (shapePath.c && i === len - 1) ? 0 : i + 1; |
| var segmentPerc = (lengthPos - accumulatedLength) / lengths[i].addedLength; |
| pt = bez.getPointInSegment(shapePath.v[initIndex], shapePath.v[endIndex], shapePath.o[initIndex], shapePath.i[endIndex], segmentPerc, lengths[i]); |
| break; |
| } else { |
| accumulatedLength += lengths[i].addedLength; |
| } |
| i += 1; |
| } |
| if (!pt) { |
| pt = shapePath.c ? [shapePath.v[0][0], shapePath.v[0][1]] : [shapePath.v[shapePath._length - 1][0], shapePath.v[shapePath._length - 1][1]]; |
| } |
| return pt; |
| }, |
| vectorOnPath: function (perc, time, vectorType) { |
| // perc doesn't use triple equality because it can be a Number object as well as a primitive. |
| perc = perc == 1 ? this.v.c ? 0 : 0.999 : perc; |
| var pt1 = this.pointOnPath(perc, time); |
| var pt2 = this.pointOnPath(perc + 0.001, time); |
| var xLength = pt2[0] - pt1[0]; |
| var yLength = pt2[1] - pt1[1]; |
| var magnitude = Math.sqrt(Math.pow(xLength, 2) + Math.pow(yLength, 2)); |
| if (magnitude === 0) { |
| return [0, 0]; |
| } |
| var unitVector = vectorType === 'tangent' ? [xLength / magnitude, yLength / magnitude] : [-yLength / magnitude, xLength / magnitude]; |
| return unitVector; |
| }, |
| tangentOnPath: function (perc, time) { |
| return this.vectorOnPath(perc, time, 'tangent'); |
| }, |
| normalOnPath: function (perc, time) { |
| return this.vectorOnPath(perc, time, 'normal'); |
| }, |
| setGroupProperty: expressionHelpers.setGroupProperty, |
| getValueAtTime: expressionHelpers.getStaticValueAtTime, |
| }; |
| extendPrototype([ShapeExpressions], ShapePropertyConstructorFunction); |
| extendPrototype([ShapeExpressions], KeyframedShapePropertyConstructorFunction); |
| KeyframedShapePropertyConstructorFunction.prototype.getValueAtTime = getShapeValueAtTime; |
| KeyframedShapePropertyConstructorFunction.prototype.initiateExpression = ExpressionManager.initiateExpression; |
| |
| var propertyGetShapeProp = ShapePropertyFactory.getShapeProp; |
| ShapePropertyFactory.getShapeProp = function (elem, data, type, arr, trims) { |
| var prop = propertyGetShapeProp(elem, data, type, arr, trims); |
| prop.propertyIndex = data.ix; |
| prop.lock = false; |
| if (type === 3) { |
| expressionHelpers.searchExpressions(elem, data.pt, prop); |
| } else if (type === 4) { |
| expressionHelpers.searchExpressions(elem, data.ks, prop); |
| } |
| if (prop.k) { |
| elem.addDynamicProperty(prop); |
| } |
| return prop; |
| }; |
| }()); |