类名 common/document/layer/baseLayer/Layer.js
import { Evented, Zondy } from '../../../base'
import { defaultValue, getGUID, defined, toJSON } from '../../../util'
import {
  FetchMethod,
  LayerEventType,
  LayerType,
  LoadStatus
} from '../../../base/enum'
import { LayerViewUpdateEvent } from '../../../base/event'
import SpatialReference from '../../../base/geometry/SpatialReference'
import { Extent } from '../../../base/geometry'

/**
 * 图层基类
 * @class Layer
 * @moduleEX LayerModule
 * @extends Evented
 * @fires Layer#图层加载完毕事件
 * @fires Layer#图层销毁完毕事件
 * @fires Layer#图层更新完毕事件
 * @fires Layer#图层显隐更新完毕事件
 * @fires Layer#图层透明度更新完毕事件
 * @fires Layer#图层顺序更新完毕事件
 * @fires Layer#图层刷新完毕事件
 * @param {Object} options 构造参数
 * @param {String} [options.title] 图层名称
 * @param {SpatialReference} [options.spatialReference] 图层坐标系
 * @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 {Object} [options.extendProps] 存储额外参数的属性
 */

/**
 * 图层加载完毕事件
 * @event Layer#图层加载完毕事件
 * @property {Object} event 事件对象
 * @property {String} [event.type = 'layerview-created'] 图层加载完毕事件
 * @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><h7>图层加载完毕事件</h7></caption>
 * Layer.on('layerview-created', function (result) {
 *   console.log("加载完毕:", result.layer)
 * });
 */

/**
 * 图层销毁完毕事件
 * @event Layer#图层销毁完毕事件
 * @property {Object} event 事件对象
 * @property {String} [event.type = 'layerview-remove'] 图层销毁完毕事件
 * @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><h7>图层销毁完毕事件</h7></caption>
 * Layer.on('layerview-remove', function (result) {
 *   console.log("销毁完毕:", result.layer)
 * });
 */

/**
 * 图层更新完毕事件
 * @event Layer#图层更新完毕事件
 * @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><h7>图层更新完毕事件</h7></caption>
 * Layer.on('layerview-update', function (result) {
 *   console.log("更新完毕:", result.layer)
 * });
 */

/**
 * 图层显隐更新完毕事件,请注意该事件是图层更新事件(layerview-update)的子事件
 * @event Layer#图层显隐更新完毕事件
 * @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 === 'visible'){
 *       console.log("图层显隐更新事件:", event);
 *     }
 *   }
 * });
 */

/**
 * 图层透明度更新完毕事件,请注意该事件是图层更新事件(layerview-update)的子事件
 * @event Layer#图层透明度更新完毕事件
 * @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 === 'opacity'){
 *       console.log("图层透明度更新事件:", event);
 *     }
 *   }
 * });
 */

/**
 * 图层顺序更新完毕事件,请注意该事件是图层更新事件(layerview-update)的子事件
 * @event Layer#图层顺序更新完毕事件
 * @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 === 'index'){
 *       console.log("图层顺序更新完毕事件:", event);
 *     }
 *   }
 * });
 */

/**
 * 图层刷新完毕事件,请注意该事件是图层更新事件(layerview-update)的子事件
 * @event Layer#图层刷新完毕事件
 * @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 === 'refresh'){
 *       console.log("图层刷新完毕事件:", event);
 *     }
 *   }
 * });
 */
class Layer extends Evented {
  constructor(options) {
    super()
    // eslint-disable-next-line no-param-reassign
    options = defaultValue(options, {})
    /**
     * 图层id
     * @readonly
     * @member {String} Layer.prototype.id
     */
    this.id = defaultValue(options.id, getGUID())
    /**
     * 图层描述
     * @readonly
     * @member {String} Layer.prototype.description
     */
    this.description = defaultValue(options.description, '图层基类')
    /**
     * 版权所有
     * @readonly
     * @member {String} Layer.prototype.copyright
     */
    this.copyright = defaultValue(options.copyright, '中地数码版权所有')
    /**
     * 图层加载状态
     * @readonly
     * @default not-loaded
     * @member {String} Layer.prototype.loadStatus
     */
    this.loadStatus = defaultValue(options.loadStatus, LoadStatus.notLoaded)
    /**
     * 是否加载完毕
     * @readonly
     * @default false
     * @member {Boolean} Layer.prototype.loaded
     */
    this.loaded = false

    /**
     * token名
     * @default token
     * @member {String} Layer.prototype.tokenKey
     */
    this.tokenKey = defaultValue(options.tokenKey, 'token')
    /**
     * token值
     * @member {String} Layer.prototype.tokenValue
     */
    this.tokenValue = defaultValue(options.tokenValue, undefined)
    /**
     * 图层顺序
     * @member {Number} Layer.prototype.index
     */
    this.index = defaultValue(options.index, undefined)
    /**
     * 图层名称
     * @member {String} Layer.prototype.title
     */
    this.title = defaultValue(options.title, undefined)
    /**
     * 最小缩放级数,仅会请求级数大于等于minScale的图片
     * @default 0
     * @member {Number} Layer.prototype.minScale
     */
    this.minScale = defaultValue(options.minScale, undefined)
    /**
     * 最大缩放级数,仅会请求级数小于等于maxScale的图片
     * @default 19
     * @member {Number} Layer.prototype.maxScale
     */
    this.maxScale = defaultValue(options.maxScale, undefined)
    /**
     * 存储额外参数的属性
     * @member {Object} Layer.prototype.extendProps
     */
    this.extendProps = defaultValue(options.extendProps, {})
    /**
     * 图层类型
     * @readonly
     * @member {String} Layer.prototype.type
     */
    this.type = LayerType.baseLayer
    /**
     * http请求方式
     * @member {String} Layer.prototype.httpMethod
     */
    this.httpMethod = defaultValue(options.httpMethod, FetchMethod.get)
    // 图层显隐私有对象
    this._visible = defaultValue(options.visible, true)
    // 透明度私有对象
    this._opacity = parseFloat(defaultValue(options.opacity, 1))
    // 私有图层坐标系对象
    this._spatialReference = options.spatialReference
      ? SpatialReference.fromJSON(options.spatialReference)
      : undefined
    // 扩展属性key
    this._extendPropertyKeys = []
    // 实际图层顺序
    this._realIndex = undefined
    this._isFromJSON = false
    // 是否是basemap上的baseLayer
    this._isBasemapLayer = false
  }

