likes
comments
collection
share

地图数据可视化-贝塞尔曲线

作者站长头像
站长
· 阅读数 20

简介

本文将基于高德地图贝塞尔曲线相关api实现地址迁移可视化

效果预览

地图数据可视化-贝塞尔曲线

准备工作

本例主要使用React+React-Amap(基于React封装的高德地图组件)来实现,react-amap帮我们封装好了一些marker和覆盖物组件,使用起来相当方便,当然你也可以阅读学习后根据你当前的技术栈来进行改造

首先安装react-amap

yarn add react-amap

//or

npm install react-amap

1.绘制中心点

...
 const centerMarkers = useMemo(() => {
    return [
      {
        position: center,//center:[lng,lat] 地图中心点
        offset: new AMap.current.Pixel(-9, -9), // 设置点标记偏移量
        anchor: 'center',
      },
    ];
  }, [center]);

const centerMarkerRender = useCallback(() => {
return (
    <div
    className={style.center}
    >
    <div className={style.inner}></div>
    </div>
);
}, []);
  ...
 <Map
   amapkey={amapkey}
   events={mapEvents}
   mapStyle="dark"
 >
    <Markers markers={centerMarkers} render={centerMarkerRender} />
</Map>

2.绘制迁移数据坐标点

 const markers = useMemo(() => {
    return list.map((item: any, index: number) => {
      const { longitude, latitude, name, id, } = item;
      return {
        position: {
          longitude,
          latitude,
        },
        offset: new AMap.current.Pixel(-6, -10), // 设置点标记偏移量
        anchor: 'center',
        name,
        id,
      };
    });
  }, [list]);

const markerRender = useCallback(
    (extData: any) => {
      const {
        name,
        id,
      } = extData as any;

      return (
        <div
          className={style.markerItem}>
          <div
              className={style.title}
            >
              {name}
            </div>
        </div>
      );
    },
    [markers],
  );

...

 <Map
   amapkey={amapkey}
   events={mapEvents}
   mapStyle="dark"
 >
    ...
    <Markers markers={markers} render={markerRender} />
    <Markers markers={centerMarkers} render={centerMarkerRender} />
</Map>

3.绘制贝塞尔曲线[参考]

//创建贝塞尔曲线对象
const createBezierCurve = useCallback(
    (path: any[]) => {
      return new AMap.current.BezierCurve({
        path: path,
        strokeColor:'#e5d035',
        strokeOpacity: 1,
        strokeWeight: 2,
        isOutline:true,
        outlineColor:'#fff',
        borderWeight:1,
        zIndex: 100,
      });
    },
    [],
  );
  //    计算位置和曲率
  const calcuLinePath = useCallback(
    (list) => {
      const { longitude: centerLng, latitude: centerLat } = center;
      let newBezierCurveList = [];
      list.forEach((item: any, index: number) => {
        const { longitude, latitude } = item;
        const radius = AMap.current.GeometryUtil.distance(
          [centerLng, centerLat],
          [longitude, latitude],
        );
        let lngFlag = longitude > centerLng ? 0.00001 : -0.00001;
        let latFlag = latitude > centerLat ? 0.00001 : -0.00001;
        if (longitude && latitude) {
          var path = [
            [centerLng, centerLat], //起点
            //第一段弧线
            [
              centerLng + radius * Math.cos(25) * lngFlag,
              centerLat + radius * Math.sin(25) * latFlag,
              longitude,
              latitude,
            ], //控制点,终点
          ];

          const bezierCurve = createBezierCurve(path);
          newBezierCurveList.push(bezierCurve);
          bezierCurve.setMap(mapInst.current);
        }

        // 缩放地图到合适的视野级别
      });
      setBezierCurveList(newBezierCurveList);
      mapInst.current.setFitView();
    },
    [
      center,
    ],
  );

首先要明确一个比例就是 经纬度/实际距离 约等于 100000/1

已知每条曲线的起点是地图中心点

那么利用简单的三角函数知识我们就可得知

曲线终点经度 = 地图中心点经度 + 迁移点与中心点距离 * Math.cos(25) * lngflag

lngflag是由迁移点经度和中心点经度比大小所得 表示在中心点的上方或下方

同理

曲线终点纬度 = 地图中心点纬度 + 迁移点与中心点距离 * Math.sin(25) * lngflag

注:这里三角函数的25度可以随意调整 也可以自己封装随机数函数来生成曲率角度

const getRandomIntInclusive = (min: number, max: number) => {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min + 1)) + min; //含最大值,含最小值
};

最后按需添加css样式即可 略

4.总结

(1)由于我们是通过实例化对象来向地图中添加贝塞尔曲线的 所以当多次渲染时上次绘制的曲线需要手动清除

mapInst.current.remove(bezierCurveList);

mapInst是高德地图map event事件中created函数的回调参数 为当前地图实例[参考]

(2)通过设置每个迁移点marker的offset属性来解决曲线和坐标点位置偏移的问题