效果
此场景针对演示场景,自由度高的数据流图不适用,经调研评估,觉得使用该方法实现自由度高的数据流图性能消耗大
二、什么是SpriteJs?
三、实现思路
- 如果无需点击等事件,则底座用dom元素绘制,否则使用spriteJs中的图片元素进行绘制,本demo为html绘制底座
- 地图采用echarts5中的地图进行绘制,且为了流向对应上,则取消地图的放缩平移
- 确定每个元素相对于canvas画布x轴和y轴的坐标位置,确定流向
- 动态计算绘制贝塞尔二次曲线
四、流图所使用SpriteJs的API及方法
1. 绘制画布
// 准备放置场景的容器
<div class="object" id="object"></div>
// 引入场景
const { Scene } = spritejs;
// 指定容器
const container = document.getElementById('object');
// 在指定容器内创建场景
const scene = new Scene({
container,
width: 1600,
height: 1100
});
// 创建图层
layer = scene.layer();
// 绘制射线
paintRay();
// 循环绘制射线,执行循环动画
interval = setInterval(() => {
paintRay();
}, 3000);
2. 绘制射线(Path, Gradient)
- 自定义计算贝塞尔曲线函数(getCurvePath)
getCurvePath = (p1, p2, curveness) => {
let cp = [];
if (p2[0] < 0) {
cp = [
(p1[0] + p2[0]) / 2 - (p2[1] - p1[1]) * curveness,
(p1[1] + p2[1]) / 2 + (p2[0] - p1[0]) * curveness,
];
} else {
cp = [
(p1[0] + p2[0]) / 2 + (p2[1] - p1[1]) * curveness,
(p1[1] + p2[1]) / 2 - (p2[0] - p1[0]) * curveness,
];
}
return `m${p1[0]},${p1[1]} q${cp[0]},${cp[1]} ${p2[0]},${p2[1]}`;
}
- 绘制线条
// 引入
const { Path, Gradient } = spritejs;
const line = new Path();
// 设置线条属性
line.attr({
pos: [sourceX, sourceY], // 坐标
lineWidth: 4, // 线宽
lineCap: 'round', // 线条类型
d: getCurvePath([0, 0], [dx, dy], 0.4) // 线条路径
});
// 将线条添加至图层
this.layer.append(line);
// 设置流向动画
const animate = new Animator(2000, (p) => {
let q = 0;
if (p > 0.818) {
q = 1 - (1 - p) / 0.182;
}
p = Math.min(p / 0.7, 1);
// 设置线条颜色
const colors = [
{ offset: 0, color: `rgba(${color[0]},${color[1]},${color[2]},0)` },
{ offset: q, color: `rgba(${color[0]},${color[1]},${color[2]},0.3)` },
{ offset: p, color: `rgba(${color[0]},${color[1]},${color[2]},1)` },
{
offset: Math.min(p + 0.06, 1),
color: `rgba(${color[0]},${color[1]},${color[2]},0.1)`,
},
];
// dx和dy为绝对距离
const vector = [0, 0, dx, dy];
// 线条渐变赋值
const gradient = new Gradient({
vector,
colors,
});
// 添加渐变颜色属性
line.attr({ strokeColor: gradient });
});
// 开始动画
await animate.animate();
// 动画结束移除线条,避免元素堆积
line.remove();