@dlr-eoc/map-cesium
Version:
This is a angular module that exports a cesium component that can handle UKIS layers. See @dlr-eoc/services-layers for supported types.
1 lines • 116 kB
Source Map (JSON)
{"version":3,"file":"dlr-eoc-map-cesium.mjs","sources":["../../../projects/map-cesium/src/lib/map-cesium.service.ts","../../../projects/map-cesium/src/lib/map-cesium.component.ts","../../../projects/map-cesium/src/lib/map-cesium.component.html","../../../projects/map-cesium/src/public-api.ts","../../../projects/map-cesium/src/dlr-eoc-map-cesium.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\nimport { Layer, VectorLayer, CustomLayer, RasterLayer, WmtsLayer, WmsLayer, TGeoExtent, TmsLayertype, WmtsLayertype, WmsLayertype, XyzLayertype, IListMatrixSet, TFiltertypesUncap, TFiltertypes } from '@dlr-eoc/services-layers';\n\nimport { ICesiumControls } from './map-cesium.component';\nimport { Cartesian3, Cesium3DTileStyle, Cesium3DTileset, CesiumTerrainProvider, Color, Credit, DataSource, EllipsoidTerrainProvider, GeoJsonDataSource, I3SDataProvider, ImageryLayer, Ion, JulianDate, KmlDataSource, Rectangle, TileMapServiceImageryProvider, TimeIntervalCollection, UrlTemplateImageryProvider, WebMapServiceImageryProvider, WebMapTileServiceImageryProvider, WebMercatorTilingScheme, Math as CesiumMath, BillboardGraphics} from '@cesium/engine';\nimport { Viewer } from '@cesium/widgets';\nimport { IMapCenter } from '@dlr-eoc/services-map-state';\n\ndeclare type Tgroupfiltertype = TFiltertypesUncap | TFiltertypes\nconst WebMercator = 'EPSG:3857';\nconst WGS84 = 'EPSG:4326';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class MapCesiumService {\n public viewer!: Viewer;\n\n //map objects for ImageryLayers\n private baseLayerImageryGroup = new Map<string, ImageryLayer>();\n private standardLayerImageryGroup = new Map<string, ImageryLayer>();\n private overlayLayerImageryGroup = new Map<string, ImageryLayer>();\n\n //map objects for vector DataSources\n private baseLayerDataSourceGroup = new Map<string, DataSource>();\n private standardLayerDataSourceGroup = new Map<string, DataSource>();\n private overlayLayerDataSourceGroup = new Map<string, DataSource>();\n\n //additional object for vector DataSource opacity\n private dataSourceOpacity = new Map<string, number>();\n\n //map objects for 3D data\n private terrainLayerGroup = new Map<string, boolean>(); //Map for terrain containing layerID and visibility\n private tilesetLayerGroup = new Map<string, Cesium3DTileset>(); //Map for 3D tilesets containing layerID and viewer handler\n\n public EPSG: string;\n\n //Time objects\n public cesiumCurrentTime = JulianDate.now();\n private cesiumTimeInterval = new TimeIntervalCollection();\n\n //Default viewer options\n private viewerOptions: Viewer.ConstructorOptions = {\n timeline: false,\n animation: false,\n sceneModePicker: false,\n homeButton: false,\n baseLayerPicker: false,\n geocoder: false, //the geocoder requires an cesium ion access token to work\n navigationHelpButton: false,\n navigationInstructionsInitiallyVisible: false,\n fullscreenButton: false,\n scene3DOnly: true,\n skyAtmosphere: false,\n infoBox: false,\n selectionIndicator: false,\n baseLayer: false\n };\n\n public defaultGlobeColor: Color = Color.WHITE;\n\n constructor() {\n this.EPSG = WebMercator;\n }\n\n //When the controlls are specified, change the default values of the viewer options\n public setControls(newControls: ICesiumControls) {\n //If an ion access token is given, set it as default. Some cesium widgets are requiring an working token.\n if (typeof newControls.ionAccessToken !== 'undefined') {\n this.addIonAccessToken(newControls.ionAccessToken);\n }\n if (typeof newControls.GoogleMapsApiKey !== 'undefined') {\n this.addGoogleMapsApiKey(newControls.GoogleMapsApiKey);\n }\n if (typeof newControls.timeline !== 'undefined') {\n this.viewerOptions.timeline = newControls.timeline;\n }\n if (typeof newControls.animation !== 'undefined') {\n this.viewerOptions.animation = newControls.animation;\n }\n if (typeof newControls.sceneModePicker !== 'undefined') {\n this.viewerOptions.sceneModePicker = newControls.sceneModePicker;\n }\n if (typeof newControls.homeButton !== 'undefined') {\n this.viewerOptions.homeButton = newControls.homeButton;\n }\n if (typeof newControls.baseLayerPicker !== 'undefined') {\n this.viewerOptions.baseLayerPicker = newControls.baseLayerPicker;\n }\n if (typeof newControls.navigationHelpButton !== 'undefined') {\n this.viewerOptions.navigationHelpButton = newControls.navigationHelpButton;\n }\n if (typeof newControls.navigationInstructionsInitiallyVisible !== 'undefined') {\n this.viewerOptions.navigationInstructionsInitiallyVisible = newControls.navigationInstructionsInitiallyVisible;\n }\n if (typeof newControls.fullscreenButton !== 'undefined') {\n this.viewerOptions.fullscreenButton = newControls.fullscreenButton;\n }\n if (typeof newControls.scene3DOnly !== 'undefined') {\n this.viewerOptions.scene3DOnly = newControls.scene3DOnly;\n }\n if (typeof newControls.infoBox !== 'undefined') {\n this.viewerOptions.infoBox = newControls.infoBox;\n }\n if (typeof newControls.selectionIndicator !== 'undefined') {\n this.viewerOptions.selectionIndicator = newControls.selectionIndicator;\n }\n if (typeof newControls.globeColor !== 'undefined') {\n this.defaultGlobeColor = Color.fromCssColorString(newControls.globeColor);\n }\n }\n\n //Create Cesium Viewer\n public createMap(target: HTMLElement) {\n\n this.viewer = new Viewer(target, this.viewerOptions);\n //remove all default baselayers\n this.viewer.imageryLayers.removeAll();\n\n //remove fog and ground atmosphere\n const scene = this.viewer.scene;\n scene.fog.enabled = false;\n scene.globe.showGroundAtmosphere = false;\n scene.sun.show = false;\n scene.moon.show = false;\n\n //reduce light effect on tilesets\n scene.globe.enableLighting = false;\n scene.highDynamicRange = false;\n\n //set default color to white for transparent backgrounds\n scene.globe.baseColor = this.defaultGlobeColor;\n\n //set start time\n this.viewer.clock.currentTime = this.cesiumCurrentTime;\n\n //change default infoBox\n if(this.viewerOptions.infoBox){\n this.viewer.infoBox.container.getElementsByTagName('iframe')[0].remove();\n const newDiv = document.createElement(\"div\");\n newDiv.className = 'cesium-infoBox-content';\n newDiv.id = 'cesiumInfoBoxContent'\n this.viewer.infoBox.container.children[0].append(newDiv);\n }\n\n //Change primitive collection settings\n this.viewer.scene.primitives.destroyPrimitives = false;\n\n return {\n viewer: this.viewer\n }\n }\n\n // Map State functions\n // Partially not transferable to 3D globe, see: https://stackoverflow.com/questions/33237064/get-current-zoom-in-cesium\n // The following implementation is therefore not perfect but an approximation\n // Connection between zoom and map scale (WGS84/ EPSG: 4326): https://docs.geoserver.org/latest/en/user/styling/ysld/reference/scalezoom.html\n // map_scale = (2^zoom_level) / 559082264\n // Connection between map scale and view height (very rough approximation):\n // map_scale = 0.1/height\n // height = 55908226 / (2^zoom_level)\n // zoom_level = log (55908226 / height) / log (2)\n // log (2) = 0.3\n // There is also a constant offset between the zoom levels of the 2D and 3D map. To make the transition between the two maps more smooth, the cesium zoom level needs to be adjusted by this constant.\n\n\n public setZoom(zoom: number, notifier?: 'map' | 'user') {\n //set screen size dependent scale constant\n const screenSizeConst = this.viewer.canvas.width / 1000;\n zoom = zoom - screenSizeConst;\n // calculate new height and get current camera position\n const height = 55908226 / Math.pow(2, zoom);\n const currentPosition = this.viewer.camera.positionCartographic;\n // set camera to new position\n this.viewer.camera.setView({\n destination: Cartesian3.fromRadians(currentPosition.longitude, currentPosition.latitude, height)\n });\n //console.log('SetZoom: ' + height + ', ' + currentPosition.longitude + ', ' + currentPosition.latitude);\n }\n\n public getZoom(): number {\n let zoom: number;\n // get current height from viewer and calculate zoom value\n if (this.viewer) {\n const height = this.viewer.camera.positionCartographic.height;\n zoom = Math.round(Math.log10(55908226 / height) / 0.3);\n if (zoom < 0) {\n zoom = 0;\n }\n } else {\n // Cesium default zoom\n zoom = 2;\n }\n //console.log('GetZoom: ' + zoom);\n const screenSizeConst = this.viewer.canvas.width / 1000;\n zoom = zoom + screenSizeConst;\n return zoom;\n }\n\n public setCenter(center: IMapCenter) {\n // to avoid confusion about the lat, lon ordering, the IMapCenter interfaced is used here\n // get current height from viewer\n const height = this.viewer.camera.positionCartographic.height;\n // set camera to new position\n this.viewer.camera.setView({\n destination: Cartesian3.fromDegrees(center.lon, center.lat, height)\n });\n //console.log('SetCenter: ' + center.lat + ', ' + center.lon + ', ' + height);\n }\n\n public getCenter(): IMapCenter {\n const currentPosition = this.viewer.camera.positionCartographic;\n const lat = currentPosition.latitude * (180 / Math.PI);\n const lon = currentPosition.longitude * (180 / Math.PI);\n //console.log('GetCenter: ' + lat + ', ' + lon);\n return {lat: lat,lon: lon};\n }\n\n public setExtent(extent: TGeoExtent, geographic?: boolean, fitOptions?: any) {\n const destination = Rectangle.fromDegrees(extent[0], extent[1], extent[2], extent[3]);\n this.viewer.camera.setView({ destination });\n //console.log('SetExtent: ' + extent[0] + ', ' + extent[1] + ', ' + extent[3] + ', ' + extent[4]);\n }\n\n\n public getCurrentExtent(geographic?: boolean): TGeoExtent {\n let extent!: TGeoExtent;\n // https://cesium.com/learn/cesiumjs/ref-doc/Rectangle.html\n const currentRectangle = this.viewer.camera.computeViewRectangle();\n if (currentRectangle) {\n const minX = currentRectangle.west * (180 / Math.PI);\n const minY = currentRectangle.south * (180 / Math.PI);\n const maxX = currentRectangle.east * (180 / Math.PI);\n const maxY = currentRectangle.north * (180 / Math.PI);\n extent = [minX, minY, maxX, maxY];\n //console.log('GetCurrentExtent: ' + minX + ', ' + minY + ', ' + maxX + ', ' + maxY);\n }\n return extent;\n }\n\n /**\n * Set initial oblique view, see https://cesium.com/learn/cesiumjs/ref-doc/Camera.html\n * subtract 90°, to get the same behavior as in openlayers\n * options of viewer.camera.flyTo`\n *\n * https://github.com/CesiumGS/cesium/blob/99d6fffe20d9cf19f2d70de97777dc00a435bc5e/packages/engine/Source/Scene/Camera.js#L1457\n * https://github.com/CesiumGS/cesium/blob/99d6fffe20d9cf19f2d70de97777dc00a435bc5e/packages/engine/Source/Scene/Camera.js#L3540-L3541\n */\n public setViewAngle(viewAngle: number, options?: any) {\n const flyToOptions = Object.assign({\n destination: this.viewer.camera.position,\n orientation: {\n heading: this.viewer.camera.heading,\n pitch: CesiumMath.toRadians(viewAngle - 90),\n roll: this.viewer.camera.roll,\n },\n }, options || {});\n\n this.viewer.camera.flyTo(flyToOptions)\n }\n\n /**\n * @param options of viewer.camera.flyTo\n */\n public setNadirViewAngle(options?: any) {\n if (this.getViewAngle() !== 0) {\n if (options) {\n this.setViewAngle(0, options);\n } else {\n this.setViewAngle(0);\n }\n }else{\n // If view angle is 0, setViewAngle(0) (flyTo) is not necessary\n console.log(typeof options.complete);\n if(options.complete && typeof options.complete === 'function'){\n options.complete();\n }\n }\n }\n\n //add 90°, to get the same behavior as in openlayers\n public getViewAngle():number{\n return CesiumMath.toDegrees(this.viewer.camera.pitch) + 90;\n }\n\n /**\n * subtract rotation degree from 360° to get the same behavior as in openlayers\n * options of viewer.camera.flyTo`\n *\n * https://github.com/CesiumGS/cesium/blob/99d6fffe20d9cf19f2d70de97777dc00a435bc5e/packages/engine/Source/Scene/Camera.js#L3424\n * https://github.com/CesiumGS/cesium/blob/99d6fffe20d9cf19f2d70de97777dc00a435bc5e/packages/engine/Source/Scene/Camera.js#L1456\n */\n public setRotation(rotation: number, options?: any) {\n const flyToOptions = Object.assign({\n destination: this.viewer.camera.position,\n orientation: {\n heading: CesiumMath.toRadians(360 - rotation),\n pitch: this.viewer.camera.pitch,\n roll: this.viewer.camera.roll,\n },\n }, options || {});\n\n this.viewer.camera.flyTo(flyToOptions);\n }\n // subtract rotation degree from 360° to get the same behavior as in openlayers\n public getRotation():number{\n return 360 - CesiumMath.toDegrees(this.viewer.camera.heading);\n }\n\n // https://sandcastle.cesium.com/index.html?src=Imagery%2520Layers.html\n // https://sandcastle.cesium.com/index.html?src=Imagery%2520Layers%2520Manipulation.html\n\n\n public getAll2DLayersSize(filtertype: Tgroupfiltertype): number {\n const lowerType = filtertype.toLowerCase() as Tgroupfiltertype;\n let length = 0;\n if (lowerType === 'baselayers') {\n length = this.baseLayerImageryGroup.size + this.baseLayerDataSourceGroup.size;\n } else if (lowerType === 'layers') {\n length = this.standardLayerImageryGroup.size + this.standardLayerDataSourceGroup.size;\n } else if (lowerType === 'overlays') {\n length = this.overlayLayerImageryGroup.size + this.overlayLayerDataSourceGroup.size;\n }\n return length;\n }\n\n public get2DImageryLayersSize(filtertype: Tgroupfiltertype): number {\n const lowerType = filtertype.toLowerCase() as Tgroupfiltertype;\n let length = 0;\n if (lowerType === 'baselayers') {\n length = this.baseLayerImageryGroup.size;\n } else if (lowerType === 'layers') {\n length = this.standardLayerImageryGroup.size;\n } else if (lowerType === 'overlays') {\n length = this.overlayLayerImageryGroup.size;\n }\n return length;\n }\n\n public getDataSourceLayersSize(filtertype: Tgroupfiltertype): number {\n const lowerType = filtertype.toLowerCase() as Tgroupfiltertype;\n let length = 0;\n if (lowerType === 'baselayers') {\n length = this.baseLayerDataSourceGroup.size;\n } else if (lowerType === 'layers') {\n length = this.standardLayerDataSourceGroup.size;\n } else if (lowerType === 'overlays') {\n length = this.overlayLayerDataSourceGroup.size;\n }\n return length;\n }\n\n public getVisible2DLayersSize(filtertype: Tgroupfiltertype): number {\n const lowerType = filtertype.toLowerCase() as Tgroupfiltertype;\n let length = 0;\n if (lowerType === 'baselayers') {\n this.baseLayerImageryGroup.forEach(value => {\n if (value.show) {\n length++;\n }\n });\n this.baseLayerDataSourceGroup.forEach(value => {\n if (value.show) {\n length++;\n }\n });\n } else if (lowerType === 'layers') {\n this.standardLayerImageryGroup.forEach(value => {\n if (value.show) {\n length++;\n }\n });\n this.standardLayerDataSourceGroup.forEach(value => {\n if (value.show) {\n length++;\n }\n });\n } else if (lowerType === 'overlays') {\n this.overlayLayerImageryGroup.forEach(value => {\n if (value.show) {\n length++;\n }\n });\n this.overlayLayerDataSourceGroup.forEach(value => {\n if (value.show) {\n length++;\n }\n });\n }\n return length;\n }\n public get3DLayersSize(filtertype: Tgroupfiltertype): number {\n const lowerType = filtertype.toLowerCase() as Tgroupfiltertype;\n let length = 0;\n if (lowerType === 'baselayers') {\n length = this.terrainLayerGroup.size;\n } else if (lowerType === 'layers') {\n length = this.tilesetLayerGroup.size;\n }\n return length;\n }\n\n public getVisible3DLayersSize(filtertype: Tgroupfiltertype): number {\n const lowerType = filtertype.toLowerCase() as Tgroupfiltertype;\n let length = 0;\n if (lowerType === 'baselayers') {\n this.terrainLayerGroup.forEach(value => {\n if (value) {\n length++;\n }\n });\n } else if (lowerType === 'layers') {\n this.tilesetLayerGroup.forEach(value => {\n if (value.show) {\n length++;\n }\n });\n }\n return length;\n }\n\n public set2DUkisLayers(layers: Array<Layer>, filtertype: Tgroupfiltertype) {\n const lowerType = filtertype.toLowerCase() as Tgroupfiltertype;\n const tempLayers: ImageryLayer[] = [];\n this.remove2DLayers(lowerType);\n\n layers.forEach((newLayer) => {\n const layerType = newLayer.type;\n if (layerType === 'geojson' || layerType === 'kml') {\n const dataSourceLayer = this.create_dataSource_layer(newLayer as VectorLayer);\n if (typeof dataSourceLayer !== 'undefined') {\n if (lowerType === 'baselayers') {\n this.baseLayerDataSourceGroup.set(newLayer.id, dataSourceLayer);\n } else if (lowerType === 'layers') {\n this.standardLayerDataSourceGroup.set(newLayer.id, dataSourceLayer);\n } else if (lowerType === 'overlays') {\n this.overlayLayerDataSourceGroup.set(newLayer.id, dataSourceLayer);\n }\n this.viewer.dataSources.add(dataSourceLayer);\n }\n } else {\n const layer = this.create_2D_layer(newLayer);\n // check if layer not undefined\n if (typeof layer !== 'undefined') {\n tempLayers.push(layer);\n let layerIndex = layers.indexOf(newLayer);\n // index must be greater than or equal to zero and less than or equal to the number of the layers.\n\n if (layerIndex > this.viewer.imageryLayers.length) {\n layerIndex = this.viewer.imageryLayers.length;\n }\n if (lowerType === 'baselayers') {\n this.baseLayerImageryGroup.set(newLayer.id, layer);\n } else if (lowerType === 'layers') {\n layerIndex += this.get2DImageryLayersSize('baselayers');\n this.standardLayerImageryGroup.set(newLayer.id, layer);\n } else if (lowerType === 'overlays') {\n layerIndex += (this.get2DImageryLayersSize('baselayers') + this.get2DImageryLayersSize('layers'));\n this.overlayLayerImageryGroup.set(newLayer.id, layer);\n }\n this.viewer.imageryLayers.add(layer, layerIndex);\n }\n }\n });\n }\n\n public set3DUkisLayers(layers: Array<Layer>, filtertype: Tgroupfiltertype) {\n const lowerType = filtertype.toLowerCase() as Tgroupfiltertype;\n this.remove3DLayers(lowerType);\n\n layers.forEach((newLayer) => {\n this.create_3D_layer(newLayer as CustomLayer);\n })\n }\n\n private create_2D_layer(newLayer: Layer) {\n let newImageryLayer!: ImageryLayer;\n switch (newLayer.type) {\n case XyzLayertype:\n newImageryLayer = this.create_xyz_layer(newLayer as RasterLayer);\n break;\n case WmsLayertype:\n newImageryLayer = this.create_wms_layer(newLayer as WmsLayer);\n break;\n case WmtsLayertype:\n newImageryLayer = this.create_wmts_layer(newLayer as WmtsLayer);\n break;\n case TmsLayertype:\n if (newLayer instanceof RasterLayer) {\n newImageryLayer = this.create_xyz_layer(newLayer as RasterLayer);\n break;\n } else if (newLayer instanceof VectorLayer) {\n newImageryLayer = this.create_tms_layer(newLayer as VectorLayer);\n break;\n } else {\n console.log('Not supportet layer type: ' + newLayer.type + ' layer: ' + newLayer.name);\n break;\n }\n /*\n case WfsLayertype:\n // WFS is currently (01/2023) not supported by Cesium\n break;\n */\n default:\n console.log('Not supportet layer type: ' + newLayer.type + ' layer: ' + newLayer.name);\n break;\n }\n\n return newImageryLayer;\n }\n\n private create_3D_layer(newLayer: CustomLayer) {\n\n if (newLayer.custom_layer instanceof CesiumTerrainProvider) {\n this.setTerrain(newLayer);\n } else if (newLayer.custom_layer instanceof EllipsoidTerrainProvider) {\n this.setTerrain(newLayer);\n } else if (newLayer.custom_layer instanceof Cesium3DTileset || newLayer.custom_layer instanceof I3SDataProvider) {\n this.create_3Dtileset_layer(newLayer);\n } else {\n console.log('Not supportet layer type: ' + newLayer.name);\n }\n\n }\n\n\n private create_xyz_layer(l: RasterLayer): ImageryLayer {\n let maxLevel = 20;\n let enablePopups = false;\n if (l.maxZoom) {\n maxLevel = l.maxZoom;\n }\n if (l.popup) {\n enablePopups = true;\n }\n const newImageryLayer = new ImageryLayer(\n new UrlTemplateImageryProvider({\n url: l.url,\n subdomains: l.subdomains,\n credit: l.attribution,\n maximumLevel: maxLevel,\n enablePickFeatures: enablePopups\n }),\n {\n show: l.visible,\n alpha: l.opacity\n });\n return newImageryLayer;\n }\n\n private create_wms_layer(l: WmsLayer): ImageryLayer {\n let defaultFormat = 'image/png';\n let maxLevel = 20;\n if (l.maxZoom) {\n maxLevel = l.maxZoom;\n }\n if (l.params.FORMAT) {\n defaultFormat = l.params.FORMAT;\n }\n let wmsOptions = {} as WebMapServiceImageryProvider.ConstructorOptions;\n if (l.bbox) {\n wmsOptions.rectangle = Rectangle.fromDegrees(l.bbox[0], l.bbox[1], l.bbox[2], l.bbox[3]);\n }\n wmsOptions = {\n url: l.url,\n credit: l.attribution,\n layers: l.params.LAYERS,\n parameters: { transparent: l.params.TRANSPARENT, format: defaultFormat, tiled: l.params.TILED },\n maximumLevel: maxLevel,\n srs: this.EPSG,\n tilingScheme: new WebMercatorTilingScheme()\n }\n\n if (l.params.TIME) {\n wmsOptions.clock = this.viewer.clock;\n wmsOptions.times = this.cesiumTimeInterval;\n }\n\n if (l.popup) {\n wmsOptions.enablePickFeatures = true;\n } else {\n wmsOptions.enablePickFeatures = false;\n }\n\n const newImageryLayer = new ImageryLayer(\n new WebMapServiceImageryProvider(wmsOptions),\n {\n show: l.visible,\n alpha: l.opacity\n });\n return newImageryLayer;\n }\n\n private create_wmts_layer(l: WmtsLayer): ImageryLayer {\n let maxLevel = 16;\n if (l.maxZoom) {\n let maxLevel = l.maxZoom;\n }\n const matrixOptions = l.params.matrixSetOptions as IListMatrixSet;\n let wmtsOptions = {} as WebMapTileServiceImageryProvider.ConstructorOptions;\n if (matrixOptions.matrixIds) {\n wmtsOptions = {\n url: l.url,\n credit: l.attribution,\n layer: l.params.layer,\n style: l.params.style,\n format: l.params.format,\n tileMatrixSetID: matrixOptions.matrixSet,\n tileMatrixLabels: matrixOptions.matrixIds,\n maximumLevel: matrixOptions.matrixIds.length - 1\n };\n } else {\n wmtsOptions = {\n url: l.url,\n credit: l.attribution,\n layer: l.params.layer,\n style: l.params.style,\n format: l.params.format,\n tileMatrixSetID: this.EPSG,\n tileMatrixLabels: Array(maxLevel + 1).fill(null).map((e, i) => this.EPSG + ':' + i),\n maximumLevel: maxLevel\n };\n }\n if (l.bbox) {\n wmtsOptions.rectangle = Rectangle.fromDegrees(l.bbox[0], l.bbox[1], l.bbox[2], l.bbox[3]);\n }\n if (l.popup) {\n //Not supported by cesium as 07/2024, https://cesium.com/learn/cesiumjs/ref-doc/WebMapTileServiceImageryProvider.html#pickFeatures\n }\n const newImageryLayer = new ImageryLayer(\n new WebMapTileServiceImageryProvider(wmtsOptions),\n {\n show: l.visible,\n alpha: l.opacity\n });\n return newImageryLayer;\n }\n\n private create_tms_layer(l: VectorLayer): ImageryLayer {\n const constructorOptions = {\n url: l.url,\n fileExtension: 'png',\n maximumLevel: l.maxZoom,\n minimumLevel: l.minZoom\n } as TileMapServiceImageryProvider.ConstructorOptions;\n\n if (l.attribution) {\n constructorOptions.credit = new Credit(l.attribution);\n }\n\n const tmsImageryProvider = new TileMapServiceImageryProvider(constructorOptions);\n\n const imageryOptions = {\n show: l.visible,\n alpha: l.opacity\n };\n\n return new ImageryLayer(tmsImageryProvider, imageryOptions);\n }\n\n private create_dataSource_layer(l: VectorLayer): DataSource {\n let newDataSource;\n if (l.type === 'geojson') {\n newDataSource = this.create_geojson_layer(l);\n } else if (l.type === 'kml') {\n newDataSource = this.create_kml_layer(l);\n }\n return newDataSource as DataSource;\n }\n\n private create_geojson_layer(l: VectorLayer): GeoJsonDataSource {\n const newGeoJsonDataSource = new GeoJsonDataSource();\n // default UKIS values\n let fillColor = Color.fromCssColorString('#FFFFFF99');\n let strokeColor = Color.fromCssColorString('#3399CC');\n let strokeWidth = 1;\n let clamp = false;\n\n if(l.options && l.options.style){\n const styleProperties = l.options.style(l.data)[0];\n if(styleProperties){\n fillColor = Color.fromCssColorString(styleProperties.fill_.color_) || fillColor;\n strokeColor = Color.fromCssColorString(styleProperties.stroke_.color_) || strokeColor;\n strokeWidth = styleProperties.stroke_.width_ || strokeWidth;\n }\n if(l.options['clampToGround']){\n clamp = l.options['clampToGround'];\n }\n }\n const dataSourceOptions = {\n // as Cesium cannot handle an opacity for the whole datasource, we need to modify the layer opacity,\n // in case the cesium color already has an opacity value\n fill: fillColor.withAlpha(l.opacity*fillColor.alpha),\n stroke: strokeColor.withAlpha(l.opacity*strokeColor.alpha),\n strokeWidth: strokeWidth,\n clampToGround: clamp\n } as GeoJsonDataSource.LoadOptions;\n\n if (l.attribution) {\n dataSourceOptions.credit = new Credit(l.attribution);\n }\n\n newGeoJsonDataSource.load(l.data, dataSourceOptions).then(function(){\n let i = 0;\n const entityArray = newGeoJsonDataSource.entities.values;\n //check if vector data has icon features and set the icon graphic accordingly\n entityArray.forEach(entity => {\n if(l.data['features'] && l.data['features'][i]['properties'] && l.data['features'][i]['properties']['iconUrl']){\n entity.billboard = new BillboardGraphics({\n image: l.data['features'][i]['properties']['iconUrl'],\n width: 20,\n height: 20\n });\n entity.description = l.data['features'][i]['properties']['id'];\n }\n i++;\n });\n });\n newGeoJsonDataSource.show = l.visible;\n newGeoJsonDataSource.name = l.name;\n\n this.dataSourceOpacity.set(l.id, l.opacity);\n return newGeoJsonDataSource;\n }\n\n private create_kml_layer(l: VectorLayer): KmlDataSource {\n const newKmlDataSource = new KmlDataSource();\n\n const dataSourceOptions = {} as KmlDataSource.ConstructorOptions;\n if (l.attribution) {\n dataSourceOptions.credit = new Credit(l.attribution);\n }\n newKmlDataSource.load(l.data, dataSourceOptions);\n newKmlDataSource.show = l.visible;\n newKmlDataSource.name = l.id;\n return newKmlDataSource;\n }\n\n public getLayerById(id: string, filtertype: Tgroupfiltertype): ImageryLayer | DataSource | undefined {\n const lowerType = filtertype.toLowerCase() as Tgroupfiltertype;\n let wantedLayer;\n if (lowerType === 'baselayers') {\n if (this.baseLayerImageryGroup.has(id)) {\n wantedLayer = this.baseLayerImageryGroup.get(id);\n } else if(this.baseLayerDataSourceGroup.has(id)){\n wantedLayer = this.baseLayerDataSourceGroup.get(id);\n }\n } else if (lowerType === 'layers') {\n if (this.standardLayerImageryGroup.has(id)) {\n wantedLayer = this.standardLayerImageryGroup.get(id);\n } else if(this.standardLayerDataSourceGroup.has(id)){\n wantedLayer = this.standardLayerDataSourceGroup.get(id);\n }\n } else if (lowerType === 'overlays') {\n if (this.overlayLayerImageryGroup.has(id)) {\n wantedLayer = this.overlayLayerImageryGroup.get(id);\n } else if(this.overlayLayerDataSourceGroup.has(id)){\n wantedLayer = this.overlayLayerDataSourceGroup.get(id);\n }\n }\n return wantedLayer;\n }\n\n public removeAll2DLayers() {\n let IDs = Array.from(this.baseLayerImageryGroup.keys());\n this.remove2DLayer(IDs, 'baselayers');\n IDs = Array.from(this.standardLayerImageryGroup.keys());\n this.remove2DLayer(IDs, 'layers');\n IDs = Array.from(this.overlayLayerImageryGroup.keys());\n this.remove2DLayer(IDs, 'overlays');\n IDs = Array.from(this.baseLayerDataSourceGroup.keys());\n this.remove2DLayer(IDs, 'baselayers');\n IDs = Array.from(this.standardLayerDataSourceGroup.keys());\n this.remove2DLayer(IDs, 'layers');\n IDs = Array.from(this.overlayLayerDataSourceGroup.keys());\n this.remove2DLayer(IDs, 'overlays');\n }\n\n public remove2DLayers(filtertype: Tgroupfiltertype) {\n const lowerType = filtertype.toLowerCase() as Tgroupfiltertype;\n if (lowerType === 'baselayers') {\n let IDs = Array.from(this.baseLayerImageryGroup.keys());\n this.remove2DLayer(IDs, 'baselayers');\n IDs = Array.from(this.baseLayerDataSourceGroup.keys());\n this.remove2DLayer(IDs, 'baselayers');\n } else if (lowerType === 'layers') {\n let IDs = Array.from(this.standardLayerImageryGroup.keys());\n this.remove2DLayer(IDs, 'layers');\n IDs = Array.from(this.standardLayerDataSourceGroup.keys());\n this.remove2DLayer(IDs, 'layers');\n } else if (lowerType === 'overlays') {\n let IDs = Array.from(this.overlayLayerImageryGroup.keys());\n this.remove2DLayer(IDs, 'overlays');\n IDs = Array.from(this.overlayLayerDataSourceGroup.keys());\n this.remove2DLayer(IDs, 'overlays');\n }\n }\n\n public remove2DLayer(layerId: string[], filtertype: Tgroupfiltertype) {\n const lowerType = filtertype.toLowerCase() as Tgroupfiltertype;\n if (lowerType === 'baselayers') {\n layerId.forEach(id => {\n if (this.baseLayerImageryGroup.has(id)) {\n this.viewer.imageryLayers.remove(this.baseLayerImageryGroup.get(id)!);\n this.baseLayerImageryGroup.delete(id);\n } else if (this.baseLayerDataSourceGroup.has(id)) {\n this.viewer.dataSources.remove(this.baseLayerDataSourceGroup.get(id)!);\n this.baseLayerDataSourceGroup.delete(id);\n if (this.dataSourceOpacity.has(id)) {\n this.dataSourceOpacity.delete(id);\n }\n }\n });\n } else if (lowerType === 'layers') {\n layerId.forEach(id => {\n if (this.standardLayerImageryGroup.has(id)) {\n this.viewer.imageryLayers.remove(this.standardLayerImageryGroup.get(id)!);\n this.standardLayerImageryGroup.delete(id);\n } else if (this.standardLayerDataSourceGroup.has(id)) {\n this.viewer.dataSources.remove(this.standardLayerDataSourceGroup.get(id)!);\n this.standardLayerDataSourceGroup.delete(id);\n if (this.dataSourceOpacity.has(id)) {\n this.dataSourceOpacity.delete(id);\n }\n }\n });\n } else if (lowerType === 'overlays') {\n layerId.forEach(id => {\n if (this.overlayLayerImageryGroup.has(id)) {\n this.viewer.imageryLayers.remove(this.overlayLayerImageryGroup.get(id)!);\n this.overlayLayerImageryGroup.delete(id);\n } else if (this.overlayLayerDataSourceGroup.has(id)) {\n this.viewer.dataSources.remove(this.overlayLayerDataSourceGroup.get(id)!);\n this.overlayLayerDataSourceGroup.delete(id);\n if (this.dataSourceOpacity.has(id)) {\n this.dataSourceOpacity.delete(id);\n }\n }\n });\n }\n\n }\n\n public removeAll3DLayers() {\n let IDs = Array.from(this.terrainLayerGroup.keys());\n this.remove3DLayer(IDs, 'baselayers');\n IDs = Array.from(this.tilesetLayerGroup.keys());\n this.remove3DLayer(IDs, 'layers');\n }\n\n public remove3DLayers(filtertype: Tgroupfiltertype) {\n const lowerType = filtertype.toLowerCase() as Tgroupfiltertype;\n if (lowerType === 'baselayers') {\n const IDs = Array.from(this.terrainLayerGroup.keys());\n this.remove3DLayer(IDs, 'baselayers');\n } else if (lowerType === 'layers') {\n const IDs = Array.from(this.tilesetLayerGroup.keys());\n this.remove3DLayer(IDs, 'layers');\n this.tilesetLayerGroup.clear();\n }\n }\n\n public remove3DLayer(layerId: string[], filtertype: Tgroupfiltertype) {\n const lowerType = filtertype.toLowerCase() as Tgroupfiltertype;\n if (lowerType === 'baselayers') {\n layerId.forEach(id => {\n if (this.terrainLayerGroup.has(id)) {\n this.removeTerrain()\n this.terrainLayerGroup.delete(id);\n }\n });\n } else if (lowerType === 'layers') {\n layerId.forEach(id => {\n if (this.tilesetLayerGroup.has(id)) {\n const temp = this.viewer.scene.primitives.remove(this.tilesetLayerGroup.get(id)!);\n this.tilesetLayerGroup.delete(id);\n }\n });\n }\n }\n\n public update2DLayerOpacity(layers: Layer[], filtertype: Tgroupfiltertype) {\n const lowerType = filtertype.toLowerCase() as Tgroupfiltertype;\n\n if (lowerType === 'baselayers') {\n for (const layer of layers) {\n if (this.baseLayerImageryGroup.has(layer.id)) {\n const viewerLayer = this.baseLayerImageryGroup.get(layer.id);\n if (viewerLayer && viewerLayer.alpha !== layer.opacity) {\n viewerLayer.alpha = layer.opacity;\n }\n } else if (this.baseLayerDataSourceGroup.has(layer.id)) {\n //only set new datasource, if opacity has changed\n if (this.dataSourceOpacity.get(layer.id) != layer.opacity) {\n const oldDataSourceLayer = this.baseLayerDataSourceGroup.get(layer.id) as DataSource;\n this.viewer.dataSources.remove(oldDataSourceLayer);\n const newDataSourceLayer = this.create_dataSource_layer(layer as VectorLayer);\n this.viewer.dataSources.add(newDataSourceLayer);\n this.baseLayerDataSourceGroup.set(layer.id, newDataSourceLayer);\n this.dataSourceOpacity.set(layer.id, layer.opacity);\n }\n }\n }\n } else if (lowerType === 'layers') {\n for (const layer of layers) {\n if (this.standardLayerImageryGroup.has(layer.id)) {\n const viewerLayer = this.standardLayerImageryGroup.get(layer.id);\n\n if (viewerLayer && viewerLayer.alpha !== layer.opacity) {\n viewerLayer.alpha = layer.opacity;\n }\n } else if (this.standardLayerDataSourceGroup.has(layer.id)) {\n //only set new datasource, if opacity has changed\n if (this.dataSourceOpacity.get(layer.id) != layer.opacity) {\n const oldDataSourceLayer = this.standardLayerDataSourceGroup.get(layer.id) as DataSource;\n this.viewer.dataSources.remove(oldDataSourceLayer);\n const newDataSourceLayer = this.create_dataSource_layer(layer as VectorLayer);\n this.viewer.dataSources.add(newDataSourceLayer);\n this.standardLayerDataSourceGroup.set(layer.id, newDataSourceLayer);\n this.dataSourceOpacity.set(layer.id, layer.opacity);\n }\n }\n }\n } else if (lowerType === 'overlays') {\n for (const layer of layers) {\n if (this.overlayLayerImageryGroup.has(layer.id)) {\n const viewerLayer = this.overlayLayerImageryGroup.get(layer.id);\n\n if (viewerLayer && viewerLayer.alpha !== layer.opacity) {\n viewerLayer.alpha = layer.opacity;\n }\n } else if (this.overlayLayerDataSourceGroup.has(layer.id)) {\n //only set new datasource, if opacity has changed\n if (this.dataSourceOpacity.get(layer.id) != layer.opacity) {\n const oldDataSourceLayer = this.overlayLayerDataSourceGroup.get(layer.id) as DataSource;\n this.viewer.dataSources.remove(oldDataSourceLayer);\n const newDataSourceLayer = this.create_dataSource_layer(layer as VectorLayer);\n this.viewer.dataSources.add(newDataSourceLayer);\n this.overlayLayerDataSourceGroup.set(layer.id, newDataSourceLayer);\n this.dataSourceOpacity.set(layer.id, layer.opacity);\n }\n }\n }\n }\n }\n\n public update2DLayerVisibility(layers: Layer[], filtertype: Tgroupfiltertype) {\n const lowerType = filtertype.toLowerCase() as Tgroupfiltertype;\n for (const layer of layers) {\n if (layer.type === 'geojson' || layer.type === 'kml') {\n if (lowerType === 'baselayers') {\n const dataSourceLayer = this.baseLayerDataSourceGroup.get(layer.id);\n if (dataSourceLayer && dataSourceLayer.show !== layer.visible) {\n dataSourceLayer.show = layer.visible;\n }\n } else if (lowerType === 'layers') {\n const dataSourceLayer = this.standardLayerDataSourceGroup.get(layer.id);\n if (dataSourceLayer && dataSourceLayer.show !== layer.visible) {\n dataSourceLayer.show = layer.visible;\n }\n } else if (lowerType === 'overlays') {\n const dataSourceLayer = this.overlayLayerDataSourceGroup.get(layer.id);\n if (dataSourceLayer && dataSourceLayer.show !== layer.visible) {\n dataSourceLayer.show = layer.visible;\n }\n }\n } else {\n if (lowerType === 'baselayers') {\n if (this.baseLayerImageryGroup.has(layer.id)) {\n const viewerLayer = this.baseLayerImageryGroup.get(layer.id);\n\n if (viewerLayer && viewerLayer.show !== layer.visible) {\n viewerLayer.show = layer.visible;\n }\n }\n } else if (lowerType === 'layers') {\n if (this.standardLayerImageryGroup.has(layer.id)) {\n const viewerLayer = this.standardLayerImageryGroup.get(layer.id);\n if (viewerLayer && viewerLayer.show !== layer.visible) {\n viewerLayer.show = layer.visible;\n }\n }\n } else if (lowerType === 'overlays') {\n if (this.overlayLayerImageryGroup.has(layer.id)) {\n const viewerLayer = this.overlayLayerImageryGroup.get(layer.id);\n\n if (viewerLayer && viewerLayer.show !== layer.visible) {\n viewerLayer.show = layer.visible;\n }\n }\n }\n }\n }\n\n }\n\n public update2DLayerZIndex(layers: Layer[], filtertype: Tgroupfiltertype) {\n const lowerType = filtertype.toLowerCase() as Tgroupfiltertype;\n const layerCollection = this.viewer.imageryLayers;\n\n if (lowerType === 'baselayers') {\n for (const layer of layers) {\n if (this.baseLayerImageryGroup.has(layer.id)) {\n const viewerLayer = this.baseLayerImageryGroup.get(layer.id);\n if (viewerLayer) {\n const cesiumIndex = layerCollection.indexOf(viewerLayer);\n const layerIndex = layers.indexOf(layer);\n if (cesiumIndex !== layerIndex) {\n const diffIndex = cesiumIndex - layerIndex;\n if (diffIndex < 0) {\n // Move layer up in collection\n for (let i = 0; i < Math.abs(diffIndex); i++) {\n layerCollection.raise(viewerLayer);\n }\n } else if (diffIndex > 0) {\n // Move layer down in collection\n for (let i = 0; i < Math.abs(diffIndex); i++) {\n layerCollection.lower(viewerLayer);\n }\n }\n }\n }\n }\n }\n } else if (lowerType === 'layers') {\n for (const layer of layers) {\n if (this.standardLayerImageryGroup.has(layer.id)) {\n const viewerLayer = this.standardLayerImageryGroup.get(layer.id);\n if (viewerLayer) {\n const cesiumIndex = layerCollection.indexOf(viewerLayer);\n const layerIndex = layers.indexOf(layer) + this.get2DImageryLayersSize('baselayers');\n //console.log('CesiumIndex: '+ cesiumIndex);\n //console.log('LayerIndex: '+ layerIndex);\n if (cesiumIndex !== layerIndex) {\n const diffIndex = cesiumIndex - layerIndex;\n if (diffIndex < 0) {\n // Move layer up in collection\n for (let i = 0; i < Math.abs(diffIndex); i++) {\n layerCollection.raise(viewerLayer);\n }\n } else if (diffIndex > 0) {\n // Move layer down in collection\n for (let i = 0; i < Math.abs(diffIndex); i++) {\n layerCollection.lower(viewerLayer);\n }\n }\n }\n }\n }\n }\n } else if (lowerType === 'overlays') {\n for (const layer of layers) {\n if (this.overlayLayerImageryGroup.has(layer.id)) {\n const viewerLayer = this.overlayLayerImageryGroup.get(layer.id);\n if (viewerLayer) {\n const cesiumIndex = layerCollection.indexOf(viewerLayer);\n const layerIndex = layers.indexOf(layer) + this.get2DImageryLayersSize('baselayers') + this.get2DImageryLayersSize('layers');\n if (cesiumIndex !== layerIndex) {\n const diffIndex = cesiumIndex - layerIndex;\n if (diffIndex < 0) {\n // Move layer up in collection\n for (let i = 0; i < Math.abs(diffIndex); i++) {\n layerCollection.raise(viewerLayer);\n }\n } else if (diffIndex > 0) {\n // Move layer down in collection\n for (let i = 0; i < Math.abs(diffIndex); i++) {\n layerCollection.lower(viewerLayer);\n }\n }\n }\n }\n }\n }\n }\n\n }\n\n public updateDataSourceZIndex(layers: Layer[], filtertype: Tgroupfiltertype) {\n const dataSourceCollection = this.viewer.dataSources;\n if(dataSourceCollection.length>1){\n const lowerType = filtertype.toLowerCase() as Tgroupfiltertype;\n if (lowerType === 'baselayers') {\n for (const layer of layers) {\n if (this.baseLayerDataSourceGroup.has(layer.id)) {\n const viewerLayer = this.baseLayerDataSourceGroup.get(layer.id);\n if (viewerLayer) {\n const cesiumIndex = dataSourceCollection.indexOf(viewerLayer);\n const layerIndex = layers.indexOf(layer);\n if (cesiumIndex !== layerIndex && cesiumIndex >= 0) {\n const diffIndex = cesiumIndex - layerIndex;\n if (diffIndex < 0) {\n // Move layer up in collection\n for (let i = 0; i < Math.abs(diffIndex); i++) {\n dataSourceCollection.raise(viewerLayer);\n }\n } else if (diffIndex > 0) {\n // Move layer down in collection\n for (let i = 0; i < Math.abs(diffIndex); i++) {\n dataSourceCollection.lower(viewerLayer);\n }\n }\n }\n }\n }\n }\n } else if (lowerType === 'layers') {\n for (const layer of layers) {\n if (this.standardLayerDataSourceGroup.has(layer.id)) {\n const viewerLayer = this.standardLayerDataSourceGroup.get(layer.id);\n if (viewerLayer) {\n const cesiumIndex = dataSourceCollection.indexOf(viewerLayer);\n const layerIndex = layers.indexOf(layer) + this.getDataSourceLayersSize('baselayers');\n if (cesiumIndex !== layerIndex && cesiumIndex >= 0) {\n const diffIndex = cesiumIndex - layerIndex;\n if (diffIndex < 0) {\n // Move layer up in collection\n for (let i = 0; i < Math.abs(diffIndex); i++) {\n dataSourceCollection.raise(viewerLayer);\n }\n } else if (diffIndex > 0) {\n // Move layer down in collection\n for (let i = 0; i < Math.abs(diffIndex); i++) {\n dataSourceCollection.lower(viewerLayer);\n }\n }\n }\n }\n }\n }\n } else if (lowerType === 'overlays') {\n for (const layer of layers) {\n if (this.overlayLayerDataSourceGroup.has(layer.id)) {\n const viewerLayer = this.overlayLayerDataSourceGroup.get(layer.id);\n if (viewerLayer) {\n const cesiumIndex = dataSourceCollection.indexOf(viewerLayer);\n const layerIndex = layers.indexOf(layer) + this.getDataSourceLayersSize('baselayers') + this.getDataSourceLayersSize('layers');\n if (cesiumIndex !== layerIndex && cesiumIndex >= 0){\n const diffIndex = cesiumIndex - layerIndex;\n if (diffIndex < 0) {\n // Move layer up in collection\n for (let i = 0; i < Math.abs(diffIndex); i++) {\n dataSourceCollection.raise(viewerLayer);\n }\n } else if (diffIndex > 0) {\n // Move layer down in collection\n for (let i = 0; i < Math.abs(diffIndex); i++) {\n dataSourceCollection.lower(viewerLayer);\n }\n }\n }\n }\n }\n }\n }\n }\n }\n\n\n //Adding terrain provider from Layer\n public setTerrain(terrainLayer: CustomLayer) {\n if (terrainLayer.visible) {\n this.viewer.terrainProvider = terrainLayer.custom_layer;\n }\n this.terrainLayerGroup.set(terrainLayer.id, terrainLayer.visible);\n }\n\n public setDefaultTerrain() {\n this.viewer.terrainProvider = new EllipsoidTerrainProvider();\n }\n\n public removeTerrain() {\n this.viewer.terrainProvider = new EllipsoidTerrainProvider({});\n }\n\n private create_3Dtileset_layer(tilesetLayer: CustomLayer) {\n try {\n const new_tileset_layer = this.viewer.scene.primitives.add(tilesetLayer.custom_layer);\n if (new_tileset_layer.style == undefined) {\n new_tileset_layer.style = new Cesium3DTileStyle({\n \"show\": \"true\",\n \"color\": \"color('white',\" + tilesetLayer.opacity + \")\"\n });\n }\n new_tileset_layer.credit = new Credit(tilesetLayer.attribution!);\n\n //set the luminance of the tileset. A high value reduces the day/night sun based lighting effect. Default value is 0.2\n if(tilesetLayer.custom_layer.imageBasedLighting){\n new_tileset_layer.imageBasedLighting.luminanceAtZenith = tilesetLayer.custom_layer.imageBasedLighting.luminanceAtZenith;\n }\n\n this.tilesetLayerGroup.set(tilesetLayer.id, new_tileset_layer);\n } catch (error) {\n console.log(`There was an error creating the 3D Data Provider: ${error}`);\n }\n\n }\n\n private dataCallback(interval: { stop: JulianDate; start: JulianDate; }, index: number) {\n let time;\n if (index === 0) {\n time = JulianDate.toIso8601(interval.stop);\n } else {\n time = JulianDate.toIso8601(interval.start);\n }\n\n return {\n Time: time\n };\n }\n\n public update3DLayerVisibility(layers: Layer[], filtertype: Tgroupfiltertype) {\n const lowerType = filtertype.toLowerCase() as Tgroupfiltertype;\n for (const layer of layers) {\n if (lowerType === 'baselayers') {\n const customLayer = layer as CustomLayer;\n if (customLayer.custom_layer instanceof CesiumTerrainProvider || customLayer.custom_layer instanceof EllipsoidTerrainProvider) {\n if (layer.visible) {\n this.removeTerrain();\n this.setTerrain(customLayer);\n }\n }\n } else if (lowerType === 'layers') {\n if (this.tilesetLayerGroup.has(layer.id)) {\n const tilesetLayer = this.tilesetLayerGroup.get(layer.id);\n if (tilesetLayer && tilesetLayer.show !== layer.visible) {\n tilesetLayer.show = layer.visible;\n }\n }\n }\n }\n }\n\n public update3DLayerOpacity(layers: Layer[], filtertype: Tgroupfiltertype) {\n const lowerType = filtertype.toLowerCase() as Tgroupfiltertype;\n for (const layer of layers) {\n if (lowerType === 'baselayers') {\n //not needed\n } else if (lowerType === 'layers') {\n\n const customLayer = layer as CustomLayer;\n if (customLayer.custom_layer instanceof Cesium3DTileset) {\n if (this.tilesetLayerGroup.has(layer.id)) {\n const viewerLayer = this.tilesetLayerGroup.get(layer.id);\n if (viewerLayer) {\n viewerLayer.style = new Cesium3DTileStyle({\n \"show\": \"true\",\n \"color\": \"color('lightgrey',\" + layer.opacity + \")\"\n });\n }\n }\n }\n }\n }\n }\n\n public initTime(startTime: string) {\n this.c