| /** | |||||
| * @Author: Caven | |||||
| * @Date: 2020-01-03 09:38:21 | |||||
| */ | |||||
| import { Util } from '@dc-modules/utils' | |||||
| import State from '@dc-modules/state/State' | |||||
| import { LayerEventType, OverlayEventType, LayerEvent } from '@dc-modules/event' | |||||
| import LayerType from './LayerType' | |||||
| const { Cesium } = DC.Namespace | |||||
| class Layer { | |||||
| constructor(id) { | |||||
| this._id = Util.uuid() | |||||
| this._bid = id || Util.uuid() | |||||
| this._delegate = undefined | |||||
| this._viewer = undefined | |||||
| this._state = undefined | |||||
| this._show = true | |||||
| this._cache = {} | |||||
| this._attr = {} | |||||
| this._layerEvent = new LayerEvent() | |||||
| this._layerEvent.on(LayerEventType.ADD, this._onAdd, this) | |||||
| this._layerEvent.on(LayerEventType.REMOVE, this._onRemove, this) | |||||
| this._state = undefined | |||||
| this.type = undefined | |||||
| } | |||||
| get layerId() { | |||||
| return this._id | |||||
| } | |||||
| get id() { | |||||
| return this._bid | |||||
| } | |||||
| get delegate() { | |||||
| return this._delegate | |||||
| } | |||||
| set show(show) { | |||||
| this._show = show | |||||
| this._delegate && (this._delegate.show = this._show) | |||||
| } | |||||
| get show() { | |||||
| return this._show | |||||
| } | |||||
| get layerEvent() { | |||||
| return this._layerEvent | |||||
| } | |||||
| set attr(attr) { | |||||
| this._attr = attr | |||||
| } | |||||
| get attr() { | |||||
| return this._attr | |||||
| } | |||||
| get state() { | |||||
| return this._state | |||||
| } | |||||
| /** | |||||
| * The hook for added | |||||
| * @private | |||||
| */ | |||||
| _addedHook() {} | |||||
| /** | |||||
| * The hook for removed | |||||
| * @private | |||||
| */ | |||||
| _removedHook() {} | |||||
| /** | |||||
| * The layer added callback function | |||||
| * Subclasses need to be overridden | |||||
| * @param viewer | |||||
| * @private | |||||
| */ | |||||
| _onAdd(viewer) { | |||||
| this._viewer = viewer | |||||
| if (!this._delegate) { | |||||
| return | |||||
| } | |||||
| if (this._delegate instanceof Cesium.PrimitiveCollection) { | |||||
| this._viewer.scene.primitives.add(this._delegate) | |||||
| } else { | |||||
| this._viewer.dataSources.add(this._delegate) | |||||
| } | |||||
| this._addedHook && this._addedHook() | |||||
| this._state = State.ADDED | |||||
| } | |||||
| /** | |||||
| * The layer added callback function | |||||
| * Subclasses need to be overridden | |||||
| * @private | |||||
| */ | |||||
| _onRemove() { | |||||
| if (!this._delegate) { | |||||
| return | |||||
| } | |||||
| if (this._viewer) { | |||||
| this._cache = {} | |||||
| if (this._delegate instanceof Cesium.PrimitiveCollection) { | |||||
| this._delegate.removeAll() | |||||
| this._viewer.scene.primitives.remove(this._delegate) | |||||
| } else if (this._delegate.then) { | |||||
| this._delegate.then(dataSource => { | |||||
| dataSource.entities.removeAll() | |||||
| }) | |||||
| this._viewer.dataSources.remove(this._delegate) | |||||
| } else { | |||||
| this._delegate.entities && this._delegate.entities.removeAll() | |||||
| this._viewer.dataSources.remove(this._delegate) | |||||
| } | |||||
| this._removedHook && this._removedHook() | |||||
| this._state = State.REMOVED | |||||
| } | |||||
| } | |||||
| /** | |||||
| * The layer add overlay | |||||
| * @param overlay | |||||
| * @private | |||||
| */ | |||||
| _addOverlay(overlay) { | |||||
| if ( | |||||
| overlay && | |||||
| overlay.overlayEvent && | |||||
| !this._cache.hasOwnProperty(overlay.overlayId) | |||||
| ) { | |||||
| overlay.overlayEvent.fire(OverlayEventType.ADD, this) | |||||
| this._cache[overlay.overlayId] = overlay | |||||
| if (this._state === State.CLEARED) { | |||||
| this._state = State.ADDED | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * The layer remove overlay | |||||
| * @param overlay | |||||
| * @private | |||||
| */ | |||||
| _removeOverlay(overlay) { | |||||
| if ( | |||||
| overlay && | |||||
| overlay.overlayEvent && | |||||
| this._cache.hasOwnProperty(overlay.overlayId) | |||||
| ) { | |||||
| overlay.overlayEvent.fire(OverlayEventType.REMOVE, this) | |||||
| delete this._cache[overlay.overlayId] | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Add overlay | |||||
| * @param overlay | |||||
| * @returns {Layer} | |||||
| */ | |||||
| addOverlay(overlay) { | |||||
| this._addOverlay(overlay) | |||||
| return this | |||||
| } | |||||
| /** | |||||
| * Add overlays | |||||
| * @param overlays | |||||
| * @returns {Layer} | |||||
| */ | |||||
| addOverlays(overlays) { | |||||
| if (Array.isArray(overlays)) { | |||||
| overlays.forEach(item => { | |||||
| this._addOverlay(item) | |||||
| }) | |||||
| } | |||||
| return this | |||||
| } | |||||
| /** | |||||
| * Remove overlay | |||||
| * @param overlay | |||||
| * @returns {Layer} | |||||
| */ | |||||
| removeOverlay(overlay) { | |||||
| this._removeOverlay(overlay) | |||||
| return this | |||||
| } | |||||
| /** | |||||
| * Returns the overlay by overlayId | |||||
| * @param overlayId | |||||
| * @returns {*|undefined} | |||||
| */ | |||||
| getOverlay(overlayId) { | |||||
| return this._cache[overlayId] || undefined | |||||
| } | |||||
| /** | |||||
| * Returns the overlay by bid | |||||
| * @param id | |||||
| * @returns {any} | |||||
| */ | |||||
| getOverlayById(id) { | |||||
| let overlay = undefined | |||||
| Object.keys(this._cache).forEach(key => { | |||||
| if (this._cache[key].id === id) { | |||||
| overlay = this._cache[key] | |||||
| } | |||||
| }) | |||||
| return overlay | |||||
| } | |||||
| /** | |||||
| * Returns the overlays by attrName and AttrVal | |||||
| * @param attrName | |||||
| * @param attrVal | |||||
| * @returns {[]} | |||||
| */ | |||||
| getOverlaysByAttr(attrName, attrVal) { | |||||
| let result = [] | |||||
| this.eachOverlay(item => { | |||||
| if (item.attr[attrName] === attrVal) { | |||||
| result.push(item) | |||||
| } | |||||
| }, this) | |||||
| return result | |||||
| } | |||||
| /** | |||||
| * Iterate through each overlay and pass it as an argument to the callback function | |||||
| * @param method | |||||
| * @param context | |||||
| * @returns {Layer} | |||||
| */ | |||||
| eachOverlay(method, context) { | |||||
| Object.keys(this._cache).forEach(key => { | |||||
| method && method.call(context || this, this._cache[key]) | |||||
| }) | |||||
| return this | |||||
| } | |||||
| /** | |||||
| * Returns all overlays | |||||
| * @returns {[]} | |||||
| */ | |||||
| getOverlays() { | |||||
| let result = [] | |||||
| Object.keys(this._cache).forEach(key => { | |||||
| result.push(this._cache[key]) | |||||
| }) | |||||
| return result | |||||
| } | |||||
| /** | |||||
| * Clears all overlays | |||||
| * Subclasses need to be overridden | |||||
| */ | |||||
| clear() {} | |||||
| /** | |||||
| * Removes from the viewer | |||||
| */ | |||||
| remove() { | |||||
| if (this._viewer) { | |||||
| this._viewer.removeLayer(this) | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Adds to the viewer | |||||
| * @param viewer | |||||
| * @returns {Layer} | |||||
| */ | |||||
| addTo(viewer) { | |||||
| if (viewer && viewer.addLayer) { | |||||
| viewer.addLayer(this) | |||||
| } | |||||
| return this | |||||
| } | |||||
| /** | |||||
| * sets the style, the style will apply to every overlay of the layer | |||||
| * Subclasses need to be overridden | |||||
| * @param style | |||||
| */ | |||||
| setStyle(style) {} | |||||
| /** | |||||
| * Registers Type | |||||
| * @param type | |||||
| */ | |||||
| static registerType(type) { | |||||
| if (type) { | |||||
| LayerType[type.toLocaleUpperCase()] = type.toLocaleLowerCase() | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Returns type | |||||
| * @param type | |||||
| * @returns {*|undefined} | |||||
| */ | |||||
| static getLayerType(type) { | |||||
| return LayerType[type.toLocaleUpperCase()] || undefined | |||||
| } | |||||
| } | |||||
| export default Layer |
| /** | |||||
| * @Author: Caven | |||||
| * @Date: 2020-05-10 08:21:19 | |||||
| */ | |||||
| let LayerType = {} | |||||
| export default LayerType |
| /** | |||||
| * @Author: Caven | |||||
| * @Date: 2021-03-13 13:46:19 | |||||
| */ | |||||
| export { default as LayerType } from './LayerType' | |||||
| export { default as Layer } from './Layer' | |||||
| /** | |||||
| * types | |||||
| */ | |||||
| export { default as ClusterLayer } from './type/ClusterLayer' | |||||
| export { default as CzmlLayer } from './type/CzmlLayer' | |||||
| export { default as GeoJsonLayer } from './type/GeoJsonLayer' | |||||
| export { default as HeatLayer } from './type/HeatLayer' | |||||
| export { default as HtmlLayer } from './type/HtmlLayer' | |||||
| export { default as KmlLayer } from './type/KmlLayer' | |||||
| export { default as LabelLayer } from './type/LabelLayer' | |||||
| export { default as LayerGroup } from './type/LayerGroup' | |||||
| export { default as PrimitiveLayer } from './type/PrimitiveLayer' | |||||
| export { default as TilesetLayer } from './type/TilesetLayer' | |||||
| export { default as TopoJsonLayer } from './type/TopoJsonLayer' | |||||
| export { default as VectorLayer } from './type/VectorLayer' |
| /** | |||||
| * @Author: Caven | |||||
| * @Date: 2020-02-10 10:05:41 | |||||
| */ | |||||
| import State from '@dc-modules/state/State' | |||||
| import Layer from '../Layer' | |||||
| const { Cesium } = DC.Namespace | |||||
| const DEF_OPT = { | |||||
| size: 18, | |||||
| pixelRange: 40, | |||||
| gradient: { | |||||
| 0.0001: Cesium.Color.DEEPSKYBLUE, | |||||
| 0.001: Cesium.Color.GREEN, | |||||
| 0.01: Cesium.Color.ORANGE, | |||||
| 0.1: Cesium.Color.RED | |||||
| }, | |||||
| fontSize: 12, | |||||
| fontColor: Cesium.Color.BLACK, | |||||
| style: 'circle' | |||||
| } | |||||
| class ClusterLayer extends Layer { | |||||
| constructor(id, options = {}) { | |||||
| super(id) | |||||
| this._delegate = new Cesium.CustomDataSource(id) | |||||
| this._options = { | |||||
| ...DEF_OPT, | |||||
| ...options | |||||
| } | |||||
| this._delegate.clustering.enabled = true | |||||
| this._delegate.clustering.clusterEvent.addEventListener( | |||||
| this._clusterEventHandler, | |||||
| this | |||||
| ) | |||||
| this._delegate.clustering.pixelRange = this._options.pixelRange | |||||
| this.type = Layer.getLayerType('cluster') | |||||
| this._state = State.INITIALIZED | |||||
| } | |||||
| set enableCluster(enableCluster) { | |||||
| this._delegate.clustering.enabled = enableCluster | |||||
| return this | |||||
| } | |||||
| /** | |||||
| * | |||||
| * @param color | |||||
| * @param numLength | |||||
| * @returns {*} | |||||
| * @private | |||||
| */ | |||||
| _drawCircle(color, numLength) { | |||||
| let size = this._options.size * (numLength + 1) | |||||
| let key = color.toCssColorString() + '-' + size | |||||
| if (!this._cache[key]) { | |||||
| let canvas = document.createElement('canvas') | |||||
| canvas.width = size | |||||
| canvas.height = size | |||||
| let context2D = canvas.getContext('2d') | |||||
| context2D.save() | |||||
| context2D.scale(size / 24, size / 24) //Added to auto-generated code to scale up to desired size. | |||||
| context2D.fillStyle = color.withAlpha(0.2).toCssColorString() //Modified from auto-generated code. | |||||
| context2D.beginPath() | |||||
| context2D.arc(12, 12, 9, 0, 2 * Math.PI) | |||||
| context2D.closePath() | |||||
| context2D.fill() | |||||
| context2D.beginPath() | |||||
| context2D.arc(12, 12, 6, 0, 2 * Math.PI) | |||||
| context2D.fillStyle = color.toCssColorString() | |||||
| context2D.fill() | |||||
| context2D.closePath() | |||||
| context2D.restore() | |||||
| this._cache[key] = canvas.toDataURL() | |||||
| } | |||||
| return this._cache[key] | |||||
| } | |||||
| /** | |||||
| * | |||||
| * @param color | |||||
| * @param numLength | |||||
| * @returns {*} | |||||
| * @private | |||||
| */ | |||||
| _drawClustering(color, numLength) { | |||||
| let size = this._options.size * (numLength + 1) | |||||
| let key = color.toCssColorString() + '-' + size | |||||
| let startAngle = -Math.PI / 12 | |||||
| let angle = Math.PI / 2 | |||||
| let intervalAngle = Math.PI / 6 | |||||
| if (!this._cache[key]) { | |||||
| let canvas = document.createElement('canvas') | |||||
| canvas.width = size | |||||
| canvas.height = size | |||||
| let context2D = canvas.getContext('2d') | |||||
| context2D.save() | |||||
| context2D.scale(size / 24, size / 24) //Added to auto-generated code to scale up to desired size. | |||||
| context2D.beginPath() | |||||
| context2D.arc(12, 12, 6, 0, 2 * Math.PI) | |||||
| context2D.fillStyle = color.toCssColorString() | |||||
| context2D.fill() | |||||
| context2D.closePath() | |||||
| context2D.lineWidth = 2 | |||||
| for (let i = 0; i < 3; i++) { | |||||
| context2D.beginPath() | |||||
| context2D.arc(12, 12, 8, startAngle, startAngle + angle, false) | |||||
| context2D.strokeStyle = color.withAlpha(0.4).toCssColorString() | |||||
| context2D.stroke() | |||||
| context2D.arc(12, 12, 11, startAngle, startAngle + angle, false) | |||||
| context2D.strokeStyle = color.withAlpha(0.2).toCssColorString() | |||||
| context2D.stroke() | |||||
| context2D.closePath() | |||||
| startAngle = startAngle + angle + intervalAngle | |||||
| } | |||||
| context2D.restore() | |||||
| this._cache[key] = canvas.toDataURL() | |||||
| } | |||||
| return this._cache[key] | |||||
| } | |||||
| /** | |||||
| * | |||||
| * @param {*} clusteredEntities | |||||
| * @param {*} cluster | |||||
| */ | |||||
| _clusterEventHandler(clusteredEntities, cluster) { | |||||
| if (!this._delegate.clustering.enabled) { | |||||
| return | |||||
| } | |||||
| cluster.billboard.show = true | |||||
| cluster.label.font = `bold ${this._options.fontSize}px sans-serif` | |||||
| cluster.label.fillColor = this._options.fontColor | |||||
| cluster.label.disableDepthTestDistance = Number.POSITIVE_INFINITY | |||||
| if (this._delegate.entities.values.length) { | |||||
| let allCount = this._delegate.entities.values.length || 0 | |||||
| for (let key in this._options.gradient) { | |||||
| if (clusteredEntities.length >= allCount * key) { | |||||
| let numLength = String(clusteredEntities.length).length | |||||
| if (this._options.style === 'circle') { | |||||
| cluster.billboard.image = this._drawCircle( | |||||
| this._options.gradient[key], | |||||
| numLength | |||||
| ) | |||||
| } else { | |||||
| cluster.billboard.image = this._drawClustering( | |||||
| this._options.gradient[key], | |||||
| numLength | |||||
| ) | |||||
| } | |||||
| cluster.label.show = true | |||||
| if (numLength === 1) { | |||||
| cluster.label.pixelOffset = new Cesium.Cartesian2(-2, 3) | |||||
| } else { | |||||
| cluster.label.pixelOffset = new Cesium.Cartesian2( | |||||
| -5 * (numLength - 1), | |||||
| 5 | |||||
| ) | |||||
| } | |||||
| } else if (clusteredEntities.length <= 1) { | |||||
| cluster.label.show = false | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| clear() { | |||||
| this._delegate.entities.removeAll() | |||||
| this._cache = {} | |||||
| this._state = State.CLEARED | |||||
| return this | |||||
| } | |||||
| } | |||||
| Layer.registerType('cluster') | |||||
| export default ClusterLayer |
| /** | |||||
| * @Author: Caven | |||||
| * @Date: 2020-01-19 13:38:48 | |||||
| */ | |||||
| import State from '@dc-modules/state/State' | |||||
| import Layer from '../Layer' | |||||
| const { Cesium } = DC.Namespace | |||||
| class CzmlLayer extends Layer { | |||||
| constructor(id, url = '', options = {}) { | |||||
| super(id) | |||||
| this._delegate = Cesium.CzmlDataSource.load(url, options) | |||||
| this.type = Layer.getLayerType('czml') | |||||
| this._state = State.INITIALIZED | |||||
| } | |||||
| set show(show) { | |||||
| this._show = show | |||||
| this._delegate && | |||||
| this._delegate.then(dataSource => { | |||||
| dataSource.show = this._show | |||||
| }) | |||||
| } | |||||
| get show() { | |||||
| return this._show | |||||
| } | |||||
| /** | |||||
| * | |||||
| * @param method | |||||
| * @param context | |||||
| * @returns {CzmlLayer} | |||||
| */ | |||||
| eachOverlay(method, context) { | |||||
| if (this._delegate) { | |||||
| this._delegate.then(dataSource => { | |||||
| let entities = dataSource.entities.values | |||||
| entities.forEach(item => { | |||||
| method.call(context, item) | |||||
| }) | |||||
| }) | |||||
| return this | |||||
| } | |||||
| } | |||||
| } | |||||
| Layer.registerType('czml') | |||||
| export default CzmlLayer |
| /** | |||||
| * @Author: Caven | |||||
| * @Date: 2020-01-13 10:13:53 | |||||
| */ | |||||
| import State from '@dc-modules/state/State' | |||||
| import { Billboard, Polyline, Polygon, Model } from '@dc-modules/overlay' | |||||
| import Layer from '../Layer' | |||||
| import VectorLayer from './VectorLayer' | |||||
| const { Cesium } = DC.Namespace | |||||
| class GeoJsonLayer extends Layer { | |||||
| constructor(id, url, options = {}) { | |||||
| if (!url) { | |||||
| throw new Error('GeoJsonLayer:the url invalid') | |||||
| } | |||||
| super(id) | |||||
| this._delegate = Cesium.GeoJsonDataSource.load(url, options) | |||||
| this.type = Layer.getLayerType('geojson') | |||||
| this._state = State.INITIALIZED | |||||
| } | |||||
| set show(show) { | |||||
| this._show = show | |||||
| this._delegate && | |||||
| this._delegate.then(dataSource => { | |||||
| dataSource.show = this._show | |||||
| }) | |||||
| } | |||||
| get show() { | |||||
| return this._show | |||||
| } | |||||
| _createBillboard(entity) { | |||||
| if (entity.position && entity.billboard) { | |||||
| return Billboard.fromEntity(entity) | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Returns polyline Entity | |||||
| * @param entity | |||||
| * @returns {any} | |||||
| * @private | |||||
| */ | |||||
| _createPolyline(entity) { | |||||
| if (entity.polyline) { | |||||
| return Polyline.fromEntity(entity) | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Returns polygon Entity | |||||
| * @param entity | |||||
| * @returns {any} | |||||
| * @private | |||||
| */ | |||||
| _createPolygon(entity) { | |||||
| if (entity.polygon) { | |||||
| return Polygon.fromEntity(entity) | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Returns model Entity | |||||
| * @param entity | |||||
| * @param modelUrl | |||||
| * @returns {Model} | |||||
| * @private | |||||
| */ | |||||
| _createModel(entity, modelUrl) { | |||||
| if (entity) { | |||||
| return Model.fromEntity(entity, modelUrl) | |||||
| } | |||||
| } | |||||
| /** | |||||
| * | |||||
| * @param method | |||||
| * @param context | |||||
| * @returns {GeoJsonLayer} | |||||
| */ | |||||
| eachOverlay(method, context) { | |||||
| if (this._delegate) { | |||||
| this._delegate.then(dataSource => { | |||||
| let entities = dataSource.entities.values | |||||
| entities.forEach(item => { | |||||
| method.call(context, item) | |||||
| }) | |||||
| }) | |||||
| return this | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Converts to VectorLayer | |||||
| * @returns {VectorLayer} | |||||
| */ | |||||
| toVectorLayer() { | |||||
| let layer = new VectorLayer(this.id) | |||||
| this.eachOverlay(item => { | |||||
| if (item.billboard) { | |||||
| layer.addOverlay(this._createBillboard(item)) | |||||
| } else if (item.polyline) { | |||||
| layer.addOverlay(this._createPolyline(item)) | |||||
| } else if (item.polygon) { | |||||
| layer.addOverlay(this._createPolygon(item)) | |||||
| } | |||||
| }, this) | |||||
| return layer | |||||
| } | |||||
| /** | |||||
| * Converts to VectorLayer | |||||
| * @param modelUrl | |||||
| * @returns {VectorLayer} | |||||
| */ | |||||
| toModelLayer(modelUrl) { | |||||
| let layer = new VectorLayer(this.id) | |||||
| this.eachOverlay(item => { | |||||
| layer.addOverlay(this._createModel(item, modelUrl)) | |||||
| }, this) | |||||
| return layer | |||||
| } | |||||
| } | |||||
| Layer.registerType('geojson') | |||||
| export default GeoJsonLayer |
| /** | |||||
| * @Author: Caven | |||||
| * @Date: 2020-02-27 00:35:35 | |||||
| */ | |||||
| import State from '@dc-modules/state/State' | |||||
| import { SceneEventType } from '@dc-modules/event' | |||||
| import { Transform } from '@dc-modules/transform' | |||||
| import Position from '@dc-modules/position/Position' | |||||
| import { DomUtil, Util } from '@dc-modules/utils' | |||||
| import Layer from '../Layer' | |||||
| const { Cesium } = DC.Namespace | |||||
| const h337 = require('heatmap.js/build/heatmap.min') | |||||
| const DEF_OPTS = { | |||||
| maxOpacity: 0.8, // the maximum opacity used if not given in the heatmap options object | |||||
| minOpacity: 0.1, // the minimum opacity used if not given in the heatmap options object | |||||
| blur: 0.85, // the blur used if not given in the heatmap options object | |||||
| maxCanvasSize: 2000, | |||||
| minCanvasSize: 700, | |||||
| radius: 25, | |||||
| gradient: { | |||||
| '0.4': 'blue', | |||||
| '0.6': 'green', | |||||
| '0.8': 'yellow', | |||||
| '0.9': 'red' | |||||
| } | |||||
| } | |||||
| class HeatLayer extends Layer { | |||||
| constructor(id, options) { | |||||
| super(id) | |||||
| this._options = { | |||||
| ...DEF_OPTS, | |||||
| ...options | |||||
| } | |||||
| this._heat = undefined | |||||
| this._bounds = undefined | |||||
| this._mBounds = undefined | |||||
| this._scale = 1 | |||||
| this._positions = [] | |||||
| this._options.spacing = this._options.radius * 1.5 | |||||
| this._delegate = new Cesium.CustomDataSource(id) | |||||
| this._entity = new Cesium.Entity() | |||||
| this.type = Layer.getLayerType('heat') | |||||
| this._state = State.INITIALIZED | |||||
| } | |||||
| get options() { | |||||
| return this._options | |||||
| } | |||||
| /** | |||||
| * The hook for added | |||||
| */ | |||||
| _addedHook() { | |||||
| this._redraw() | |||||
| this._viewer.on(SceneEventType.CAMERA_MOVE_END, this._reset, this) | |||||
| } | |||||
| /** | |||||
| * The hook for removed | |||||
| */ | |||||
| _removedHook() { | |||||
| this._viewer.off(SceneEventType.CAMERA_MOVE_END, this._reset, this) | |||||
| } | |||||
| /** | |||||
| * | |||||
| * @param {*} position | |||||
| */ | |||||
| _transformWGS84ToHeatmap(position) { | |||||
| position = Transform.transformWGS84ToMercator(position) | |||||
| let coord = {} | |||||
| coord.x = Math.round( | |||||
| (position.lng - this._mBounds.west) / this._scale + this._options.spacing | |||||
| ) | |||||
| coord.y = Math.round( | |||||
| (position.lat - this._mBounds.south) / this._scale + this._options.spacing | |||||
| ) | |||||
| coord.y = this._heat._renderer.canvas.height - coord.y | |||||
| return coord | |||||
| } | |||||
| /** | |||||
| * | |||||
| * @returns {{east: *, south: *, north: *, west: *}} | |||||
| * @private | |||||
| */ | |||||
| _getMBounds() { | |||||
| let mWestSouth = Transform.transformWGS84ToMercator( | |||||
| new Position(this._bounds.west, this._bounds.south) | |||||
| ) | |||||
| let mEastNorth = Transform.transformWGS84ToMercator( | |||||
| new Position(this._bounds.east, this._bounds.north) | |||||
| ) | |||||
| return { | |||||
| west: mWestSouth.lng, | |||||
| south: mWestSouth.lat, | |||||
| east: mEastNorth.lng, | |||||
| north: mEastNorth.lat | |||||
| } | |||||
| } | |||||
| /** | |||||
| * | |||||
| * @private | |||||
| */ | |||||
| _initCanvas() { | |||||
| let diffLng = Math.abs(this._mBounds.east - this._mBounds.west) | |||||
| let diffLat = Math.abs(this._mBounds.north - this._mBounds.south) | |||||
| let max = Math.max(diffLng, diffLat) | |||||
| let min = Math.min(diffLng, diffLat) | |||||
| let scale = 1 | |||||
| if (max > this._options.maxCanvasSize) { | |||||
| scale = max / this._options.maxCanvasSize | |||||
| if (min / scale < this._options.minCanvasSize) { | |||||
| scale = min / this._options.minCanvasSize | |||||
| } | |||||
| } else if (min < this._options.minCanvasSize) { | |||||
| scale = min / this._options.minCanvasSize | |||||
| if (max / scale > this._options.maxCanvasSize) { | |||||
| scale = max / this._options.maxCanvasSize | |||||
| } | |||||
| } | |||||
| this._scale = scale | |||||
| if (!this._options.container) { | |||||
| this._options.container = DomUtil.create( | |||||
| 'div', | |||||
| 'heat-map', | |||||
| document.getElementsByClassName('dc-container')[0] | |||||
| ) | |||||
| } | |||||
| this._options.container.style.cssText = ` | |||||
| width:${diffLng / this._scale}px; | |||||
| height:${diffLat / this._scale}px; | |||||
| margin:0; | |||||
| display:none` | |||||
| if (!this._heat) { | |||||
| this._heat = h337.create(this._options) | |||||
| } else { | |||||
| this._heat.configure(this._options) | |||||
| } | |||||
| } | |||||
| /** | |||||
| * | |||||
| */ | |||||
| _initEntity() { | |||||
| let offset = this._options.spacing * this._scale | |||||
| this._mBounds.west -= offset | |||||
| this._mBounds.south -= offset | |||||
| this._mBounds.east += offset | |||||
| this._mBounds.north += offset | |||||
| let westSouth = Transform.transformMercatorToWGS84({ | |||||
| lng: this._mBounds.west, | |||||
| lat: this._mBounds.south | |||||
| }) | |||||
| let eastNorth = Transform.transformMercatorToWGS84({ | |||||
| lng: this._mBounds.east, | |||||
| lat: this._mBounds.north | |||||
| }) | |||||
| let bounds = Cesium.Rectangle.fromDegrees( | |||||
| westSouth.lng, | |||||
| westSouth.lat, | |||||
| eastNorth.lng, | |||||
| eastNorth.lat | |||||
| ) | |||||
| this._entity.show = false | |||||
| this._entity.rectangle = { | |||||
| coordinates: bounds, | |||||
| fill: false, | |||||
| distanceDisplayCondition: this._options.distanceDisplayCondition | |||||
| } | |||||
| this._delegate.entities.add(this._entity) | |||||
| } | |||||
| _reset() { | |||||
| let cameraHeight = Math.floor( | |||||
| this._viewer.camera.positionCartographic.height | |||||
| ) | |||||
| let radius = (1e4 / cameraHeight) * 60 | |||||
| if (radius < 10) { | |||||
| radius = 10 | |||||
| } | |||||
| if (radius > 60) { | |||||
| radius = 60 | |||||
| } | |||||
| this._options.radius = radius | |||||
| this._options.spacing = this._options.radius * 1.5 | |||||
| this._heat && this._heat.configure(this._options) | |||||
| } | |||||
| _redraw() { | |||||
| /** set bounds */ | |||||
| if (!this._bounds) { | |||||
| return false | |||||
| } | |||||
| let mBounds = this._getMBounds() | |||||
| if ( | |||||
| !this._mBounds || | |||||
| mBounds.west !== this._mBounds.west || | |||||
| mBounds.south !== this._mBounds.south || | |||||
| mBounds.east !== this._mBounds.east || | |||||
| mBounds.north !== this._mBounds.north | |||||
| ) { | |||||
| this._mBounds = mBounds | |||||
| this._initCanvas() | |||||
| } | |||||
| let data = [] | |||||
| this._positions.forEach(item => { | |||||
| let coord = this._transformWGS84ToHeatmap({ | |||||
| lng: item.lng || item.x, | |||||
| lat: item.lat || item.y | |||||
| }) | |||||
| data.push({ | |||||
| x: coord.x, | |||||
| y: coord.y, | |||||
| value: item.value || 1 | |||||
| }) | |||||
| }) | |||||
| this._heat.setData({ | |||||
| min: 0, | |||||
| max: 1, | |||||
| data | |||||
| }) | |||||
| this._delegate.entities.remove(this._entity) | |||||
| this._initEntity() | |||||
| let material = new Cesium.ImageMaterialProperty({ | |||||
| image: this._heat._renderer.canvas, | |||||
| transparent: true | |||||
| }) | |||||
| Util.merge(this._entity.rectangle, { | |||||
| fill: true, | |||||
| material: material | |||||
| }) | |||||
| this._entity.show = true | |||||
| } | |||||
| /** | |||||
| * | |||||
| * @param {*} positions | |||||
| */ | |||||
| setPositions(positions) { | |||||
| if (!positions || !Array.isArray(positions)) { | |||||
| return this | |||||
| } | |||||
| this._positions = positions | |||||
| this._bounds = Cesium.Math.bounds(this._positions) | |||||
| this._redraw() | |||||
| return this | |||||
| } | |||||
| /** | |||||
| * | |||||
| * @param {*} position | |||||
| */ | |||||
| addPosition(position) { | |||||
| this._positions.push(position) | |||||
| this._bounds = Cesium.Math.bounds(this._positions) | |||||
| this._redraw() | |||||
| return this | |||||
| } | |||||
| /** | |||||
| * | |||||
| * @param {*} options | |||||
| */ | |||||
| setOptions(options) { | |||||
| Util.merge(this._options, options) | |||||
| if (this._heat) { | |||||
| this._options.spacing = this._options.radius * 1.5 | |||||
| this._heat.configure(this._options) | |||||
| } | |||||
| return this | |||||
| } | |||||
| } | |||||
| Layer.registerType('heat') | |||||
| export default HeatLayer |
| /** | |||||
| * @Author: Caven | |||||
| * @Date: 2020-02-12 21:43:33 | |||||
| */ | |||||
| import { DomUtil } from '@dc-modules/utils' | |||||
| import State from '@dc-modules/state/State' | |||||
| import { Transform } from '@dc-modules/transform' | |||||
| import Layer from '../Layer' | |||||
| const { Cesium } = DC.Namespace | |||||
| class HtmlLayer extends Layer { | |||||
| constructor(id) { | |||||
| super(id) | |||||
| this._delegate = DomUtil.create('div', 'html-layer', undefined) | |||||
| this._delegate.setAttribute('id', this._id) | |||||
| this._renderRemoveCallback = undefined | |||||
| this.type = Layer.getLayerType('html') | |||||
| this._state = State.INITIALIZED | |||||
| } | |||||
| set show(show) { | |||||
| this._show = show | |||||
| this._delegate.style.visibility = this._show ? 'visible' : 'hidden' | |||||
| this._cache.keys().forEach(key => { | |||||
| this._cache[key].show = show | |||||
| }) | |||||
| return this | |||||
| } | |||||
| get show() { | |||||
| return this._show | |||||
| } | |||||
| /** | |||||
| * add handler | |||||
| * @param viewer | |||||
| * @private | |||||
| */ | |||||
| _onAdd(viewer) { | |||||
| this._viewer = viewer | |||||
| this._viewer.dcContainer.appendChild(this._delegate) | |||||
| let scene = this._viewer.scene | |||||
| this._renderRemoveCallback = scene.postRender.addEventListener(() => { | |||||
| let cameraPosition = this._viewer.camera.positionWC | |||||
| this.eachOverlay(item => { | |||||
| if (item && item.position) { | |||||
| let position = Transform.transformWGS84ToCartesian(item.position) | |||||
| let windowCoord = Cesium.SceneTransforms.wgs84ToWindowCoordinates( | |||||
| scene, | |||||
| position | |||||
| ) | |||||
| let distance = Cesium.Cartesian3.distance(position, cameraPosition) | |||||
| item._updateStyle({ transform: windowCoord }, distance) | |||||
| } | |||||
| }, this) | |||||
| }, this) | |||||
| this._state = State.ADDED | |||||
| } | |||||
| /** | |||||
| * remove handler | |||||
| * @returns {boolean} | |||||
| * @private | |||||
| */ | |||||
| _onRemove() { | |||||
| this._renderRemoveCallback && this._renderRemoveCallback() | |||||
| this._viewer.dcContainer.removeChild(this._delegate) | |||||
| this._state = State.REMOVED | |||||
| } | |||||
| /** | |||||
| * Clears all divIcons | |||||
| * @returns {HtmlLayer} | |||||
| */ | |||||
| clear() { | |||||
| while (this._delegate.hasChildNodes()) { | |||||
| this._delegate.removeChild(this._delegate.firstChild) | |||||
| } | |||||
| this._cache = {} | |||||
| this._state = State.CLEARED | |||||
| return this | |||||
| } | |||||
| } | |||||
| Layer.registerType('html') | |||||
| export default HtmlLayer |
| /** | |||||
| * @Author: Caven | |||||
| * @Date: 2020-01-19 11:03:17 | |||||
| */ | |||||
| import State from '@dc-modules/state/State' | |||||
| import Layer from '../Layer' | |||||
| const { Cesium } = DC.Namespace | |||||
| class KmlLayer extends Layer { | |||||
| constructor(id, url, options = {}) { | |||||
| if (!url) { | |||||
| throw new Error('KmlLayer: the url is empty') | |||||
| } | |||||
| super(id) | |||||
| this._delegate = Cesium.KmlDataSource.load(url, options) | |||||
| this.type = Layer.getLayerType('kml') | |||||
| this._state = State.INITIALIZED | |||||
| } | |||||
| set show(show) { | |||||
| this._show = show | |||||
| this._delegate && | |||||
| this._delegate.then(dataSource => { | |||||
| dataSource.show = this._show | |||||
| }) | |||||
| } | |||||
| get show() { | |||||
| return this._show | |||||
| } | |||||
| eachOverlay(method, context) { | |||||
| if (this._delegate) { | |||||
| this._delegate.then(dataSource => { | |||||
| let entities = dataSource.entities.values | |||||
| entities.forEach(item => { | |||||
| method.call(context, item) | |||||
| }) | |||||
| }) | |||||
| return this | |||||
| } | |||||
| } | |||||
| } | |||||
| Layer.registerType('kml') | |||||
| export default KmlLayer |
| /** | |||||
| * @Author: Caven | |||||
| * @Date: 2020-03-30 17:14:00 | |||||
| */ | |||||
| import State from '@dc-modules/state/State' | |||||
| import { Label } from '@dc-modules/overlay' | |||||
| import Layer from '../Layer' | |||||
| const { Cesium } = DC.Namespace | |||||
| class LabelLayer extends Layer { | |||||
| constructor(id, url = '') { | |||||
| super(id) | |||||
| this._dataSource = Cesium.GeoJsonDataSource.load(url) | |||||
| this._delegate = new Cesium.CustomDataSource(id) | |||||
| this._initLabel() | |||||
| this.type = Layer.registerType('label') | |||||
| this._state = State.INITIALIZED | |||||
| } | |||||
| _createLabel(entity) { | |||||
| if (entity.position && entity.name) { | |||||
| return Label.fromEntity(entity) | |||||
| } | |||||
| } | |||||
| _initLabel() { | |||||
| this._dataSource.then(dataSource => { | |||||
| let entities = dataSource.entities.values | |||||
| entities.forEach(item => { | |||||
| let label = this._createLabel(item) | |||||
| this.addOverlay(label) | |||||
| }) | |||||
| }) | |||||
| } | |||||
| } | |||||
| Layer.registerType('label') | |||||
| export default LabelLayer |
| /** | |||||
| * @Author: Caven | |||||
| * @Date: 2020-08-27 19:50:32 | |||||
| */ | |||||
| import { Util } from '@dc-modules/utils' | |||||
| import State from '@dc-modules/state/State' | |||||
| import { LayerGroupEventType, LayerGroupEvent } from '@dc-modules/event' | |||||
| import Layer from '../Layer' | |||||
| class LayerGroup { | |||||
| constructor(id) { | |||||
| this._id = id || Util.uuid() | |||||
| this._cache = {} | |||||
| this._show = true | |||||
| this._viewer = undefined | |||||
| this._layerGroupEvent = new LayerGroupEvent() | |||||
| this._layerGroupEvent.on(LayerGroupEventType.ADD, this._onAdd, this) | |||||
| this._layerGroupEvent.on(LayerGroupEventType.REMOVE, this._onRemove, this) | |||||
| this.type = Layer.getLayerType('layer_group') | |||||
| this._state = State.INITIALIZED | |||||
| } | |||||
| get id() { | |||||
| return this._id | |||||
| } | |||||
| set show(show) { | |||||
| this._show = show | |||||
| Object.keys(this._cache).forEach(key => { | |||||
| this._cache[key].show = this._show | |||||
| }) | |||||
| } | |||||
| get show() { | |||||
| return this._show | |||||
| } | |||||
| get layerGroupEvent() { | |||||
| return this._layerGroupEvent | |||||
| } | |||||
| get state() { | |||||
| return this._state | |||||
| } | |||||
| /** | |||||
| * | |||||
| * @param viewer | |||||
| * @private | |||||
| */ | |||||
| _onAdd(viewer) { | |||||
| this._viewer = viewer | |||||
| Object.keys(this._cache).forEach(key => { | |||||
| this._viewer.addLayer(this._cache[key]) | |||||
| }) | |||||
| this._state = State.ADDED | |||||
| } | |||||
| /** | |||||
| * | |||||
| * @private | |||||
| */ | |||||
| _onRemove() { | |||||
| Object.keys(this._cache).forEach(key => { | |||||
| this._viewer && this._viewer.removeLayer(this._cache[key]) | |||||
| }) | |||||
| this._cache = {} | |||||
| this._state = State.REMOVED | |||||
| } | |||||
| /** | |||||
| * Adds a layer | |||||
| * @param layer | |||||
| * @returns {LayerGroup} | |||||
| */ | |||||
| addLayer(layer) { | |||||
| if (!Object(this._cache).hasOwnProperty(layer.id)) { | |||||
| this._cache[layer.id] = layer | |||||
| this._viewer && this._viewer.addLayer(layer) | |||||
| } | |||||
| return this | |||||
| } | |||||
| /** | |||||
| * Removes a layer | |||||
| * @param layer | |||||
| * @returns {LayerGroup} | |||||
| */ | |||||
| removeLayer(layer) { | |||||
| if (Object(this._cache).hasOwnProperty(layer.id)) { | |||||
| this._viewer && this._viewer.removeLayer(layer) | |||||
| delete this._cache[layer.id] | |||||
| } | |||||
| return this | |||||
| } | |||||
| /** | |||||
| * Returns a layer by id | |||||
| * @param id | |||||
| * @returns {*|undefined} | |||||
| */ | |||||
| getLayer(id) { | |||||
| return this._cache[id] || undefined | |||||
| } | |||||
| /** | |||||
| * Returns all layers | |||||
| * @returns {[]} | |||||
| */ | |||||
| getLayers() { | |||||
| let result = [] | |||||
| Object.keys(this._cache).forEach(key => { | |||||
| result.push(this._cache[key]) | |||||
| }) | |||||
| return result | |||||
| } | |||||
| /** | |||||
| * Adds to the viewer | |||||
| * @param viewer | |||||
| * @returns {LayerGroup} | |||||
| */ | |||||
| addTo(viewer) { | |||||
| if (viewer && viewer.addLayerGroup) { | |||||
| viewer.addLayerGroup(this) | |||||
| } | |||||
| return this | |||||
| } | |||||
| /** | |||||
| * | |||||
| * @returns {LayerGroup} | |||||
| */ | |||||
| remove() { | |||||
| this._viewer && this._viewer.removeLayerGroup(this) | |||||
| return this | |||||
| } | |||||
| } | |||||
| Layer.registerType('layer_group') | |||||
| export default LayerGroup |
| /** | |||||
| * @Author: Caven | |||||
| * @Date: 2020-10-11 18:16:47 | |||||
| */ | |||||
| import State from '@dc-modules/state/State' | |||||
| import Layer from '../Layer' | |||||
| const { Cesium } = DC.Namespace | |||||
| class PrimitiveLayer extends Layer { | |||||
| constructor(id) { | |||||
| super(id) | |||||
| this._delegate = new Cesium.PrimitiveCollection() | |||||
| this.type = Layer.getLayerType('primitive') | |||||
| this._state = State.INITIALIZED | |||||
| } | |||||
| /** | |||||
| * Clears all primitives | |||||
| * @returns {PrimitiveLayer} | |||||
| */ | |||||
| clear() { | |||||
| this._delegate && this._delegate.removeAll() | |||||
| this._cache = {} | |||||
| this._state = State.CLEARED | |||||
| return this | |||||
| } | |||||
| } | |||||
| Layer.registerType('primitive') | |||||
| export default PrimitiveLayer |
| /** | |||||
| * @Author: Caven | |||||
| * @Date: 2020-01-09 09:16:27 | |||||
| */ | |||||
| import State from '@dc-modules/state/State' | |||||
| import Layer from '../Layer' | |||||
| const { Cesium } = DC.Namespace | |||||
| /** | |||||
| * TilesetLayer is used to add various tileset | |||||
| */ | |||||
| class TilesetLayer extends Layer { | |||||
| constructor(id) { | |||||
| super(id) | |||||
| this._delegate = new Cesium.PrimitiveCollection() | |||||
| this.type = Layer.getLayerType('tileset') | |||||
| this._state = State.INITIALIZED | |||||
| } | |||||
| /** | |||||
| * Clear all tileset | |||||
| * @returns {TilesetLayer} | |||||
| */ | |||||
| clear() { | |||||
| this._delegate.removeAll() | |||||
| this._cache = {} | |||||
| this._state = State.CLEARED | |||||
| return this | |||||
| } | |||||
| } | |||||
| Layer.registerType('tileset') | |||||
| export default TilesetLayer |
| /** | |||||
| * @Author: Caven | |||||
| * @Date: 2020-09-11 19:32:22 | |||||
| */ | |||||
| import State from '@dc-modules/state/State' | |||||
| import GeoJsonLayer from './GeoJsonLayer' | |||||
| class TopoJsonLayer extends GeoJsonLayer { | |||||
| constructor(id, url, options = {}) { | |||||
| if (!url) { | |||||
| throw new Error('TopoJsonLayer:the url invalid') | |||||
| } | |||||
| super(id, url, options) | |||||
| this.type = GeoJsonLayer.getLayerType('topojson') | |||||
| this._state = State.INITIALIZED | |||||
| } | |||||
| } | |||||
| GeoJsonLayer.registerType('topojson') | |||||
| export default TopoJsonLayer |
| /** | |||||
| * @Author: Caven | |||||
| * @Date: 2020-01-02 16:42:03 | |||||
| */ | |||||
| import State from '@dc-modules/state/State' | |||||
| import Layer from '../Layer' | |||||
| const { Cesium } = DC.Namespace | |||||
| /** | |||||
| * The vector layer is used to add various entity, which is essentially a CustomDataSource | |||||
| * that is used to place entities of the same class or business attribute into the same layer | |||||
| */ | |||||
| class VectorLayer extends Layer { | |||||
| constructor(id) { | |||||
| super(id) | |||||
| this._delegate = new Cesium.CustomDataSource(id) | |||||
| this.type = Layer.getLayerType('vector') | |||||
| this._state = State.INITIALIZED | |||||
| } | |||||
| /** | |||||
| * Clears all entities | |||||
| * @returns {VectorLayer} | |||||
| */ | |||||
| clear() { | |||||
| this._delegate.entities && this._delegate.entities.removeAll() | |||||
| this._cache = {} | |||||
| this._state = State.CLEARED | |||||
| return this | |||||
| } | |||||
| } | |||||
| Layer.registerType('vector') | |||||
| export default VectorLayer |