类名 common/document/layer/ogc/WMSLayer.js
import {defaultValue, isNull, Log, toJSON} from '../../../util'
import {Collection, Zondy} from '../../../base'
import { WMSServer } from '../../../service'
import { LoadStatus, LayerType } from '../../../base/enum'
import {Extent, Geometry, SpatialReference} from '../../../base/geometry'
import WMSSubLayer from './WMSSubLayer'
import { setSublayer } from '../Utils'
import OGCLayer from './OGCLayer'
import {jsonClone} from '../../../util/Utils';

/**
 * WMS图层,<br/>
 * 目前二维上支持4326(包括4490,4214以及4610),3857以及EPSG支持的自定义坐标系,三维上仅支持4326(包括4490,4214以及4610)以及3857坐标系,会自动读取元信息上的坐标系,不需要用户指定,同时所有的WMS服务都支持动态投影,用户也可指定任意该服务支持的坐标系<br/>
 * <br>[ES5引入方式]:<br/>
 * Zondy.Layer.WMSLayer() <br/>
 * [ES6引入方式]:<br/>
 * import { WMSLayer } from "@mapgis/webclient-common" <br/>
 * <br/>
 * 针对图层的操作请在图层加载完毕事件中进行<br/>
 * Layer.on('layerview-created', function (result) {<br/>
 *   console.log("加载完毕:", result.layer)<br/>
 * });<br/>
 * 如果不想在该事件中放入业务代码,则请确认图层资源已加载完毕后再进行操作<br/>
 * if(layer.loadStatus === 'loaded') {<br/>
 *   // 你的业务逻辑<br/>
 * }
 * @class WMSLayer
 * @moduleEX LayerModule
 * @extends OGCLayer
 * @fires Layer#图层加载完毕事件
 * @fires Layer#图层销毁完毕事件
 * @fires Layer#图层更新完毕事件
 * @fires Layer#图层显隐更新完毕事件
 * @fires Layer#图层透明度更新完毕事件
 * @fires Layer#图层顺序更新完毕事件
 * @fires Layer#图层刷新完毕事件
 * @fires WMSLayer#子图层显隐更新完毕事件
 * @param {Object} options 构造参数
 * @param {String} [options.url] 服务基地址,支持的服务如下:<br/>
 * 1、支持MapGIS的WMS服务,格式为:http://{ip}:{port}/igs/rest/services/{ServiceName}/WMSServer,参考示例:<a href='#MapIGS'>[加载MapGIS的WMS服务]</a><br/>
 * 2、支持ArcGIS的WMS服务,格式为:http://{ip}:{port}/arcgis/rest/services/{ServiceName}/WMSServer,参考示例:<a href='#ArcGIS'>[加载ArcGIS的WMS服务]</a>
 * @param {String} [options.title] 图层名称
 * @param {SpatialReference} [options.spatialReference] 图层坐标系,支持4326、3857以及EPSG上的自定义坐标系,坐标系默认从元信息中获取,也可指定坐标系,
 * 参考示例:<a href='#spatialReference'>[设置图层坐标系]</a>
 * @param {Number} [options.opacity = 1] 图层透明度,0到1之间的值,0为完全透明,1为不透明,参考示例:<a href='#opacity'>[设置图层透明度]</a>
 * @param {Boolean} [options.visible = true] 图层显示或隐藏,true则显示,false则隐藏,参考示例:<a href='#visible'>[设置图层显隐]</a>
 * @param {Number} [options.imageWidth = 256] 图片宽度,单位px
 * @param {Number} [options.imageHeight = 256] 图片高度,单位px
 * @param {Number} [options.minScale = 0] 最小缩放级数,仅会请求级数小于等于maxScale的图片
 * @param {Number} [options.maxScale = 19] 最大缩放级数,仅会请求级数小于等于maxScale的图片
 * @param {Boolean} [options.imageTransparency = true] 图片中没有数据的地方是否透明,默认为true,即透明
 * @param {Polygon|Extent|Circle|null} [options.clippingArea = null] 图层空间裁剪范围,仅支持多边形裁剪、矩形裁剪、圆形裁剪
 * @param {Array} [options.sublayers = []] 指定子图层参数,可设置子图层是否显示,若不填则显示所有子图层,若有值则只显示visible为true的子图层,<br/>
 * 参考示例:<br/>
 * <a href='#SubLayers'>[1、初始化时,设置子图层显隐]</a><br/>
 * <a href='#SubLayers-Method'>[2、通过方法,设置子图层显隐]</a><br/>
 * <a href='#SubLayers-Property'>[3、通过修改子图参数,设置子图层显隐]</a>
 * @param {String} [options.tokenKey = 'token'] token名
 * @param {String} [options.tokenValue] token值,只有当tokenValue存在时,才会绑定token
 *
 * @summary <h5>支持如下方法:</h5>
 * <a href='#load'>[1、加载图层资源]</a><br/>
 * <a href='#setSubLayer'>[2、设置子图层参数]</a><br/>
 * <a href='#findSublayerById'>[3、根据子图层id查询图层]</a><br/>
 * <a href='#fromJSON'>[4、通过传入的json构造并返回一个新的几何对象]</a><br/>
 * [5、导出为json对象]{@link OGCLayer#toJSON}<br/>
 * [6、克隆几何对象]{@link OGCLayer#clone}
 *
 * @example <caption><h7 id='MapIGS'>添加WMS图层示例</h7></caption>
 * // ES5引入方式
 * const { Map, MapView } = Zondy
 * const { WMSLayer } = Zondy.Layer
 * // ES6引入方式
 * import { Map, MapView, WMSLayer } from "@mapgis/webclient-common"
 * // 初始化图层管理容器
 * const map = new Map();
 * // 初始化二维地图视图对象
 * const mapView = new MapView({
 *   // 视图id
 *   viewId: "viewer-id",
 *   // 图层管理容器
 *   map: map
 * });
 * // 初始化wms图层
 * const wmsLayer = new WMSLayer({
 *   // 服务基地址
 *   url: 'http://{ip}:{port}/igs/rest/services/{serviceName}/WMSServer'
 * });
 * // 将图层加入容器中
 * map.add(wmsLayer);
 *
 * // 图层加载完毕
 * wmsLayer.on('layerview-created', function (result) {
 *   console.log("加载完毕:", result.layer)
 *   // 视点跳转
 *   mapView.flyTo({
 *     extent: result.layer.extent
 *   })
 * })
 *
 * @example <caption><h7 id='opacity'>设置图层透明度</h7></caption>
 * // ES5引入方式
 * const { WMSLayer } = Zondy.Layer
 * // ES6引入方式
 * import { WMSLayer } from "@mapgis/webclient-common"
 * // 初始化时设置
 * const wmsLayer = new WMSLayer({
 *   // 服务基地址
 *   url: 'http://{ip}:{port}/igs/rest/services/{serviceName}/WMSServer',
 *  // 设置透明度
 *   opacity: 1.0
 * });
 * // 将图层加入容器中
 * map.add(wmsLayer);
 *
 * // 加载完成后设置
 * wmsLayer.on('layerview-created', function (result) {
 *   console.log("加载完毕:", result.layer)
 *   // 设置透明度
 *   wmsLayer.opacity = 0.5
 * })
 *
 * @example <caption><h7 id='visible'>显示或隐藏图层</h7></caption>
 * // ES5引入方式
 * const { WMSLayer } = Zondy.Layer
 * // ES6引入方式
 * import { WMSLayer } from "@mapgis/webclient-common"
 * // 初始化时设置
 * const wmsLayer = new WMSLayer({
 *   // 服务基地址
 *   url: 'http://{ip}:{port}/igs/rest/services/{serviceName}/WMSServer',
 *   // 显示或隐藏图层
 *   visible: true
 * });
 * // 将图层加入容器中
 * map.add(wmsLayer);
 *
 * // 加载完成后设置
 * wmsLayer.on('layerview-created', function (result) {
 *   console.log("加载完毕:", result.layer)
 *   // 显示或隐藏图层
 *   wmsLayer.visible = !wmsLayer.visible
 * })
 *
 * @example <caption><h7 id='spatialReference'>设置图层坐标系</h7></caption>
 * // ES5引入方式
 * const { WMSLayer } = Zondy.Layer
 * const { SpatialReference } = Zondy
 * // ES6引入方式
 * import { WMSLayer, SpatialReference } from "@mapgis/webclient-common"
 * // 初始化wms图层
 * const wmsLayer = new WMSLayer({
 *   // 服务基地址
 *   url: 'http://{ip}:{port}/igs/rest/services/{serviceName}/WMSServer',
 *   // 指定图层坐标系
 *   spatialReference: new SpatialReference({
 *     // 坐标系的wkid,可在https://epsg.io/网站查询
 *     wkid: 4326
 *   })
 * });
 * // 将图层加入容器中
 * map.add(wmsLayer);
 *
 * @example <caption><h7>删除图层</h7></caption>
 * map.remove(wmsLayer)
 *
 * @example <caption><h7 id='ArcGIS'>添加ArcGIS的WMS图层示例</h7></caption>
 * // ES5引入方式
 * const { Map, MapView } = Zondy
 * const { WMSLayer } = Zondy.Layer
 * // ES6引入方式
 * import { Map, MapView, WMSLayer } from "@mapgis/webclient-common"
 * // 初始化图层管理容器
 * const map = new Map();
 * // 初始化二维地图视图对象
 * const mapView = new MapView({
 *   // 视图id
 *   viewId: "viewer-id",
 *   // 图层管理容器
 *   map: map
 * });
 * // 初始化WMS图层
 * const wmsLayer = new WMSLayer({
 *   url: 'http://219.142.81.85/arcgis/rest/services/10wanZH/MapServer/WMSServer',
 *   // 注意一个WMS图层可能支持多个坐标系,这里指定3857坐标系
 *   spatialReference: new Zondy.SpatialReference({
 *     wkid: 3857
 *   })
 * });
 * // 将图层加入容器中
 * map.add(wmsLayer);
 * // 图层加载完毕
 * wmsLayer.on('layerview-created', function (result) {
 *   console.log("加载完毕:", result.layer)
 *   // 视点跳转
 *   mapView.flyTo({
 *     extent: result.layer.extent
 *   })
 * })
 *
 * @example <caption><h7 id='SubLayers'>初始化时,设置子图层显隐</h7></caption>
 * // ES5引入方式
 * const { Map, MapView } = Zondy
 * const { WMSLayer } = Zondy.Layer
 * // ES6引入方式
 * import { Map, MapView, WMSLayer } from "@mapgis/webclient-common"
 * // 初始化图层管理容器
 * const map = new Map();
 * // 初始化地图视图对象
 * const mapView = new MapView({
 *   // 视图id
 *   viewId: "mapgis-3d-viewer",
 *   // 图层管理容器
 *   map: map
 * });
 * // 初始化WMS图层
 * const wmsLayer = new WMSLayer({
 *   // 服务基地址
 *   url: 'http://{ip}:{port}/igs/rest/services/{ServiceName}/WMSServer',
 *   // 要显示的子图层,若不填,则默显示所有子图层
 *   sublayers: [{
 *     id: 0,
 *     visible: true
 *   }, {
 *     id: 1,
 *     visible: true
 *   }]
 * });
 * map.add(wmsLayer);
 * // 图层加载完毕
 * wmsLayer.on('layerview-created', function (result) {
 *   console.log("加载完毕:", result.layer)
 *   // 视点跳转
 *   mapView.flyTo({
 *     extent: result.layer.extent
 *   })
 * })
 * @example <caption><h7 id='SubLayers-Method'>通过方法,设置子图层显隐</h7></caption>
 * // ES5引入方式
 * const { WMSLayer } = Zondy.Layer
 * // ES6引入方式
 * import { WMSLayer } from "@mapgis/webclient-common"
 * // 初始化WMS图层
 * const wmsLayer = new WMSLayer({
 *   // 服务基地址
 *   url: 'http://{ip}:{port}/igs/rest/services/{ServiceName}/WMSServer'
 * });
 * // 添加到容器中
 * map.add(wmsLayer);
 *
 * // 通过图层id来设置显隐
 * wmsLayer.setSubLayer({
 *   id: 0,
 *   visible: false
 * })
 * // 或者通过图层名称设置显隐
 * wmsLayer.setSubLayer({
 *   name: "Map_Hubei4326:t1",
 *   visible: true
 * })
 * @example <caption><h7 id='SubLayers-Property'>通过修改子图参数,设置子图层显隐</h7></caption>
 * // ES5引入方式
 * const { WMSLayer } = Zondy.Layer
 * // ES6引入方式
 * import { WMSLayer } from "@mapgis/webclient-common"
 * // 初始化WMS图层
 * const wmsLayer = new WMSLayer({
 *   // 服务基地址
 *   url: 'http://{ip}:{port}/igs/rest/services/{ServiceName}/WMSServer'
 * });
 * // 添加到容器中
 * map.add(wmsLayer);
 *
 * // 根据id获取子图层
 * const wmsSubLayer = wmsLayer.findSublayerById(0)
 * // 设置子图层显隐
 * wmsSubLayer.visible = false
 * */

