在数据可视化中,飞线图是十分常见的,迁徙图、路线图、消息传递图等等数不胜数。是十分重要的可视化手段之一,下面就来介绍一下飞线的实现方式。
博主知道有三种实现方式:
1、粒子动效
所谓粒子动效,本质就是使用大量的点充当粒子,将这些粒子由大到小排列,沿着指定路线不断更新粒子的位置,这样就使线在视觉角度上动起来了,形成飞线效果。
粒子动效主要是依靠着色器来实现,
曲线:使用threejs根据坐标生成一条曲线,threejs中提供了许多曲线的插值结果,样条曲线、贝塞尔曲线等等,详细可以看官方文档,根据文档要求组织输入参数,生成曲线作为路径。
粒子:生成粒子,这步可以使用曲线对象的getPoints方法,根据曲线生成若干点作为粒子。
着色器:控制粒子颜色,从大到小排列以及粒子运动起来,这些操作主要靠着色器来实现,下面给出着色器代码:
顶点着色器:
attribute float percent;
uniform float time;
uniform float number;
uniform float speed;
uniform float length;
uniform float size;
varying float opacity;
void main() {
float l = clamp(1.0 - length, 0.0, 1.0);
gl_PointSize = clamp(fract(percent * number + l - time * number * speed) - l, 0.0, 1.0) * size * (1.0 / length);
opacity = gl_PointSize / size;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
片元着色器:
varying float opacity;
uniform vec3 color;
void main(){
if(opacity <= 0.3) {
discard;
} else {
gl_FragColor = vec4(color, 1.0);
}
}
生成Mesh:使用着色器生成ShaderMaterial材质,将之前生成的粒子做成BufferGeometry,生成Mesh加到Scene中。
在render函数中修改material.uniform.time.value的值即可完成动效。
效果参考之前分享的地址。
2、TubeGeometry
第二种方式是使用three提供的管道缓冲集合体TubeGeometry。顾名思义,他是用来将三维曲线做成管道的几何对象。
首先,也需要生成曲线,与之前介绍的一样,使用threejs生成一条三维样条曲线。
const curve = new THREE.CatmullRomCurve3([
new THREE.Vector3(-10, 0, 10),
new THREE.Vector3(-5, 5, 5),
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(5, -5, 5),
new THREE.Vector3(10, 0, 10),
]);
使用曲线生成TubeGeometry,并使用贴图生成材质。
const geometry = new THREE.TubeGeometry( curve, 20, 1, 8, false );
const material = new THREE.MeshBasicMaterial({
color: new THREE.Color(0xffffff),
map: texture,
transparent: true,
});
使用geometry与material生成Mesh,放入scene中。
在render函数中修改texture.offset.y属性,即可实现飞线动效。
3、meshline
meshline是一个扩展库,可以帮助我们绘制线,使用meshline生成飞线非常简单方便。
let curve = new THREE.CatmullRomCurve3(resPoints);
const vertices = curve.getPoints(50);
const geo = new THREE.BufferGeometry().setFromPoints(vertices);
const meshLine = new MeshLine();
meshLine.setGeometry(geo);
const material = new MeshLineMaterial({
useMap: 1,
color: new THREE.Color(0xff0000),
lineWidth: 1,
transparent: true,
dashArray: 2,
map: texture,
});
const mesh = new THREE.Mesh(meshLine, material);
在render函数中改变.material.uniforms.dashOffset.value的值即可实现飞线动效。