类名 common/document/layer/igserver/IGSTileLayer.js
import { TileLayer } from '../baseLayer'
import { Zondy } from '../../../base'
import { defaultValue, Log, toJSON } from '../../../util'
import { LayerType, LoadStatus } from '../../../base/enum'
import { TileServer } from '../../../service'
import {
  Extent,
  Geometry,
  SpatialReference,
  Point
} from '../../../base/geometry'
import TileInfoUtil from '../support/TileInfoUtil'

/**
 * IGS瓦片图层,<br>
 * 支持IGS1.0和2.0两个服务版本,支持自定义坐标系,当IGS版本是1.0时,需要手动设置图层坐标系,当IGS版本是2.0时,会自动读取元信息上的坐标系,不需要用户指定,
 * <br><br>[ES5引入方式]:<br/>
 * Zondy.Layer.IGSTileLayer() <br/>
 * [ES6引入方式]:<br/>
 * import { IGSTileLayer } 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 IGSTileLayer
 * @moduleEX LayerModule
 * @extends Layer
 * @fires Layer#图层加载完毕事件
 * @fires Layer#图层销毁完毕事件
 * @fires Layer#图层更新完毕事件
 * @fires Layer#图层显隐更新完毕事件
 * @fires Layer#图层透明度更新完毕事件
 * @fires Layer#图层顺序更新完毕事件
 * @fires Layer#图层刷新完毕事件
 * @param {Object} options 构造参数
 * @param {String} [options.url] 服务基地址,<br/>
 * IGS1.0的服务为:http://{ip}:{port}/igs/rest/mrms/tile/{serviceName},暂时无法从元信息中获取坐标系,请自行指定图层坐标系,参考示例:<a href='#igs-1'>[IGS1.0的瓦片图层示例]</a><br/>
 * IGS2.0的服务为:http://{ip}:{port}/igs/rest/services/{folder}/{serviceName}/TileServer,参考示例:<a href='#igs-2'>[IGS2.0的瓦片图层示例]</a><br/>
 * 删除图层方法:<a href='#remove-layer'>[删除图层]</a>
 * @param {String} [options.id] 图层id,不给则给一个随机的id
 * @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 {SpatialReference} [options.spatialReference] 图层坐标系,默认从服务元信息上读取,当为igs1.0服务时,需要用户指定坐标系,
 * 参考示例:<a href='#igs-1'>[设置图层坐标系(IGS1.0)]</a>
 * @param {Number} [options.minScale = null] 最小比例尺,只有当地图视图的比例尺大于最小比例尺时显示瓦片图层
 * @param {Number} [options.maxScale = null] 最大比例尺,只有当地图视图的比例尺小于最大比例尺时显示瓦片图层
 * @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='#getTileUrl'>[2、根据级数以及行列号获取瓦片的url]</a><br/>
 * <a href='#toJSON'>[3、将图层转为json对象]</a><br/>
 * <a href='#fromJSON'>[4、通过传入的json构造并返回一个新的几何对象]</a><br/>
 * [5、导出为json对象]{@link OGCLayer#toJSON}<br/>
 * [6、克隆几何对象]{@link OGCLayer#clone}
 *
 * @example <caption><h7 id='igs-1'>IGS1.0的瓦片图层示例</h7></caption>
 * // ES5引入方式
 * const { Map ,MapView,SpatialReference} = Zondy
 * const { IGSTileLayer} = Zondy.Layer
 * // ES6引入方式
 * import { Map ,MapView,IGSTileLayer } from "@mapgis/webclient-common"
 * // 初始化图层管理容器
 * const map = new Map();
 * // 初始化地图视图对象
 * const mapView = new MapView({
 *   // 视图id
 *   viewId: "viewer-id",
 *   // 图层管理容器
 *   map: map
 * });
 * const igsTileLayer = new IGSTileLayer({
 *   // 服务基地址
 *   url: 'http://{ip}:{port}/igs/rest/mrms/tile/{serviceName}',
 *   // IGS1.0服务,暂时无法从元信息中获取坐标系,请自行指定图层坐标系
 *   spatialReference: new SpatialReference({
 *     wkid: 4326
 *   })
 * });
 * map.add(igsTileLayer);
 *
 * @example <caption><h7 id='igs-2'>IGS2.0的瓦片图层示例</h7></caption>
 * // ES5引入方式
 * const { Map ,MapView,SpatialReference} = Zondy
 * const { IGSTileLayer} = Zondy.Layer
 * // ES6引入方式
 * import { Map ,MapView,IGSTileLayer } from "@mapgis/webclient-common"
 * // 初始化图层管理容器
 * const map = new Map();
 * // 初始化地图视图对象
 * const mapView = new MapView({
 *   // 视图id
 *   viewId: "viewer-id",
 *   // 图层管理容器
 *   map: map
 * });
 * const igsTileLayer = new IGSTileLayer({
 *   // 服务基地址
 *   url: 'http://{ip}:{port}/igs/rest/services/Tile/{serviceName}/TileServer'
 * });
 * map.add(igsTileLayer);
 *
 * @example <caption><h7 id='opacity'>设置图层透明度</h7></caption>
 * // ES5引入方式
 * const { IGSTileLayer} = Zondy.Layer
 * // ES6引入方式
 * import { IGSTileLayer } from "@mapgis/webclient-common"
 * // 初始化时设置
 * const igsTileLayer = new IGSTileLayer({
 *   // 服务基地址
 *   url: 'http://{ip}:{port}/igs/rest/services/Tile/{serviceName}/TileServer',
 *   // 设置图层透明度
 *   opacity: 1.0
 * });
 * map.add(igsTileLayer);
 * // 加载完成后设置
 * arcgisTileLayer.on('layerview-created', function (result) {
 *   console.log("加载完毕:", result.layer)
 * igsTileLayer.opacity = 0.5
 * })
 *
 * @example <caption><h7 id='visible'>设置图层显示或隐藏</h7></caption>
 * * // ES5引入方式
 * const { IGSTileLayer} = Zondy.Layer
 * // ES6引入方式
 * import { IGSTileLayer } from "@mapgis/webclient-common"
 * // 初始化时设置
 * const igsTileLayer = new IGSTileLayer({
 *   // 服务基地址
 *   url: 'http://{ip}:{port}/igs/rest/services/Tile/{serviceName}/TileServer',
 *   // 设置图层显示或隐藏
 *   visible: true
 * });
 * map.add(igsTileLayer);
 *
 * // 加载完成后设置
 * arcgisTileLayer.on('layerview-created', function (result) {
 *   console.log("加载完毕:", result.layer)
 *   // 设置图层显示或隐藏
 *   igsTileLayer.visible = !igsTileLayer.visible
 * })
 *
 * @example <caption><h7>ArcGIS的瓦片图层示例</h7></caption>
 *  // ES5引入方式
 * const { Map ,SceneView } = Zondy
 * const { IGSTileLayer} = Zondy.Layer
 * // ES6引入方式
 * import { Map ,MapView,IGSTileLayer } from "@mapgis/webclient-common"
 * //初始化图层管理容器
 * const map = new Map();
 * //初始化地图视图对象
 * const sceneView = new SceneView({
 *   //视图id
 *   viewId: "mapgis-3d-viewer",
 *   //图层管理容器
 *   map: map
 * });
 * const arcgisTileLayer = new IGSTileLayer({
 *   url: 'https://services.arcgisonline.com/arcgis/rest/services/World_Terrain_Base/MapServer'
 * });
 * map.add(arcgisTileLayer);
 * // 视点跳转
 * arcgisTileLayer.on('layerview-created', function (result) {
 *   console.log("加载完毕:", result.layer)
 *   sceneView.flyTo({
 *     extent: result.layer.extent
 *   })
 * })
 *
 * @example <caption><h7 id='remove-layer'>删除图层</h7></caption>
 * map.remove(igsTileLayer)
 *
 * @example <caption><h7 id='index'>图层顺序</h7></caption>
 * // 加载完毕后,更改图层顺序
 * map.reorder(igsTileLayer, '要移动到的index');
 * */