/**
 * 子图层显隐更新完毕事件,请注意该事件是图层更新事件(layerview-update)的子事件
 * @event WMSLayer#子图层显隐更新完毕事件
 * @property {Object} event 事件对象
 * @property {String} [event.type = 'layerview-update'] 图层更新完毕事件
 * @property {String} [event.message = null] 更新描述
 * @property {Array<UpdateContent>} [event.updateContent = null] 更新详情对象
 * @property {Layer} [event.layer = null] 地图图层对象
 * @property {MapView} [event.layerView = null] 图层的视图对象
 * @property {Layer} [event.sourceTarget = null] 事件发起对象
 * @property {Map} [event.target = null] 事件接收对象
 * @example <caption><h5>子图层显隐更新完毕事件</h5></caption>
 * Layer.on('layerview-update', function (event) {
 *   // 获取更新事件对象
 *   console.log("更新完毕:", event)
 *   // 获取更新详情数组
 *   const updateContent = event.updateContent
 *   // 循环数组,根据事件名进行后续操作
 *   for (let i = 0; i < updateContent.length; i++) {
 *     // 子图层显隐更新完毕事件
 *     if(updateContent[i].name === 'sublayerVisible'){
 *       console.log("子图层显隐更新完毕事件:", event);
 *     }
 *   }
 * });
 */