  /**
   * @description 判断图层是否加载成功
   * @return {Boolean} 图层是否加载成功
   */
  isLoaded() {
    return this.loadStatus === LoadStatus.loaded
  }

  /**
   * @function Layer.load
   * @description 图层资源加载
   * @return {Promise<Layer>} 资源加载完毕的图层
   */
  load() {
    if (this._isFromJSON) {
      return new Promise((resolve, reject) => {
        this.loadStatus = LoadStatus.loaded
        this.loaded = true
        resolve(this)
        reject('资源请求失败!')
      })
    } else {
      return this._load()
    }
  }

  /**
   * @function setMap
   * @description 设置图层管理容器
   */
  setMap(map) {
    this._map = map
  }

  destroy() {}

  /**
   * @function extendProperty
   * @description 属性扩展
   * @param {String} key 属性名
   * @param {any} value 默认属性值
   */
  extendProperty(key, value) {
    if (!defined(this[key])) {
      // 添加扩展的属性字段
      this._extendPropertyKeys.push(key)
      this[key] = value
    }
  }

  /**
   * @private
   * @description 封装发送的更新事件
   * @param {String} message 属性名
   * @param {any} updateContentz 默认属性值
   */
  _fireUpdateEvent(message, updateContent) {
    if (!this._map) return
    this._map.fire(
      LayerEventType.layerUpdate,
      new LayerViewUpdateEvent({
        type: LayerEventType.layerUpdate,
        target: this._map,
        layer: this,
        message,
        updateContent
      })
    )
  }

  /**
   * @description 转换为json对象
   * @return {Object} json对象
   */
  toJSON() {
    return {
      id: this.id,
      description: this.description,
      copyright: this.copyright,
      loadStatus: this.loadStatus,
      loaded: this.loaded,
      tokenKey: this.tokenKey,
      tokenValue: this.tokenValue,
      index: this.index,
      title: this.title,
      minScale: this.minScale,
      maxScale: this.maxScale,
      type: this.type,
      visible: this.visible,
      opacity: this.opacity,
      spatialReference: toJSON(this.spatialReference, SpatialReference),
      extent: toJSON(this.extent, Extent)
    }
  }

  /**
   * @description 克隆方法
   * @return {Layer} 图层
   */
  clone() {
    return new Layer(this.toJSON())
  }

  /**
   * @description 根据服务url加载图层(通过判断url链接获取图层,等图层全部封装完毕后处理此函数)
   * @param {String} url 服务地址
   * @param {Object} options 图层配置
   * @return {Promise<Layer>} 从url中加载图层
   */
  static fromServerUrl(url, options) {
    return new Promise((reslove) => {
      options.url = url
      reslove(new Layer(options))
    })
  }

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

  /**
   * 更新图层顺序
   * @private
   * */
  _updateIndex() {
    this._fireUpdateEvent('修改图层的index', [
      {
        name: 'index',
        params: [this],
        dataChanged: true,
        operationType: 'property'
      }
    ])
  }
}

Object.defineProperties(Layer.prototype, {
  /**
   * 图层显示或隐藏,true则显示,false则隐藏,会触发图层更新完毕事件
   * @member Layer.prototype.visible
   * @type {Number}
   */
  visible: {
    get() {
      return this._visible
    },
    set(value) {
      this._visible = value
      this._fireUpdateEvent('显隐变化', [
        {
          name: 'visible',
          params: [this._visible],
          dataChanged: true,
          operationType: 'property'
        }
      ])
    }
  },
  /**
   * 图层透明度,0到1之间的值,0为完全透明,1为不透明,会触发图层更新完毕事件
   * @member Layer.prototype.opacity
   * @type {Number}
   */
  opacity: {
    get() {
      return this._opacity
    },
    set(value) {
      this._opacity = Number(value)
      this._fireUpdateEvent('透明度变化', [
        {
          name: 'opacity',
          params: [this._opacity],
          dataChanged: true,
          operationType: 'property'
        }
      ])
    }
  },
  /**
   * 图层坐标系对象
   * @member Layer.prototype.spatialReference
   * @type {SpatialReference}
   */
  spatialReference: {
    get() {
      return this._spatialReference
    },
    set(value) {
      this._spatialReference = value
    }
  },
  /**
   * 图层范围,从服务元信息中获取
   * @readonly
   * @member {Extent} Layer.prototype.extent
   */
  extent: {
    get() {
      return this._extentSrc
    },
    set(value) {
      this._extentSrc = value
    }
  }
})

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