类名 common/document/layer/arcgis/ArcGISMapImageLayer.js
import { MapImageLayer } from '../baseLayer'
import { Zondy } from '../../../base'
import { LayerEventType, LayerType, LoadStatus } from '../../../base/enum'
import { defaultValue, getGUID, isNull, Log } from '../../../util'
import { MapServer } from '../../../service'
import { Extent, SpatialReference } from '../../../base/geometry'
import ArcGISMapImageSubLayer from './ArcGISMapImageSubLayer'
import { fireEvent, setSublayer } from '../Utils'

/**
 * ArcGIS地图图片图层,<br/>
 * 目前二维上支持4326(包括4490,4214以及4610),3857以及EPSG支持的自定义坐标系,三维上仅支持4326(包括4490,4214以及4610)以及3857坐标系,会自动读取元信息上的坐标系,不需要用户指定
 * <br><br>[ES5引入方式]:<br/>
 * Zondy.Layer.ArcGISMapImageLayer() <br/>
 * [ES6引入方式]:<br/>
 * import { ArcGISMapImageLayer } 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 ArcGISMapImageLayer
 * @moduleEX LayerModule
 * @classdesc ArcGIS地图图片图层
 * @extends MapImageLayer
 * @fires Layer#图层加载完毕事件
 * @fires Layer#图层销毁完毕事件
 * @fires Layer#图层更新完毕事件
 * @param {Object} options 构造参数
 * @param {String} [options.url] 服务基地址,<br/>
 * https://{ip}:{port}/arcgis/rest/services/{serviceName}/MapServer,参考示例:<a href='#arcgis'>[ArcGIS的地图图片图层示例]</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] 图层坐标系,支持4326(包含4490,4214以及4610)、3857以及EPSG上的自定义坐标系,坐标系默认从元信息中获取,也可指定坐标系,
 * 参考示例:<a href='#spatialReference'>[指定图层的坐标系示例]</a>
 * @param {Number} [options.imageWidth = 256] 图片宽度,单位px,参考示例:<a href='#tileSize'>[设置图片大小]</a>
 * @param {Number} [options.imageHeight = 256] 图片高度,单位px,参考示例:<a href='#tileSize'>[设置图片大小]</a>
 * @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 {Boolean} [options.imageTransparency = true] 图片中没有数据的地方是否透明,默认为true,即透明
 *
 * @summary <h5>支持如下方法:</h5>
 * <a href='#load'>[1、加载图层资源]</a><br/>
 * <a href='#findSublayerById'>[2、根据子图层id查询子图层]</a><br/>
 * <a href='#refresh'>[3、刷新图层]</a><br/>
 * <a href='#fetchImage'>[4、根据范围和大小获取image标签]</a><br/>
 * <a href='#createServiceSublayers'>[5、创建一个该服务的子图层克隆对象]</a><br/>
 * <a href='#getImageUrl'>[6、根据参数获取图片的url]</a><br/>
 * <a href='#setSubLayer'>[7、更新子图层]</a><br/>
 * <a href='#fromJSON'>[8、通过传入的json构造并返回一个新的几何对象]</a><br/>
 * [9、导出为json对象]{@link OGCLayer#toJSON}<br/>
 * [10、克隆几何对象]{@link OGCLayer#clone}
 *
 * @example <caption><h7 id='arcgis'>ArcGIS的地图图片图层示例</h7></caption>
 * // 初始化图层管理容器
 * // ES5引入方式
 * const { Map,MapView } = Zondy
 * const { ArcGISMapImageLayer } = Zondy.Layer
 * // ES6引入方式
 * import { Map,MapView,ArcGISMapImageLayer } from "@mapgis/webclient-common"
 * const map = new Map();
 * // 初始化地图视图对象
 * const mapView = new MapView({
 *   // 视图id
 *   viewId: "viewer-id",
 *   // 图层管理容器
 *   map: map
 * });
 * // 添加图层
 * const arcGISMapImageLayer = new ArcGISMapImageLayer({
 *   // 服务基地址
 *   url: 'http://{ip}:{port}/arcgis/rest/services/{serviceName}/MapServer'
 * });
 * map.add(arcGISMapImageLayer);
 *
 * @example <caption><h7 id='spatialReference'>指定图层的坐标系示例</h7></caption>
 * // ES5引入方式
 * const { ArcGISMapImageLayer } = Zondy.Layer
 * const { SpatialReference } = Zondy
 * // ES6引入方式
 * import { ArcGISMapImageLayer,SpatialReference } from "@mapgis/webclient-common"
 * // 添加图层
 * const arcGISMapImageLayer = new ArcGISMapImageLayer({
 *   // 服务基地址
 *   url: 'http://{ip}:{port}/arcgis/rest/services/{serviceName}/MapServer',
 *   // 自定义坐标新
 *   spatialReference: new SpatialReference({
 *     // 指定的wkid号,可在https://epsg.io/网站查询
 *     wkid: '指定的wkid号'
 *   })
 * });
 * map.add(arcGISMapImageLayer);
 *
 * @example <caption><h7 id='tileSize'>地图图层示例 - 设置图片大小</h7></caption>
 * // ES5引入方式
 * const { Map,MapView } = Zondy
 * const { ArcGISMapImageLayer } = Zondy.Layer
 * // ES6引入方式
 * import { Map,MapView,ArcGISMapImageLayer } from "@mapgis/webclient-common"
 * // 初始化图层管理容器
 * const map = new Map();
 * // 初始化地图视图对象
 * const mapView = new MapView({
 *   // 视图id
 *   viewId: "viewer-id",
 *   // 图层管理容器
 *   map: map
 * });
 * // 添加图层
 * const arcGISMapImageLayer = new ArcGISMapImageLayer({
 *   // 服务基地址
 *   url: 'http://{ip}:{port}/arcgis/rest/services/{serviceName}/MapServer',
 *   // 瓦片宽度
 *   imageWidth: 512,
 *   // 瓦片高度
 *   imageHeight: 512
 * });
 * map.add(arcGISMapImageLayer);
 *
 * @example <caption><h7 id='opacity'>设置图层透明度</h7></caption>
 * // ES5引入方式
 * const { ArcGISMapImageLayer } = Zondy.Layer
 * // ES6引入方式
 * import { ArcGISMapImageLayer } from "@mapgis/webclient-common"
 * // 初始化时设置
 * const arcGISMapImageLayer = new ArcGISMapImageLayer({
 *   // 服务基地址
 *   url: 'http://{ip}:{port}/arcgis/rest/services/{serviceName}/MapServer',
 *   // 设置透明度
 *   opacity: 1.0
 * });
 * map.add(arcGISMapImageLayer);
 * // 加载完成后设置
 * arcGISMapImageLayer.on('layerview-created', function (result) {
 *   console.log("加载完毕:", result.layer)
 *   // 视点跳转
 *   ArcGISMapImageLayer.opacity = 0.5
 * })
 *
 * @example <caption><h7 id='visible'>显示或隐藏图层</h7></caption>
 *  // ES5引入方式
 * const { ArcGISMapImageLayer } = Zondy.Layer
 * // ES6引入方式
 * import { ArcGISMapImageLayer } from "@mapgis/webclient-common"
 * // 初始化时设置
 * const arcGISMapImageLayer = new ArcGISMapImageLayer({
 *   // 服务基地址
 *   url: 'http://{ip}:{port}/arcgis/rest/services/{serviceName}/MapServer',
 *   // 显示或隐藏图层
 *   visible: true
 * });
 * map.add(arcGISMapImageLayer);
 * // 加载完成后设置
 * arcGISMapImageLayer.on('layerview-created', function (result) {
 *   console.log("加载完毕:", result.layer)
 *   // 显示或隐藏图层
 *   arcGISMapImageLayer.visible = !ArcGISMapImageLayer.visible
 * })
 *
 * @example <caption><h7 id='remove-layer'>删除图层</h7></caption>
 * map.remove(arcGISMapImageLayer)
 *
 * @example <caption><h7 id='index'>图层顺序</h7></caption>
 * // 加载完毕后,更改图层顺序
 * map.reorder(arcGISMapImageLayer, '要移动到的index');
 */
