Pārlūkot izejas kodu

重构热区图层

tags/1.0.0
Caven Chen pirms 5 gadiem
vecāks
revīzija
0b575102dd

+ 13
- 4
src/core/layer/Layer.js Parādīt failu

@@ -2,7 +2,7 @@
* @Author: Caven
* @Date: 2020-01-03 09:38:21
* @Last Modified by: Caven
* @Last Modified time: 2020-04-20 19:27:43
* @Last Modified time: 2020-04-23 13:16:03
*/
import Cesium from '@/namespace'
import { LayerEvent } from '@/core/event'
@@ -56,6 +56,16 @@ class Layer {
return this._state
}

/**
* The hook for added
*/
_addedHook() {}

/**
* The hook for removed
*/
_removedHook() {}

/**
*
* The layer added callback function
@@ -65,14 +75,12 @@ class Layer {
*/
_addHandler(viewer) {
this._viewer = viewer
if (!this._delegate) {
return false
}
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 = DC.LayerState.ADDED
}

@@ -98,6 +106,7 @@ class Layer {
this._delegate.entities && this._delegate.entities.removeAll()
this._viewer.dataSources.remove(this._delegate)
}
this._removedHook && this._removedHook()
this._state = DC.LayerState.REMOVED
}
}

+ 36
- 0
src/core/math/getBounds.js Parādīt failu

@@ -0,0 +1,36 @@
/*
* @Author: Caven
* @Date: 2020-04-23 09:29:56
* @Last Modified by: Caven
* @Last Modified time: 2020-04-23 12:38:10
*/

export default function getBounds(positions = [], expand = 0) {
let minLng = 180
let minLat = 90
let maxLng = -180
let maxLat = -90
positions
.filter(item => item instanceof DC.Position)
.forEach(item => {
minLng = Math.min(minLng, item.lng)
minLat = Math.min(minLat, item.lat)
maxLng = Math.max(maxLng, item.lng)
maxLat = Math.max(maxLat, item.lat)
})

if (expand > 0) {
let diffLng = Math.abs(maxLng - maxLng)
let diffLat = Math.abs(maxLat - minLat)
minLng -= diffLng * expand
minLat -= diffLat * expand
maxLng += diffLng * expand
maxLat += diffLat * expand
}
return {
west: minLng,
south: minLat,
east: maxLng,
north: maxLat
}
}

+ 4
- 1
src/core/math/index.js Parādīt failu

@@ -2,12 +2,15 @@
* @Author: Caven
* @Date: 2020-03-31 20:57:36
* @Last Modified by: Caven
* @Last Modified time: 2020-04-16 20:27:49
* @Last Modified time: 2020-04-23 09:40:08
*/

import getBounds from './getBounds'
import getDistance from './getDistance'
import getHeading from './getHeading'
import isBetween from './isBetween'

DC.Math.getBounds = getBounds
DC.Math.getDistance = getDistance
DC.Math.getHeading = getHeading
DC.Math.isBetween = isBetween

+ 1
- 4
src/core/overlay/Overlay.js Parādīt failu

@@ -2,7 +2,7 @@
* @Author: Caven
* @Date: 2020-01-03 12:18:17
* @Last Modified by: Caven
* @Last Modified time: 2020-04-20 10:31:54
* @Last Modified time: 2020-04-22 22:43:45
*/
import { OverlayEvent } from '@/core/event'

@@ -80,9 +80,6 @@ class Overlay {
* @param {*} layer
*/
_addHandler(layer) {
if (!layer) {
return false
}
this._layer = layer
this._mountedHook && this._mountedHook()
if (this._layer && this._layer.delegate && this._layer.delegate.entities) {

+ 31
- 1
src/core/transform/DC.T.js Parādīt failu

@@ -2,10 +2,12 @@
* @Author: Caven
* @Date: 2020-01-07 09:00:32
* @Last Modified by: Caven
* @Last Modified time: 2020-04-11 11:53:40
* @Last Modified time: 2020-04-23 12:46:21
*/
import Cesium from '@/namespace'

const WMP = new Cesium.WebMercatorProjection()

DC.T = class {
/**
*
@@ -82,4 +84,32 @@ DC.T = class {
? WSG84Arr.map(item => DC.T.transformWSG84ToCartesian(item))
: []
}

/**
*
* @param {*} position
*
*/
static transformWgs84ToMercator(position) {
let mp = WMP.project(
Cesium.Cartographic.fromDegrees(position.lng, position.lat, position.alt)
)
return new DC.Position(mp.x, mp.y, mp.z)
}

/**
*
* @param {*} position
*
*/
static transformMercatorToWgs84(position) {
let mp = WMP.unproject(
new Cesium.Cartesian3(position.lng, position.lat, position.alt)
)
return new DC.Position(
Cesium.Math.toDegrees(mp.longitude),
Cesium.Math.toDegrees(mp.latitude),
mp.height
)
}
}

+ 277
- 0
src/plugins/layer/DC.HeatLayer.js Parādīt failu

@@ -0,0 +1,277 @@
/*
* @Author: Caven
* @Date: 2020-02-27 00:35:35
* @Last Modified by: Caven
* @Last Modified time: 2020-04-24 10:35:18
*/
import Cesium from '@/namespace'
import Layer from '@/core/layer/Layer'
const h337 = require('heatmap')

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'
}
}
DC.HeatLayer = class 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._state = DC.LayerState.INITIALIZED
this.type = DC.LayerType.HEAT
}