class WMSLayer extends OGCLayer {
  constructor(options) {
    super(options)
    options = defaultValue(options, {})
    this._sublayers = defaultValue(options.sublayers, [])
    /**
     * 服务基地址
     * @readonly
     * @member {String} WMSLayer.prototype.url
     */
    this.url = defaultValue(options.url, '')
    /**
     * 用户自定义的子图层参数
     * @member {Array} WMSLayer.prototype.sublayers
     */
    this.sublayers = defaultValue(options.sublayers, [])
    /**
     * 图片宽度,单位px
     * @member {Number} WMSLayer.prototype.imageWidth
     */
    this.imageWidth = defaultValue(options.imageWidth, 256)
    /**
     * 图片高度,单位px
     * @member {Number} WMSLayer.prototype.imageHeight
     */
    this.imageHeight = defaultValue(options.imageHeight, 256)

    /**
     * 所有子图层对象信息
     * @member {Array} WMSLayer.prototype.allSublayers
     */
    this.allSublayers = []
    /**
     * WMS服务要加载的图层id,多个id以逗号分割
     * @readonly
     * @member {String} WMSLayer.prototype.layers
     */
    this.layers = defaultValue(options.layers, undefined)
    /**
     * 图片格式
     * @member {String} WMSLayer.prototype.imageFormat
     */
    this.imageFormat = defaultValue(options.imageFormat, 'image/png')
    /**
     * 图片格式数组,表示服务支持的所有图片格式
     * @readonly
     * @member {Array} WMSLayer.prototype.imageFormats
     */
    this.imageFormats = ['image/png']
    /**
     * 图层中的非数据部分是否透明
     * @member {Boolean} WMSLayer.prototype.imageTransparency
     */
    this.imageTransparency = defaultValue(options.imageTransparency, true)
    /**
     * WMS服务版本号
     * @readonly
     * @member {String} WMSLayer.prototype.version
     */
    this.version = defaultValue(options.version, '1.1.1')
    /**
     * 图层类型
     * @readonly
     * @member {String} WMSLayer.prototype.type
     */
    this.type = LayerType.wms

    /**
     * 图层支持的所有坐标系
     * @member {Array<SpatialReference>} WMSLayer.prototype.spatialReferences
     */
    this.spatialReferences = defaultValue(options.spatialReferences, [])
    // 空间裁剪范围
    this._clippingArea = defaultValue(options.clippingArea, null)

    // 图层在不同坐标系上的全图范围
    this._extentList = []

    // WMSServer对象
    this._WMSServer = new WMSServer({
      url: this.url,
      version: '1.3.0'
    })
  }