class ArcGISMapImageLayer extends MapImageLayer {
  constructor(options) {
    super(options)
    options = defaultValue(options, {})
    /**
     * 图层类型
     * @readonly
     * @member {String} ArcGISMapImageLayer.prototype.type
     */
    this.type = LayerType.arcgisMapImage
    this.description = 'ArcGIS地图图片图层'

    // 地图服务对象
    this._mapServer = new MapServer({
      url: this.url
    })
  }

  /**
   * 加载图层资源
   * @example <caption><h7 id='load'>不加载图层,仅获取图层信息</h7></caption>
   * // ES5引入方式
   * const { ArcGISMapImageLayer } = Zondy.Layer
   * // ES6引入方式
   * import { ArcGISMapImageLayer } from "@mapgis/webclient-common"
   * // 初始化图层
   * const arcGISMapImageLayer = new ArcGISMapImageLayer({
   *   // 服务基地址
   *   url: 'http://{ip}:{port}/arcgis/rest/services/{serviceName}/MapServer',
   * });
   * arcGISMapImageLayer.load().then((result) => {
   *   // 获取完图层信息
   *   console.log(result)
   * })
   * */
  load() {
    const self = this
    return this._mapServer.queryServerInfo().then((result) => {
      Log.info('MapServer信息查询成功:', result)
      const data = result.data
      // 查询图层列表参数
      const queryLayerListOpts = {}

      self.documentInfo = data.documentInfo
      self.mapName = data.mapName
      self.capabilities = data.capabilities
      self.tileInfo = defaultValue(data.tileInfo, {})

      if (!isNull(data.spatialReference)) {
        self._spatialReferenceSrc = new SpatialReference({
          wkid: data.spatialReference.latestWkid || data.spatialReference.wkid
        })

        if (isNull(self.spatialReference)) {
          self._spatialReference = SpatialReference.fromJSON(
            self._spatialReferenceSrc.toJSON()
          )
        }
      }

      if (!isNull(data.fullExtent)) {
        self._extentSrc = new Extent({
          xmin: data.fullExtent.xmin,
          ymin: data.fullExtent.ymin,
          xmax: data.fullExtent.xmax,
          ymax: data.fullExtent.ymax,
          spatialReference: self._spatialReferenceSrc
        })
      }

      return self._mapServer
        .queryLayerList(queryLayerListOpts)
        .then((layerList) => {
          Log.info('子图层信息查询成功:', layerList)

          const sublayers = layerList.data.layers
          self.serviceSublayers = sublayers

          for (let i = 0; i < sublayers.length; i++) {
            sublayers[i].layer = self
            self.allSublayers.push(new ArcGISMapImageSubLayer(sublayers[i]))
          }
          for (let i = 0; i < self._sublayers.length; i++) {
            for (let j = 0; j < self.allSublayers.length; j++) {
              if (
                String(self._sublayers[i].id) ===
                  String(self.allSublayers[j].id) ||
                String(self._sublayers[i].name) ===
                  String(self.allSublayers[j].name)
              ) {
                if (!(self._sublayers[i] instanceof ArcGISMapImageSubLayer)) {
                  const options = Object.assign(
                    JSON.parse(JSON.stringify(self.allSublayers[j])),
                    self._sublayers[i]
                  )
                  options.layer = self
                  options.id = String(options.id)
                  self._sublayers[i] = new ArcGISMapImageSubLayer(options)
                  self.allSublayers[j] = new ArcGISMapImageSubLayer(options)
                }
                break
              }
            }
          }
          // 设置子图层显隐
          self._setLayers()
          // 图层信息加载完毕
          self.loadStatus = LoadStatus.loaded
          self.loaded = true
          return new Promise((resolve) => {
            resolve(self)
          })
        })
    })
  }