class IGSTileLayer extends TileLayer {
  constructor(options) {
    super(options)
    options = defaultValue(options, {})

    this.type = LayerType.igsTile
    this.description = 'IGS瓦片图层'
    /**
     * 服务基地址
     * @member {String} IGSTileLayer.prototype.url
     */
    this.url = defaultValue(options.url, '')
    /**
     * 服务名称
     * @member {String} IGSTileLayer.prototype.mapName
     */
    this.mapName = defaultValue(options.mapName, '')
    // 空间裁剪范围
    this._clippingArea = defaultValue(options.clippingArea, null)
    // IGS服务版本号
    this._igsVersion = '2.0'
    if (this.url.indexOf('/igs/rest/mrms/tile/') > -1) {
      this._igsVersion = '1.0'
    }
    // 瓦片服务
    this._tileServer = new TileServer({
      url: this.url
    })
  }

  /**
   * 加载图层资源
   * @example <caption><h7 id='load'>不加载图层,仅获取图层信息</h7></caption>
   * // 初始化图层
   * const igsTileLayer = new Zondy.Layer.IGSTileLayer({
   *   // 服务基地址
   *   url: 'http://{ip}:{port}/igs/rest/services/Tile/{serviceName}/TileServer'
   * });
   * igsTileLayer.load().then((result) => {
   *   // 获取完图层信息
   *   console.log(wmsLayer)
   * })
   * */
  load() {
    return super.load()
  }