  /**
   * 通过传入的json构造并返回一个新的几何对象<a id='fromJSON'></a>
   * @param {Object} [json] JSON对象
   * @example <caption><h7>通过传入的json构造并返回一个新的几何对象</h7></caption>
   * // ES5引入方式
   * const { WMSLayer } = Zondy.Layer
   * // ES6引入方式
   * import { WMSLayer } from "@mapgis/webclient-common"
   * const json = {
   *   // 服务基地址
   *   url: 'http://{ip}:{port}/igs/rest/services/{ServiceName}/WMSServer'
   * }
   * const wmsLayer = new WMSLayer.fromJSON(json)
   */
  static fromJSON(json) {
    json = jsonClone(json)
    const _layer = new WMSLayer(json)
    _layer._isFromJSON = true

    const _extentList = []
    for (let i = 0; i < json.extentList.length; i++) {
      _extentList.push(Geometry.fromJSON(json.extentList[i]))
    }
    _layer._extentList = _extentList

    function formatSublayer(sublayer) {
      sublayer.extent = Geometry.fromJSON(sublayer.extent)
      sublayer.spatialReference = SpatialReference.fromJSON(
        sublayer.spatialReference
      )
      for (let j = 0; j < sublayer.spatialReferences.length; j++) {
        sublayer.spatialReferences[j] = SpatialReference.fromJSON(
          sublayer.spatialReferences[j]
        )
      }
    }
    const _sublayers = json.sublayers
    if (_sublayers && _sublayers instanceof Array) {
      _layer._sublayers = new Collection()
      for (let i = 0; i < _sublayers.length; i++) {
        formatSublayer(_sublayers[i])
        _layer._sublayers.add(new WMSSubLayer(_sublayers[i]))
      }
    }

    const _allSublayers = json.allSublayers
    if (_allSublayers && _allSublayers instanceof Array) {
      _layer.allSublayers = new Collection()
      for (let i = 0; i < _allSublayers.length; i++) {
        formatSublayer(_allSublayers[i])
        _layer.allSublayers.add(new WMSSubLayer(_allSublayers[i]))
      }
    }

    return _layer
  }

