Commit be66c9a8 authored by wjf's avatar wjf

2.0.30

parent 46806a25
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -75,21 +75,26 @@ ...@@ -75,21 +75,26 @@
if (name.indexOf(".svga") >= 0) { if (name.indexOf(".svga") >= 0) {
SvgaParser.loadSvga(src, (v) => { SvgaParser.loadSvga(src, (v) => {
console.log(v) console.log(v)
window.asd= stage.addChild(new FYGE.SvgaAni(v)) window.asd = stage.addChild(new FYGE.SvgaAni(v))
// .position.set( // .position.set(
// (750 - v.videoSize.width) / 2, // (750 - v.videoSize.width) / 2,
// (stage.viewRect.height - v.videoSize.height) / 2, // (stage.viewRect.height - v.videoSize.height) / 2,
// ) // )
window.asd.stop(); // window.asd.stop();
}) }, (e) => { console.log(e) })
} else { } else {
//加载 //加载
FYGE.GlobalLoader.loadJson((s, json) => { FYGE.GlobalLoader.loadJson((s, json) => {
var l = stage.addChild(new FYGE.Lottie(json)) console.log(json)
// l.position.set((750 - json.w) / 2, (stage.viewRect.height - json.h) / 2); try {
l.play(); var l = stage.addChild(new FYGE.Lottie(json))
window.asd=l; // l.position.set((750 - json.w) / 2, (stage.viewRect.height - json.h) / 2);
window.asd.stop(); l.play();
window.asd = l;
// window.asd.stop();
} catch (e) {
console.log(e)
}
}, src) }, src)
} }
} }
...@@ -102,7 +107,7 @@ ...@@ -102,7 +107,7 @@
sssss sssss
},1000) },1000)
</script> --> </script> -->
</body> </body>
</html> </html>
\ No newline at end of file
{ {
"name": "fyge", "name": "fyge",
"version": "2.0.29", "version": "2.0.30",
"description": "canvas渲染引擎", "description": "canvas渲染引擎",
"main": "./build/fyge.min.js", "main": "./build/fyge.min.js",
"types": "./build/types.d.ts", "types": "./build/types.d.ts",
......
...@@ -387,6 +387,12 @@ ...@@ -387,6 +387,12 @@
Lottie文件里的LottieVisibleTrack类的resetValue方法里添加执行this.setValue(0); Lottie文件里的LottieVisibleTrack类的resetValue方法里添加执行this.setValue(0);
Lottie文件里的createLottieTracks方法里实例Sprite时获取纹理的逻辑修改,textures不存在或textures里字段不存在时取全局 Lottie文件里的createLottieTracks方法里实例Sprite时获取纹理的逻辑修改,textures不存在或textures里字段不存在时取全局
2.0.30 Lottie的init方法里遍历tracks加了一段给LottieExpressionTrack的帧率赋值
Lottie文件里增加setValue函数
比如LottieBaseTrack的setValue方法替换成setValue
Lottie新增时间轴LottieExpressionTrack,parseExpression函数,runExpressionNode函数
Lottie文件的createLottieTracks方法里把原先分开属性修改成["o", "r", "p", "s"]数组遍历
大尺寸纹理首次传gpu使用时会掉帧,越大耗时越多。考虑如何处理 大尺寸纹理首次传gpu使用时会掉帧,越大耗时越多。考虑如何处理
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* @name VERSION * @name VERSION
* @type {string} * @type {string}
*/ */
export const VERSION = "2.0.29"; export const VERSION = "2.0.30";
/** /**
......
...@@ -96,7 +96,14 @@ export class Lottie extends AnimationNode { ...@@ -96,7 +96,14 @@ export class Lottie extends AnimationNode {
data.compositions data.compositions
); );
//初始值设置下 //初始值设置下
tracks.forEach((t) => { t.resetValue() }); tracks.forEach((t) => {
//初始值重置下
t.resetValue();
//表达式的加一个帧率,其实是最好createLottieTracks传入,再说了
if (t.instanceType == "LottieExpressionTrack") {
(t as LottieExpressionTrack).frameRate = data.fr;
}
});
//合成所有时间轴 //合成所有时间轴
if (!this.animationClip) { if (!this.animationClip) {
this.animationClip = new AnimationClip(tracks, this.totalFrames); this.animationClip = new AnimationClip(tracks, this.totalFrames);
...@@ -230,21 +237,22 @@ class LottieBaseTrack extends HashObject implements IAnimationTrack { ...@@ -230,21 +237,22 @@ class LottieBaseTrack extends HashObject implements IAnimationTrack {
setValue(time: number) { setValue(time: number) {
time -= this.ip; time -= this.ip;
// if (!this.obj.visible) return // if (!this.obj.visible) return
var value = this.cacValue(time); setValue(this.obj, this.cacValue(time), this.type)
switch (this.type) { // var value = this.cacValue(time);
case "r": // switch (this.type) {
this.obj.rotation = value[0]; // case "r":
break; // this.obj.rotation = value[0];
case "o": // break;
this.obj.alpha = value[0] / 100; // case "o":
break; // this.obj.alpha = value[0] / 100;
case "s": // break;
this.obj.scale.set(value[0] / 100, value[1] / 100); // case "s":
break; // this.obj.scale.set(value[0] / 100, value[1] / 100);
case "p": // break;
this.obj.position.set(value[0] - this.obj.anchorX, value[1] - this.obj.anchorY); // case "p":
break; // this.obj.position.set(value[0] - this.obj.anchorX, value[1] - this.obj.anchorY);
} // break;
// }
} }
/** /**
* *
...@@ -364,7 +372,48 @@ class LottieVisibleTrack extends HashObject implements IAnimationTrack { ...@@ -364,7 +372,48 @@ class LottieVisibleTrack extends HashObject implements IAnimationTrack {
this.obj = null this.obj = null
} }
} }
/**
* 纯表达式的时间轴
*/
class LottieExpressionTrack extends HashObject implements IAnimationTrack {
/**
* 帧率,外部给吧
*/
public frameRate: number;
private node
constructor(
protected obj: Sprite,
private type: "r" | "o" | "s" | "p",
private expression: string,
private origionValue: number | number[],
private ip: number = 0,//偏移
) {
super();
this._instanceType = "LottieExpressionTrack";
let e = this.expression.split("$bm_rt = ")[1]//取后面的//前面的var $bm_rt;\n$bm_rt = 没用
this.node = parseExpression(e);
// console.log(this.node)
}
/**
* @param time
*/
setValue(time: number) {
time -= this.ip;
time /= this.frameRate;//注意修改FPS时需要遍历该类时间轴
// if(this.type=="o") console.log(runExpressionNode(this.node, time))
setValue(
this.obj,
runExpressionNode(this.node, time),
this.type
)
}
resetValue() {
setValue(this.obj, this.origionValue, this.type);
}
destroy() {
this.obj = null
}
}
function loopOut(type: LoopType, duration: number, keyframes: KeyAniData[], currentFrame: number) { function loopOut(type: LoopType, duration: number, keyframes: KeyAniData[], currentFrame: number) {
var lastKeyFrame = keyframes[keyframes.length - 1].t; var lastKeyFrame = keyframes[keyframes.length - 1].t;
...@@ -458,6 +507,24 @@ function getLoopData(x: string): LoopData { ...@@ -458,6 +507,24 @@ function getLoopData(x: string): LoopData {
return { loopInOrOut, type, duration: rr } return { loopInOrOut, type, duration: rr }
} }
function setValue(obj: Sprite, value: number | number[], type: "r" | "o" | "s" | "p") {
//转下数字的为数组
if (typeof value == "number") value = [value];
switch (type) {
case "r":
obj.rotation = value[0];
break;
case "o":
obj.alpha = value[0] / 100;
break;
case "s":
obj.scale.set(value[0] / 100, value[1] / 100);
break;
case "p":
obj.position.set(value[0] - obj.anchorX, value[1] - obj.anchorY);
break;
}
}
/** /**
* *
*/ */
...@@ -541,7 +608,7 @@ function createLottieTracks( ...@@ -541,7 +608,7 @@ function createLottieTracks(
offset: number, offset: number,
textures: { [key: string]: Texture }, textures: { [key: string]: Texture },
compositions?: { [key: string]: LayerData[] }, compositions?: { [key: string]: LayerData[] },
tracks: (LottieVisibleTrack | LottieBaseTrack)[] = [], tracks: (LottieVisibleTrack | LottieBaseTrack | LottieExpressionTrack)[] = [],
) { ) {
for (var i = layers.length - 1; i >= 0; i--) { for (var i = layers.length - 1; i >= 0; i--) {
let layer = layers[i]; let layer = layers[i];
...@@ -581,52 +648,27 @@ function createLottieTracks( ...@@ -581,52 +648,27 @@ function createLottieTracks(
var ad = typeof ks.a.k[0] == "number" ? ks.a.k : ks.a.k[0].s; var ad = typeof ks.a.k[0] == "number" ? ks.a.k : ks.a.k[0].s;
c.anchor.set(ad[0], ad[1]); c.anchor.set(ad[0], ad[1]);
//加显示隐藏的 //加显示隐藏的
tracks.push(new LottieVisibleTrack(c, ip, op, st, offset)) tracks.push(new LottieVisibleTrack(c, ip, op, st, offset));
//@ts-ignore透明度 ["o", "r", "p", "s"].forEach((type: "o" | "r" | "p" | "s") => {
if (ks.o.k.length) { let k: KeyAniData[] | number[] | number = ks[type].k;
tracks.push( let expression: string = ks[type].x;
//@ts-ignore
new LottieBaseTrack(c, "o", ks.o.k, getLoopData(ks.o.x), offset)
)
} else {
//@ts-ignore
c.alpha = ks.o.k / 100
}
//@ts-ignore 旋转
if (ks.r.k.length) {
tracks.push(
//@ts-ignore
new LottieBaseTrack(c, "r", ks.r.k, getLoopData(ks.r.x), offset)
)
} else {
//@ts-ignore
c.rotation = ks.r.k
}
//位置
if (typeof ks.p.k[0] != "number") {
tracks.push(
//@ts-ignore
new LottieBaseTrack(c, "p", ks.p.k, getLoopData(ks.p.x), offset)
)
} else {
//@ts-ignore //@ts-ignore
var p = ks.p.k; if (((type == "o" || type == "r") && k.length) ||//透明度和旋转,k有长度就是关键帧,
c.position.set(p[0] - ad[0], p[1] - ad[1]) ((type == "s" || type == "p") && typeof k[0] != "number")) {//透明度和旋转,k有长度就是关键帧,位置和缩放得k的元素里不是number
} tracks.push(
new LottieBaseTrack(c as Sprite, type, k as KeyAniData[], getLoopData(expression), offset)
//缩放 )
if (typeof ks.s.k[0] != "number") { } else {
tracks.push( //没有关键帧的设置下初始值
//@ts-ignore setValue(c as Sprite, k as number, type);
new LottieBaseTrack(c, "s", ks.s.k, getLoopData(ks.s.x), offset) //表达式判断,但是不管loop那些表达式,因为已经进BaseTrack了的,也不管位移和缩放的先
) if (expression && expression.indexOf("loop") == -1 && type !== "s" && type !== "p") {
} else { tracks.push(
//@ts-ignore new LottieExpressionTrack(c as Sprite, type, expression, k as number, offset)
var s = ks.s.k; )
c.scale.set(s[0] / 100, s[1] / 100) }
} }
})
} }
return tracks; return tracks;
} }
...@@ -681,5 +723,202 @@ function createLottieMask(masksProperties: ILottieMaskData[], w: number, h: numb ...@@ -681,5 +723,202 @@ function createLottieMask(masksProperties: ILottieMaskData[], w: number, h: numb
return mask return mask
} }
//表达式的各种范式匹配
//
//30+time*10 "var $bm_rt;\n$bm_rt = $bm_sum(30, $bm_mul(time, 10));"
//time*30 "var $bm_rt;\n$bm_rt = $bm_mul(time, 30);"
// "var $bm_rt;\n$bm_rt = $bm_sum([\n time * 10,\n time * 5\n], value);"
function $bm_sum(a, b) {
// var tOfA = typeof a;
// var tOfB = typeof b;
// if(tOfA === 'string' || tOfB === 'string'){
// return a + b;
// }
// if(isNumerable(tOfA, a) && isNumerable(tOfB, b)) {
// return a + b;
// }
// if($bm_isInstanceOfArray(a) && isNumerable(tOfB, b)){
// a = a.slice(0);
// a[0] = a[0] + b;
// return a;
// }
// if(isNumerable(tOfA, a) && $bm_isInstanceOfArray(b)){
// b = b.slice(0);
// b[0] = a + b[0];
// return b;
// }
// if($bm_isInstanceOfArray(a) && $bm_isInstanceOfArray(b)){
// var i = 0, lenA = a.length, lenB = b.length;
// var retArr = [];
// while(i<lenA || i < lenB){
// if((typeof a[i] === 'number' || a[i] instanceof Number) && (typeof b[i] === 'number' || b[i] instanceof Number)){
// retArr[i] = a[i] + b[i];
// }else{
// retArr[i] = b[i] === undefined ? a[i] : a[i] || b[i];
// }
// i += 1;
// }
// return retArr;
// }
// return 0;
}
function $bm_sub(a, b) {
// var tOfA = typeof a;
// var tOfB = typeof b;
// if (isNumerable(tOfA, a) && isNumerable(tOfB, b)) {
// if (tOfA === 'string') {
// a = parseInt(a);
// }
// if (tOfB === 'string') {
// b = parseInt(b);
// }
// return a - b;
// }
// if ($bm_isInstanceOfArray(a) && isNumerable(tOfB, b)) {
// a = a.slice(0);
// a[0] = a[0] - b;
// return a;
// }
// if (isNumerable(tOfA, a) && $bm_isInstanceOfArray(b)) {
// b = b.slice(0);
// b[0] = a - b[0];
// return b;
// }
// if ($bm_isInstanceOfArray(a) && $bm_isInstanceOfArray(b)) {
// var i = 0, lenA = a.length, lenB = b.length;
// var retArr = [];
// while (i < lenA || i < lenB) {
// if ((typeof a[i] === 'number' || a[i] instanceof Number) && (typeof b[i] === 'number' || b[i] instanceof Number)) {
// retArr[i] = a[i] - b[i];
// } else {
// retArr[i] = b[i] === undefined ? a[i] : a[i] || b[i];
// }
// i += 1;
// }
// return retArr;
// }
// return 0;
}
function $bm_mul(a, b) {
// var tOfA = typeof a;
// var tOfB = typeof b;
// var arr;
// if (isNumerable(tOfA, a) && isNumerable(tOfB, b)) {
// return a * b;
// }
// var i, len;
// if ($bm_isInstanceOfArray(a) && isNumerable(tOfB, b)) {
// len = a.length;
// arr = createTypedArray('float32', len);
// for (i = 0; i < len; i += 1) {
// arr[i] = a[i] * b;
// }
// return arr;
// }
// if (isNumerable(tOfA, a) && $bm_isInstanceOfArray(b)) {
// len = b.length;
// arr = createTypedArray('float32', len);
// for (i = 0; i < len; i += 1) {
// arr[i] = a * b[i];
// }
// return arr;
// }
// return 0;
}
function $bm_div(a, b) {
// var tOfA = typeof a;
// var tOfB = typeof b;
// var arr;
// if (isNumerable(tOfA, a) && isNumerable(tOfB, b)) {
// return a / b;
// }
// var i, len;
// if ($bm_isInstanceOfArray(a) && isNumerable(tOfB, b)) {
// len = a.length;
// arr = createTypedArray('float32', len);
// for (i = 0; i < len; i += 1) {
// arr[i] = a[i] / b;
// }
// return arr;
// }
// if (isNumerable(tOfA, a) && $bm_isInstanceOfArray(b)) {
// len = b.length;
// arr = createTypedArray('float32', len);
// for (i = 0; i < len; i += 1) {
// arr[i] = a / b[i];
// }
// return arr;
// }
// return 0;
}
function $bm_isInstanceOfArray(arr) {
return arr.constructor === Array || arr.constructor === Float32Array;
}
function isNumerable(tOfV, v) {
return tOfV === 'number' || tOfV === 'boolean' || tOfV === 'string' || v instanceof Number;
}
//解析表达式,暂时只有一维数据的加减乘除
function parseExpression(source: string) {
let pos = 0
let word = ''
let stack = []
let node
let char
while (char = source[pos++]) {
switch (char) {
case '(':
node = { op: word, args: [] }
word = ''
stack.push(node)
break;
case ')':
push()
node = stack[stack.length - 1]
stack.pop()
break;
case ',':
push()
break;
case ' ':
break;
default:
word += char
}
}
return node
function push() {
let val = word
// if (!isNaN(word)) {
// val = parseFloat(word)
// }
stack[stack.length - 1].args.push(word ? val : node)
word = ''
}
}
//四种函数的映射
const expressionFuns = {
$bm_sum: (a, b) => a + b,
$bm_sub: (a, b) => a - b,
$bm_mul: (a, b) => a * b,
$bm_div: (a, b) => a / b
};
function runExpressionNode(node, time: number) {
return opp(node.op, node.args[0], node.args[1], time);
function opp(op: string, a, b, time) {
if (a.op) {
a = opp(a.op, a.args[0], a.args[1], time);
} else if (a == "time") {
a = time
}
if (b.op) {
b = opp(b.op, b.args[0], b.args[1], time);
} else if (b == "time") {
b = time;
}
return expressionFuns[op](+a, +b)
}
}
import { AnimationClip, IAnimationTrack } from "../AnimationClip";
import { HashObject } from "../HashObject";
import { Container, Sprite } from "../display";
import { BaseTexture, Texture } from "../texture";
import { getBezierEasing } from "./forLottie/BezierEaser"
import { buildBezierProp } from "./forLottie/buildBezierProp";
import { createImage, TextureCache } from "../utils";
import { Shape } from "../graphics";
import { AnimationNode } from "./AnimationNode";
//20210719备份
export class Lottie extends AnimationNode {
/**
* 原始数据,尽量只获取,不修改
*/
protected rawData: LottieData;
/**
* 总时间,秒计
*/
get totalTime(): number {
if (!this.rawData) return 0;
const { op, ip } = this.rawData;
return (op - ip) * (1 / this.fps);
};
/**
* 总帧数
*/
get totalFrames(): number {
if (!this.rawData) return 0;
const { op, ip } = this.rawData;
return op - ip;
};
/**
* 动画显示宽度
*/
get videoWidth(): number {
return this.rawData && this.rawData.w || 0;
};
/**
* 动画显示高度
*/
get videoHeight(): number {
return this.rawData && this.rawData.h || 0;
};
/**
* 重写
* 每秒刷新帧数,没设置过直接用数据里的
*/
get fps() {
//没设置过就用数据里的
return this._fps || this.rawData && this.rawData.fr || null;
}
set fps(v: number) {
this._fps = v;
}
//lottie图层主容器
private lottieContainer: LottieContainer;
constructor(data: LottieData) {
super(data);//里面执行了init
this._instanceType = "Lottie";
}
/**
* 初始化方法
* @param data
* @returns
*/
public init(data: LottieData) {
if (!data || data == this.rawData) return;
this.rawData = data;
//名字
this.name = data.nm;
//初始化图片 有assets但无textures
if (data.assets && !data.textures) {
data.textures = {};
data.assets.forEach((a) => {
if (a.layers) {//合成嵌套的情况
data.compositions = data.compositions || {};
data.compositions[a.id] = a.layers;
return;
}
let imgTag = createImage();
imgTag.src = a.p;
data.textures[a.id] = new Texture(new BaseTexture(imgTag));
})
}
//原先有的,先销毁
this.lottieContainer && this.lottieContainer.destroy();
//初始化一个容器;
this.lottieContainer = this.addChild(new LottieContainer());
//生成时间轴
var tracks = createLottieTracks(
this.lottieContainer,
data.layers,
data.ip,
data.textures,
data.compositions
);
//初始值设置下
tracks.forEach((t) => { t.resetValue() });
//合成所有时间轴
if (!this.animationClip) {
this.animationClip = new AnimationClip(tracks, this.totalFrames);
} else {
this.animationClip.init(tracks, this.totalFrames)
}
//数据更新
this._onRawDataUpdate();
}
}
interface LottieData {
"fr": number,//帧率 30 60等
"ip": number,//开始帧
"op": number,//结束帧
"w": number,//宽度
"h": number,//高度
"nm": string,//名字
"layers": LayerData[],
"assets"?: {
"id": string,//图片id,与layers里的refId对应
"w": number,
"h": number,
"p": string,//base64数据
"layers": LayerData[],//合成嵌套的
}[],
"textures"?: { [key: string]: Texture }//缓存的贴图,为了上面的assets里的图片数据,不进全局缓存,
// "components"?: { [key: string]: LottieData }
compositions?: { [key: string]: LayerData[] }
}
interface LayerData {
"ind": number,//id唯一
"ty": number,//类型,2是图片,0是合成
"nm": string//"owl_sleep.png",//暂时就是图片
"refId": string,
"parent"?: number,//父级id
"ks": KsData;
"ip": number,//开始帧
"op": number,//结束帧
"st": number,
"w"?: number,//合成的会有
"h"?: number,//合成的会有
hasMask?: boolean,
masksProperties?: ILottieMaskData[],//遮罩数据
}
interface KsData {
o: KeyData //透明度
r: KeyData //旋转
p: KeyData //位置
a: KeyData //锚点
s: KeyData //缩放
}
interface KeyData {
a: number,//貌似没用
k: KeyAniData[] | number[] | number,
x: string,//可能有表达式
}
interface KeyAniData {
t: number,
s: number[],
i: { x: number | number[], y: number | number[] },
o: { x: number | number[], y: number | number[] },
to: number[],
ti: number[],
h: number,//暂时用是否存在判断。有标识瞬切,不缓动,待测试
//后面记录的东西
bezierData?,//to存在时的贝塞尔数据
fnc?,//贝塞尔函数,可能是数组,
}
interface ILottieMaskData {
inv: boolean,//true需要处理矩形wh的矩形遮罩
mode: "n" | "a",//遮罩模式,一般是a
pt: {
"a": number,
"k": {
"i": [number, number][],
"o": [number, number][],
"v": [number, number][],
"c": boolean
},
"ix": number
},
"o": {
"a": number,
"k": number,
"ix": number
},
"x": {
"a": number,
"k": number,
"ix": number
},
"nm": string
}
//"var $bm_rt;\n$bm_rt = $bm_mul(time, -60);"
//"var $bm_rt;\n$bm_rt = loopOut('cycle', 0);"
//"var $bm_rt;\n$bm_rt = loopIn('cycle', 0);"
//"var $bm_rt;\n$bm_rt = loopIn('pingpong', 0);"
enum LoopType {
pingpong = "pingpong",
cycle = "cycle",
}
//表达式类型
enum ExpressionType {
loopIn = "loopIn",
loopOut = "loopOut",
$bm_mul = "$bm_mul"
}
interface ExpressionData {
// loopInOrOut: 0 | 1 | 2,//0表示没有,1表示in前面循环,2表示out后续循环
loopType?: LoopType,//针对loopOut和loopIn
loopDuration?: number,//为0表示全循环
type: ExpressionType,//表达式类型
time?: number,//针对$bm_mul
}
/**
* 内部使用,不对外导出,这里track的时间统统是帧时间,所以对于AnimationClip的update传的时间做换算
* 注意lottie的透明度是不影响子级的
*/
class LottieBaseTrack extends HashObject implements IAnimationTrack {
constructor(
protected obj: Sprite,
private type?: "r" | "o" | "s" | "p",
private times?: KeyAniData[],
private expression?: ExpressionData,
private ip: number = 0,//偏移
) {
super();
this._instanceType = "LottieBaseTrack";
}
/**
* 子类重写
* @param time
*/
setValue(time: number) {
time -= this.ip;
// if (!this.obj.visible) return
var value = this.cacValue(time);
switch (this.type) {
case "r":
this.obj.rotation = value[0];
break;
case "o":
this.obj.alpha = value[0] / 100;
break;
case "s":
this.obj.scale.set(value[0] / 100, value[1] / 100);
break;
case "p":
this.obj.position.set(value[0] - this.obj.anchorX, value[1] - this.obj.anchorY);
break;
}
}
/**
*
* @param time
* @returns
*/
protected cacValue(time: number) {
//计算真实时间,因为部分又表达式的
if (this.expression) {
//如果是$bm_mul
if (this.expression.type == ExpressionType.$bm_mul) {
console.log(this.expression.time * time/24)
return [this.expression.time * time/24];
}
else {
time = (this.expression.type == ExpressionType.loopIn ? loopIn : loopOut)(this.expression.loopType, this.expression.loopDuration, this.times, time)
}
}
if (time <= this.times[0].t) return this.times[0].s;
if (time >= this.times[this.times.length - 1].t) return this.times[this.times.length - 1].s;
//其他的计算补间了要,找前后两个索引
var after = this.findIndex(time);
var before = after - 1;
var da = this.times[after];
var db = this.times[before];
var beforeValue = db.s, afterValue = da.s;
var value: number[]
//有路径的
if (db.to) {
db.fnc = db.fnc || getBezierEasing(db.o.x, db.o.y, db.i.x, db.i.y).get;
value = buildBezierProp(
beforeValue,
afterValue,
db.to,
db.ti,
db.t,
da.t,
time,
db.fnc
)
}
//有h的
else if (db.h === 1) {
value = beforeValue
} else {
db.fnc = db.fnc || generateFuncs(db.o, db.i, beforeValue.length);
var newValue = [], perc: number, delta = da.t - db.t;
for (var i = 0; i < beforeValue.length; i += 1) {
if (time >= da.t) {
perc = 1;
} else if (time < db.t) {
perc = 0;
} else {
if (!db.fnc) {//线性
perc = (time - db.t) / delta;
}
else if (db.fnc.constructor === Array) {
perc = db.fnc[i]((time - db.t) / delta);
} else {
perc = db.fnc((time - db.t) / delta);
}
}
newValue[i] = beforeValue[i] + (afterValue[i] - beforeValue[i]) * perc;;
}
value = newValue
}
return value;
}
/**
* 首尾已判断,得到后一位索引
* @param times
* @param time
* @returns
*/
protected findIndex(time: number): number {
var low = 0;
var high = this.times.length - 2;
if (high == 0) return 1;
var current = high >>> 1;
while (true) {
if (this.times[current + 1].t <= time)
low = current + 1;
else
high = current;
if (low == high)
return low + 1;
current = (low + high) >>> 1;
}
}
resetValue() {
//表达式$bm_mul时应该怎么记录初始值,否则这样就永远是0
this.setValue(0)
}
destroy() {
this.obj = null;
}
}
/**
* 部件的出场时间,就是个范围,
* 每个对象都有,优先判断
*/
class LottieVisibleTrack extends HashObject implements IAnimationTrack {
constructor(
protected obj: Container,
private inTime: number,
private outTime: number,
private startTime: number,
private ip: number = 0,//偏移
) {
super();
this._instanceType = "LottieVisibleTrack";
}
/**
* @param time
*/
setValue(time: number) {
time -= this.ip;
this.obj.visible = this.inTime <= time && this.outTime >= time
}
resetValue() {
this.setValue(0);
}
destroy() {
this.obj = null
}
}
function loopOut(type: LoopType, duration: number, keyframes: KeyAniData[], currentFrame: number) {
var lastKeyFrame = keyframes[keyframes.length - 1].t;
if (currentFrame <= lastKeyFrame) return currentFrame;
if (!duration || duration > keyframes.length - 1) {
duration = keyframes.length - 1;
}
var firstKeyFrame = keyframes[keyframes.length - 1 - duration].t;
var cycleDuration = lastKeyFrame - firstKeyFrame;
// var i, len, ret;
if (type === 'pingpong') {
var iterations = Math.floor((currentFrame - firstKeyFrame) / cycleDuration);
if (iterations % 2 !== 0) {
return cycleDuration - (currentFrame - firstKeyFrame) % cycleDuration + firstKeyFrame;
}
}
//其他的再说
// else if(){
// }
return (currentFrame - firstKeyFrame) % cycleDuration + firstKeyFrame;
}
//给出时间就行,自行判断是否计算,根据
function loopIn(type: LoopType, duration: number, keyframes: KeyAniData[], currentFrame: number) {
var firstKeyFrame = keyframes[0].t;
if (currentFrame >= firstKeyFrame) return currentFrame;
//0时取全部
if (!duration || duration > keyframes.length - 1) {
duration = keyframes.length - 1;
}
var lastKeyFrame = keyframes[duration].t;
var cycleDuration = lastKeyFrame - firstKeyFrame;
// var i, len, ret;
if (type === LoopType.pingpong) {
var iterations = Math.floor((firstKeyFrame - currentFrame) / cycleDuration);
if (iterations % 2 === 0) {
return (firstKeyFrame - currentFrame) % cycleDuration + firstKeyFrame;
}
}
//其他的再说
// else if(){
// }
return cycleDuration - (firstKeyFrame - currentFrame) % cycleDuration + firstKeyFrame;
}
function generateFuncs(outV, inV, len) {
//无参数时直接返回null
if (!outV || !inV) return null;
var outX, outY, inX, inY
if (outV.x.constructor === Array) {
var fncts = [];
for (var i = 0; i < len; i++) {
outX = (typeof outV.x[i] === 'undefined') ? outV.x[0] : outV.x[i];
outY = (typeof outV.y[i] === 'undefined') ? outV.y[0] : outV.y[i];
inX = (typeof inV.x[i] === 'undefined') ? inV.x[0] : inV.x[i];
inY = (typeof inV.y[i] === 'undefined') ? inV.y[0] : inV.y[i];
fncts[i] = getBezierEasing(outX, outY, inX, inY).get;
}
return fncts;
} else {
outX = outV.x;
outY = outV.y;
inX = inV.x;
inY = inV.y;
return getBezierEasing(outX, outY, inX, inY).get;
}
}
function getLoopData(x: string): ExpressionData {
if (!x) return null;
//取数字
var rr = +x.replace(/[^\d\.\-]/g, "");
//取函数类型
var type: ExpressionType;
if (x.indexOf("loopOut") >= 0) {
type = ExpressionType.loopOut
} else if (x.indexOf("loopIn") >= 0) {
type = ExpressionType.loopIn
} else if (x.indexOf("$bm_mul") >= 0) {
type = ExpressionType.$bm_mul
}
//如果是$bm_mul
if (type == ExpressionType.$bm_mul) {
return { type, time: rr };
}
//取循环类型
var loopType: LoopType;
if (x.indexOf("pingpong") >= 0) {
loopType = LoopType.pingpong
} else if (x.indexOf("cycle") >= 0) {
loopType = LoopType.cycle
}
return { loopType, type, loopDuration: rr }
}
/**
*
*/
interface ILottieLater {
_mark: boolean;
_isLottieLayer: boolean;
_ind: number
_parentId: number
}
/**
* 一个子级完全平铺,但是子级却存在父级id记录的容器类,lottie会继承自他,还有合成的也继承自他
*/
class LottieContainer extends Container {
/**
* 是图片,但有额外属性
*/
children: ((Sprite | LottieContainer) & ILottieLater)[];
/**
* 对所有的进行刷新,,根据cParent进行迭代刷新
* 层级有问题,只能平铺,手动计算矩阵
* 因为要平铺,所以记录cParent和ind 从1开始,也许只需要+1就行,还是用ind记录查找吧
* 遍历找
*/
updateTransform() {
//super不行,到时查
this.displayObjectUpdateTransform();
this.children.forEach((c) => {
this._recursivePostUpdateTransformAA(c);
})
this.children.forEach((c) => {
c._mark = false;
})
}
private findChildByInd(ind: number) {
for (var i = 0; i < this.children.length; i++) {
if (this.children[i]._ind === ind) return this.children[i]
}
return null
}
private _recursivePostUpdateTransformAA(c: (Sprite | LottieContainer) & ILottieLater) {
if (c._isLottieLayer && c._parentId) {
//ind从1开始,所以不用考虑0,且不应该存在 p没有的情况
var p = this.findChildByInd(c._parentId)
this._recursivePostUpdateTransformAA(p);
if (!c._mark) {
c._mark = true;
// c.transform.updateWorldMatrix(p.transform);
//用临时父级的方式,否则合成嵌套的子级不会更新
const cacheParent = c.parent;
c.parent = p;
c.updateTransform();
c.parent = cacheParent;
//透明度单独计算,不跟p保持,这个到时要测试下,可以需要向上递归取透明度才是对的
c._worldAlpha = c.alpha * c.parent._worldAlpha;
}
}
//直接进行tans
else if (!c._mark) {
c.updateTransform();//alpha跟父级有关,这里透明度也一样
c._mark = true
}
}
}
/**
* 递归创建lottie时间轴,
* @param root
* @param layers
* @param offset
* @param textures
* @param compositions
* @param tracks
* @returns
*/
function createLottieTracks(
root: LottieContainer,
layers: LayerData[],
offset: number,
textures: { [key: string]: Texture },
compositions?: { [key: string]: LayerData[] },
tracks: (LottieVisibleTrack | LottieBaseTrack)[] = [],
) {
for (var i = layers.length - 1; i >= 0; i--) {
let layer = layers[i];
const { ty, refId, ks, parent, ind, ip, op, st, hasMask, masksProperties } = layer;
let c: (Sprite | LottieContainer) & ILottieLater;
//如果存在组件嵌套
if (ty == 0 && compositions) {
c = root.addChild(new LottieContainer()) as LottieContainer & ILottieLater;
//递归创建,宽高和名字暂时不需要,
createLottieTracks(
c,
compositions[refId],
offset + ip,
textures,
compositions,
tracks
);
}
//图片图层,不能判断2.因为有部分是Container
else {
c = root.addChild(new Sprite(
refId ?
textures && textures[refId] ||
TextureCache[refId] ||
TextureCache[refId + ".png"] : null
) as Sprite & ILottieLater);
}
//遮罩数据,遮罩矩阵和c一致,所以加在c里面
if (hasMask && masksProperties && masksProperties.length) {
c.mask = c.addChild(createLottieMask(masksProperties, layer.w, layer.h));
}
//标记下
c._isLottieLayer = true;
//记录一下数据,查找父级的时候有用
c._ind = ind, c._parentId = parent;
//处理下锚点,基本不会有锚点动画
var ad = typeof ks.a.k[0] == "number" ? ks.a.k : ks.a.k[0].s;
c.anchor.set(ad[0], ad[1]);
//加显示隐藏的
tracks.push(new LottieVisibleTrack(c, ip, op, st, offset))
//@ts-ignore透明度
if (ks.o.k.length) {
tracks.push(
//@ts-ignore
new LottieBaseTrack(c, "o", ks.o.k, getLoopData(ks.o.x), offset)
)
} else {
//@ts-ignore
c.alpha = ks.o.k / 100
}
//@ts-ignore 旋转
if (ks.r.k.length) {
tracks.push(
//@ts-ignore
new LottieBaseTrack(c, "r", ks.r.k, getLoopData(ks.r.x), offset)
)
} else {
//@ts-ignore
c.rotation = ks.r.k;
//有表达式的,但是没有关键帧
if (ks.r.x && ks.r.x.indexOf(ExpressionType.$bm_mul) >= 0) {
console.log(123123)
tracks.push(
//@ts-ignore
new LottieBaseTrack(c, "r", ks.r.k, getLoopData(ks.r.x), offset)
)
}
}
//位置
if (typeof ks.p.k[0] != "number") {
tracks.push(
//@ts-ignore
new LottieBaseTrack(c, "p", ks.p.k, getLoopData(ks.p.x), offset)
)
} else {
//@ts-ignore
var p = ks.p.k;
c.position.set(p[0] - ad[0], p[1] - ad[1])
}
//缩放
if (typeof ks.s.k[0] != "number") {
tracks.push(
//@ts-ignore
new LottieBaseTrack(c, "s", ks.s.k, getLoopData(ks.s.x), offset)
)
} else {
//@ts-ignore
var s = ks.s.k;
c.scale.set(s[0] / 100, s[1] / 100)
}
}
return tracks;
}
/**
* 生成lottie的遮罩矢量
* @param masksProperties
* @param w
* @param h
* @returns
*/
function createLottieMask(masksProperties: ILottieMaskData[], w: number, h: number): Shape {
var mask = new Shape();
mask.beginFill();
masksProperties.forEach((m) => {
if (m.mode !== 'n') {
if (m.inv) {
mask.moveTo(0, 0);
mask.lineTo(w, 0);
mask.lineTo(w, h);
mask.lineTo(0, h);
mask.lineTo(0, 0);
}
var data = m.pt.k;
mask.moveTo(data.v[0][0], data.v[0][1]);
var j, jLen = data.v.length;
for (j = 1; j < jLen; j++) {
mask.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]
);
}
mask.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]
);
if (data.c) {
//TODO
}
}
})
mask.endFill();
return mask
}
//对于多种表达式//loopIn和loopOut已经有了
/**
* $bm_mul表达式
* loopIn和loopOut
* @param a
* @param b
* @returns
*/
// function $bm_mul(a: number, b: number) {
// var tOfA = typeof a;
// var tOfB = typeof b;
// var arr;
// if (isNumerable(tOfA, a) && isNumerable(tOfB, b)) {
// return a * b;
// }
// var i, len;
// if ($bm_isInstanceOfArray(a) && isNumerable(tOfB, b)) {
// len = a.length;
// arr = createTypedArray('float32', len);
// for (i = 0; i < len; i += 1) {
// arr[i] = a[i] * b;
// }
// return arr;
// }
// if (isNumerable(tOfA, a) && $bm_isInstanceOfArray(b)) {
// len = b.length;
// arr = createTypedArray('float32', len);
// for (i = 0; i < len; i += 1) {
// arr[i] = a * b[i];
// }
// return arr;
// }
// return 0;
// }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment