import { VectorTileLayer } from '../baseLayer'
import { LayerEventType, LayerType, LoadStatus } from '../../../base/enum'
import { Zondy } from '../../../base'
import { defaultValue, isNull, isNumber, Log, toJSON } from '../../../util'
import { VectorTileServer } from '../../../service'
import { Extent, Point, SpatialReference } from '../../../base/geometry'
import IGSVectorTileSubLayer from './IGSVectorTileSubLayer'
import { LayerViewUpdateEvent } from '../../../base/event'
import TileInfoUtil from '../support/TileInfoUtil'
import TileInfo from '../support/TileInfo'
import { jsonClone } from '../../../util/Utils'
/**
* IGS矢量瓦片图层
* 支持IGS1.0和2.0两个服务版本,目前二维和三维上支持4326(包括4490,4214以及4610),3857,会自动读取元信息上的坐标系,不需要用户指定,
* <br><br>[ES5引入方式]:<br/>
* Zondy.Layer.IGSVectorTileLayer() <br/>
* [ES6引入方式]:<br/>
* import { IGSVectorTileLayer } 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/>
* }
* <br/>
* <br/>
* 注意:三维上,不支持简单Marker样式设定;二维上,简单Marker的颜色,外边线样式,旋转角度无法在图层初始化和初始化后修改,须在制作数据时进行指定
* @class IGSVectorTileLayer
* @moduleEX LayerModule
* @classdesc IGS矢量瓦片图层
* @extends VectorTileLayer
* @fires Layer#图层加载完毕事件
* @fires Layer#图层销毁完毕事件
* @fires Layer#图层更新完毕事件
* @fires Layer#图层显隐更新完毕事件
* @fires Layer#图层透明度更新完毕事件
* @param {Object} options 构造参数
* @param {String} [options.url] 服务基地址,<br>
* IGS1.0的服务为:http://{ip}:6163/igs/rest/mrms/tiles/{serviceName},需要注意由于igs1.0版本不再新增功能,无法解析矢量瓦片Lod信息以及坐标系信息,目前需要在矢量瓦片图层接口上显式设置坐标系信息,默认坐标系3857,可选4326或3857,参考示例:<a href='#igs-1'>[IGS1.0的矢量瓦片示例]</a><br/>
* IGS2.0的服务为:http://{ip}:{port}/igs/rest/services/VectorTile/{serviceName}/VectorTileServer,参考示例:<a href='#igs-2'>[IGS2.0的矢量瓦片示例]</a><br/>
* 删除图层方法:<a href='#remove-layer'>[删除图层]</a>
* @param {Number} [options.minScale = null] 最小比例尺,只有当地图视图的比例尺大于最小比例尺时显示矢量瓦片图层
* @param {Number} [options.maxScale = null] 最大比例尺,只有当地图视图的比例尺小于最大比例尺时显示矢量瓦片图层
* @param {Number} [options.opacity = 1] 图层透明度,0到1之间的值,0为完全透明,1为不透明,参考示例:<a href='#opacity'>[设置图层透明度]</a>
* @param {String} [options.tokenKey = 'token'] token名
* @param {String} [options.tokenValue] token值,只有当tokenValue存在时,才会绑定token
* @param {Boolean} [options.visible = true] 图层显示或隐藏,true则显示,false则隐藏,参考示例:<a href='#visible'>[设置图层显隐]</a>
* @param {Array<IGSVectorTileSubLayer>} [options.sublayers=[]] 子图层信息。指定的和服务器端获取图层的交集, 默认不设置,加载全部图层。可设置子图层的可见性,以及专题图参数。<br/>
* @param {String} [option.labelsRenderMode = 'off-screen'] 指定矢量瓦片注记的渲染模式,仅在三维上有效。on-screen表示使用三维接口实时渲染注记;off-screen表示通过先将注记渲染到图片上,再通过三维接口渲染到屏幕。
* @param {Polygon|Extent|Circle|null} [options.clippingArea = null] 图层空间裁剪范围,仅支持多边形裁剪、矩形裁剪、圆形裁剪
* 专题图参数仅支持IGS2.0服务,目前子图层支持的专题图如下:<br/>
* [1、单值专题图]{@link UniqueValueRenderer}<br/>
* [2、分段专题图]{@link ClassBreakRenderer}<br/>
* [3、统一专题图]{@link SimpleRenderer}<br/>
* 参考示例:<br/>
* <a href='#showAllSubLayers'>[1、显示所有子图层]</a><br/>
* <a href='#showSubLayersById'>[2、根据id显示子图层]</a><br/>
* <a href='#showSubLayers-property'>[3、通过修改子图参数,设置子图层显隐]</a><br/>
* <a href='#setLayerRenderer-unique'>[4、设置子图层专题图-单值专题图]</a><br/>
* <a href='#setLayerRenderer-break'>[5、设置子图层专题图-分段专题图]</a><br/>
* <a href='#setLayerRenderer-simple'>[6、设置子图层专题图-统一专题图]</a><br/>
* <a href='#setLayerRenderer-property'>[7、通过修改子图参数,设置子图层专题图]</a><br/>
*
*@summary <h5>支持如下方法:</h5>
* <a href='#findSublayerById'>[1、根据子图层id查询图层]</a><br/>
* <a href='#loadStyle'>[2、获取矢量瓦片样式]</a><br/>
* <a href='#fromJSON'>[3、通过传入的json构造并返回一个新的几何对象]</a><br/>
* [4、导出为json对象]{@link OGCLayer#toJSON}<br/>
* [5、克隆几何对象]{@link OGCLayer#clone}
* <a href='#getLayoutProperties'>[6、获取图层布局属性]</a><br/>
* <a href='#setLayoutProperties'>[7、设置图层布局属性]</a><br/>
* <a href='#getPaintProperties'>[8、获取图层绘制属性]</a><br/>
* <a href='#setPaintProperties'>[9、设置图层绘制属性]</a><br/>
* <a href='#getStyleLayer'>[10、获取图层]</a><br/>
* <a href='#setStyleLayer'>[11、设置图层属性对象]</a><br/>
* <a href='#deleteStyleLayer'>[12、删除图层]</a><br/>
* <a href='#setStyleLayerVisible'>[13、设置图层可见性]</a><br/>
* <a href='#getStyleLayerVisible'>[14、获取图层可见性]</a><br/>
* <a href='#getStyleLayerFilter'>[15、获取属性过滤条件]</a><br/>
* <a href='#setStyleLayerFilter'>[16、属性过滤]</a><br/>
* <a href='#getStyleLayerZoomRange'>[17、获取图层最小、最大层级]</a><br/>
* <a href='#setStyleLayerZoomRange'>[18、设置图层最小、最大层级]</a><br/>
*
* @example <caption><h7 id='igs-1'>IGS1.0的矢量瓦片示例</h7></caption>
* //初始化地图管理容器
* // ES5引入方式
* const { IGSVectorTileLayer } = Zondy.Layer
* const { Map,MapView,SpatialReference } = Zondy
* // ES6引入方式
* import { IGSVectorTileLayer,Map,MapView } from "@mapgis/webclient-common"
* const map = new Map();
* //初始化地图引擎
* const mapView = new MapView({
* //指定视图id
* viewId: "viewer-id",
* //绑定地图管理容器
* map: map
* });
* //添加矢量瓦片图层
* const igsVectorTileLayer = new IGSVectorTileLayer({
* url: 'http://{ip}:6163/igs/rest/mrms/tiles/{serviceName}',
* spatialReference:new SpatialReference('EPSG:4326')
* });
* map.add(igsVectorTileLayer);
*
* @example <caption><h7 id='igs-2'>IGS2.0的矢量瓦片示例</h7></caption>
* // ES5引入方式
* const { IGSVectorTileLayer } = Zondy.Layer
* const { Map,MapView } = Zondy
* // ES6引入方式
* import { IGSVectorTileLayer } from "@mapgis/webclient-common"
* //初始化地图管理容器
* const map = new Map();
* //初始化地图引擎
* const mapView = new MapView({
* //指定视图id
* viewId: "viewer-id",
* //绑定地图管理容器
* map: map
* });
* //添加矢量瓦片图层
* const igsVectorTileLayer = new IGSVectorTileLayer({
* url: 'http://{ip}:{port}/igs/rest/services/VectorTile/{serviceName}/VectorTileServer'
* });
* map.add(igsVectorTileLayer);
*
* @example <caption><h7 id='opacity'>设置图层透明度</h7></caption>
* igsVectorTileLayer.opacity = 0.5
*
* @example <caption><h7 id='visible'>显示或隐藏图层</h7></caption>
* igsVectorTileLayer.visible = !igsVectorTileLayer.visible
*
* @example <caption><h7 id='remove-layer'>删除图层</h7></caption>
* map.remove(igsVectorTileLayer)
*
* @example <caption><h7 id='showAllSubLayers'>显示所有子图层</h7></caption>
* // ES5引入方式
* const { IGSVectorTileLayer } = Zondy.Layer
* // ES6引入方式
* import { IGSVectorTileLayer } from "@mapgis/webclient-common"
* // 添加图层
* const igsVectorTileLayer = new IGSVectorTileLayer({
* // 服务基地址
* url: 'http://{ip}:{port}/igs/rest/services/VectorTile/{serviceName}/VectorTileServer',
* //默认不设置sublayers,加载全部图层
* });
* map.add(igsVectorTileLayer);
*
* @example <caption><h7 id='showSubLayersById'>根据id显示子图层</h7></caption>
* // ES5引入方式
* const { IGSVectorTileLayer } = Zondy.Layer
* // ES6引入方式
* import { IGSVectorTileLayer } from "@mapgis/webclient-common"
* // 添加图层
* const igsVectorTileLayer = new IGSVectorTileLayer({
* // 服务基地址
* url: 'http://{ip}:{port}/igs/rest/services/VectorTile/{serviceName}/VectorTileServer',
* // 根据id显示子图层
* sublayers: [
* {
* // 子图层id
* id: '子图层id',
* // 显示子图层
* visible: true
* }
* ]
* });
* map.add(igsVectorTileLayer);
*
* @example <caption><h7 id='showSubLayers-property'>通过修改子图参数,设置子图层显隐</h7></caption>
* // ES5引入方式
* const { IGSVectorTileLayer } = Zondy.Layer
* // ES6引入方式
* import { IGSVectorTileLayer } from "@mapgis/webclient-common"
* // 添加图层
* const igsVectorTileLayer = new IGSVectorTileLayer({
* // 服务基地址
* url: 'http://{ip}:{port}/igs/rest/services/VectorTile/{serviceName}/VectorTileServer'
* });
* map.add(igsVectorTileLayer);
* igsVectorTileLayer.on('layerview-created', function (result) {
* console.log("加载完毕:", result.layer)
* // 根据id获取子图层
* const subLayer = igsVectorTileLayer.findSublayerById('图层id')
* // 设置子图层显隐
* subLayer.visible = false
* // 视点跳转
* sceneView.flyTo({
* extent: result.layer.extent
* })
* })
*
* @example <caption><h7 id='setLayerRenderer-unique'>设置子图层专题图-单值专题图</h7></caption>
* // ES5引入方式
* const { IGSVectorTileLayer } = Zondy.Layer
* const { UniqueValueRenderer } = Zondy.Renderer
* const { SimpleFillSymbol,SimpleLineSymbol } = Zondy.Symbol
* const { Color } = Zondy
* // ES6引入方式
* import { IGSVectorTileLayer,UniqueValueRenderer ,SimpleFillSymbol,SimpleLineSymbol,Color} from "@mapgis/webclient-common"
* const igsVectorTileLayer = new IGSVectorTileLayer({
* // 服务基地址,当不指定图层名称时,默认查询第一个子图层
* url: 'http://{ip}:{port}/igs/rest/services/VectorTile/{serviceName}/VectorTileServer',
* // 设置子图层专题图
* sublayers: [
* {
* // 子图层id
* id: '子图层id',
* // 设置渲染样式-单值专题图
* renderer: new UniqueValueRenderer({
* //专题图过滤字段名
* field: '你的字段名',
* // 默认样式,当没有匹配到指定值时,会使用默认样式
* //因为该数据的几何类型为区,因此设置区样式
* defaultSymbol: new SimpleFillSymbol({
* // 填充颜色
* color: 'rgba(1,1,252,0)',
* // 外边线样式
* outline: new SimpleLineSymbol({
* //线颜色
* color: new Color(255, 1, 0, 1),
* //线宽
* width: 1
* })
* }),
* //单值专题图过滤调条件数组
* uniqueValueInfos: [{
* //指定字段值
* value: "指定的值",
* //匹配到该值后的样式
* //因为该数据的几何类型为区,因此设置区样式
* symbol: new SimpleFillSymbol({
* // 填充颜色
* color: 'rgba(1,1,252,1)',
* // 外边线样式
* outline: new SimpleLineSymbol({
* //线符号颜色
* color: new Color(255, 1, 0, 11),
* //线宽
* width: 1
* })
* })
* },{
* //指定字段值
* value: "指定的值",
* //匹配到该值后的样式
* //因为该数据的几何类型为区,因此设置区样式
* symbol: new SimpleFillSymbol({
* // 填充颜色
* color: new Color(211, 111, 11, 1)
* })
* }]
* })
* }
* ]
* });
* map.add(igsVectorTileLayer);
*
* @example <caption><h7 id='setLayerRenderer-break'>设置子图层专题图-分段专题图</h7></caption>
* // ES5引入方式
* const { IGSVectorTileLayer } = Zondy.Layer
* const { ClassBreakRenderer } = Zondy.Renderer
* const { SimpleFillSymbol,SimpleLineSymbol } = Zondy.Symbol
* const { Color } = Zondy
* // ES6引入方式
* import { IGSVectorTileLayer,ClassBreakRenderer ,SimpleFillSymbol,SimpleLineSymbol,Color} from "@mapgis/webclient-commo
* const igsVectorTileLayer = new IGSVectorTileLayer({
* // 服务基地址,当不指定图层名称时,默认查询第一个子图层
* url: 'http://{ip}:{port}/igs/rest/services/VectorTile/{serviceName}/VectorTileServer',
* // 设置子图层专题图
* sublayers: [
* {
* // 子图层id
* id: '子图层id',
* // 设置渲染样式-分段专题图
* renderer: new ClassBreakRenderer({
* //专题图过滤字段名
* field: '你的字段名',
* // 默认样式,当没有匹配到指定值时,会使用默认样式
* // 因为该数据的几何类型为区,因此设置区样式
* defaultSymbol: new SimpleFillSymbol({
* // 填充颜色
* color: 'rgba(222,1,252,1)',
* // 线符号样式
* outline: new SimpleLineSymbol({
* //线符号颜色
* color: new Color(255, 1, 0, 1),
* //线宽
* width: 1
* })
* }),
* //分段专题图过滤条件数组
* classBreakInfos: [{
* // 最大过滤范围,field对应的值小于maxValue
* maxValue: "最大范围",
* // 最小过滤范围,field对应的值大于等于minValue
* minValue: "最小范围",
* // 匹配到该值后的样式
* // 因为该数据的几何类型为区,因此设置区样式
* symbol: new SimpleFillSymbol({
* // 填充颜色
* color: 'rgba(1,1,252,1)',
* // 线符号样式
* outline: new SimpleLineSymbol({
* //线符号颜色
* color: new Color(255, 1, 0, 1),
* //线宽
* width: 1
* })
* })
* }]
* })
* }
* ]
* });
* map.add(igsVectorTileLayer);
*
* @example <caption><h7 id='setLayerRenderer-property'>通过修改子图参数,设置子图层专题图</h7></caption>
* // ES5引入方式
* const { IGSVectorTileLayer } = Zondy.Layer
* const { ClassBreakRenderer } = Zondy.Renderer
* const { SimpleFillSymbol,SimpleLineSymbol } = Zondy.Symbol
* const { Color } = Zondy
* // ES6引入方式
* import { IGSVectorTileLayer,ClassBreakRenderer ,SimpleFillSymbol,SimpleLineSymbol,Color} from "@mapgis/webclient-commo
* const igsVectorTileLayer = new IGSVectorTileLayer({
* // 服务基地址
* url: 'http://{ip}:{port}/igs/rest/services/VectorTile/{serviceName}/VectorTileServer'
* });
* map.add(igsVectorTileLayer);
* // 根据id获取子图层
* const subLayer = igsVectorTileLayer.findSublayerById('子图层id')
* // 设置渲染样式-分段专题图
* subLayer.renderer = new ClassBreakRenderer({
* // 专题图过滤字段名
* field: '你的字段名',
* // 默认样式,当没有匹配到指定值时,会使用默认样式
* // 因为该数据的几何类型为区,因此设置区样式
* defaultSymbol: new SimpleFillSymbol({
* // 填充颜色
* color: 'rgba(222,1,252,1)',
* // 线符号样式
* outline: new SimpleLineSymbol({
* //线符号颜色
* color: new Color(255, 1, 0, 1),
* //线宽
* width: 1
* })
* }),
* //分段专题图过滤条件数组
* classBreakInfos: [{
* // 最大过滤范围,field对应的值小于maxValue
* maxValue: "最大范围",
* // 最小过滤范围,field对应的值大于等于minValue
* minValue: "最小范围",
* // 匹配到该值后的样式
* // 因为该数据的几何类型为区,因此设置区样式
* symbol: new SimpleFillSymbol({
* // 填充颜色
* color: 'rgba(1,1,252,1)',
* // 线符号样式
* outline: new SimpleLineSymbol({
* //线符号颜色
* color: new Color(255, 1, 0, 1),
* //线宽
* width: 1
* })
* })
* }]
* })
* @example <caption><h7 id='setLayerRenderer-simple'>统一专题图</h7></caption>
* // ES5引入方式
* const { IGSVectorTileLayer } = Zondy.Layer
* const { SimpleRenderer } = Zondy.Renderer
* const { SimpleFillSymbol,SimpleLineSymbol } = Zondy.Symbol
* const { Color } = Zondy
* // ES6引入方式
* import { IGSVectorTileLayer,SimpleRenderer ,SimpleFillSymbol,SimpleLineSymbol,Color} from "@mapgis/webclient-commo
* const igsVectorTileLayer = new IGSVectorTileLayer({
* // 服务基地址,当不指定图层名称时,默认查询第一个子图层
* url: 'http://{ip}:{port}/igs/rest/services/VectorTile/{serviceName}/VectorTileServer',
* // 设置渲染样式-统一专题图
* renderer: new SimpleRenderer({
* // 因为该数据的几何类型为区,因此设置区样式
* symbol: new SimpleFillSymbol({
* // 填充颜色
* color: new Zondy.Color(255, 0, 0),
* // 外边线样式
* outline: new SimpleLineSymbol({
* // 线颜色
* color: new Color(0, 0, 0),
* // 线宽度
* width: 1
* })
* })
* })
* })
*/
class IGSVectorTileLayer extends VectorTileLayer {
constructor(options) {
super(options)
options = defaultValue(options, {})
this.type = LayerType.igsVectorTile
this.description = 'IGS矢量瓦片图层'
this.vectorTileType = 'igs'
/**
* 矢量瓦片服务地址
* @member {String} IGSVectorTileLayer.prototype.url
*/
this.url = defaultValue(options.url, '')
/**
* 矢量瓦片子图层
* @member {Array<IGSVectorTileSubLayer>} IGSVectorTileLayer.prototype.sublayers
*/
this.sublayers = defaultValue(options.sublayers, [])
/**
* 服务支持的能力
* @member {Array<String>} IGSVectorTileLayer.prototype.capabilities
*/
this.capabilities = []
// 空间裁剪范围
this._clippingArea = defaultValue(options.clippingArea, null)
/**
* 图层加载状态
* @readonly
* @default not-loaded
* @member {LoadStatus} IGSMapImageLayer.prototype.loadStatus
*/
this.loadStatus = LoadStatus.notLoaded
/**
* 指定矢量瓦片注记的渲染模式(目前仅支持三维上矢量瓦片注记的渲染)
* @member {String} IGSVectorTileLayer.prototype.labelsRenderMode
*/
this.labelsRenderMode = defaultValue(options.labelsRenderMode, 'off-screen')
// 当前mvt矢量瓦片样式
this._style = defaultValue(options._style, {})
// 测试接口
this.labelingInfo = defaultValue(options.labelingInfo, [])
// 矢量瓦片服务
this._vectorTileServer = new VectorTileServer({
url: this.url
})
// 所有图层
this._allSublayers = []
}
load() {
// 发起请求
const self = this
const promise = this._vectorTileServer.queryServerInfo()
return promise
.then((result) => {
Log.info('矢量瓦片信息查询成功:', result)
const data = result.data
// 初始化参考系
const initSpatialReference = self._spatialReference
? self._spatialReference.clone()
: null
// 外部未设置空间参考系信息时,优先读取空间参考系相关信息
if (data && data.tileInfo && data.tileInfo.spatialReference) {
const spatialReference =
data.spatialReference || data.tileInfo.spatialReference
// 设置数据空间参考系
if (spatialReference) {
if (data.spatialReference.wkid) {
self._spatialReference = new SpatialReference({
wkid: parseInt(data.spatialReference.wkid)
})
} else if (data.spatialReference.wkt) {
self._spatialReference = new SpatialReference({
wkt: data.spatialReference.wkt
})
} else {
Log.error(
'矢量瓦片服务坐标系信息不存在,请检查igs返回的矢量瓦片服务元信息!'
)
}
}
// 获取瓦片信息
self.tileInfo = TileInfoUtil.parseTileInfo2(data.tileInfo)
// 重置extent
if (isNull(self.extent) && data.extent) {
self.extent = new Extent({
xmin: data.extent.xmin,
ymin: data.extent.ymin,
xmax: data.extent.xmax,
ymax: data.extent.ymax,
spatialReference: self._spatialReference
})
}
}
// 初始化坐标系 目前仅支持标准3857或4326
if (initSpatialReference) {
// 外部设置有参考系
// 判断是否为地理坐标系
self._spatialReference = initSpatialReference
const geoCoodsArr = [4326, 4490, 4610, 4214]
if (geoCoodsArr.indexOf(initSpatialReference.wkid) > -1) {
self.tileInfo = new TileInfo({
origin: new Point({
coordinates: [-180, 90]
}),
lods: TileInfoUtil.getLods(1.40625, 'degree', 21),
size: [256, 256],
spatialReference: new SpatialReference('EPSG:4326')
})
self._spatialReference.extent = new Extent({
xmin: -180,
ymin: -90,
xmax: 180,
ymax: 90,
spatialReference: new SpatialReference('EPSG:4326')
})
self._extent = self._spatialReference.extent.clone()
}
}
// 没有设置坐标系时,默认为3857
if (!self._spatialReference) {
self._spatialReference = new SpatialReference('EPSG:3857')
// web墨卡托
self.tileInfo = new TileInfo({
origin: new Point({
coordinates: [-20037508.342787, 20037508.342787]
}),
lods: TileInfoUtil.getLods(156543.033925625, 'm', 21),
size: [256, 256],
spatialReference: new SpatialReference('EPSG:3857')
})
self._spatialReference.extent = new Extent({
xmin: -20037508.342787,
ymin: -20037508.342787,
xmax: 20037508.342787,
ymax: 20037508.342787,
spatialReference: new SpatialReference('EPSG:3857')
})
self._extent = self._spatialReference.extent.clone()
}
// 支持mapbox加载矢量瓦片
if (self._spatialReference && self.tileInfo) {
const tileInfo = self.tileInfo
let tileSize = 256
if (Array.isArray(tileInfo.size)) {
tileSize = Math.max(tileInfo.size[0], tileInfo.size[1])
}
const cols = self.tileInfo.cols || 256
const rols = self.tileInfo.rols || 256
self._spatialReference._mapboxTileSize = Math.max(
tileSize,
cols,
rols
)
}
// 解析服务器提供的能力
if (data.capabilities) {
self.capabilities = Array.isArray(data.capabilities)
? data.capabilities
: [data.capabilities]
}
return self._vectorTileServer
.getStyle()
.then((result) => {
Log.info('矢量瓦片样式查询成功:', result)
// 获取矢量瓦片样式信息
self._style = result.data
// 获取所有子图层
const layers = self._style.layers
const sublayers = []
// 初始化图层
if (Array.isArray(self.sublayers) && self.sublayers.length > 0) {
self.sublayers.forEach((sublayer) => {
for (let i = 0; i < layers.length; i++) {
const layerInfo = layers[i]
if (layerInfo.id === sublayer.id) {
const subLayer = new IGSVectorTileSubLayer(
// eslint-disable-next-line prefer-object-spread
Object.assign(
{
type: layerInfo.type,
id: layerInfo.id,
title: layerInfo.description,
style: layerInfo,
visible: undefined,
minZoom: layerInfo.minZoom,
maxZoom: layerInfo.maxZoom,
sublayers: [],
layer: self
},
sublayer
)
)
sublayers.push(subLayer)
}
}
})
} else {
for (let i = 0; i < layers.length; i++) {
const layerInfo = layers[i]
const subLayer = new IGSVectorTileSubLayer({
type: layerInfo.type,
id: layerInfo.id,
title: layerInfo.description,
style: layerInfo,
visible: undefined,
minZoom: layerInfo.minZoom,
maxZoom: layerInfo.maxZoom,
sublayers: [],
layer: self
})
sublayers.push(subLayer)
}
}
self.sublayers = sublayers
return new Promise((resolve) => {
self.loadStatus = LoadStatus.loaded
self.loaded = true
resolve(self)
})
})
.catch((result) => {
Log.error('矢量瓦片样式查询失败:', result)
})
})
.catch((result) => {
Log.error('矢量瓦片信息查询失败:', result)
})
}
get allSublayers() {
if (this._allSublayers.length === 0) {
this.sublayers.forEach((element) => {
this._getSubLayers(element, this._allSublayers)
})
}
return this._allSublayers
}
get style() {
const style = JSON.parse(JSON.stringify(this._style))
// 设置图层样式
style.layers = this.sublayers.map((v) =>
JSON.parse(JSON.stringify(v.style))
)
return style
}
/**
* 获取矢量瓦片子图层
* @private
* @param {IGSVectorTileSubLayer} subLayer 子图层
* @param {Array<IGSVectorTileSubLayer>} 矢量瓦片子图层数组
*/
_getSubLayers(subLayer, sublayers) {
sublayers.push(subLayer)
if (subLayer.sublayers && subLayer.sublayers.length > 0) {
subLayer.sublayers.forEach((element) => {
this._getSubLayers(element, sublayers)
})
}
}
/**
* @description 根据子图层id查询图层
* @param {String} sublayerID 图层ID
* @return {IGSVectorTileSubLayer} 子图层
* @example <caption><h7 id='findSublayerById'>根据子图层id查询图层</h7></caption>
* // ES5引入方式
* const { IGSVectorTileLayer } = Zondy.Layer
* // ES6引入方式
* import { IGSVectorTileLayer} from "@mapgis/webclient-common"
* const igsVectorTileLayer = new IGSVectorTileLayer({
* // 服务基地址
* url: 'http://{ip}:{port}/igs/rest/services/VectorTile/{serviceName}/VectorTileServer'
* });
* map.add(igsVectorTileLayer);
* // 根据id获取子图层
* const subLayer = igsVectorTileLayer.findSublayerById('子图层id')
*/
findSublayerById(sublayerID) {
for (let i = 0; i < this.allSublayers.length; i++) {
if (this.allSublayers[i].id === sublayerID) {
return this.allSublayers[i]
}
}
return null
}
/**
* 发送图层更新事件
* @private
* @param {Array<LayerViewUpdateContent>} 更新内容
* @fires IGSVectorTileLayer#图层样式更新事件
*/
_fireLayerUpdateEvent(updateContent) {
if (!this._map) return
this._map.fire(
LayerEventType.layerUpdate,
new LayerViewUpdateEvent({
type: LayerEventType.layerUpdate,
target: this._map,
layer: this,
message: '',
updateContent
})
)
}
/**
* <a id='getLayoutProperties'/>
* 获取图层布局属性
* @param {String} layerId 图层id
* @return {Object|null} 返回图层布局属性
*/
getLayoutProperties(layerId) {
const sublayer = this.findSublayerById(layerId)
if (sublayer) {
const style = sublayer.style
return style.layout || {}
}
return null
}
/**
* <a id='setLayoutProperties'/>
* 设置图层布局属性
* @param {String} layerId 图层id
* @param {Object} layout 布局属性
*/
setLayoutProperties(layerId, layout) {
const sublayer = this.findSublayerById(layerId)
if (sublayer && sublayer.style) {
sublayer.style.layout = Object.assign(
sublayer.style.layout || {},
layout || {}
)
}
this._fireLayerUpdateEvent([
{
params: arguments,
dataChanged: true,
name: 'setLayoutProperties',
operationType: 'method'
}
])
}
/**
* <a id='getPaintProperties'/>
* 获取图层绘制属性
* @param {String} layerId 图层id
* @return {Object|null} 返回图层绘制属性
*/
getPaintProperties(layerId) {
const sublayer = this.findSublayerById(layerId)
if (sublayer) {
const style = sublayer.style
return style.paint || {}
}
return null
}
/**
* <a id='setPaintProperties'/>
* 设置图层绘制属性
* @param {String} layerId 图层id
* @param {Object} paint 绘制属性
*/
setPaintProperties(layerId, paint) {
const sublayer = this.findSublayerById(layerId)
if (sublayer && sublayer.style) {
sublayer.style.paint = Object.assign(
sublayer.style.paint || {},
paint || {}
)
}
this._fireLayerUpdateEvent([
{
params: arguments,
dataChanged: true,
name: 'setPaintProperties',
operationType: 'method'
}
])
}
/**
* <a id='getStyleLayer'/>
* 获取图层
* @param {String} layerId 图层id
* @return {Object|null} 图层对象。可以查看矢量瓦片json中layers属性对图层的定义或者查看mvt style文件标准。
*/
getStyleLayer(layerId) {
const sublayer = this.findSublayerById(layerId)
if (sublayer) {
return sublayer.style
}
return null
}
/**
* <a id='setStyleLayer'/>
* 设置图层属性对象,可以对图层进行修改、重新排序等。布局属性和绘制属性推荐用setLayoutProperties和setPaintProperties实现。
* @param {Object} layer 图层对象
* @param {String} index 图层顺序
*/
setStyleLayer(layer, index) {
const layerObject = layer || {}
const sublayer = this.findSublayerById(layerObject.id)
if (sublayer) {
const sublayers = this.sublayers
const sortIndex = sublayers.findIndex((v) => v.id === sublayer.id)
// 先移除
sublayers.splice(sortIndex, 1)
// 插入点
const insertIndex = parseInt(defaultValue(index, sublayers.length))
// 计算插入点index
const i = Math.min(Math.max(0, insertIndex), sublayers.length)
// 插入sublayers
sublayers.splice(i, 0, sublayer)
this._fireLayerUpdateEvent([
{
params: arguments,
dataChanged: true,
name: 'setStyleLayer',
operationType: 'method'
}
])
}
}
/**
* <a id='deleteStyleLayer'/>
* 删除图层
* @param {String} layerId 图层id
*/
deleteStyleLayer(layerId) {
const sublayer = this.findSublayerById(layerId)
if (sublayer) {
// 移除sublayer
const sublayers = this.sublayers
const sortIndex = sublayers.findIndex((v) => v === sublayer)
sublayers.splice(sortIndex, 1)
// 发送事件
this._fireLayerUpdateEvent([
{
params: arguments,
dataChanged: true,
name: 'deleteStyleLayer',
operationType: 'method'
}
])
}
}
/**
* <a id='setStyleLayerVisible'/>
* 设置图层可见性,visible为true,显示图层,为false,隐藏图层
* @param {String} layerId 图层id
* @param {Boolean} visible 可见性
*/
setStyleLayerVisible(layerId, visible) {
const visibleDesc = visible ? 'visible' : 'none'
this.setLayoutProperties(layerId, {
visibility: visibleDesc
})
}
/**
* 获取图层可见性
* <a id='getStyleLayerVisible'/>
* @param {String} layerId 图层id
* @return {Boolean} 图层可见性状态
*/
getStyleLayerVisible(layerId) {
const layout = this.getLayoutProperties(layerId)
if (layout) {
return layout.visibility === 'visible'
}
return false
}
/**
* <a id='getStyleLayerFilter'/>
* 获取属性过滤条件
* @param {String} layerId 图层ID
* @return {Array<String>} filter 属性过滤条件数组
*/
getStyleLayerFilter(layerId) {
const sublayer = this.findSublayerById(layerId)
if (sublayer) {
return sublayer.style.filter || undefined
}
return undefined
}
/**
* <a id='setStyleLayerFilter'/>
* 属性过滤
* @param {String} layerId 图层ID
* @param {Array<String>} filter 过滤条件数组
*/
setStyleLayerFilter(layerId, filter) {
const sublayer = this.findSublayerById(layerId)
if (sublayer) {
const style = sublayer.style
style.filter = filter
this._fireLayerUpdateEvent([
{
params: arguments,
dataChanged: true,
name: 'setStyleLayerFilter',
operationType: 'method'
}
])
}
}
/**
* <a id='getStyleLayerZoomRange'/>
* 获取图层最小、最大层级
* @param {String} layerId 图层id
* @return {Array<Number>}
*/
getStyleLayerZoomRange(layerId) {
const sublayer = this.findSublayerById(layerId)
if (sublayer) {
const style = sublayer.style
const { minzoom, maxzoom } = style
return [minzoom, maxzoom]
}
}
/**
* <a id='setStyleLayerZoomRange'/>
* 设置图层最小、最大层级
* @param {String} layerId 图层id
* @param {Number} minZoom 最小层级
* @param {Number} maxZoom 最大层级
*/
setStyleLayerZoomRange(layerId, minZoom, maxZoom) {
if (!isNumber(minZoom) || !isNumber(maxZoom) || minZoom > maxZoom) {
Log.error('setStyleLayerZoomRange zoom参数输入有误')
return
}
const sublayer = this.findSublayerById(layerId)
if (sublayer) {
const style = sublayer.style
style.minzoom = minZoom
style.maxzoom = maxZoom
this._fireLayerUpdateEvent([
{
params: arguments,
dataChanged: true,
name: 'setStyleLayerZoomRange',
operationType: 'method'
}
])
}
}
destroy() {}
/**
* <a id='loadStyle'/>
* 获取矢量瓦片样式
* @return {Promise<Object>} 返回mvtStyle
* @example <caption><h7 id='loadStyle'>获取矢量瓦片样式</h7></caption>
* // ES5引入方式
* const { IGSVectorTileLayer } = Zondy.Layer
* // ES6引入方式
* import { IGSVectorTileLayer} from "@mapgis/webclient-common"
* const igsVectorTileLayer = new IGSVectorTileLayer.({
* // 服务基地址
* url: 'http://{ip}:{port}/igs/rest/services/VectorTile/{serviceName}/VectorTileServer'
* });
* const style=igsVectorTileLayer.loadStyle()
*/
loadStyle() {
return this._vectorTileServer.getStyle().then((res) => res.data)
}
/**
* 通过传入的json构造并返回一个新的几何对象<a id='fromJSON'></a>
* @param {Object} [json] JSON对象
* @example <caption><h7>通过传入的json构造并返回一个新的几何对象</h7></caption>
* // ES5引入方式
* const { IGSVectorTileLayer } = Zondy.Layer
* // ES6引入方式
* import { IGSVectorTileLayer } from "@mapgis/webclient-common"
* const json = {
* // 服务基地址
* url: 'http://{ip}:{port}/igs/rest/services/Tile/{serviceName}/TileServer'
* }
* const igsVectorTileLayer = new IGSVectorTileLayer.fromJSON(json)
*/
static fromJSON(json) {
json = jsonClone(json)
const _layer = new IGSVectorTileLayer(json)
_layer._isFromJSON = true
return _layer
}
/**
* @description 转换为json对象
* @return {Object} json对象
*/
toJSON() {
const json = super.toJSON()
json.type = this.type
json.description = this.description
json.capabilities = this.capabilities
json.url = this.url
json.sublayers = this.sublayers.map((sublayer) =>
toJSON(sublayer, IGSVectorTileSubLayer)
)
json.labelsRenderMode = this.labelsRenderMode
return json
}
}
Object.defineProperties(IGSVectorTileLayer.prototype, {
/**
* 空间裁剪范围
* @member IGSVectorTileLayer.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.IGSVectorTileLayer = IGSVectorTileLayer
export default IGSVectorTileLayer