前言
ArcGIS API好像国内用的不多,除了设计院以外,大多数还是用的百度和高德API。
ArcGIS API的文档是全英文,因此分享一些小功能的实现思路。
需求
ArcGIS中,新添加的图层永远在最上面,就像这样:
而在业务逻辑上,有时我们需要某个图层置顶。
比如用来统计面积大小的图层,如果它被其他图层覆盖掉,就不能正常的统计面积和显示被选中的地块了:
本文就来解决这个问题
先说原理,非常简单,使用到生命周期钩子函数。
尝试的其他方法
首先尝试了add图层的时候能不能手动设置order,也就是给它设置的位置很高,比如100:
为了便于交流,我们暂时把这个图层叫做areaSumLayer
。
// 业务上需要置顶的图层
let areaSumLayer: GraphicsLayer
// 添加图层时设置的很高
map.add(areaSumLayer,100);
事实上这样不行,因为前面提到它的逻辑是:“新添加的图层永远在最上面”
即使以前的图层设置的很高,新图层还会更高,比如位置在101。
因此我们的思路是:
无法在创建areaSumLayer
时保证它以后是置顶的
而是在创建其他图层时维护一下areaSumLayer
的位置
生命周期钩子
什么是生命周期?所有的前端组件都使用了这个思想。生命周期指的是从一个组件从创建到消亡的过程。
拿前端框架Angular举例,最常见的包括:
- ngOnInit(): 组件创建
- ngOnChanges(): 绑定的数据发生变化时
- ngOnDestoryed(): 组件销毁
https://angular.cn/guide/lifecycle-hooks
或者VUE中:
- created(): 组件创建
- mounted(): 组件渲染完毕
- beforeUpdate():发生变更前
- updated(): 发生变更
- unmounted(): 组件注销
https://cn.vuejs.org/guide/essentials/lifecycle.html
这些生命周期钩子是在框架开发者编写时就写好的,要使用这些周期函数,只需要用回调的方式,传入一个我们自己写好的方法,这个方法会在适当的时机(生命周期发生时)被自动调用,用到的就是订阅者-观察者模式。
ArcGIS API
接下来看看ArcGIS的图层有什么生命周期(官方称之为事件event):
https://developers.arcgis.com/javascript/latest/api-reference...
- before-add:添加前
- after-add:添加后
- before-changes:变更前
- change:变更
- after-changes:变更后
- before-remove:销毁前
- after-remove:销毁后
有这么多生命周期,而我们的业务上用到的是添加后,也就是“当新图层添加后,我们手动的更新一下需要置顶的areaSumLayer
图层。
after-add是这样用的:
https://developers.arcgis.com/javascript/latest/api-reference...
map.layers.on("after-add", function(event){
console.log(event.item.id);
});
- map.layers.on是开启监听,map就是Map类创建的对象
- "after-add"是监听的事件类型,我们需要监听添加图层之后的事件
- event是自己写的回调函数中的变量
- 方法体是我们要在回调时执行的操作
正常情况下,当有新的图层被添加进来时,控制台就会输出它的ID。
接下来是寻找:areaSumLayer
有没有已经被添加
需要用到collection集合的find方法:
https://developers.arcgis.com/javascript/latest/api-reference...
find方法是寻找某个图层在不在图层集合中,使用的还是回调函数:
// 如果此时图层集合中有面积的图层
if (map.layers.find(function (layer) {
return layer.id === areaSumLayer.id
})){
console.log("true");
}
逐条解释:
我们定义了一个方法:
function (layer) {
return layer.id === areaSumLayer.id
}
- layer是回调时的变量,可以随便写,但要和方法体中对应
- 方法的内容就是:判断回调变量的图层id和我们的id是否相等,如果相等,说明我们要查询的图层在这个集合中,返回true
接下来处理“调整图层顺序”的步骤:
// 重新添加面积图层
map.remove(areaSumLayer);
map.add(areaSumLayer);
- 就是先隐藏再重新添加
因此合起来就变成了这样:
/**
* 地图生命周期
* 当图层创建后,把预览图片的图层重新添加一下,使其永远置顶
*/
map.layers.on('after-add', (event) => {
// 如果此时图层集合中有areaSumLayer图层
if (map.layers.find(function (layer) {
return layer.id === areaSumLayer.id
})) {
// 重新添加areaSumLayer图层
map.remove(areaSumLayer);
map.add(areaSumLayer);
}
})
此时,只要有别的图层添加完毕,钩子函数就会重新把areaSumLayer
置顶。
但现在有个问题:如果新添加的图层就是areaSumLayer
呢?还会触发这个钩子函数吗?
答案是:会发生死循环。
解决这个问题很简单,先从event中把刚刚添加的图层id获取到:
// 刚刚添加的图层id,为了防止死循环
let justAddedId = event.item.id;
此时,如果justAddedId等于areaSumLayer的id,就说明刚才添加的就是areaSumLayer图层,就不用再执行调整操作了。
最终的代码:
/**
* 地图生命周期
* 当图层创建后,把预览图片的图层重新添加一下,使其永远置顶
*/
map.layers.on('after-add', (event) => {
// 获取刚刚添加的图层id,为了防止死循环
let justAddedId = event.item.id;
// 如果此时图层集合中有areaSumLayer图层
if (map.layers.find(function (layer) {
return layer.id === areaSumLayer.id
// 并且刚添加的图层不是areaSumLayer图层
}) && (justAddedId != areaSumLayer.id)) {
// 重新添加areaSumLayer图层
map.remove(areaSumLayer);
map.add(areaSumLayer);
}
})
总结
当我刚接手这个功能的时候,我甚至没有完整的看一遍ArcGIS的文档(又是英文,又特别长,文档内容比Angular都多)。
但所有框架的思想都是相通的,编程编的就是思想,根据其他框架的经验就可以推断ArcGIS一定有类似的方法,再去文档中查询即可。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。