get options() {
return this._options
}

/**
* The hook for added
*/
_addedHook() {
this._reDraw()
this._viewer.on(DC.SceneEventType.CAMERA_MOVE_END, this._reset, this)
}

/**
* The hook for removed
*/
_removedHook() {
this._viewer.off(DC.SceneEventType.CAMERA_MOVE_END, this._reset, this)
}

/**
*
*/
_initContainer() {}

/**
*
* @param {*} position
*/
_transformWgs84ToHeatmap(position) {
position = DC.T.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
}

/**
*
* @param {*} bounds
*/
_getMBounds() {
let mWestSouth = DC.T.transformWgs84ToMercator(
new DC.Position(this._bounds.west, this._bounds.south)
)
let mEastNorth = DC.T.transformWgs84ToMercator(
new DC.Position(this._bounds.east, this._bounds.north)
)
return {
west: mWestSouth.lng,
south: mWestSouth.lat,
east: mEastNorth.lng,
north: mEastNorth.lat
}
}

_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 = DC.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 = DC.T.transformMercatorToWgs84({
lng: this._mBounds.west,
lat: this._mBounds.south
})
let eastNorth = DC.T.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.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
})
if (!this._entity.rectangle) {
this._initEntity()
}
let material = new Cesium.ImageMaterialProperty({
image: this._heat._renderer.canvas,
transparent: true
})
DC.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 = DC.Math.getBounds(this._positions)
this._reDraw()
return this
}

/**
*
* @param {*} position
*/
addPosition(position) {
this._positions.push(position)
this._bounds = DC.Math.getBounds(this._positions)
this._reDraw()
return this
}

/**
*
* @param {*} options
*/
setOptions(options) {
DC.Util.merge(this._options, options)
if (this._heat) {
this._options.spacing = this._options.radius * 1.5
this._heat.configure(this._options)
}
return this
}
}

DC.LayerType.HEAT = 'heat'

+ 0
- 246
src/plugins/layer/DC.HeatmapLayer.js Parādīt failu

@@ -1,246 +0,0 @@
/*
* @Author: Caven
* @Date: 2020-02-27 00:35:35
* @Last Modified by: Caven
* @Last Modified time: 2020-03-09 21:28:43
*/
import Cesium from '@/namespace'
import Layer from '@/core/layer/Layer'