  /**
   * 根据子图层id查询子图层<a id='findSublayerById'></a>
   * @param {String} id 子图层id
   * @return Object 子图层信息
   * */
  findSublayerById(id) {
    if (
      this.loadStatus === LoadStatus.loaded &&
      this.allSublayers &&
      this.allSublayers instanceof Array
    ) {
      for (let i = 0; i < this.allSublayers.length; i++) {
        if (String(this.allSublayers[i].id) === String(id)) {
          return this.allSublayers[i]
        }
      }
    }
  }

  /**
   * 刷新图层<a id='refresh'></a>
   * */
  refresh() {
    this._fireUpdateEvent('刷新图层', [
      {
        params: arguments,
        dataChanged: true,
        name: 'refresh',
        operationType: 'method'
      }
    ])
  }

  /**
   * 根据范围和大小获取image标签
   * @param {Extent} extent
   * @param {Number} [width = 256] 图片宽度,单位px
   * @param {Number} [height = 256] 图片高度,单位px
   * @example <caption><h7 id='fetchImage'>根据范围和大小获取image标签</h7></caption>
   *  // ES5引入方式
   * const { Extent } = Zondy.Geometry
   * // ES6引入方式
   * import { Extent } from "@mapgis/webclient-common"
   * arcGISMapImageLayer.fetchImage({
   *   // 你的范围
   *   extent: new Extent(),
   *   // 图片宽度
   *   width: 256,
   *   // 图片高度
   *   height: 256
   * }).then((image) => {
   *   // 这里返回一个html的image标签
   * })
   * */
  fetchImage(extent, width, height) {
    width = defaultValue(width, 256)
    height = defaultValue(height, 256)
    const url = this.getImageUrl({
      extent,
      width,
      height
    })

    return new Promise((resolve) => {
      const image = new Image()
      image.src = url
      image.width = width
      image.height = height
      resolve(image)
    })
  }

