类名 common/document/layer/ogc/WMTSLayer.js
import { Zondy, Collection, WMTSStyle } from '../../../base'
import { LayerType, LoadStatus } from '../../../base/enum'
import { defaultValue, Log, toJSON } from '../../../util'
import { WMTSServer } from '../../../service'
import WMTSSubLayer from './WMTSSubLayer'
import TileMatrixSet from '../../../base/TileMatrixSet'
import { Extent, Point, SpatialReference } from '../../../base/geometry'
import {
  getEPSGCodeFromOGCSupportedCRSString,
  getEPSGFromTileMatrixSetId,
  getTileResolution,
  initCorporationType
} from '../support/Utils'
import OGCLayer from './OGCLayer'
import TileInfo from '../support/TileInfo'
import LOD from '../support/LOD'
import Projection from '../../../base/Projection'

/**
 * WMTS图层,<br>
 * 目前二维上支持4326(包括4490,4214以及4610),3857以及EPSG支持的自定义坐标系,三维上仅支持4326(包括4490,4214以及4610)以及3857坐标系,WMTS服务会自动读取元信息上的坐标系,不需要用户指定
 * <br><br>[ES5引入方式]:<br/>
 * Zondy.Layer.WMTSLayer() <br/>
 * [ES6引入方式]:<br/>
 * import { WMTSLayer } 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 WMTSLayer
 * @moduleEX LayerModule
 * @extends OGCLayer
 * @fires Layer#图层加载完毕事件
 * @fires Layer#图层销毁完毕事件
 * @fires Layer#图层更新完毕事件
 * @fires Layer#图层显隐更新完毕事件
 * @fires Layer#图层透明度更新完毕事件
 * @fires Layer#图层顺序更新完毕事件
 * @fires Layer#图层刷新完毕事件
 * @param {Object} options 构造参数
 * @param {String} [options.url] 服务基地址,支持如下服务:<br/>
 * 1、支持MapGIS的WMTS服务,格式为:http://{ip}:{port}/igs/rest/services/{ServiceName}/WMTSServer,请注意,当在IGS中发布自定义坐标系的WMTS服务时,可能会有部分地图无法正确的进行预览,
 * 并且该服务中的范围参数是错误的,请自行指定跳转范围,或从该服务对应的瓦片服务中获取,参考示例:<a href='#MapIGS'>[加载MapGIS的WMTS服务]</a><br/>
 * 2、支持ArcGIS的WMTS服务,格式为:http://{ip}:{port}/arcgis/rest/services/{ServiceName}/MapServer/WMTS,参考示例:<a href='#ArcGIS'>[加载ArcGIS的WMTS服务]</a><br/>
 * 3、支持天地图的WMTS服务:格式为:http://t{0~6的随机数}.tianditu.gov.cn/{图层类型}_{坐标系}/wmts,<br/>
 * 其中天地图层类型如下:<br/>
 * vec:矢量底图、img:卫星影像底图、cva: 矢量注记图层(中文)、eva: 矢量注记图层(英文)、cia: 注记图层(中文)、eia: 注记图层(英文)、ter: 地形晕渲底图、cta: 注记(中文)、ibo: 全球国界<br/>
 * 坐标系如下:<br/>
 * w:墨卡托坐标系(3857)、c:经纬度坐标系(4326)<br/>
 * 参考示例:<a href='#tdt'>[加载天地图的WMTS服务]</a><br/>
 * @param {Number} [options.opacity = 1] 图层透明度,0到1之间的值,0为完全透明,1为不透明,参考示例:<a href='#opacity'>[修改图层透明度]
 * @param {Boolean} [options.visible = true] 图层显示或隐藏,true则显示,false则隐藏,参考示例:<a href='#visible'>[设置图层显隐]
 * @param {Number} [options.minScale = 0] 最小缩放级数,仅会请求级数大于等于minScale的图片
 * @param {Number} [options.maxScale = 19] 最大缩放级数,仅会请求级数小于等于maxScale的图片
 * @param {String} [options.tokenKey = 'token'] token名
 * @param {String} [options.tokenValue] token值,只有当tokenValue存在时,才会绑定token
 * @param {Polygon|Extent|Circle|null} [options.clippingArea = null] 图层空间裁剪范围,仅支持多边形裁剪、矩形裁剪、圆形裁剪
 *
 * @summary <h5>支持如下方法:</h5>
 * <a href='#load'>[1、加载图层资源]</a><br/>
 * <a href='#findSublayerById'>[2、根据子图层id查询图层]</a><br/>
 * <a href='#fromServerUrl'>[3、通过url创建图层对象]</a><br/>
 * <a href='#fromJSON'>[4、通过传入的json构造并返回一个新的几何对象]</a><br/>
 * [5、导出为json对象]{@link OGCLayer#toJSON}<br/>
 * [6、克隆几何对象]{@link OGCLayer#clone}
 *
 * @example <caption><h7 id='MapIGS'>加载WMTS图层</h7></caption>
 * // ES5引入方式
 * const { Map, MapView, SceneView } = Zondy
 * const { WMTSLayer } = Zondy.Layer
 * // ES6引入方式
 * import { Map, MapView, SceneView, WMTSLayer } from "@mapgis/webclient-common"
 * // 初始化图层管理容器
 * const map = new Map();
 * // 初始化二维地图视图对象
 * const mapView = new MapView({
 *   // 视图id
 *   viewId: "viewer-id",
 *   // 图层管理容器
 *   map: map
 * });
 * // 初始化三维地图视图对象
 * const mapView = new SceneView({
 *   // 视图id
 *   viewId: "viewer-id",
 *   // 图层管理容器
 *   map: map
 * });
 * // 初始化WMTS图层
 * const wmtsLayer = new WMTSLayer({
 *   // 服务基地址
 *   url: 'http://{ip}:{port}/igs/rest/services/{serviceName}/WMTSServer'
 * });
 * // 将图层加入容器中
 * map.add(wmtsLayer);
 * // 图层加载完毕
 * wmsLayer.on('layerview-created', function (result) {
 *   console.log("加载完毕:", result.layer)
 *   // 视点跳转
 *   sceneView.flyTo({
 *     extent: result.layer.extent
 *   })
 * });
 *
 * @example <caption><h7 id='ArcGIS'>添加ArcGIS的WMTS图层示例</h7></caption>
 * // ES5引入方式
 * const { Map, MapView, SceneView } = Zondy
 * const { WMTSLayer } = Zondy.Layer
 * // ES6引入方式
 * import { Map, MapView, SceneView, WMTSLayer } from "@mapgis/webclient-common"
 * // 初始化图层管理容器
 * const map = new Map();
 * // 初始化二维地图视图对象
 * const mapView = new MapView({
 *   // 视图id
 *   viewId: "viewer-id",
 *   // 图层管理容器
 *   map: map
 * });
 * // 初始化三维地图视图对象
 * const mapView = new SceneView({
 *   // 视图id
 *   viewId: "viewer-id",
 *   // 图层管理容器
 *   map: map
 * });
 * // 初始化WMTS图层
 * const wmtsLayer = new WMTSLayer({
 *   url: 'http://{ip}:{port}/arcgis/rest/services/{serviceName}/MapServer/WMTS'
 * });
 * // 将图层加入容器中
 * map.add(wmtsLayer);
 * // 图层加载完毕
 * wmsLayer.on('layerview-created', function (result) {
 *   console.log("加载完毕:", result.layer)
 *   // 视点跳转
 *   sceneView.flyTo({
 *     extent: result.layer.extent
 *   })
 * });
 *
 * @example <caption><h7 id='tdt'>加载天地图的WMTS服务</h7></caption>
 * // ES5引入方式
 * const { Map, MapView, SceneView } = Zondy
 * const { WMTSLayer } = Zondy.Layer
 * // ES6引入方式
 * import { Map, MapView, SceneView, WMTSLayer } from "@mapgis/webclient-common"
 * // 初始化图层管理容器
 * const map = new Map();
 * // 初始化二维地图视图对象
 * const mapView = new MapView({
 *   // 视图id
 *   viewId: "viewer-id",
 *   // 图层管理容器
 *   map: map
 * });
 * // 初始化三维地图视图对象
 * const mapView = new SceneView({
 *   // 视图id
 *   viewId: "viewer-id",
 *   // 图层管理容器
 *   map: map
 * });
 * 初始化WMTS图层
 * const wmtsLayer = new WMTSLayer({
 *   // 加载经纬度的影像地图
 *   url: 'http://t6.tianditu.gov.cn/img_c/wmts',
 *   // 天地图必须加token,且token名为tk
 *   tokenKey: 'tk',
 *   // token请在天地图官网申请
 *   tokenValue: '天地图token'
 * });
 * // 将图层加入容器中
 * map.add(wmtsLayer);
 * // 图层加载完毕
 * wmsLayer.on('layerview-created', function (result) {
 *   console.log("加载完毕:", result.layer)
 *   // 视点跳转
 *   sceneView.flyTo({
 *     extent: result.layer.extent
 *   })
 * });
 *
 * @example <caption><h7 id='opacity'>修改图层透明度</h7></caption>
 * // ES5引入方式
 * const { WMTSLayer } = Zondy.Layer
 * // ES6引入方式
 * import { WMTSLayer } from "@mapgis/webclient-common"
 * // 初始化时设置
 * const wmtsLayer = new WMTSLayer({
 *   // 服务基地址
 *   url: 'http://{ip}:{port}/igs/rest/services/{serviceName}/WMTSServer',
 *   // 设置透明度
 *   opacity: 1.0
 * });
 * // 将图层加入容器中
 * map.add(wmtsLayer);
 *
 * // 加载完成后设置
 * wmsLayer.on('layerview-created', function (result) {
 *   console.log("加载完毕:", result.layer)
 *   // 设置透明度
 *   wmtsLayer.opacity = 0.5
 * })
 *
 * @example <caption><h7 id='visible'>设置图层显隐</h7></caption>
 * // ES5引入方式
 * const { WMTSLayer } = Zondy.Layer
 * // ES6引入方式
 * import { WMTSLayer } from "@mapgis/webclient-common"
 * // 初始化时设置
 * const wmtsLayer = new WMTSLayer({
 *   // 服务基地址
 *   url: 'http://{ip}:{port}/igs/rest/services/{serviceName}/WMTSServer',
 *   // 设置图层显隐
 *   visible: true
 * });
 * // 将图层加入容器中
 * map.add(wmtsLayer);
 *
 * // 加载完成后设置
 * wmsLayer.on('layerview-created', function (result) {
 *   console.log("加载完毕:", result.layer)
 *   // 设置图层显隐
 *   wmtsLayer.visible = !wmtsLayer.visible
 * })
 *
 * @example <caption><h7>删除图层</h7></caption>
 * map.remove(wmtsLayer)
 */
