arcgis js api 4.x 动态展示一个服务里面的图层(MapImageLayer)

1,448 阅读4分钟

哟哟哟哟哟哟哟哟哟~ 私密马赛同志们! 看我今天敲的什么代码。

d576-ikvenft7332922.jpg 使用MapImageLayer动态的展示地图服务里的图层

我在这里给大家展示的是官网的例子,如果不想看的话可以直接去看官网的示例(俺么有自己的地图服务)

Snipaste_2022-04-17_09-51-06.png

废话不多说开始正题

首先看下这个MapImageLayer官网是如何解释的

MapImageLayer allows you to display and analyze data from sublayers defined in a map service, exporting images instead of features. Map service images are dynamically generated on the server based on a request, which includes an LOD (level of detail), a bounding box, dpi, spatial reference and other options. In 2D, the exported image is of the entire map extent specified. In 3D, two images are exported: an image with higher resolution for the area closer to the camera and a lower resolution image for the area farther away from the camera.

翻译就是

Mapimageelayer 允许您显示和分析来自地图服务中定义的子层的数据\color{red}{允许您显示和分析来自地图服务中定义的子层的数据},导出图像而不是特性。地图服务映像是基于请求在服务器上动态生成的,该请求包括 LOD (详细级别)、边界框、 dpi、空间引用和其他选项。在2d 中,导出的图像是指定的整个映射范围。在3d 中,输出两个图像: 一个图像具有更高的分辨率的区域接近相机和一个较低的分辨率的图像区域远离相机。

要想动态的展示图层就要用到下面这个属性(sublayers)

Snipaste_2022-04-17_10-10-08.png

Snipaste_2022-04-17_10-13-51.png

有的小伙伴可能用的地图服务是其他公司提供的,跟你对接的那个人就只给了你一个链接其他什么都没说(就像我一样)不要急!兄弟 我这不是来了吗

首先点开对方给的地图服务链接你会看到下面的页面(是我的个人理解,有不对的地方还请指出)

Snipaste_2022-04-17_10-58-47.png

Snipaste_2022-04-17_11-06-36.png 看完地图的信息以后我们就能知道这个服务是否支持动态的图层加载了 再分享一个属性:代码中如何去看这个图层都支持那些功能capabilities 这是一个只读属性哦 下面是使用sublayers 的代码

        const layer = new MapImageLayer({
          url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer",
          sublayers: [
            {
              id: 2,
              visible: true
            },
            {
              id: 4,
              visible: false,
              title: "Railroads",
              renderer: renderer,
              source: {
                // indicates the source of the sublayer is a dynamic data layer
                type: "data-layer",
                // this object defines the data source of the layer
                // in this case it's a feature class table from a file geodatabase
                dataSource: {
                  type: "table",
                  // workspace name
                  workspaceId: "MyDatabaseWorkspaceIDSSR2",
                  // table name
                  dataSourceName: "ss6.gdb.Railroads"
                }
              }
            },
            {
              id: 1,
              visible: true
            },
            {
              id: 0,
              visible: true
            }
          ]
        });

visible 是控制图层的显示和隐藏

可以看下官方的示例如何是动态隐藏或显示图层的

        const sublayersElement = document.querySelector(".sublayers");
        sublayersElement.addEventListener("click", (event) => {
          const id = event.target.getAttribute("data-id");
          if (id) {
            const sublayer = layer.findSublayerById(parseInt(id));
            const node = document.querySelector(
              ".sublayers-item[data-id='" + id + "']"
            );
            sublayer.visible = !sublayer.visible;
            node.classList.toggle("visible-layer");
          }
        });

以上方式适合是自定义的页面,如果你加载的图层是Tree这种数据结构的图层又恰好你的UI图是下面这种

Snipaste_2022-04-17_11-29-18.png 那么上面的方法应该是不适合的

element 的Tree 树形控件 在点击获取到的是所有选中的一个数组集合而我们又不能把已经添加在地图上面的图层再次添加(当然如果不考虑页面性能,只求代码能跑也不是不行嗷)显然这并不是最优雅的解决办法

我的思路是将图层的ID作为Tree的key获取到所有选中的key之后第一次肯定都是要添加到地图上面的然后用一个全局变量记录下来这个key的数组集合,第二次点击Tree与这个数组对比取差集\color{red}{差集}得到一个新的数组去判断里面的ID 是否在地图上如果在地图上就隐藏掉,如果不在就显示。

loadDynamicGroupLayers(data) {

      if (!this.oldCheckedId.length) {

        this.oldCheckedId = data

        this.oldCheckedId.forEach(item => {

          this.loadDynamicLayers({ id: item, visible: true })

        })

      } else {

        const newArr = this.oldCheckedId.concat(data)

        // 统计选中的check 出现几次

        const diffObj = {}

        for (let i = 0; i < newArr.length; i++) {

          const item = newArr[i]

          if (diffObj[item]) {

            diffObj[item] = ++diffObj[item]

          } else {

            diffObj[item] = 1

          }

        }

        for (const val in diffObj) {

          if (diffObj[val] === 1) {

            if (this.dynamicGroupLayers.findLayerById(val)) {

              this.dynamicGroupLayers.findLayerById(val).destroy()

            } else {

              this.loadDynamicLayers({ id: Number(val), visible: true })

            }

          }

        }

        this.oldCheckedId = data

      }

    }

上面是取差集的代码 感觉不是太好 不建议使用

还有一个思路 就是获取到key的数组后直接取判断在地图上是显示还是隐藏 所有的图层id都可以获取到直接取对比就行了 我当时为什么没有想到呢 终究是我菜了 反正实现的方法有很多

如果不介意控制图层的样式可以看下官网的这个示例 arcgis 提供了一个UI 组件 LayerList 也可以去控制图层的显示或隐藏 这里不过多介绍可以看下文档

如果你的地图服务怎么都加载不出来并且确定你方法没有错那么可以看下Network是否有地图的切片图片

Snipaste_2022-04-17_12-08-25.png 这里还可以看你传递的参数

Snipaste_2022-04-17_12-10-11.png

如果你的参数没有问题请求到的是空的图片 那么90%是他们的问题,对接的人如果还是说这个服务没问题那么就卑微的让人家写个示例吧 等人家发现问题就行了。 没办法 就是这么卑微

20171215154244_5VXQz.jpeg

今天的分享就到这里了!具体的示例代码看官网示例吧 我就不贴了