const h337 = require('heatmap')
const WMP = new Cesium.WebMercatorProjection()
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
xField: 'lng',
yField: 'lat',
gradient: {
'0.5': 'blue',
'0.8': 'red',
'0.95': 'white',
'0.6': 'yellow',
'0.5': 'green'
}
}
DC.HeatmapLayer = class extends Layer {
constructor(id, bounds, options) {
if (!bounds || bounds.length !== 2) {
throw new Error('the bounds is empty')
}
super(id)
this._options = {
...DEF_OPTS,
...options
}
this._delegate = new Cesium.CustomDataSource(id)
this._data = []
this._width = 0
this._height = 0
this._scale = 1
this._mBounds = this._computeMercatorBounds(bounds)
this._oriX = this._mBounds.west
this._oriY = this._mBounds.south
this._computeWidthAndHeight()
this._options.radius = Math.round(
this._options.radius
? this._options.radius
: Math.max(this._width, this._height) / 60
)
this._spacing = this._options.radius * 1.5
this._heatmapInstance = undefined
this._entity = new Cesium.Entity()
this._prepareHeatmap()
this._state = DC.LayerState.INITIALIZED
this.type = DC.LayerType.HEAT
}

/**
*
* @param {*} position
*/
_transformWgs84ToMercator(position) {
let mp = WMP.project(
Cesium.Cartographic.fromDegrees(position.lng, position.lat)
)
return {
lng: mp.x,
lat: mp.y
}
}

/**
*
* @param {*} position
*/
_transformMercatorToWgs84(position) {
let mp = WMP.unproject(new Cesium.Cartesian3(position.lng, position.lat))
return {
lng: Cesium.Math.toDegrees(mp.longitude),
lat: Cesium.Math.toDegrees(mp.latitude)
}
}

/**
*
* @param {*} position
*/
_transformWgs84ToHeatmap(position) {
position = this._transformWgs84ToMercator(position)
let coord = {}
coord.lng = Math.round(
(position.lng - this._oriX) / this._scale + this._spacing
)
coord.lat = Math.round(
(position.lat - this._oriY) / this._scale + this._spacing
)
coord.lat = this._height - coord.lat
return coord
}

/**
*
* @param {*} bounds
*/
_computeMercatorBounds(bounds) {
let mWestSouth = this._transformWgs84ToMercator(bounds[0])
let mEastNorth = this._transformWgs84ToMercator(bounds[1])
return {
west: mWestSouth.lng,
south: mWestSouth.lat,
east: mEastNorth.lng,
north: mEastNorth.lat
}
}

/**
*
*/
_computeWidthAndHeight() {
this._width =
this._mBounds.east > 0 && this._mBounds.west < 0
? this._mBounds.east + Math.abs(this._mBounds.west)
: Math.abs(this._mBounds.east - this._mBounds.west)
this._height =
this._mBounds.north > 0 && this._mBounds.south < 0
? this._mBounds.north + Math.abs(this._mBounds.south)
: Math.abs(this._mBounds.north - this._mBounds.south)
let maxCanvasSize = 2000
let minCanvasSize = 700
let max = Math.max(this._width, this._height)
let min = Math.min(this._width, this._height)
if (max > maxCanvasSize) {
this._scale = max / maxCanvasSize
if (min / this._scale < minCanvasSize) {
this._scale = min / minCanvasSize
}
} else if (min < minCanvasSize) {
this._scale = min / minCanvasSize
if (max > maxCanvasSize) {
this._scale = max / maxCanvasSize
}
}
this._width = this._width / this._scale
this._height = this._height / this._scale
}

/**
*
*/
_prepareHeatmap() {
let width = Math.round(this._width + this._spacing * 2)
let height = Math.round(this._height + this._spacing * 2)
let container = DC.DomUtil.create(
'div',
'heat-map',
document.getElementsByClassName('dc-container')[0]
)
container.style.cssText = `
width:${width}px;
height:${height}px;
margin:0;
display:none`

this._options.container = container
this._heatmapInstance = h337.create(this._options)
let offset = this._spacing * this._scale
let westSouth = this._transformMercatorToWgs84({
lng: this._mBounds.west - offset,
lat: this._mBounds.south - offset
})
let eastNorth = this._transformMercatorToWgs84({
lng: this._mBounds.east + offset,
lat: this._mBounds.north + offset
})
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)
}

_parseData() {
let data = []
if (!this._data || !this._data.length) {
return {
min: 0,
max: 0,
data
}
}
let min = this._data[0] && this._data[0].value ? this._data[0].value : 0
let max = this._data[0] && this._data[0].value ? this._data[0].value : 1
this._data.forEach(item => {
min = Math.min(min, item.value)
max = Math.max(max, item.value)
let coord = this._transformWgs84ToHeatmap({
lng: item.lng || item.x,
lat: item.lat || item.y
})
data.push({
lng: coord.lng,
lat: coord.lat,
value: item.value || 0
})
})
return {
min,
max,
data
}
}

_reDraw() {
this._heatmapInstance.setData(this._parseData())
}

setPositions(positions) {
if (!positions || !Array.isArray(positions)) {
return this
}
this._data = positions
this._reDraw()
if (this._entity && this._entity.rectangle) {
let material = new Cesium.ImageMaterialProperty({
image: this._heatmapInstance._renderer.canvas,
transparent: true
})
this._entity.show = true
DC.Util.merge(this._entity.rectangle, {
fill: true,
material: material
})
}
}
}

DC.LayerType.HEAT = 'heat'

+ 2
- 2
src/plugins/layer/index.js Parādīt failu

@@ -2,9 +2,9 @@
* @Author: Caven
* @Date: 2020-01-19 11:04:45
* @Last Modified by: Caven
* @Last Modified time: 2020-04-09 20:36:29
* @Last Modified time: 2020-04-23 15:16:53
*/
import './DC.HeatmapLayer'
import './DC.HeatLayer'
import './DC.ClusterLayer'
import './DC.CzmlLayer'
import './DC.KmlLayer'

Notiek ielāde…
Atcelt
Saglabāt