class WMTSLayer extends OGCLayer {
  constructor(options) {
    super(options)
    options = defaultValue(options, {})

    /**
     * 图层类型
     * @readonly
     * @member {type} WMTSLayer.prototype.type
     */
    this.type = LayerType.wmts

    /**
     * 当前处于活动状态的子图层
     * @member {WMTSSubLayer} WMTSLayer.prototype.activeLayer
     */
    this.activeLayer = defaultValue(options.activeLayer, new WMTSSubLayer())
    /**
     * WMTSSublayer 子图层对象的集合
     * @readonly
     * @member {Array<WMTSSubLayer>} WMTSLayer.prototype.sublayers
     */
    this.sublayers = defaultValue(options.sublayers, new Collection())
    if (!(this.sublayers instanceof Collection)) {
      this.sublayers = new Collection(this.sublayers)
    }
    /**
     * 服务基地址
     * @readonly
     * @member {String} WMTSLayer.prototype.url
     */
    this.url = defaultValue(options.url, undefined)
    /**
     * 空间参考
     * @readonly
     * @member {SpatialReference} WMTSLayer.prototype.spatialReference
     */
    this.spatialReference = SpatialReference.fromJSON(options.spatialReference)
    /**
     * 图块矩阵集的集合
     * @readonly
     * @member {Array<TileMatrixSet>} WMTSLayer.prototype.tileMatrixSets
     */
    this.tileMatrixSets = defaultValue(options.tileMatrixSets, [])
    /**
     * WMTS 公司代码
     * @readonly
     * @member {String} WMTSLayer.prototype.corporationType
     */
    this.corporationType = initCorporationType(this.url)
    /**
     * 最小缩放级别
     * @member {Number} WMTSLayer.prototype.minScale
     */
    this.minScale = defaultValue(options.minScale, 0)
    /**
     * 最大缩放级别
     * @member {Number} WMTSLayer.prototype.maxScale
     */
    this.maxScale = defaultValue(options.maxScale, 19)
    /**
     * 图片宽度
     * @readonly
     * @member {Number} WMTSLayer.prototype.imageWidth
     */
    this.imageWidth = 256
    /**
     * 图片高度
     * @readonly
     * @member {Number} WMTSLayer.prototype.imageHeight
     */
    this.imageHeight = 256
    // 空间裁剪范围
    this._clippingArea = defaultValue(options.clippingArea, null)
    // 地图服务对象
    this._mapServer = new WMTSServer({
      url: this.url
    })
  }

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

