地图要素框选的超简实现

496 阅读2分钟

8d188cd0-c3b4-11ec-bd84-c60f6b59270a-v4_t10000011-weyioyfkzJ.2022-04-27 23_46_31.gif

8d188cd0-c3b4-11ec-bd84-c60f6b59270a-v4_t10000011-weyioyfkzJ.2022-04-27 23_46_31.gif 在地图可视化中的绘制中,实现地图要素的框选是十分常见的需求。下面就让我们来看看如何使用 antv/L7 快速实现上述的框选效果。

首先让我们来添加地图底图,为了实现框选的操作,我们先将地图的拖动设置关闭。

const scene = new Scene({
  id: 'map',
  map: new GaodeMap({
    center: [ 110, 30 ],
    zoom: 2.5,
    style: 'dark',
    dragEnable: false // 关闭地图拖动
  })
});

然后让我们来绘制地图上显示的行政区划以及边框。

 const chinaPolygonLayer = new PolygonLayer({
        autoFit: true
      })
        .source(data)
        .color("name", [
          "rgb(239,243,255)",
          "rgb(189,215,231)",
          "rgb(107,174,214)",
          "rgb(49,130,189)",
          "rgb(8,81,156)"
        ])
        .shape("fill");
       
      //  图层边界
      const chinaBorderLineLayer = new LineLayer({
        zIndex: 2
      })
        .source(data)
        .color("rgb(93,112,146)")
        .size(0.6);

为了表示我们的框选操作以及我们的框选结果,我们使用两个单独的图层来表示。

   const selectLineLayer = new LineLayer({ // 表示我们框选的结果
        zIndex: 2
      })
        .source(emptyFeatureCollextion)
        .color("#fff")
        .size(2);

      const boxLayer = new PolygonLayer({}) // 表示我们框选的操作
        .source(emptyFeatureCollextion)
        .color("#fff")
        .size(2)
        .style({
          opacity: 0.6,
          lineType: 'dash',
          dashArray: [5, 5]
        })
        .shape("line");

为了实现实时的框选操作,我们需要监听场景的拖动事件(这也是我们先将地图的拖动关闭的原因)。antv/L7 默认就会将拖拽对应的事件抛出,我们只需要注册监听就可以了。

// 在拖拽开始的时候初始化计算相关的参数
      scene.on("dragstart", (e) => {
        selectLineLayer.setData(emptyFeatureCollextion);
        startLngLat = {
          ...e.lngLat,
          x: e.target.x,
          y: e.target.y
        };
      });

// 在拖拽操作的时候我们需要实时更新选框(选框用于辅助,方便可视化操作)
      scene.on('dragging',e => {
          const {
            lng: startLng,
            lat: startLat
          } = startLngLat;
          const { lng: endLng, lat: endLat } = e.lngLat;
          boxLayer.setData({
            type: 'FeatureCollection',
            features: [{
              type: 'Feature',
              properties: {},
              geometry: {
                type: 'Polygon',
                coordinates: [[
                    [ startLng, endLat ],
                    [ endLng, endLat ],
                    [ endLng, startLat ],
                    [ startLng, startLat ],
                    [ startLng, endLat ]]]
              }}]
          });
        });

// 在拖拽结束的时候计算本次拖拽操作选中的地图要素,同时更新线图层来表示我们当前选中的要素
      scene.on('dragend', e => {
        const {
          x: startX,
          y: startY
        } = startLngLat;
        const { x: endX, y: endY } = e.target;
        boxLayer.setData(emptyFeatureCollextion);
        const selectData = [ startX - left, startY - top, endX - left, endY - top ];
        chinaPolygonLayer.boxSelect(getSelectData(selectData),
          features => {
            const currentSelectNames = features
              .map(item => item.properties.name)
              .join(',');
            if (currentSelectNames !== selectNames) {
              selectLineLayer.setData({
                type: 'FeatureCollection',
                features: [ ...features ]
              });
            }});
      });

在上述操作中,核心代码只用一句,那就是调用 boxSelect 方法:

chinaPolygonLayer.boxSelect([startX, startY, endX, endY])

通过调用该方法,我们可以很方便的计算出当前框选范围内有哪些地图要素。大家感兴趣的话可以查看在线案例。

在线案例

欢迎大家来 github 给 L7 提一提 issues!PR!Star! github.com/antvis/L7

欢迎大家搜索加入 L7 的钉钉答疑群:32292906