一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情。
合并地图区域,即geojson所生成地图的多边形合为一块多边形,是可视化业务常见的场景,如下图所示:
今天就来跟大家分享实现这个需求的一种方式, 建议不了解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() // 退出选择区域状态
然后就大功告成啦!如果文中有误或有更好的解决办法,欢迎在评论区指出!