背景:公司对leaflet地图新增了一项需求,如下:
后端返回数据为对象数组,每一个对象可能为点,线,圈,区域其中一个,通过type区分渲染到地图上。同时又通过zIndex来确定每一项的层级
查找资料的过程
1.刚开始接到这个需求的时候觉得挺容易的,因为之前看过marker的配置项中有zIndexOffset属性可以设置层级,之后发现这个属性在polyline等内容中没有。网上搜索polyline设置层级的方案,发现大多使用layerGroup包起来,layerGroup设置zIndex的方案。遂决定使用marker用zIndexOffse,polyline使用layerGroup的方案。 好景不长,实际使用过程中发现并没有自己想象中的效果,并没有起到层级覆盖的效果。放弃!
2.之后在github中查找问题时发现有相关问题,发现了两个方法
bringToFront:将该元素放置在其他窗口上方
bringToBack:将该元素放置在其他窗口下方
虽然并不可以设置层级,但在后续解决中给了我启发
解决
1.polyline,circle,geoJson层级的实现
通过git成员对svg不支持zIndex的解读和对Element的监控,发现他们三者的层级关系是通过谁先渲染决定的。即第一个渲染的在最下面,最后面渲染的在最上面。于是问题到这里已经开始迎刃而解了,即后端对返回的数据进行排序,zIndex低的最先addTo 地图中(最先渲染)即可
最先渲染的path在最底层
2.marker层级的实现
marker的实现以为是最简单的,只需要加zIndexOffse即可,但结果却不尽人意。当图标大小大到一定程度时,想象中在底部的marker却在上面,于是研究起了marker的zIndex的实现
结果发现是使用了该值,猜测是因为不能指定某个marker的zIndex:1,2,3等固定值,但这种做法并没有考虑到大图标marker的层叠。即离窗口顶部越近的zIndex越小,离窗口底部越近的zIndex越大。那么当两个marker的大小都有窗口大小的时候,会显示离窗口底部越近的,因为其zIndex越大。
这时我设置了zIndexOffse为1,2,3
zIndex对应加上了1,2,3。但是依旧对于刚才的问题无济于事,即marker大到一定程度后只会显示离底部近的。当然这种问题一般不会存在,毕竟marker一般也不会大到该程度。
这个问题困扰了我一段时间,期间对于坐标,z-index,图标宽高进行了一系列的计算。最终得出了一个较为稳妥的方案。
假设最大markerA的宽度或高度为60px,那么它的半径为30px。这时只要在它30px范围内的marker即为重叠。假设有一个markerB刚好在它30px处,那么他们两个的transform距离为400(B)和430(A)。为什么B在400处,因为这是设计的最极端情况,B的先天条件zIndex比A小,但最后得到的结果B的层级要比A大。
那么B现在后端返回给我的zIndex为1,A为0。我得出的公式为(半径乘以zIndex)为zIndexOffse设置的层级。即B现在的层级为400+(30 * 1)=430,A为430+(30 * 0)=430;但这样好像层级相同了。是会有这个问题,不过这是极端情况了。只有在距离刚刚好为30并且两个点的zIndex相邻的情况下会出现这种结果。后续会支持该情况的破解(不一定会记得发布在博客)。
最后的公式为
leafletMarker.setZIndexOffset(zIndex * 半径)