  /**
   * 创建一个该服务的子图层克隆对象,注意不是本地的子图层对象<a id='createServiceSublayers'></a>
   * @return {Array} 服务上的子图层对象
   * */
  createServiceSublayers() {
    return this.serviceSublayers
  }

  /**
   * 根据参数获取图片的url
   * @param options
   * @param {Extent} [options.extent] 图片范围
   * @param {Number} [options.width] 图片宽度
   * @param {Number} [options.height] 图片高度
   * @return String 图片的url
   * @example <caption><h7 id='getImageUrl'>根据参数获取图片的url</h7></caption>
   *  // ES5引入方式
   * const { Extent } = Zondy.Geometry
   * // ES6引入方式
   * import { Extent } from "@mapgis/webclient-common"
   * const url = arcGISMapImageLayer.getImageUrl({
   *   // 你的范围
   *   extent: new Extent(),
   *   // 图片宽度
   *   width: 256,
   *   // 图片高度
   *   height: 256
   * })
   * */
  getImageUrl(options) {
    return this._mapServer.getImage(options)
  }

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

  /**
   * 更新子图层<a id='setSubLayer'></a>
   * @param {ArcGISMapImageSubLayer} ArcGISMapImageSubLayer 要更新的子图层
   * */
  setSubLayer(ArcGISMapImageSubLayer) {
    // 更新子图层
    setSublayer(this, ArcGISMapImageSubLayer, ArcGISMapImageSubLayer)
    // 设置子图层显隐
    this._setLayers()
    // 发送更新事件
    fireEvent(
      this,
      LayerEventType.layerUpdate,
      LayerEventType.layerSublayerVisible
    )
  }

  _setLayers() {
    // 设置子图层显隐
    let layers = 'show:'
    for (let i = 0; i < this.allSublayers.length; i++) {
      if (this.allSublayers[i].visible) {
        layers += `${this.allSublayers[i].id},`
      }
    }
    // 如果不显示任何子图层,则用exclude
    if (layers === 'show:') {
      layers = 'exclude:'
      for (let i = 0; i < this.allSublayers.length; i++) {
        layers += `${this.allSublayers[i].id},`
      }
    }
    layers = layers.substring(0, layers.length - 1)
    this.layers = layers
  }
}

Object.defineProperties(ArcGISMapImageLayer.prototype, {
  /**
   * 子图层对象
   * @member ArcGISMapImageLayer.prototype.sublayers
   * @type {Array}
   */
  sublayers: {
    get() {
      return this._sublayers
    },
    set(value) {
      this._sublayers = value
    }
  }
})

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