  /**
   * 加载图层资源<a id='load'></a>
   * @example <caption><h7>不加载图层,仅获取图层信息</h7></caption>
   * // ES5引入方式
   * const { WMSLayer } = Zondy.Layer
   * // ES6引入方式
   * import { WMSLayer } from "@mapgis/webclient-common"
   * // 初始化图层
   * const wmsLayer = new WMSLayer({
   *   // 服务基地址
   *   url: 'http://{ip}:{port}/igs/rest/services/{serviceName}/WMSServer'
   * });
   * wmsLayer.load().then((result) => {
   *   // 获取完图层信息
   *   console.log(wmsLayer)
   * })
   * */
  load() {
    return super.load()
  }

  /**
   * 子类加载服务器端资源的方法
   * @private
   * */
  _load() {
    const self = this
    return this._WMSServer
      .getCapabitities()
      .then((result) => {
        Log.info('WMS信息查询成功:', result)

        // 1.清空之前缓存的元数据信息
        self.spatialReferences = []
        self._extentList = []

        // 2.解析请求回来的元数据
        const data = result.data
        // 2.1获取图层名称
        self.title = data.title

        // 2.2解析图层支持的参考系列表、图层范围列表
        for (let i = 0; i < data.crs.length; i++) {
          for (let j = 0; j < data.boundingBox.length; j++) {
            if (data.crs[i] === data.boundingBox[j].crs) {
              const spatialReference = new SpatialReference(data.crs[i])
              const boundingBox = data.boundingBox[j]
              const extent = new Extent({
                xmin: Number(boundingBox.minx),
                ymin: Number(boundingBox.miny),
                ymax: Number(boundingBox.maxy),
                xmax: Number(boundingBox.maxx),
                spatialReference
              })

              self.spatialReferences.push(spatialReference)
              self._extentList.push(extent)
              break
            }
          }
        }

        // 2.3设置图层的默认空间参考系、全图范围
        // 如果用户没有主动设置就用第一个
        if (isNull(self.spatialReference)) {
          self._spatialReference = self.spatialReferences[0]
        }

        self._extentSrc = self._getExtentBySP(self._spatialReference)

        // 清空子图层
        self.allSublayers = []

        // 2.4获取所有子图层信息
        for (let i = 0; i < data.layer.length; i++) {
          data.layer[i].id = String(i)
          data.layer[i].visible = true
          data.layer[i].spatialReference = self.spatialReference
          data.layer[i].spatialReferences = []
          const _crs = data.layer[i].crs
          for (let j = 0; j < _crs.length; j++) {
            data.layer[i].spatialReferences.push(
              SpatialReference.fromJSON(_crs[i])
            )
          }
          const _boundingBox = data.layer[i].boundingBox
          for (let j = 0; j < _boundingBox.length; j++) {
            if (`EPSG:${self.spatialReference.wkid}` === _boundingBox[j].crs) {
              data.layer[i].extent = new Extent({
                xmin: Number(_boundingBox[j].minx),
                ymin: Number(_boundingBox[j].miny),
                xmax: Number(_boundingBox[j].maxx),
                ymax: Number(_boundingBox[j].maxy)
              })
            }
          }
          self.allSublayers.push(
            new WMSSubLayer(
              Object.assign(data.layer[i], {
                layer: this
              })
            )
          )
        }

        // 2.5获取所有要显示子图层名
        if (self._sublayers.length > 0) {
          // 生成子图层对象
          for (let i = 0; i < data.layer.length; i++) {
            for (let j = 0; j < self._sublayers.length; j++) {
              if (
                String(self._sublayers[j].id) === String(data.layer[i].id) ||
                String(self._sublayers[j].name) === String(data.layer[i].name)
              ) {
                self._sublayers[j] = new WMSSubLayer(
                  Object.assign(data.layer[i], self._sublayers[j], {
                    layer: this
                  })
                )
                break
              }
            }
          }
          self._getLayersFromSubLayers()
        } else {
          // 没有则全部显示
          self._getLayersFromAllSubLayers()
        }
        return new Promise((resolve) => {
          // 图层加载完毕
          self.loadStatus = LoadStatus.loaded
          self.loaded = true
          resolve(self)
        })
      })
      .catch((result) => {
        self.loadStatus = Log.error('WMS信息查询失败:', result)
      })
  }

