用turf实现基于geojson的地图区域合并

2,465 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

合并地图区域,即geojson所生成地图的多边形合为一块多边形,是可视化业务常见的场景,如下图所示:

演示2.gif

今天就来跟大家分享实现这个需求的一种方式, 建议不了解geojson格式的同学先去了解一下哦

原理本质是利用turf的计算能力,对想要组合的区域多边形进行组合,生成一个新的合成后的多边形区域。

所以不需要界面交互的话,纯数据操作也是可以的,我这里用echarts进行渲染来展示。

首先,获取geojson,echarts注册地图

var geoData;
var myChart = echarts.init(chartDom);
request("./geo/100000_full.json").then((res) => {
geoData = res;
echarts.registerMap("testMap", res);
myChart.setOption({
  series: [
    {
      name: "china",
      type: "map",
      roam: true,
      map: "testMap",
    },
  ],
});
});

然后写一下界面交互的逻辑

界面交互主要就是点击进入区域选择后,显示输入合成后区域的名称的输入框及确认和取消按钮,同时开启echarts区域多选

注意echarts默认是有单选高亮的,我们在想要选中多个区域时,需要将echarts实例的selectedMode设置为'multiple',代码如下:

 const onSelectArea = () => { // 开启待合并区域选择
    selectBtn.style.display = "none";
    selectTools.style.display = "block"
    myChart.setOption({
        series:[
          {selectedMode:'multiple'}
        ]
      })
};
const cancelSelectArea = () => { // 取消
    selectBtn.style.display = "block";
    selectTools.style.display = "none"
    inputDom.value=""
    myChart.setOption({
        series:[
          {selectedMode:'single',selectedMap:null}
        ]
      })
};

接下来进行最重要的,合成逻辑的处理

前文已提到,turf本质是对区域多边形的计算,即geojson中的点位数据coordinates,所以我们需要获取到已选中区域的点位数据

我这边用的echarts,用echarts实例的series中的selectedMap获取到选中区域的名称,然后遍历geojson,利用名称来建立映射关系。

在遍历geojson的同时,去除掉已选中的区域点位,后续用合成后的区域点位代替。

const names = myChart.getOption().series[0].selectedMap; // 获取到选中区域的名称
const polygons = [];
geoData.features = geoData.features.filter((i) => { // 去除掉选中的区域,后续会用合成后的区域代替
  if(names[i.properties.name]){ // 该区域被选中了
    const points = i.geometry.coordinates;
    polygons.push(turf.multiPolygon(points)); // 收集选中区域的点位并转换成turf的多边形组格式,用于后续计算
    return false
  }
  return true;
});

收集到点位之后,就是对点位进行合成计算,然后更新地图。

注意turf的合成只能接受两个参数,所以需要调多次:

   let unionGeo = polygons.reduce((pre, cur) => turf.union(pre, cur)); // union只支持两个参数,当选择多个多边形时需要重复合并

得到的结果即是geojson的features,然后再加上合成后区域的名称(名称会显示在合成后区域的中心位置)

unionGeo.properties.name = inputDom.value || '自定义区域'
geoData.features.push(unionGeo);
echarts.registerMap("new Map", geoData); // 更新地图需要重新注册
myChart.setOption({ 
  series:[{
    map:"new Map"
  }]
})
cancelSelectArea() // 退出选择区域状态

然后就大功告成啦!如果文中有误或有更好的解决办法,欢迎在评论区指出!

demo地址

完整代码

全国geojson地图数据