/* eslint guard-for-in: "off" */
import {Animate} from './Animate';
import {BezierCurve} from '../math/BezierCurve';
import {Point} from '../math/Point';
import {Utils} from '../utils/Utils';
import {prepareEaseing, getEaseing, getEaseingPath} from '../utils/Easeing';
const PROPS_MAP = {
o: {
props: ['alpha'],
scale: 0.01,
},
r: {
props: ['rotation'],
scale: 1,
},
p: {
props: ['x', 'y'],
scale: 1,
},
a: {
props: ['pivotX', 'pivotY'],
scale: 1,
},
s: {
props: ['scaleX', 'scaleY'],
scale: 0.01,
},
};
/**
* 判断数值是否在(min, max]区间内
* @param {number} v 待比较的值
* @param {number} min 最小区间
* @param {number} max 最大区间
* @return {boolean} 是否在(min, max]区间内
*/
function inRange(v, min, max) {
return v > min && v <= max;
}
/**
* 判断当前进度在哪一帧内
* @param {array} steps 帧数组
* @param {number} progress 当前进度
* @return {number} 当前进度停留在第几帧
*/
function findStep(steps, progress) {
const last = steps.length - 1;
for (let i = 0; i < last; i++) {
const step = steps[i];
if (inRange(progress, step.jcst, step.jcet)) {
return i;
}
}
}
/**
* KeyFrames类型动画对象
*
* @class
* @memberof JC
* @param {object} [options] 动画配置信息
*/
function KeyFrames(options) {
Animate.call(this, options);
this.layer = Utils.copyJSON(options.layer);
this.fr = options.fr || 30;
this.tpf = 1000 / this.fr;
this.iipt = this.layer.ip * this.tpf;
this.iopt = this.layer.op * this.tpf;
this.ip = options.ip === undefined ? this.layer.ip : options.ip;
this.op = options.op === undefined ? this.layer.op : options.op;
this.tfs = Math.floor(this.op - this.ip);
this.duration = this.tfs * this.tpf;
// this.keyState = {};
this.aks = {};
this.kic = {};
this.preParser();
this.nextPose();
}
KeyFrames.prototype = Object.create(Animate.prototype);
/**
* 预解析关键帧
* @private
*/
KeyFrames.prototype.preParser = function() {
const ks = this.layer.ks;
for (const key in ks) {
if (ks[key].a) {
this.parserDynamic(key);
} else {
this.parserStatic(key);
}
}
};
/**
* 预解析动态属性的关键帧
* @private
* @param {string} key 所属的属性
*/
KeyFrames.prototype.parserDynamic = function(key) {
const ksp = this.layer.ks[key];
const kspk = ksp.k;
ksp.jcst = kspk[0].t * this.tpf;
ksp.jcet = kspk[kspk.length - 1].t * this.tpf;
for (let i = 0; i < kspk.length; i++) {
const sbk = kspk[i];
const sek = kspk[i + 1];
if (sek) {
sbk.jcst = sbk.t * this.tpf;
sbk.jcet = sek.t * this.tpf;
if (Utils.isString(sbk.n) && sbk.ti && sbk.to) {
prepareEaseing(sbk.o.x, sbk.o.y, sbk.i.x, sbk.i.y);
const sp = new Point(sbk.s[0], sbk.s[1]);
const ep = new Point(sbk.e[0], sbk.e[1]);
const c1 = new Point(sbk.s[0] + sbk.ti[0], sbk.s[1] + sbk.ti[1]);
const c2 = new Point(sbk.e[0] + sbk.to[0], sbk.e[1] + sbk.to[1]);
sbk.curve = new BezierCurve([sp, c1, c2, ep]);
} else {
for (let i = 0; i < sbk.n.length; i++) {
prepareEaseing(sbk.o.x[i], sbk.o.y[i], sbk.i.x[i], sbk.i.y[i]);
}
}
}
}
this.aks[key] = ksp;
};
/**
* 预解析静态属性的关键帧
* @private
* @param {string} key 所属的属性
*/
KeyFrames.prototype.parserStatic = function(key) {
// const prop = PM[key].label;
// const scale = PM[key].scale;
// let k = 0;
// if (Utils.isString(prop)) {
// if (Utils.isNumber(ks[key].k)) {
// k = ks[key].k;
// }
// if (Utils.isArray(ks[key].k)) {
// k = ks[key].k[0];
// }
// this.element[prop] = scale * k;
// } else if (Utils.isArray(prop)) {
// for (let i = 0; i < prop.length; i++) {
// k = ks[key].k[i];
// this.element[prop[i]] = scale * k;
// }
// }
const ksp = this.layer.ks[key];
let kspk = ksp.k;
if (Utils.isNumber(kspk)) kspk = [kspk];
this.setValue(key, kspk);
};
/**
* 计算下一帧状态
* @private
* @return {object}
*/
KeyFrames.prototype.nextPose = function() {
const pose = {};
for (const key in this.aks) {
const ak = this.aks[key];
pose[key] = this.interpolation(key, ak);
this.setValue(key, pose[key]);
}
return pose;
};
/**
* 计算关键帧属性值
* @private
* @param {string} key 关键帧配置
* @param {object} ak 所属的属性
* @return {array}
*/
KeyFrames.prototype.interpolation = function(key, ak) {
const akk = ak.k;
const progress = Utils.clamp(this.progress, 0, ak.jcet);
const skt = ak.jcst;
const ekt = ak.jcet;
const invisible = progress < this.iipt;
if (invisible === this.element.visible) this.element.visible = !invisible;
if (progress <= skt) {
return akk[0].s;
} else if (progress >= ekt) {
const last = akk.length - 2;
return akk[last].e;
} else {
let kic = this.kic[key];
if (
!Utils.isNumber(kic) ||
!inRange(progress, akk[kic].jcst, akk[kic].jcet)
) {
kic = this.kic[key] = findStep(akk, progress);
}
const frame = akk[kic];
const rate = (progress - frame.jcst) / (frame.jcet - frame.jcst);
if (frame.curve) {
return getEaseingPath(frame.curve, frame.n, rate);
} else {
return getEaseing(frame.s, frame.e, frame.n, rate);
}
}
};
/**
* 更新元素的属性值
* @private
* @param {string} key 属性
* @param {array} value 属性值
*/
KeyFrames.prototype.setValue = function(key, value) {
const props = PROPS_MAP[key].props;
const scale = PROPS_MAP[key].scale;
for (let i = 0; i < props.length; i++) {
const v = value[i];
this.element[props[i]] = scale * v;
}
};
export {KeyFrames};