  /**
   * 通过图层名称或id来设置子图层,若找到相同图层仅会覆盖相同名称的参数,若没有则在最后新增一个<a id='setSubLayer'></a>
   * @param {WMSSubLayer | Object} wmsSublayer 子图层对象
   * @example <caption><h7>设置子图层参数</h7></caption>
   * // ES5引入方式
   * const { WMSLayer } = Zondy.Layer
   * // ES6引入方式
   * import { WMSLayer } from "@mapgis/webclient-common"
   * // 初始化WMS图层
   * const wmsLayer = new WMSLayer({
   *   // 服务基地址
   *   url: 'http://{ip}:{port}/igs/rest/services/{ServiceName}/WMSServer'
   * });
   * map.add(wmsLayer);
   * // 通过setSubLayer方法设置子图层显隐
   * // 通过图层id来设置显隐
   * wmsLayer.setSubLayer({
   *   id: 0,
   *   visible: false
   * })
   * // 或者通过图层名称设置显隐
   * wmsLayer.setSubLayer({
   *   name: "Map_Hubei4326:t1",
   *   visible: true
   * })
   * */
  setSubLayer(wmsSublayer) {
    // 更新子图层
    setSublayer(this, wmsSublayer, WMSSubLayer)
    // 更新layers信息
    this._getLayersFromAllSubLayers()
    // 发送更新事件
    this._fireUpdateEvent('更新子图层', [
      {
        name: 'sublayerVisible',
        params: [this],
        dataChanged: true,
        operationType: 'method'
      }
    ])
  }