  /**
   * 子类请求服务资源的方法
   * @private
   * */
  _load() {
    const self = this
    return this._tileServer
      .queryServerInfo()
      .then((result) => {
        Log.info('TileServer信息查询成功:', result)
        const data = result.data
        // igs1.0服务
        if (self._igsVersion === '1.0') {
          // 获取瓦片大小
          self.tileSize = data.tileWidth
          // 获取图层信息
          self.tileInfo = TileInfoUtil.parseTileInfo1(data)
          self.tileInfo.origin.spatialReference = self._spatialReference
          self.tileInfo.spatialReference = self._spatialReference
          if (!self._spatialReference) {
            Log.error('IGS1.0服务必须设置参考系')
          }
          // 获取图层范围
          self.extent = new Extent({
            xmin: data.xMin,
            ymin: data.yMin,
            xmax: data.xMax,
            ymax: data.yMax,
            spatialReference: SpatialReference.fromJSON(self._spatialReference)
          })
        }
        // igs2.0服务
        else {
          // 获取图层名称
          self.mapName = data.mapName
          // 获取瓦片大小
          self.tileSize = data.tileInfo.cols
          // 获取图层信息
          self.tileInfo = TileInfoUtil.parseTileInfo2(data.tileInfo)
          // 获取图层坐标系
          self.spatialReference = new SpatialReference(
            self.tileInfo.spatialReference
          )
          // 获取图层范围
          self.extent = new Extent({
            xmin: data.extent.xmin,
            ymin: data.extent.ymin,
            xmax: data.extent.xmax,
            ymax: data.extent.ymax,
            spatialReference: SpatialReference.fromJSON(self.spatialReference)
          })
        }

        return new Promise((resolve) => {
          self.loadStatus = LoadStatus.loaded
          self.loaded = true
          resolve(self)
        })
      })
      .catch((result) => {
        Log.error('TileServer信息查询失败:', result)
      })
  }

  /**
   * 根据级数以及行列号获取瓦片的url
   * @param {Number} level 瓦片级数
   * @param {Number} row 行号
   * @param {Number} col 列号
   * @example <caption><h7 id='getTileUrl'>根据级数以及行列号获取瓦片的url</h7></caption>
   * const url = igsTileLayer.getTileUrl(0, 1, 2)
   * */
  getTileUrl(level, row, col) {
    return `${this.url}/tileImage/${level}/${row}/${col}?f=image`
  }

  /**
   * 通过传入的json构造并返回一个新的几何对象<a id='fromJSON'></a>
   * @param {Object} [json] JSON对象
   * @example <caption><h7>通过传入的json构造并返回一个新的几何对象</h7></caption>
   * const json = {
   *   // 服务基地址
   *   url: 'http://{ip}:{port}/igs/rest/services/Tile/{serviceName}/TileServer'
   * }
   * const igsTileLayer = new Zondy.Layer.IGSTileLayer.fromJSON(json)
   */
  static fromJSON(json) {
    json = defaultValue(json, {})
    const _layer = new IGSTileLayer(json)
    _layer._isFromJSON = true
    _layer.tileSize = json.tileSize
    _layer.tileInfo = {
      dpi: json.tileInfo.dpi,
      format: json.tileInfo.format,
      size: json.tileInfo.size,
      spatialReference: SpatialReference.fromJSON(
        json.tileInfo.spatialReference
      ),
      lods: json.tileInfo.lods,
      origin: Geometry.fromJSON(json.tileInfo.origin)
    }
    _layer.spatialReference = SpatialReference.fromJSON(json.spatialReference)
    _layer.extent = Geometry.fromJSON(json.extent)

    return _layer
  }

  /**
   * @description 转换为json对象
   * @return {Object} json对象
   */
  toJSON() {
    const json = super.toJSON()
    json.description = this.description
    json.url = this.url
    json.mapName = this.mapName
    json.tileSize = this.tileSize
    const _tileInfo = {
      size: this.tileInfo.size,
      dpi: this.tileInfo.dpi,
      format: this.tileInfo.format,
      spatialReference: toJSON(
        this.tileInfo.spatialReference,
        SpatialReference
      ),
      origin: toJSON(this.tileInfo.origin, Point),
      lods: this.tileInfo.lods
    }
    json.tileInfo = _tileInfo

    return json
  }
}

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