mapboxgl 飞线

注意

不推荐 使用这种方式绘制飞线,效率太低,飞线数量如果超过二十条会有明显卡顿。既然用了Mapbox,推荐使用 Antv/L7

前言

领导想实现一个飞线图,显示农村搬迁情况。我第一反应是Echart,这个简单,但Leader说领导有可能会要求叠加影像,这个就难办了。Leader喜欢高德地图的那种飞线图,只是不能叠加EPSG:4329的影像。最后才不得已让我好好研究一下,这一研究就是一天。。。

参考

Mapbox官方 动画线渐变线

网友博客 D3.js绘制飞线总结

工具

turf.js,主要是alonglengthbezierSpline

思路
  1. 创建贝塞尔曲线
    根据这篇博客在起点、终点之间创建“二阶贝塞尔曲线控制点”

    下面这段代码来自上面的博客,在此感谢!

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)
  1. 分割线
    对上一步生成的曲线进行切割,借助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)
  }
}
  1. 样式
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')
  1. 动画
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++
}
效果

线条的终点数据是随机生成的,底图来自 天地图浙江

飞线效果

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值