动画是在AnimateLayer动画层,播放节点和连线时间线上的不同状态。
一、播放流程
播放动画方式一
预览时自动播放,设置节点/连线的animatePlay属性即可。
播放动画方式二
// 修改动画帧数组,需要先准备动画数据环境
0. pen.initAnimate();
- 播放动画: pen.startAnimate();
- 暂停动画: pen.pauseAnimate();
- 停止动画: pen.stopAnimate(); // 停止动画指下次从0开始播放
每次代码调整过node.animateFrames,可能需要执行node.initAnimate(),恢复到初始状态
不要在for循环中执行上面操作
播放动画方式三
// 标记一组节点为相同tag
topology.animateLayer.readyPlay(tag);
topology.animateLayer.animate();
播放动画方式四
for(…) {
pen.animateStart = Date.now();
}
topology.animateLayer.readyPlay();
topology.animateLayer.animate();
二、节点动画
节点动画用帧表示,帧的数据为Node的animateFrames。
animateFrames
名称 | 类型 | 是否必选 | 描述 |
---|---|---|---|
duration | number | 是 | 当前帧播放时长 |
start | number | 否 | 动画层添加节点AnimateLayer.addNode自动计算。相对于整个动画时长,当前帧在什么时候播放。 |
end | number | 否 | 动画层添加节点AnimateLayer.addNode自动计算。相对于整个动画时长,当前帧在什么时候结束。 |
state | Node | 是 | 当前帧,节点显示状态 |
linear | boolean | 否 | 动画属性是否线性变化 |
initState | Node | 否 | 当前帧播放前,初始状态。 自动计算。 |
如何设置节点动画
// 1. 设置node.animateFrames
// 复制当前节点状态
const state = Node.cloneState(node);
// 修改状态位置
state.rect.y -= 10;
state.rect.ey -= 10;
node.animateFrames.push({
duration: 100,
linear: true,
state
});
// 回到初始状态
const state2 = Node.cloneState(node);
node.animateFrames.push({
duration: 100,
linear: true,
state: state2
});
node.animateDuration = 0;
for (const item of node.animateFrames) {
node.animateDuration += item.duration;
}
// 修改动画帧数组,需要先准备动画数据环境
node.initAnimate();
// A 开始播放
node.startAnimate();
// B 停止播放
node.stopAnimate();
// 参考源码中的函数:
onChangeAnimate() {
if (this.props.data.animateType === 'custom') {
return;
}
this.props.data.animateFrames = [];
const state = Node.cloneState(this.props.data);
switch (this.props.data.animateType) {
case 'upDown':
state.rect.y -= 10;
state.rect.ey -= 10;
this.props.data.animateFrames.push({
duration: 100,
linear: true,
state
});
this.props.data.animateFrames.push({
duration: 100,
linear: true,
state: Node.cloneState(this.props.data)
});
this.props.data.animateFrames.push({
duration: 200,
linear: true,
state: Node.cloneState(state)
});
break;
case 'leftRight':
state.rect.x -= 10;
state.rect.ex -= 10;
this.props.data.animateFrames.push({
duration: 100,
linear: true,
state: Node.cloneState(state)
});
state.rect.x += 20;
state.rect.ex += 20;
this.props.data.animateFrames.push({
duration: 80,
linear: true,
state: Node.cloneState(state)
});
state.rect.x -= 20;
state.rect.ex -= 20;
this.props.data.animateFrames.push({
duration: 50,
linear: true,
state: Node.cloneState(state)
});
state.rect.x += 20;
state.rect.ex += 20;
this.props.data.animateFrames.push({
duration: 30,
linear: true,
state: Node.cloneState(state)
});
this.props.data.animateFrames.push({
duration: 300,
linear: true,
state: Node.cloneState(this.props.data)
});
break;
case 'heart':
state.rect.x -= 5;
state.rect.ex += 5;
state.rect.y -= 5;
state.rect.ey += 5;
state.rect.width += 5;
state.rect.height += 10;
this.props.data.animateFrames.push({
duration: 100,
linear: true,
state
});
this.props.data.animateFrames.push({
duration: 400,
linear: true,
state: Node.cloneState(this.props.data)
});
break;
case 'success':
state.strokeStyle = '#237804';
this.props.data.animateFrames.push({
duration: 100,
linear: true,
state
});
this.props.data.animateFrames.push({
duration: 100,
linear: true,
state: Node.cloneState(this.props.data)
});
state.strokeStyle = '#237804';
this.props.data.animateFrames.push({
duration: 100,
linear: true,
state
});
this.props.data.animateFrames.push({
duration: 100,
linear: true,
state: Node.cloneState(this.props.data)
});
state.strokeStyle = '#237804';
state.fillStyle = '#389e0d22';
this.props.data.animateFrames.push({
duration: 3000,
linear: true,
state
});
break;
case 'warning':
state.strokeStyle = '#fa8c16';
state.dash = 2;
this.props.data.animateFrames.push({
duration: 300,
linear: true,
state
});
state.strokeStyle = '#fa8c16';
state.dash = 0;
this.props.data.animateFrames.push({
duration: 500,
linear: true,
state: Node.cloneState(state)
});
state.strokeStyle = '#fa8c16';
state.dash = 2;
this.props.data.animateFrames.push({
duration: 300,
linear: true,
state: Node.cloneState(state)
});
break;
case 'error':
state.strokeStyle = '#cf1322';
state.fillStyle = '#cf132222';
this.props.data.animateFrames.push({
duration: 100,
linear: true,
state
});
break;
case 'show':
state.strokeStyle = '#fa541c';
state.rotate = -10;
this.props.data.animateFrames.push({
duration: 100,
linear: true,
state: Node.cloneState(state)
});
state.rotate = 10;
this.props.data.animateFrames.push({
duration: 100,
linear: true,
state: Node.cloneState(state)
});
state.rotate = 0;
this.props.data.animateFrames.push({
duration: 100,
linear: true,
state: Node.cloneState(state)
});
break;
}
this.onAnimateDuration();
}
三、连线动画
连线动画,目前仅为从起点到终点的动态流量显示。
连线动画属性
名称 | 类型 | 是否必选 | 描述 |
---|---|---|---|
animateColor | string | 否 | 动画颜色 |
animateSpan | number | 是 | 连线动画移动大小,像素 |
animateType | string | 否 | 来自于pen。动画播放类型: 空(默认), beads(水珠流动), dot(圆点), comet(彗星) |
animatePos | number | 否 | 动画当前位置,自动计算。 |
// 1. 设置动画类型,默认
line.animateType = '';
// A 开始播放
node.startAnimate();
// B 停止播放
node.stopAnimate();
四、自动播放动画
设置节点/连线的animatePlay属性即可。canvas.open的时候,就好自动播放。
五、自动播放下一个动画
置节点/连线的nextAnimate属性值为下一个节点/连线的tags数组中的一个值。此节点/连线动画播放结束时,自动播放下一个动画。
六、动画时长
节点的动画时长由动画帧数组决定;连线的动画时长与连线长度和播放速度animateSpan有关。