  /**
   * 从sublayers中获取layers字符串
   * @private
   * @return {String} layers字符串
   * */
  _getLayersFromSubLayers() {
    let layers = ''

    // 获取要显示的子图层
    for (let i = 0; i < this._sublayers.length; i++) {
      if (this._sublayers[i].visible && this._sublayers[i].name) {
        layers += `${this._sublayers[i].name},`
      }
    }

    // 删除最后一个逗号
    layers = layers.substring(0, layers.length - 1)
    this.layers = layers

    return layers
  }

  /**
   * 从allSublayers中获取layers字符串
   * @private
   * @return {String} layers字符串
   * */
  _getLayersFromAllSubLayers() {
    let layers = ''

    for (let i = 0; i < this.allSublayers.length; i++) {
      if (this.allSublayers[i].visible && this.allSublayers[i].name) {
        layers += `${this.allSublayers[i].name},`
      }
    }
    layers = layers.substring(0, layers.length - 1)
    this.layers = layers

    return layers
  }

  /**
   * 获取指定空间参照系对应的范围
   * @private
   * @param {SpatialReference} sp 空间参照系,必须是该图层支持的空间参照系
   * @return {Extent} 图层在指定空间参照系的全图范围
   * */
  _getExtentBySP(sp) {
    let extent = null

    if (!isNull(sp)) {
      for (let i = 0; i < this._extentList.length; i++) {
        if (this._extentList[i].spatialReference.equals(sp)) {
          extent = this._extentList[i]

          break
        }
      }
    }

    return extent
  }

