import { ElevationInfo, FeatureSet, Zondy, Feature } from '../../base'
import { LayerType, LoadStatus } from '../../base/enum'
import {defaultValue, toJSON} from '../../util'
import { Layer } from './baseLayer'
import FeatureCollection from './support/FeatureCollection'
import {jsonClone} from '../../util/Utils';
import {setElevationInfo} from './Utils';
/**
* 几何图形图层,不支持在线数据,仅支持传入多个几何对象并绘制<br/>
* 目前二维和三维上支持4326(包括4490,4214以及4610),3857以及EPSG支持的自定义坐标系,若是想要绘制非4326坐标系几何,需要在初始化要素对象的几何时,指定具体坐标系
* <br><br>[ES5引入方式]:<br/>
* Zondy.Layer.GraphicsLayer() <br/>
* [ES6引入方式]:<br/>
* import { GraphicsLayer } 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 GraphicsLayer
* @moduleEX LayerModule
* @classdesc 几何图形图层
* @extends Layer
* @fires Layer#图层加载完毕事件
* @fires Layer#图层销毁完毕事件
* @fires Layer#图层更新完毕事件
* @fires Layer#图层显隐更新完毕事件
* @fires Layer#图层透明度更新完毕事件
* @fires Layer#图层顺序更新完毕事件
* @fires GraphicsLayer#添加要素事件
* @fires GraphicsLayer#添加多个要素事件
* @fires GraphicsLayer#删除要素事件
* @fires GraphicsLayer#删除多个要素事件
* @fires GraphicsLayer#删除所有要素事件
* @param {Object} options 构造参数
* @param {Array<Feature>} [options.graphics] 几何对象,支持的几何数据如下:<br/>
* [1、点几何]{@link Point}<br/>
* [2、多点几何]{@link MultiPoint}<br/>
* [3、线几何]{@link LineString}<br/>
* [4、多线几何]{@link MultiLineString}<br/>
* [5、区几何]{@link Polygon}<br/>
* [6、多区几何]{@link MultiPolygon}<br/>
* [7、矩形几何]{@link Extent}<br/>
* [8、圆几何]{@link Circle}<br/>
* 参考示例:<br/>
* <a href='#GraphicsLayer'>[1、创建图层]</a><br/>
* <a href='#remove'>[2、删除图层]</a><br/>
* <a href='#add'>[3、添加要素]</a><br/>
* <a href='#add-custom'>[4、添加自定义坐标系的要素]</a>
* @param {String} [options.id] 图层id,不给则给一个随机的id
* @param {Boolean} [options.visible = show] 图层可见性,参考示例:<a href='#visible'>[图层可见性]</a>
* @param {Number} [options.opacity = 1] 图层透明度,0~1之间的值,0完全透明,1不透明,参考示例:<a href='#opacity'>[图层透明度]</a>
* @param {ElevationInfo} [options.ElevationInfo] 高度参数
*
* @summary <h5>支持如下方法:</h5>
* <a href='#add-feature'>[1、添加要素]</a><br/>
* <a href='#delete-feature'>[2、删除要素]</a><br/>
* <a href='#addMany'>[3、添加要素组]</a><br/>
* <a href='#removeMany'>[4、删除要素组]</a><br/>
* <a href='#removeAll'>[5、删除全部要素]</a><br/>
* <a href='#fromJSON'>[6、通过传入的json构造并返回一个新的几何对象]</a><br/>
* [7、导出为json对象]{@link OGCLayer#toJSON}<br/>
* [8、克隆几何对象]{@link OGCLayer#clone}
*
* @example <caption><h7 id='GraphicsLayer'>初始化图层</h7></caption>
* // ES5引入方式
* const { Map,MapView,Feature,Color} = Zondy
* const { Circle } = Zondy.Geometry
* const { SimpleFillSymbol } = Zondy.Symbol
* const { GraphicsLayer } = Zondy.Layer
* // ES6引入方式
* import { Map,MapView,Color,Feature,Circle, GraphicsLayer,SimpleFillSymbol} from "@mapgis/webclient-common"
* // 初始化图层管理容器
* const map = new Map();
* // 初始化地图视图对象
* const mapView = new MapView({
* // 视图id
* viewId: "viewer-id",
* // 图层管理容器
* map: map
* });
* // 创建一个要素
* const feature = new Feature({
* //不填则创建一个随机的guid
* id: '你的id',
* //设置属性
* attributes: {},
* //构建几何
* geometry: new Circle({
* // 中心点
* center: [113, 30],
* // 半径
* radius: 4
* }),
* //设置样式
* symbol: new SimpleFillSymbol({
* //设置颜色
* color: new Color(255, 0, 112, 1)
* })
* })
* // 初始化几何图层
* const graphicsLayer = new GraphicsLayer({
* graphics:[feature]
* })
* map.add(graphicsLayer)
*
* @example <caption><h7 id='remove'>删除图层</h7></caption>
* map.remove(graphicsLayer)
*
* @example <caption><h7 id='add'>将要素添加入图层</h7></caption>
* // ES5引入方式
* const { Feature,Color} = Zondy
* const { Circle } = Zondy.Geometry
* const { SimpleFillSymbol } = Zondy.Symbol
* const { GraphicsLayer } = Zondy.Layer
* // ES6引入方式
* import { Feature,Color,Circle, GraphicsLayer,SimpleFillSymbol} from "@mapgis/webclient-common"
* // 创建一个要素
* const feature = new Feature({
* //不填则创建一个随机的guid
* id: '你的id',
* //设置属性
* attributes: {},
* //构建几何
* geometry: new Circle({
* // 中心点
* center: [113, 30],
* // 半径
* radius: 4
* }),
* //设置样式
* symbol: new SimpleFillSymbol({
* //设置颜色
* color: new Color(255, 0, 112, 1)
* })
* })
* // 创建图层
* const graphicsLayer = new GraphicsLayer()
* map.add(graphicsLayer)
* // 添加要素
* graphicsLayer.add(feature)
*
* @example <caption><h7 id='add-custom'>添加自定义坐标系的要素</h7></caption>
* // ES5引入方式
* const { Feature,SpatialReference,Color} = Zondy
* const { Circle } = Zondy.Geometry
* const { SimpleFillSymbol } = Zondy.Symbol
* const { GraphicsLayer } = Zondy.Layer
* // ES6引入方式
* import { Feature,SpatialReference,Color,Circle, GraphicsLayer,SimpleFillSymbol} from "@mapgis/webclient-common"
* // 创建一个要素
* const feature = new Feature({
* //构建几何
* geometry: new Circle({
* // 中心点
* center: [403511.251934197, 3320534.43647428],
* // 半径,单位像素
* radius: 4,
* // 设置坐标系
* spatialReference: new SpatialReference({
* wkid: '坐标系的wkid'
* })
* }),
* //设置样式
* symbol: new SimpleFillSymbol({
* //设置颜色
* color: new Color(255, 0, 112, 1)
* })
* })
* // 创建图层
* const graphicsLayer = new GraphicsLayer()
* map.add(graphicsLayer)
* // 添加要素
* graphicsLayer.add(feature)
*
* @example <caption><h7 id='visible'>图层可见性</h7></caption>
* // ES5引入方式
* const { GraphicsLayer } = Zondy.Layer
* // ES6引入方式
* import { GraphicsLayer } from "@mapgis/webclient-common"
* // 创建图层时设置可见性
* const graphicsLayer = new GraphicsLayer({
* // 设置图层visible
* visible: true
* })
* map.add(graphicsLayer)
*
* // 图层加载完成后,设置可见性
* graphicsLayer.visible = !graphicsLayer.visible
*
* @example <caption><h7 id='opacity'>图层透明度</h7></caption>
* // ES5引入方式
* const { GraphicsLayer } = Zondy.Layer
* // ES6引入方式
* import { GraphicsLayer } from "@mapgis/webclient-common"
* // 创建图层时设置透明度
* const graphicsLayer = new GraphicsLayer({
* opacity: 1
* })
* map.add(graphicsLayer)
*
* // 图层加载完成后,设置可见性
* graphicsLayer.opacity = 0.5
*
* @example <caption><h7 id='index'>图层顺序</h7></caption>
* // 加载完毕后,更改图层顺序
* map.reorder(graphicsLayer, '要移动到的index');
*/
/**
* 添加要素事件,请注意该事件是图层更新事件(layerview-update)的子事件
* @event GraphicsLayer#添加要素事件
* @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 === 'add'){
* console.log("添加要素事件:", event);
* }
* }
* });
*/
/**
* 添加多个要素事件,请注意该事件是图层更新事件(layerview-update)的子事件
* @event GraphicsLayer#添加多个要素事件
* @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 === 'addMany'){
* console.log("添加多个要素事件:", event);
* }
* }
* });
*/
/**
* 删除要素事件,请注意该事件是图层更新事件(layerview-update)的子事件
* @event GraphicsLayer#删除要素事件
* @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 === 'remove'){
* console.log("删除要素事件:", event);
* }
* }
* });
*/
/**
* 删除多个要素事件,请注意该事件是图层更新事件(layerview-update)的子事件
* @event GraphicsLayer#删除多个要素事件
* @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 === 'removeMany'){
* console.log("删除多个要素事件:", event);
* }
* }
* });
*/
/**
* 删除所有要素事件,请注意该事件是图层更新事件(layerview-update)的子事件
* @event GraphicsLayer#删除所有要素事件
* @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 === 'removeAll'){
* console.log("删除所有要素事件:", event);
* }
* }
* });
*/
class GraphicsLayer extends Layer {
constructor(options) {
super(options)
options = defaultValue(options, {})
this.type = LayerType.graphics
/**
* 最小比例尺,只有当地图视图的比例尺大于最小比例尺时显示覆盖物图层
* @member {Number} GraphicsLayer.prototype.minScale
*/
this.minScale = defaultValue(options.minScale, undefined)
/**
* 最大比例尺,只有当地图视图的比例尺小于最大比例尺时显示覆盖物图层
* @member {Number} GraphicsLayer.prototype.maxScale
*/
this.maxScale = defaultValue(options.maxScale, undefined)
/**
* token名
* @member {String} GraphicsLayer.prototype.tokenKey
*/
this.tokenKey = defaultValue(options.tokenKey, 'token')
/**
* token值
* @member {String} GraphicsLayer.prototype.tokenValue
*/
this.tokenValue = defaultValue(options.tokenValue, undefined)
/**
* 高程信息
* @member {ElevationInfo} GraphicsLayer.prototype.elevationInfo
*/
this.elevationInfo = defaultValue(
options.elevationInfo,
new ElevationInfo()
)
/**
* 几何对象数组
* @member {FeatureCollection<Feature>} GraphicsLayer.prototype.graphics
*/
this.graphics = this._decorate(
'graphics',
options.graphics,
FeatureCollection,
FeatureCollection.collect
)
this.loadStatus = LoadStatus.loaded
}
/**
* 添加要素,参考示例:<a id='add-feature' href='#add'>[添加要素]</a>
* @param {Feature} feature 要添加的要素
*/
add(feature) {
if (!feature) return
if (this._getFeatureIndexById(feature.id) > -1) {
throw new Error(`id为'${feature.id}'的要素重复添加,请检查传入要素的id`)
}
// 如果要素上没有高程参数,就用图层上的,否则用要素自己的
setElevationInfo(feature, this)
this.graphics.add(feature)
this._fireUpdateEvent('添加要素', [
{
params: arguments,
dataChanged: true,
name: 'add',
operationType: 'method'
}
])
}
/**
* 删除要素
* @param {Feature} feature 要删除的要素
* @example <caption><h7 id='delete-feature'>删除要素</h7></caption>
* // ES5引入方式
* const { Feature,Color } = Zondy
* const { Circle } = Zondy.Geometry
* const { GraphicsLayer } = Zondy.Layer
* const { SimpleFillSymbol } = Zondy.Symbol
* // ES6引入方式
* import { Feature,Color,Circle,GraphicsLayer,SimpleFillSymbol } from "@mapgis/webclient-common"
* // 创建一个要素
* const feature = new Feature({
* //不填则创建一个随机的guid
* id: '你的id',
* //设置属性
* attributes: {},
* //构建几何
* geometry: new Circle({
* // 中心点
* center: [113, 30],
* // 半径
* radius: 4
* }),
* //设置样式
* symbol: new SimpleFillSymbol({
* //设置颜色
* color: new Color(255, 0, 112, 1)
* })
* })
* // 创建图层
* const graphicsLayer = new GraphicsLayer()
* graphicsLayer.add(feature)
* map.add(graphicsLayer)
* // 删除要素
* graphicsLayer.remove(feature)
*/
remove(feature) {
if (!feature) return
const fIndex = this._getFeatureIndexById(feature.id)
if (fIndex === -1) return
this._removeGraphicByIndex(fIndex)
this._fireUpdateEvent('移除要素', [
{
params: arguments,
dataChanged: true,
name: 'remove',
operationType: 'method'
}
])
}
/**
* 添加要素组
* @param {FeatureSet | Array<Feature>} features 要添加的要素数组或集合
* @example <caption><h7 id='addMany'>添加要素组</h7></caption>
* // ES5引入方式
* const { Feature } = Zondy
* const { Circle } = Zondy.Geometry
* const { GraphicsLayer } = Zondy.Layer
* // ES6引入方式
* import { Feature,Circle,GraphicsLayer } from "@mapgis/webclient-common"
* // 创建一个要素
* const feature1 = new Feature({
* //构建几何
* geometry: new Circle({
* // 中心点
* center: [113, 30],
* // 半径
* radius: 4
* })
* })
* const feature2 = new Feature({
* //构建几何
* geometry: new Circle({
* // 中心点
* center: [123, 33],
* // 半径
* radius: 4
* })
* })
* // 创建图层
* const graphicsLayer = new GraphicsLayer()
* map.add(graphicsLayer)
* // 一次添加多个要素
* graphicsLayer.addMany([feature1, feature2])
*/
addMany(features) {
let featureArr = []
if (features instanceof FeatureSet) {
featureArr = features.clone().features.map((v) => v.clone())
} else {
featureArr = features.map((v) => v.clone())
}
featureArr.forEach((feature) => {
this.graphics.add(feature)
})
this._fireUpdateEvent('添加要素组', [
{
params: arguments,
dataChanged: true,
name: 'addMany',
operationType: 'method'
}
])
}
/**
* 删除要素组
* @param {Array<Feature>} features 要删除的要素数组或集合
* @example <caption><h7 id='removeMany'>删除要素组</h7></caption>
* // ES5引入方式
* const { Feature } = Zondy
* const { Circle } = Zondy.Geometry
* const { GraphicsLayer } = Zondy.Layer
* // ES6引入方式
* import { Feature,Circle,GraphicsLayer } from "@mapgis/webclient-common"
* // 创建一个要素
* const feature1 = new Feature({
* //构建几何
* geometry: new Circle({
* // 中心点
* center: [113, 30],
* // 半径
* radius: 4
* })
* })
* const feature2 = new Feature({
* //构建几何
* geometry: new Circle({
* // 中心点
* center: [123, 33],
* // 半径
* radius: 4
* })
* })
* // 创建图层
* const graphicsLayer = new GraphicsLayer({
* graphics: [feature1, feature2]
* })
* map.add(graphicsLayer)
* // 一次删除多个要素
* graphicsLayer.removeMany([feature1, feature2])
*/
removeMany(features) {
const featureArr = []
if (!Array.isArray(features)) return
features.forEach((v) => {
const feature = this._getFeatureById(v.id)
if (feature) {
this._removeGraphic(feature)
featureArr.push(feature)
}
})
this._fireUpdateEvent('删除要素组', [
{
params: featureArr,
dataChanged: true,
name: 'removeMany',
operationType: 'method'
}
])
}
/**
* 删除全部要素
* @example <caption><h7 id='removeAll'>删除全部要素</h7></caption>
* // ES5引入方式
* const { Feature } = Zondy
* const { Circle } = Zondy.Geometry
* const { GraphicsLayer } = Zondy.Layer
* // ES6引入方式
* import { Feature,Color,Circle,GraphicsLayer } from "@mapgis/webclient-common"
* // 创建一个要素
* const feature1 = new Feature({
* //构建几何
* geometry: new Circle({
* // 中心点
* center: [113, 30],
* // 半径
* radius: 4
* })
* })
* const feature2 = new Feature({
* //构建几何
* geometry: new Circle({
* // 中心点
* center: [123, 33],
* // 半径
* radius: 4
* })
* })
* // 创建图层
* const graphicsLayer = new GraphicsLayer({
* graphics: [feature1, feature2]
* })
* map.add(graphicsLayer)
* // 删除全部要素
* graphicsLayer.removeAll()
*/
removeAll() {
this.graphics = []
this._fireUpdateEvent('删除全部要素', [
{
params: arguments,
dataChanged: true,
name: 'removeAll',
operationType: 'method'
}
])
}
/**
* 通过传入的json构造并返回一个新的几何对象<a id='fromJSON'></a>
* @param {Object} [json] JSON对象
* @example <caption><h7>通过传入的json构造并返回一个新的几何对象</h7></caption>
* // ES5引入方式
* const { Feature } = Zondy
* const { Circle } = Zondy.Geometry
* const { GraphicsLayer } = Zondy.Layer
* // ES6引入方式
* import { Feature,Circle,GraphicsLayer } from "@mapgis/webclient-common"
* // 创建一个要素
* const feature1 = new Feature({
* //构建几何
* geometry: new Circle({
* // 中心点
* center: [113, 30],
* // 半径
* radius: 4
* })
* })
* const feature2 = new Feature({
* //构建几何
* geometry: new Circle({
* // 中心点
* center: [123, 33],
* // 半径
* radius: 4
* })
* })
* const json = {
* graphics: [feature1, feature2]
* }
* // 创建图层
* const graphicsLayer = new GraphicsLayer.fromJSON(json)
*/
static fromJSON(json) {
json = jsonClone(json)
const _layer = new GraphicsLayer(json)
_layer._isFromJSON = true
_layer.elevationInfo = new ElevationInfo(json.elevationInfo)
const _graphics = []
for (let i = 0; i < json.graphics.length; i++) {
_graphics.push(new Feature(json.graphics[i]))
}
_layer.graphics = _graphics
return _layer
}
/**
* 子类加载服务端元信息的方法
* @private
* */
_load() {
return new Promise((resolve, reject) => {
this.loadStatus = LoadStatus.loaded
this.loaded = true
resolve(this)
reject('资源请求失败!')
})
}
toJSON() {
const _json = super.toJSON()
_json.elevationInfo = toJSON(this.elevationInfo, ElevationInfo)
const _graphics = []
if (this.graphics) {
this.graphics.forEach(function (feature) {
_graphics.push(toJSON(feature, Feature))
})
}
_json.graphics = _graphics
return _json
}
_getFeatureIndexById(id) {
return this.graphics.findIndex((v) => v.id === id)
}
_getFeatureById(id) {
const graphicIndex = this._getFeatureIndexById(id)
if (graphicIndex > -1) {
return this.graphics[graphicIndex]
}
return null
}
_removeGraphic(feature) {
const featureIndex = this._getFeatureIndexById(feature.id)
this._removeGraphicByIndex(featureIndex)
}
_removeGraphicByIndex(index) {
if (index === -1) return
this.graphics.items.splice(index, 1)
}
}
Zondy.Layer.GraphicsLayer = GraphicsLayer
export default GraphicsLayer