注意
不推荐 使用这种方式绘制飞线,效率太低,飞线数量如果超过二十条会有明显卡顿。既然用了Mapbox,推荐使用 Antv/L7
前言
领导想实现一个飞线图,显示农村搬迁情况。我第一反应是Echart,这个简单,但Leader说领导有可能会要求叠加影像,这个就难办了。Leader喜欢高德地图的那种飞线图,只是不能叠加EPSG:4329的影像。最后才不得已让我好好研究一下,这一研究就是一天。。。
参考
网友博客 D3.js绘制飞线总结
工具
turf.js,主要是along
、length
和bezierSpline
思路
-
创建贝塞尔曲线
根据这篇博客在起点、终点之间创建“二阶贝塞尔曲线控制点”下面这段代码来自上面的博客,在此感谢!
const computeControlPoint = (ps, pe, arc = 0.2) => {
const deltaX = pe[0] - ps[0];
const deltaY = pe[1] - ps[1];
const theta = Math.atan(deltaY / deltaX);
const len = Math.sqrt((deltaX * deltaX) + (deltaY * deltaY)) / 2 * arc;
const newTheta = theta - Math.PI / 2;
return [
(ps[0] + pe[0]) / 2 + len * Math.cos(newTheta),
(ps[1] + pe[1]) / 2 + len * Math.sin(newTheta),
];
}
借助turf.js中的bezierSpline
创建贝塞尔曲线,详细说明参考turf.js官方文档
const bezier = bezierSpline(line)
- 分割线
对上一步生成的曲线进行切割,借助turf.js的along工具,我这里是对每一条曲线切割了100刀。根据长度平均切割,长度计算用到了turf.js的length
const arcs = []
const step = 100
const split = (lines) => {
for (let line of lines.features) {
const arc = []
const bezier = bezierSpline(line)
const len = length(bezier)
for (let i = 0; i < len; i += len / step) {
const p = along(bezier, i)
arc.push(p.geometry.coordinates)
}
arcs.push(arc)
}
}
- 样式
map.addSource('segment', {
type: 'geojson',
lineMetrics: true,
data: null
})
map.addLayer({
id: 'segment',
source: 'segment',
type: 'line',
paint: {
'line-color': 'red',
'line-width': 2,
'line-gradient': [
'interpolate',
['linear'],
['line-progress'],
0,
'rgba(255, 255, 255, 0.1)',
0.8,
'rgba(255, 0, 0, 0.6)',
1,
'red'
]
}
})
source = map.getSource('segment')
- 动画
const segments = {
type: 'FeatureCollection',
features: []
}
let counter = 0, source = null
const animate = () => {
if (counter === step) {
counter = 0
segments.features.forEach(f => f.geometry.coordinates.length = 0)
}
arcs.forEach((arc, i) => {
if (!segments.features[i]) {
segments.features[i] = {
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: []
}
}
}
segments.features[i].geometry.coordinates.push(arc[counter])
})
source.setData(segments)
requestAnimationFrame(animate)
counter++
}
效果
线条的终点数据是随机生成的,底图来自 天地图浙江