  /**
   * 根据子图层id查询图层<a id='findSublayerById'></a>
   * @param {String} sublayerID 图层ID
   * @return {IGSVectorTileSubLayer} 子图层
   * @example <caption><h7>根据子图层id查询图层</h7></caption>
   * // ES5引入方式
   * const { WMSLayer } = Zondy.Layer
   * // ES6引入方式
   * import { WMSLayer } from "@mapgis/webclient-common"
   * // 初始化WMS图层
   * const wmsLayer = new WMSLayer({
   *   // 服务基地址
   *   url: 'http://{ip}:{port}/igs/rest/services/{ServiceName}/WMSServer'
   * });
   * map.add(wmsLayer);
   * // 根据id获取子图层
   * const wmsSubLayer = wmsLayer.findSublayerById(0)
   */
  findSublayerById(sublayerID) {
    for (let i = 0; i < this.allSublayers.length; i++) {
      if (this.allSublayers[i].id === sublayerID) {
        return this.allSublayers[i]
      }
    }
    return null
  }

  toJSON() {
    const _json = super.toJSON()
    _json.url = this.url
    _json.imageWidth = this.imageWidth
    _json.imageHeight = this.imageHeight
    _json.imageFormat = this.imageFormat
    _json.imageFormats = this.imageFormats
    _json.imageTransparency = this.imageTransparency
    _json.version = this.version
    _json.type = this.type
    _json.layers = this.layers
    const _extentList = []
    for (let i = 0; i < this._extentList.length; i++) {
      _extentList.push(toJSON(this._extentList[i], Extent))
    }
    _json.extentList = _extentList
    const _sublayers = []
    this.sublayers.forEach(function (sublayer) {
      _sublayers.push(toJSON(sublayer, WMSSubLayer))
    })
    _json.sublayers = _sublayers
    const _allSublayers = []
    this.allSublayers.forEach(function (sublayer) {
      _allSublayers.push(toJSON(sublayer, WMSSubLayer))
    })
    _json.allSublayers = _allSublayers

    return _json
  }
}

Object.defineProperties(WMSLayer.prototype, {
  /**
   * 子图层对象
   * @member WMSLayer.prototype.sublayers
   * @type {Array}
   */
  sublayers: {
    get() {
      return this._sublayers
    },
    set(value) {
      this._sublayers = value
    }
  },
  /**
   * 图层坐标系对象
   * @member Layer.prototype.spatialReference
   * @type {SpatialReference}
   */
  spatialReference: {
    set(newSpatialReference) {
      let i = 0
      if (
        newSpatialReference &&
        this.spatialReferences &&
        this.spatialReferences instanceof Array
      ) {
        for (; i < this.spatialReferences.length; i++) {
          if (this.spatialReferences[i].equals(newSpatialReference)) {
            this._spatialReference = newSpatialReference
            this._fireUpdateEvent('修改图层坐标系', [
              {
                name: 'spatialReference',
                params: [this._spatialReference],
                dataChanged: true,
                operationType: 'property'
              }
            ])
            break
          }
        }

        if (i === this.spatialReferences.length) {
          throw new Error('该图层不支持所指定的空间参考系,设置失败!')
        }
      }
    },
    get() {
      return this._spatialReference
    }
  },
  /**
   * 图层范围,从服务中读取,仅会请求在该范围内的瓦片
   * @readonly
   * @member {String} MapImageLayer.prototype.extent
   */
  extent: {
    get() {
      return this._getExtentBySP(this.spatialReference)
    }
  }
})

/**
 * 通过url创建图层对象
 * @param {String} url 服务基地址
 * @return {WMSLayer} 新的图层对象
 * */
WMSLayer.fromServerUrl = function (url) {
  return new WMSLayer({
    url
  })
}

Object.defineProperties(WMSLayer.prototype, {
  /**
   * 空间裁剪范围
   * @member WMSLayer.prototype.clippingArea
   * @type {Polygon|Extent|Circle|null}
   */
  clippingArea: {
    get() {
      return this._clippingArea
    },
    set(value) {
      this._clippingArea = value
      this._fireUpdateEvent('空间裁剪区域', [
        {
          name: 'clippingArea',
          params: [this._clippingArea],
          dataChanged: true,
          operationType: 'property'
        }
      ])
    }
  }
})

Zondy.Layer.WMSLayer = WMSLayer
export default WMSLayer
构造函数
成员变量
方法
事件