2025-11-07 15:04:37 +08:00
|
|
|
|
import * as Cesium from 'cesium'
|
|
|
|
|
|
import { SplitDirection } from 'cesium'
|
|
|
|
|
|
|
|
|
|
|
|
// 依赖:{ viewerOrThrow, store }
|
|
|
|
|
|
export function createLayerService(deps) {
|
|
|
|
|
|
const { viewerOrThrow, store } = deps
|
|
|
|
|
|
|
|
|
|
|
|
// 影像图层 zIndex 辅助函数
|
|
|
|
|
|
function nextZIndex() {
|
|
|
|
|
|
const zIndexValues = Object.values(store.layers)
|
|
|
|
|
|
.filter((record) => record && record.type === 'imagery')
|
|
|
|
|
|
.map((record) => (record.meta && typeof record.meta.zIndex === 'number' ? record.meta.zIndex : 0))
|
|
|
|
|
|
return (zIndexValues.length ? Math.max(...zIndexValues) : 0) + 1
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 按 zIndex 重新整理影像图层的叠放顺序
|
|
|
|
|
|
function adjustImageryOrder(viewer) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const imageryRecords = Object.values(store.layers)
|
|
|
|
|
|
.filter((record) => record && record.type === 'imagery' && record.obj)
|
|
|
|
|
|
.sort((a, b) => {
|
|
|
|
|
|
const aZ = a.meta && typeof a.meta.zIndex === 'number' ? a.meta.zIndex : 0
|
|
|
|
|
|
const bZ = b.meta && typeof b.meta.zIndex === 'number' ? b.meta.zIndex : 0
|
|
|
|
|
|
return aZ - bZ
|
|
|
|
|
|
})
|
|
|
|
|
|
// raiseToTop in ascending order so the highest ends top-most
|
|
|
|
|
|
imageryRecords.forEach((record) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (viewer.imageryLayers.contains(record.obj)) viewer.imageryLayers.raiseToTop(record.obj)
|
|
|
|
|
|
} catch (e) {}
|
|
|
|
|
|
})
|
|
|
|
|
|
syncImageryOrderMeta(viewer)
|
|
|
|
|
|
} catch (e) {}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @description 同步影像图层元数据里的排序索引,保持与 Cesium 实际顺序一致
|
|
|
|
|
|
*/
|
|
|
|
|
|
function syncImageryOrderMeta(viewer) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const imageryLayers = viewer.imageryLayers
|
|
|
|
|
|
const imageryRecords = Object.values(store.layers)
|
|
|
|
|
|
.filter((record) => record && record.type === 'imagery' && record.obj)
|
|
|
|
|
|
const lookup = new Map()
|
|
|
|
|
|
imageryRecords.forEach((record) => lookup.set(record.obj, record))
|
|
|
|
|
|
const count = imageryLayers.length
|
|
|
|
|
|
for (let i = 0; i < count; i += 1) {
|
|
|
|
|
|
const layer = imageryLayers.get(i)
|
|
|
|
|
|
const record = lookup.get(layer)
|
|
|
|
|
|
if (!record) continue
|
|
|
|
|
|
if (!record.meta) record.meta = {}
|
|
|
|
|
|
record.meta.zIndex = i
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (e) {}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @description 同步矢量数据源图层顺序,记录在 meta.vectorOrder 中
|
|
|
|
|
|
*/
|
|
|
|
|
|
function syncVectorOrderMeta(viewer) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const dataSources = viewer.dataSources
|
|
|
|
|
|
const vectorRecords = Object.values(store.layers)
|
|
|
|
|
|
.filter((record) => record && (record.type === 'vector' || record.type === 'datasource') && record.obj)
|
|
|
|
|
|
const lookup = new Map()
|
|
|
|
|
|
vectorRecords.forEach((record) => lookup.set(record.obj, record))
|
|
|
|
|
|
const count = dataSources.length
|
|
|
|
|
|
for (let i = 0; i < count; i += 1) {
|
|
|
|
|
|
const ds = dataSources.get(i)
|
|
|
|
|
|
const record = lookup.get(ds)
|
|
|
|
|
|
if (!record) continue
|
|
|
|
|
|
if (!record.meta) record.meta = {}
|
|
|
|
|
|
record.meta.vectorOrder = i
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (e) {}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
async addLayer(spec) {
|
|
|
|
|
|
const viewer = viewerOrThrow()
|
|
|
|
|
|
|
|
|
|
|
|
// 兼容新旧两种参数风格(新的 serviceConfig 与旧的直传 spec)
|
|
|
|
|
|
const layerSpec = spec
|
|
|
|
|
|
const layerType = layerSpec.type
|
|
|
|
|
|
const layerId = layerSpec.id || (layerType ? `${layerType}:${Date.now().toString(36)}` : `layer:${Date.now().toString(36)}`)
|
|
|
|
|
|
if (store.layers[layerId]) return layerId
|
|
|
|
|
|
|
|
|
|
|
|
const metadata = { ...(layerSpec.meta || {}) }
|
|
|
|
|
|
if (layerSpec.zIndex != null) metadata.zIndex = Number(layerSpec.zIndex)
|
|
|
|
|
|
if (metadata.zIndex == null && (layerType && layerType !== 'terrain' && layerType !== 'primitive' && layerType !== 'vector' && layerType !== 'datasource')) {
|
|
|
|
|
|
metadata.zIndex = nextZIndex()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const layerOptions = layerSpec.options || {}
|
|
|
|
|
|
const sourceUrl = layerSpec.url
|
|
|
|
|
|
|
|
|
|
|
|
let layerRecord = null
|
|
|
|
|
|
|
|
|
|
|
|
// 注册影像图层(ImageryLayer)的辅助方法
|
|
|
|
|
|
const registerImageryLayer = (provider, extraProps = {}) => {
|
|
|
|
|
|
const imageryLayer = viewer.imageryLayers.addImageryProvider(provider)
|
|
|
|
|
|
if (typeof layerOptions.opacity === 'number') imageryLayer.alpha = layerOptions.opacity
|
|
|
|
|
|
if (typeof layerOptions.visible === 'boolean') imageryLayer.show = layerOptions.visible
|
|
|
|
|
|
imageryLayer.splitDirection = SplitDirection.NONE
|
|
|
|
|
|
const record = {
|
|
|
|
|
|
id: layerId,
|
|
|
|
|
|
type: 'imagery',
|
|
|
|
|
|
obj: imageryLayer,
|
|
|
|
|
|
owned: true,
|
|
|
|
|
|
show: imageryLayer.show,
|
|
|
|
|
|
opacity: imageryLayer.alpha,
|
|
|
|
|
|
meta: metadata,
|
|
|
|
|
|
...extraProps,
|
|
|
|
|
|
}
|
|
|
|
|
|
store.layers[layerId] = record
|
|
|
|
|
|
adjustImageryOrder(viewer)
|
|
|
|
|
|
return record
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 注册矢量数据源的辅助方法
|
|
|
|
|
|
const registerVectorLayer = async (dataSource) => {
|
|
|
|
|
|
await viewer.dataSources.add(dataSource)
|
|
|
|
|
|
dataSource.show = layerOptions.visible !== false
|
|
|
|
|
|
const record = {
|
|
|
|
|
|
id: layerId,
|
|
|
|
|
|
type: 'vector',
|
|
|
|
|
|
obj: dataSource,
|
|
|
|
|
|
owned: true,
|
|
|
|
|
|
show: dataSource.show,
|
|
|
|
|
|
opacity: typeof layerOptions.opacity === 'number' ? layerOptions.opacity : 1,
|
|
|
|
|
|
meta: metadata,
|
|
|
|
|
|
}
|
|
|
|
|
|
store.layers[layerId] = record
|
|
|
|
|
|
syncVectorOrderMeta(viewer)
|
|
|
|
|
|
return record
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 旧版直映射类型分支
|
|
|
|
|
|
if (layerType === 'imagery' || layerType === 'baseImagery') {
|
|
|
|
|
|
const provider = layerSpec.source
|
|
|
|
|
|
layerRecord = registerImageryLayer(provider)
|
|
|
|
|
|
if (layerType === 'baseImagery') viewer.imageryLayers.lowerToBottom(layerRecord.obj)
|
|
|
|
|
|
return layerId
|
|
|
|
|
|
}
|
|
|
|
|
|
if (layerType === 'vector' || layerType === 'datasource') {
|
|
|
|
|
|
const dataSource = new Cesium.CustomDataSource(layerId)
|
|
|
|
|
|
layerRecord = await registerVectorLayer(dataSource)
|
|
|
|
|
|
return layerId
|
|
|
|
|
|
}
|
|
|
|
|
|
if (layerType === 'terrain') {
|
|
|
|
|
|
if ('terrain' in viewer) viewer.terrain = layerSpec.source
|
|
|
|
|
|
else viewer.scene.terrainProvider = layerSpec.source
|
|
|
|
|
|
layerRecord = {
|
|
|
|
|
|
id: layerId,
|
|
|
|
|
|
type: 'terrain',
|
|
|
|
|
|
obj: layerSpec.source,
|
|
|
|
|
|
owned: true,
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
opacity: 1,
|
|
|
|
|
|
meta: metadata,
|
|
|
|
|
|
}
|
|
|
|
|
|
store.layers[layerId] = layerRecord
|
|
|
|
|
|
return layerId
|
|
|
|
|
|
}
|
|
|
|
|
|
if (layerType === 'primitive') {
|
|
|
|
|
|
const primitive = layerSpec.source
|
|
|
|
|
|
viewer.scene.primitives.add(primitive)
|
|
|
|
|
|
layerRecord = {
|
|
|
|
|
|
id: layerId,
|
|
|
|
|
|
type: 'primitive',
|
|
|
|
|
|
obj: primitive,
|
|
|
|
|
|
owned: true,
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
opacity: 1,
|
|
|
|
|
|
meta: metadata,
|
|
|
|
|
|
}
|
|
|
|
|
|
store.layers[layerId] = layerRecord
|
|
|
|
|
|
return layerId
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// React serviceConfig-style types
|
|
|
|
|
|
switch (layerType) {
|
|
|
|
|
|
case 'ArcGISTiledMapServiceLayer': {
|
|
|
|
|
|
const haveTemplateXYZ = typeof sourceUrl === 'string' && sourceUrl.includes('{z}/{y}/{x}')
|
|
|
|
|
|
if (!haveTemplateXYZ) {
|
|
|
|
|
|
const provider = await Cesium.ArcGisMapServerImageryProvider.fromUrl(sourceUrl, layerOptions)
|
|
|
|
|
|
registerImageryLayer(provider)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const provider = new Cesium.UrlTemplateImageryProvider({
|
|
|
|
|
|
url: sourceUrl,
|
|
|
|
|
|
tilingScheme: new Cesium.WebMercatorTilingScheme(),
|
|
|
|
|
|
maximumLevel: 18,
|
|
|
|
|
|
...layerOptions,
|
|
|
|
|
|
})
|
|
|
|
|
|
registerImageryLayer(provider)
|
|
|
|
|
|
}
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
case 'ArcGISDynamicMapServiceLayer':
|
|
|
|
|
|
case 'ArcGISImageMapServiceLayer': {
|
|
|
|
|
|
const provider = await Cesium.ArcGisMapServerImageryProvider.fromUrl(sourceUrl, {
|
|
|
|
|
|
enablePickFeatures: true,
|
|
|
|
|
|
...layerOptions,
|
|
|
|
|
|
})
|
|
|
|
|
|
registerImageryLayer(provider)
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
case 'GeoJSONServiceLayer': {
|
|
|
|
|
|
// Accept url or raw data in options.data
|
|
|
|
|
|
const data = layerOptions.data || sourceUrl
|
|
|
|
|
|
const dataSource = await Cesium.GeoJsonDataSource.load(data, layerOptions)
|
|
|
|
|
|
await registerVectorLayer(dataSource)
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
case 'WmsServiceLayer': {
|
|
|
|
|
|
const base = (sourceUrl || '').split('?')[0]
|
|
|
|
|
|
const queryParams = (sourceUrl || '').includes('?') ? new URLSearchParams((sourceUrl || '').split('?')[1]) : new URLSearchParams()
|
|
|
|
|
|
const provider = new Cesium.WebMapServiceImageryProvider({
|
|
|
|
|
|
url: base,
|
|
|
|
|
|
layers: queryParams.get('layers') || layerOptions.layers,
|
|
|
|
|
|
parameters: {
|
|
|
|
|
|
service: 'WMS',
|
|
|
|
|
|
version: queryParams.get('version') || layerOptions.version || '1.1.1',
|
|
|
|
|
|
request: 'GetMap',
|
|
|
|
|
|
format: queryParams.get('format') || layerOptions.format || 'image/png',
|
|
|
|
|
|
transparent: true,
|
2025-11-19 13:41:02 +08:00
|
|
|
|
...layerOptions.extraParameters,
|
2025-11-07 15:04:37 +08:00
|
|
|
|
...layerOptions.parameters,
|
|
|
|
|
|
},
|
|
|
|
|
|
enablePickFeatures: true,
|
|
|
|
|
|
...layerOptions,
|
|
|
|
|
|
})
|
|
|
|
|
|
registerImageryLayer(provider)
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
case 'WmtsServiceLayer':
|
|
|
|
|
|
case 'TiandituVecLayer':
|
|
|
|
|
|
case 'TiandituImgLayer':
|
|
|
|
|
|
case 'TiandituCvaLayer': {
|
|
|
|
|
|
// Try to honor tk from url or options
|
|
|
|
|
|
const urlBase = (sourceUrl || '').split('?')[0]
|
|
|
|
|
|
const queryParams = (sourceUrl || '').includes('?') ? new URLSearchParams((sourceUrl || '').split('?')[1]) : new URLSearchParams()
|
|
|
|
|
|
const tk = queryParams.get('tk') || layerOptions.tk
|
|
|
|
|
|
const wmtsUrl = tk ? `${urlBase}?tk=${tk}` : urlBase
|
|
|
|
|
|
const provider = new Cesium.WebMapTileServiceImageryProvider({
|
|
|
|
|
|
url: wmtsUrl,
|
|
|
|
|
|
layer: queryParams.get('LAYER') || queryParams.get('layer') || layerOptions.layer || 'img',
|
|
|
|
|
|
style: 'default',
|
|
|
|
|
|
format: 'tiles',
|
|
|
|
|
|
tileMatrixSetID: layerOptions.tileMatrixSetID || 'w',
|
|
|
|
|
|
tilingScheme: new Cesium.WebMercatorTilingScheme(),
|
|
|
|
|
|
maximumLevel: layerOptions.maximumLevel || 18,
|
|
|
|
|
|
subdomains: layerOptions.subdomains || ['0', '1', '2', '3', '4', '5', '6', '7'],
|
|
|
|
|
|
...layerOptions,
|
|
|
|
|
|
})
|
|
|
|
|
|
registerImageryLayer(provider)
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
case 'WebTileLayer': {
|
|
|
|
|
|
const provider = new Cesium.UrlTemplateImageryProvider({
|
|
|
|
|
|
url: sourceUrl,
|
|
|
|
|
|
tilingScheme: new Cesium.WebMercatorTilingScheme(),
|
|
|
|
|
|
subdomains: layerOptions.subdomains || ['0', '1', '2', '3', '4', '5', '6', '7'],
|
|
|
|
|
|
...layerOptions,
|
|
|
|
|
|
})
|
|
|
|
|
|
registerImageryLayer(provider)
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
case 'TMSServiceLayer': { // TMS z/x/{reverseY}
|
|
|
|
|
|
const templateUrl = typeof sourceUrl === 'string' ? sourceUrl.replace('{y}', '{reverseY}') : sourceUrl
|
|
|
|
|
|
const providerOptions = {
|
|
|
|
|
|
url: templateUrl,
|
|
|
|
|
|
tilingScheme: new Cesium.WebMercatorTilingScheme(),
|
|
|
|
|
|
maximumLevel: layerOptions.maximumLevel || layerOptions.maxZoom || 22,
|
|
|
|
|
|
...layerOptions,
|
|
|
|
|
|
}
|
|
|
|
|
|
if (layerOptions.bounds) {
|
|
|
|
|
|
const bounds = layerOptions.bounds
|
|
|
|
|
|
providerOptions.rectangle = Cesium.Rectangle.fromDegrees(bounds.west, bounds.south, bounds.east, bounds.north)
|
|
|
|
|
|
}
|
|
|
|
|
|
const provider = new Cesium.UrlTemplateImageryProvider({ ...providerOptions, url: templateUrl })
|
|
|
|
|
|
registerImageryLayer(provider)
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
case 'TmsServiceLayer': { // XYZ z/x/y
|
|
|
|
|
|
const providerOptions = {
|
|
|
|
|
|
url: sourceUrl,
|
|
|
|
|
|
tilingScheme: new Cesium.WebMercatorTilingScheme(),
|
|
|
|
|
|
maximumLevel: layerOptions.maximumLevel || layerOptions.maxZoom || 22,
|
|
|
|
|
|
...layerOptions,
|
|
|
|
|
|
}
|
|
|
|
|
|
if (layerOptions.bounds) {
|
|
|
|
|
|
const bounds = layerOptions.bounds
|
|
|
|
|
|
providerOptions.rectangle = Cesium.Rectangle.fromDegrees(bounds.west, bounds.south, bounds.east, bounds.north)
|
|
|
|
|
|
}
|
|
|
|
|
|
const provider = new Cesium.UrlTemplateImageryProvider(providerOptions)
|
|
|
|
|
|
registerImageryLayer(provider)
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
case 'Cesium3DTileService': {
|
|
|
|
|
|
const tileset = await Cesium.Cesium3DTileset.fromUrl(sourceUrl, {
|
|
|
|
|
|
...layerOptions,
|
|
|
|
|
|
})
|
|
|
|
|
|
viewer.scene.primitives.add(tileset)
|
|
|
|
|
|
layerRecord = {
|
|
|
|
|
|
id: layerId,
|
|
|
|
|
|
type: 'primitive',
|
|
|
|
|
|
obj: tileset,
|
|
|
|
|
|
owned: true,
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
opacity: 1,
|
|
|
|
|
|
meta: metadata,
|
|
|
|
|
|
}
|
|
|
|
|
|
store.layers[layerId] = layerRecord
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
default:
|
|
|
|
|
|
throw new Error('不支持的图层类型: ' + layerType)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return layerId
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 移除图层
|
|
|
|
|
|
removeLayer(id) {
|
|
|
|
|
|
const viewer = viewerOrThrow()
|
|
|
|
|
|
const record = store.layers[id]
|
|
|
|
|
|
if (!record) return false
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (record.type === 'imagery') {
|
|
|
|
|
|
viewer.imageryLayers.remove(record.obj, true)
|
|
|
|
|
|
syncImageryOrderMeta(viewer)
|
|
|
|
|
|
} else if (record.type === 'vector' || record.type === 'datasource') {
|
|
|
|
|
|
viewer.dataSources.remove(record.obj, true)
|
|
|
|
|
|
syncVectorOrderMeta(viewer)
|
|
|
|
|
|
} else if (record.type === 'primitive') {
|
|
|
|
|
|
viewer.scene.primitives.remove(record.obj)
|
|
|
|
|
|
} else if (record.type === 'terrain') {
|
|
|
|
|
|
if ('terrain' in viewer) viewer.terrain = new Cesium.EllipsoidTerrain()
|
|
|
|
|
|
else viewer.scene.terrainProvider = new Cesium.EllipsoidTerrain()
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (e) {}
|
|
|
|
|
|
delete store.layers[id]
|
|
|
|
|
|
return true
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 显隐图层
|
|
|
|
|
|
showLayer(id, visible) {
|
|
|
|
|
|
const record = store.layers[id]
|
|
|
|
|
|
if (!record) return
|
|
|
|
|
|
if (record.type === 'imagery') record.obj.show = !!visible
|
|
|
|
|
|
else if (record.type === 'vector' || record.type === 'datasource') record.obj.show = !!visible
|
|
|
|
|
|
else if (record.type === 'primitive') record.obj.show = !!visible
|
|
|
|
|
|
record.show = !!visible
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 设置透明度
|
|
|
|
|
|
setOpacity(id, alpha) {
|
|
|
|
|
|
const record = store.layers[id]
|
|
|
|
|
|
if (!record) return
|
|
|
|
|
|
if (record.type === 'imagery') {
|
|
|
|
|
|
record.obj.alpha = alpha
|
|
|
|
|
|
record.opacity = alpha
|
|
|
|
|
|
} else {
|
|
|
|
|
|
record.opacity = alpha /* TODO: walk entities/materials */
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 调整图层顺序(上/下/置顶/置底)
|
|
|
|
|
|
moveLayer(id, direction) {
|
|
|
|
|
|
const viewer = viewerOrThrow()
|
|
|
|
|
|
const record = store.layers[id]
|
|
|
|
|
|
if (!record) return
|
|
|
|
|
|
if (record.type === 'imagery') {
|
|
|
|
|
|
const imageryLayers = viewer.imageryLayers
|
|
|
|
|
|
if (direction === 'up') imageryLayers.raise(record.obj)
|
|
|
|
|
|
else if (direction === 'down') imageryLayers.lower(record.obj)
|
|
|
|
|
|
else if (direction === 'top') imageryLayers.raiseToTop(record.obj)
|
|
|
|
|
|
else if (direction === 'bottom') imageryLayers.lowerToBottom(record.obj)
|
|
|
|
|
|
syncImageryOrderMeta(viewer)
|
|
|
|
|
|
} else if (record.type === 'vector' || record.type === 'datasource') {
|
|
|
|
|
|
const dataSources = viewer.dataSources
|
|
|
|
|
|
if (direction === 'up') dataSources.raise(record.obj)
|
|
|
|
|
|
else if (direction === 'down') dataSources.lower(record.obj)
|
|
|
|
|
|
else if (direction === 'top') dataSources.raiseToTop(record.obj)
|
|
|
|
|
|
else if (direction === 'bottom') dataSources.lowerToBottom(record.obj)
|
|
|
|
|
|
syncVectorOrderMeta(viewer)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 设置卷帘(左右分屏)位置
|
|
|
|
|
|
setSplit(id, side) {
|
|
|
|
|
|
const record = store.layers[id]
|
|
|
|
|
|
if (!record || record.type !== 'imagery') return
|
|
|
|
|
|
const splitDirectionMap = {
|
|
|
|
|
|
left: SplitDirection.LEFT,
|
|
|
|
|
|
right: SplitDirection.RIGHT,
|
|
|
|
|
|
none: SplitDirection.NONE,
|
|
|
|
|
|
}
|
|
|
|
|
|
record.obj.splitDirection = splitDirectionMap[side] || SplitDirection.NONE
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 设置全局卷帘分割位置 [0,1]
|
|
|
|
|
|
setSplitPosition(position) {
|
|
|
|
|
|
const viewer = viewerOrThrow()
|
|
|
|
|
|
store.imagerySplitPosition = Math.min(1, Math.max(0, position))
|
|
|
|
|
|
try {
|
|
|
|
|
|
viewer.scene.imagerySplitPosition = store.imagerySplitPosition
|
|
|
|
|
|
} catch (e) {}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 获取图层记录
|
|
|
|
|
|
getLayer(id) {
|
|
|
|
|
|
return store.layers[id]
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 列出所有图层记录
|
|
|
|
|
|
listLayers() {
|
|
|
|
|
|
return Object.values(store.layers)
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|