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