js/QuartzCore/CAPropertyAnimation.js
'use strict'
import CAAnimation from './CAAnimation'
import CGPoint from '../CoreGraphics/CGPoint'
import CGSize from '../CoreGraphics/CGSize'
import CGRect from '../CoreGraphics/CGRect'
import SCNMatrix4 from '../SceneKit/SCNMatrix4'
//import SCNQuaternion from '../SceneKit/SCNQuaternion'
import SCNVector4 from '../SceneKit/SCNVector4'
import SCNVector3 from '../SceneKit/SCNVector3'
import SKColor from '../SpriteKit/SKColor'
import _InstanceOf from '../util/_InstanceOf'
/**
* An abstract subclass of CAAnimation for creating animations that manipulate the value of layer properties.
* @access public
* @extends {CAAnimation}
* @see https://developer.apple.com/documentation/quartzcore/capropertyanimation
*/
export default class CAPropertyAnimation extends CAAnimation {
// Creating an Animation
/**
* Creates and returns an CAPropertyAnimation instance for the specified key path.
* @access public
* @constructor
* @param {?string} path -
* @see https://developer.apple.com/documentation/quartzcore/capropertyanimation/1412534-init
*/
constructor(path) {
super()
// Animated Key Path
/**
* Specifies the key path the receiver animates.
* @type {?string}
* @see https://developer.apple.com/documentation/quartzcore/capropertyanimation/1412496-keypath
*/
this.keyPath = path
// Property Value Calculation Behavior
/**
* Determines if the value of the property is the value at the end of the previous repeat cycle, plus the value of the current repeat cycle.
* @type {boolean}
* @see https://developer.apple.com/documentation/quartzcore/capropertyanimation/1412538-iscumulative
*/
this.isCumulative = false
/**
* Determines if the value specified by the animation is added to the current render tree value to produce the new render tree value.
* @type {boolean}
* @see https://developer.apple.com/documentation/quartzcore/capropertyanimation/1412493-isadditive
*/
this.isAdditive = false
/**
* An optional value function that is applied to interpolated values.
* @type {?CAValueFunction}
* @see https://developer.apple.com/documentation/quartzcore/capropertyanimation/1412447-valuefunction
*/
this.valueFunction = null
this._isMultiplicative = false
}
/**
* @access public
* @returns {CAPropertyAnimation} -
*/
copy() {
const anim = super.copy()
//anim._copyValue(this)
anim.keyPath = this.keyPath
anim.isCumulative = this.isCumulative
anim.isAdditive = this.isAdditive
anim.valueFunction = this.valueFunction
anim._isMultiplicative = this._isMultiplicative
return anim
}
/*
_copyValue(src) {
console.log('CAPropertyAnimation._copyValue: ' + src.keyPath)
this.keyPath = src.keyPath
this.isCumulative = src.isCumulative
this.isAdditive = src.isAdditive
this.valueFunction = src.valueFunction
}
*/
/**
* apply animation to the given node.
* @access private
* @param {Object} obj - target object to apply this animation.
* @param {number} time - active time
* @param {boolean} [needTimeConversion = true] -
* @returns {void}
*/
_applyAnimation(obj, time, needTimeConversion = true) {
let t = time
if(needTimeConversion){
const baseTime = this._basetimeFromTime(time)
t = baseTime
if(this.timingFunction !== null){
t = this.timingFunction._getValueAtTime(baseTime)
}
}
let value = t
if(this.valueFunction !== null){
value = this.valueFunction._getValueAtTime(t)
}
value = this._calculateWithBaseValue(obj, value)
//console.log(`CAPropertyAnimation: obj: ${obj.name}, time: ${time}, keyPath: ${this.keyPath}, value: ${value}`)
this._applyValue(obj, value)
this._handleEvents(obj, t)
}
_calculateWithBaseValue(obj, value) {
if(this.isAdditive){
const baseValue = obj.valueForKeyPath(this.keyPath)
return this._addValues(baseValue, value)
}else if(this._isMultiplicative){
const baseValue = obj.valueForKeyPath(this.keyPath)
return this._mulValues(baseValue, value)
}
return value
}
_applyValue(obj, value) {
obj.setValueForKeyPath(value, this.keyPath)
}
_addValues(v1, v2) {
if(v1 instanceof Object){
return v1.add(v2)
}
return v1 + v2
}
_mulValues(v1, v2) {
if(v1 instanceof Object){
return v1.mul(v2)
}
return v1 * v2
}
_lerp(from, to, t) {
if(t === null){
// the animation is over.
return to
}
if(_InstanceOf(from, SCNVector4)){
// TODO: slerp for Quaternion
return from.lerp(to, t)
}else if(_InstanceOf(from, SCNVector3)){
return from.lerp(to, t)
}else if(_InstanceOf(from, SCNMatrix4)){
return from.lerp(to, t)
}else if(_InstanceOf(from, CGSize)){
// TODO: implement
}else if(_InstanceOf(from, CGPoint)){
// TODO: implement
}else if(_InstanceOf(from, CGRect)){
// TODO: implement
}else if(_InstanceOf(from, SKColor)){
return from._lerp(to, t)
}
return from + (to - from) * t
}
_slerp(from, to, t) {
if(!_InstanceOf(from, SCNVector4)){
throw new Error('CABasicAnimation._slerp: object is not SCNVector4')
}
return from.slerp(to, t)
}
}