    return _layer
  }

  /**
   * @description 转换为json对象
   * @return {Object} json对象
   */
  toJSON() {
    const json = super.toJSON()
    json.type = this.type
    json.activeLayer = toJSON(this.activeLayer, WMTSSubLayer)
    json.url = this.url
    json.spatialReference = toJSON(this.spatialReference, SpatialReference)
    json.corporationType = this.corporationType
    json.minScale = this.minScale
    json.maxScale = this.maxScale
    json.imageWidth = this.imageWidth
    json.imageHeight = this.imageHeight

    const _sublayers = []
    this.sublayers.forEach(function (sublayer) {
      _sublayers.push(toJSON(sublayer, WMTSSubLayer))
    })
    json.sublayers = _sublayers

    const _tileMatrixSets = []
    for (let i = 0; i < this.tileMatrixSets.length; i++) {
      _tileMatrixSets.push(toJSON(this.tileMatrixSets[i], TileMatrixSet))
    }
    json.tileMatrixSets = _tileMatrixSets

    return json
  }

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

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

      // IGS2.0服务
      if (
        self.url.indexOf('/igs/rest/services/') > -1 ||
        self.url.indexOf('/arcgis/rest/services/') > -1 ||
        self.url.indexOf('.tianditu.gov.cn/') > -1
      ) {
        // 获取tileMatrixSets
        data.tileMatrixSet.forEach((tileMatrixSet) => {
          const _epsgCode = getEPSGCodeFromOGCSupportedCRSString(
            tileMatrixSet.supportedCRS
          )
          const _spatialReference = new SpatialReference({
            wkid: _epsgCode
          })
          const _topLeftCorner =
            tileMatrixSet.tileMatrix[0].topLeftCorner.split(' ')
          const _lods = []
          tileMatrixSet.tileMatrix.forEach(function (tileMatrix, index) {
            const _lod = new LOD()
            // identifier不一定与level的数字对应,可能是一个字符串形式
            _lod.level = tileMatrix.identifier
            _lod.scale = Number(tileMatrix.scaleDenominator)
            if (tileMatrix.identifier) {
              // 存在两种情况,其一是参照系:级数,其二是只为级数
              const _pos = tileMatrix.identifier.lastIndexOf(':')
              if (_pos >= 0) {
                _lod.levelValue = parseInt(
                  tileMatrix.identifier.substring(_pos + 1)
                )
              } else {
                _lod.levelValue = parseInt(tileMatrix.identifier)
              }
            }
            _lod.resolution = getTileResolution(
              tileMatrixSet.identifier,
              self.corporationType,
              _lod.scale,
              _spatialReference
            )
            _lods.push(_lod)
          })
          // 经纬度或者高斯坐标左上角的点坐标是反的,YX
          let _coordinates
          // 经纬度坐标系
          if (_spatialReference.isGeographic) {
            _coordinates = [
              Number(_topLeftCorner[1]),
              Number(_topLeftCorner[0])
            ]
          }
          // 高斯坐标系
          else if (
            (_spatialReference.wkid >= 2327 &&
              _spatialReference.wkid <= 2442) ||
            (_spatialReference.wkid >= 4491 &&
              _spatialReference.wkid <= 4554) ||
            (_spatialReference.wkid >= 21413 &&
              _spatialReference.wkid <= 21423) ||
            (_spatialReference.wkid >= 21473 && _spatialReference.wkid <= 21483)
          ) {
            _coordinates = [
              Number(_topLeftCorner[1]),
              Number(_topLeftCorner[0])
            ]
          }
          // 天地图的3857坐标系是反的,YX
          else if (self.url.indexOf('.tianditu.gov.cn/') > -1) {
            // 中文注记墨卡托服务的原点是经纬度,因此要转成墨卡托坐标,由于原点纬度超过了85.05度,之上的投影都是错误的,因此写死,不进行投影
            // 参考资料https://zh.wikipedia.org/wiki/Web%E5%A2%A8%E5%8D%A1%E6%89%98%E6%8A%95%E5%BD%B1
            if (self.url.indexOf('/_w/') > -1) {
              _coordinates = [-20037508.3427892, 20037508.3427892]
            } else {
              _coordinates = [
                Number(_topLeftCorner[1]),
                Number(_topLeftCorner[0])
              ]
            }
          }
          // 其他坐标系是正的,XY
          else {
            _coordinates = [
              Number(_topLeftCorner[0]),
              Number(_topLeftCorner[1])
            ]
          }
          const _tileInfo = new TileInfo({
            origin: new Point({
              coordinates: _coordinates,
              spatialReference: _spatialReference
            }),
            size: [
              Number(tileMatrixSet.tileMatrix[0].tileWidth),
              Number(tileMatrixSet.tileMatrix[0].tileHeight)
            ],
            lods: _lods,
            spatialReference: _spatialReference
          })
          self.tileMatrixSets.push(
            new TileMatrixSet({
              extent: '',
              id: tileMatrixSet.identifier,
              tileInfo: _tileInfo,
              layer: self,
              tileMatrix: tileMatrixSet.tileMatrix,
              identifier: tileMatrixSet.identifier,
              supportedCRS: tileMatrixSet.supportedCRS
            })
          )
        })
        // 设置activeLayer以及坐标系
        if (Array.isArray(data.layer)) {
          data.layer.forEach((layer, index) => {
            if (index === 0) {
              self.activeLayer = self._createWMTSSubLayer(layer, data)
              self.spatialReference = new SpatialReference(
                getEPSGFromTileMatrixSetId(layer.tileMatrixSetId)
              )
            }
            self.sublayers.add(self._createWMTSSubLayer(layer, data))
          })
        }
        // 地图文档中只有一个图层的情况
        else {
          if (typeof data.layer.boundingBox.lowerCorner === 'string') {
            data.layer.boundingBox.lowerCorner =
              data.layer.boundingBox.lowerCorner.split(' ')
          }
          if (typeof data.layer.boundingBox.upperCorner === 'string') {
            data.layer.boundingBox.upperCorner =
              data.layer.boundingBox.upperCorner.split(' ')
          }
          // 遍历所有的tileMatrixSets,找到identifier包含028mm_GB的子元素
          // 暂时这样做,没找到更好的处理方法
          for (let i = 0; i < self.tileMatrixSets.length; i++) {
            if (
              self.tileMatrixSets[i].identifier.indexOf('028mm_GB') > -1 ||
              self.tileMatrixSets[i].identifier === 'default' ||
              self.tileMatrixSets[i].identifier === 'default028mm' ||
              self.tileMatrixSets[i].identifier === 'w' ||
              self.tileMatrixSets[i].identifier === 'c'
            ) {
              // 获取坐标系wkid
              const supportedCRS =
                self.tileMatrixSets[i].supportedCRS.split(':')
              const wkid = Number(supportedCRS[supportedCRS.length - 1])
              // 初始化坐标系
              const spatialReference = new SpatialReference({
                wkid
              })
              // 获取瓦片大小
              self.imageWidth = defaultValue(
                Number(self.tileMatrixSets[i].tileMatrix[0].tileWidth),
                256
              )
              self.imageHeight = defaultValue(
                Number(self.tileMatrixSets[i].tileMatrix[0].tileHeight),
                256
              )
              self._spatialReference = spatialReference
              // 设置地图范围
              self.extent = self._getExtentFromBoundingBox(
                data.layer.boundingBox,
                self.url
              )
            }
          }
          // 指定激活图层
          self.activeLayer = self._createWMTSSubLayer(
            data.layer,
            self.tileMatrixSets
          )
          // 新增子图层
          self.sublayers.add(
            self._createWMTSSubLayer(data.layer, self.tileMatrixSets)
          )
        }
        return new Promise((resolve) => {
          self.loadStatus = LoadStatus.loaded
          self.loaded = true
          resolve(self)
        })
      }
    })
  }

  /**
   * @description 根据id查询子图层<a id='findSublayerById'></a>
   * @param {Object} id 子图层的id
   * @return {WMTSSubLayer} 找到的子图层对象
   */
  findSublayerById(id) {
    return this.sublayers.items[id]
  }

  /**
   * 从WMTS的boundingBox参数中构造外包盒,注意天地图的范围坐标是YX,其他的都是XY
   * @private
   * @param {Object} boundingBox WMTS的boundingBox属性
   * @param {String} url 服务基地址,用来判定服务厂商
   * @return {Extent} 图层范围
   * */
  _getExtentFromBoundingBox(boundingBox, url) {
    let _extent
    // 天地图的范围坐标是反的
    if (url.indexOf('.tianditu.gov.cn/') > -1) {
      _extent = new Extent({
        xmin: Number(boundingBox.lowerCorner[0]),
        ymin: Number(boundingBox.lowerCorner[1]),
        xmax: Number(boundingBox.upperCorner[0]),
        ymax: Number(boundingBox.upperCorner[1]),
        spatialReference: SpatialReference.fromJSON(this.spatialReference)
      })
    }
    // 其他的是正的
    else {
      _extent = new Extent({
        xmin: Number(boundingBox.lowerCorner[1]),
        ymin: Number(boundingBox.lowerCorner[0]),
        xmax: Number(boundingBox.upperCorner[1]),
        ymax: Number(boundingBox.upperCorner[0]),
        spatialReference: SpatialReference.fromJSON(this.spatialReference)
      })
    }

    return _extent
  }

  _createWMTSSubLayer(layerJson, tileMatrixSets) {
    // 获取图层范围
    const _extent = this._getExtentFromBoundingBox(
      layerJson.boundingBox,
      this.url
    )

    return new WMTSSubLayer({
      identifier: layerJson.identifier,
      title: layerJson.title,
      description: 'WMTS子图层',
      imageFormat: layerJson.format,
      imageFormats: [layerJson.format],
      styleId: Array.isArray(layerJson.Style)
        ? layerJson.Style[0].identifier
        : layerJson.Style.identifier,
      styles: [
        new WMTSStyle({
          id: layerJson.Style.identifier,
          title: layerJson.Style.title
        })
      ],
      tileMatrixSets,
      tileMatrixSetId: tileMatrixSets[0].identifier,
      extent: _extent,
      resourceURLTemplates: []
    })
  }
}

/**
 * 通过url创建图层对象<a id='fromServerUrl'></a>
 * @param {String} url 服务基地址
 * @return {WMTSLayer} 新的图层对象
 * @example <caption><h7>通过url创建图层对象</h7></caption>
 * // ES5引入方式
 * const { WMTSLayer } = Zondy.Layer
 * // ES6引入方式
 * import { WMTSLayer } from "@mapgis/webclient-common"
 * // 初始化图层
 * const url = 'http://{ip}:{port}/igs/rest/services/{serviceName}/WMTSServer';
 * const wmtsLayer = new WMTSLayer.fromServerUrl(url);
 * */
WMTSLayer.fromServerUrl = function (url) {
  return new WMTSLayer({
    url
  })
}

Object.defineProperties(WMTSLayer.prototype, {
  /**
   * 空间裁剪范围
   * @member WMTSLayer.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.WMTSLayer = WMTSLayer
export default WMTSLayer
构造函数
成员变量
方法
事件