使用GeoHey SDK开发地图应用的那些小技巧(肆)

在实现比较复杂的地图项目中,我们需要在地图上叠加大量而且种类不同的图层。并且这些图层还要处于显示/隐藏、编辑、绘制等不同的状态。在这一期内容中,我们将围绕“图层管理”这个目标,一步步满足这些需求。

首先,我们的图层不仅与多个,而且包含了切片图层、矢量图形图层或绘制图层等多个种类的图层。那么,我们先来定义一下当前的地图和图层们。

let map;
let baseMapLayer,tileLayer1,tileLayer2,tileLayer3,graphicLayer,drawLayer

在添加图层时,我们在创建map对象后,首先添加baseMapLayer,添加graphicLayer和drawLayer这两个用于编辑和绘制的图层,最后将4个tileLayer类型的切片图层添加进来。这个时候,我们的默认图层顺序如下:

  • 0--baseMapLayer
  • 1--graphicLayer
  • 2--drawLayer
  • 3--tileLayer1
  • 4--tileLayer2
  • 5--tileLayer3
  • 6--tileLayer4

我们可以还将创建好的图层,存储到一个全局定义的数组中,例如:

let layerList = [baseMapLayer,graphicLayer,drawLayer,tileLayer1,tileLayer2,tileLayer3,tileLayer4];

按照顺序,将图层对象push到layerList数组中,这样,我们的准备工作就完成了。接下来,根据不同的操作的需求,我们将进行不同的处理。

1.更换底图

当我们需要更换底图时,如果更换的底图和现有的底图,在cluster等参数上一致,那么可以直接通过setUrl来更新,示例如下:

let url
baseMapLayer.setUrl(url);

如果参数并不一致,那么需要将baseMapLayer图层移除后,重新加入进来。

let url,options
baseMapLayer.remove();
baseMapLayer = new G.Layer.Tile(url,options);
baseMapLayer.addTo(map)
baseMapLayer.bringToOrder(0); //注1
baseMapLayer.bringToBottom(); //注2 

注1:这里默认是按照上面的默认图层顺序来设置
注2:按照默认图层顺序,可以使用bringToBottom()替代bringToOrder(0),将baseMapLayer移动到最下层。但是如果baseMapLayer在默认图层顺序中,不在最下层,则只能使用bringToOrder方法来调整顺序。

2.编辑graphicLayer中的内容。

如果我们要编辑graphicLayer中的内容,无论是选中要素还是编辑要素的几何形状,都需要我们首先将该图层移动到最上层。

let graphicLayer.bringToTop();//注3

注3:如果使用了全局的layerList,请不要忘记调整layerList中graphicLayer的index。

在graphicLayer移动到最上层后,我们就可以进行编辑操作了。在完成编辑后,我们将graphicLayer移动回原来的顺序位置。

graphicLayer.bringToOrder(1);

这里也可以使用bringToBottom后,再使用bringToTop,可以达成同样的效果。但是这样做,不仅操作很繁琐,而且如果图层原本的顺序索引较大,那么中间移动的步骤不仅多,造成图层顺序混乱的机会也会成倍增长。

3.绘制要素

绘制要素时,对图层的操作和graphicLayer类似:

//开始绘制
drawLayer.bringToTop();

//结束绘制
drawLayer.bringToOrder(2);

4.调整切片图层顺序

当地图中只有切片图层时,调整切片图层顺序,只是用bringToTop和bringToBottom方法就足够了。但我们的图层更多,更复杂。因此只是用上面的2个方法,就无法满足我们的要求了。

在我们这个示例中,4个tileLayer下面,还有着baseMapLayer、graphicLayer和drawLayer这三个图层。因此,在调整切片图层顺序前,首先要确定,我们要移动的这个图层,是否是我们切片图层组中的上下边界(在本示例中,图层索引3和6)。

let n = 7; //图层总数

//获取目标图层的索引值
let index = tileLayer.getOrder();

if(index == 3){
//判断是否是切片图层组中的最下层
}
if(index == (n-1)){
//判断是否是切片图层组中的最上层
}

当目标图层是切片图层组中的最下层时,应当禁止其进行向下移动操作;当它是切片图层组中的最上层时,应当禁止其进行向上移动操作。
之后在调整时,如果一次操作只上移/下移一个图层,那么可以使用bringToTop和bringToBottom来完成。但是当变动的值大于1时,建议使用bringToOrder来完成。同时要注意,移动后的图层索引值是否会超过边界。

5.交换图层

通过一些组件,我们可以在界面上实现拖动交换功能。在图层层面,实现起来会略有点复杂。我们这里来简单实现一下4个切片图层之间的拖动交换操作。
首先,我们需要两个List,一个记录图层的信息,另一个记录插入map对象中的实际的图层。

let layerInfoList = [baseMapLayerInfo,graphicLayerInfo,drawLayerInfo,tileLayer2Info,tileLayer3Info,tileLayer1Info,tileLayer4Info];

let tileLayer = [baseMapLayer,graphicLayer,drawLayer,tileLayer1,tileLayer2,tileLayer3,tileLayer4];

可以看到,这里我们将tileLayer1和tileLayer3进行了交换。这里我们将所有的图层进行重排列。

//

for (let [index, layerInfo] of layerInfoList.entries()) {

   let layer = tileLayer.find(function(value){
       return layerInfo.uid == value.uid; 
   })
   layer.bringToOrder(index);
}
layerList = afterChangeLayerList;

这样虽然能实现,但是明显过于简单粗暴。我们将上面的方法优化一下

let indexL, layerInfo; //从layerInfoList中取图层
let indexT, tile; //从afterChangeLayerList中取图层
let n = 7; //图层总数

if(layerInfo.uid === tile.uid){//确认为同一图层

    if(indexL != indexT){ //同一个图层在俩个数组中的索引不一样,判断为顺序经过了调整
    
    tile.bringToOrder(n + 3 - indexL - 1);
    //示例情况中,baseMapLayer,graphicLayer,drawLayer这3个图层默认在切片图层下面,因此调整顺序时,切片图层的索引从0+3号开始。
    //计算时,由于虽然只是拖动了一个图层,但是会导致该图层原位置索引到当前位置索引的所有图层的索引都会发生变化。因此,需要对所有两个数组中,表示同一个图层但是索引编号不同的图层,进行bringToOrder操作。
    }
}

到这里,比较基本的图层管理的需求,我们就都可以满足了。

------------我是每次都会出现的footer---------------

对我们的SDK在使用上有问题的同学,可以先访问我们的示例页面,在其中进行在线调试。如果依然有问题,也可以关注我们的公众号,或是加入我们的QQ交流群(164183186)。