您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

HeatLayer.js 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /**
  2. * @Author: Caven
  3. * @Date: 2020-02-27 00:35:35
  4. */
  5. import { Cesium } from '@dc-modules/namespace'
  6. import State from '@dc-modules/state/State'
  7. import { Layer } from '@dc-modules/layer'
  8. import { createWebGLHeatmap } from './webgl-heatmap'
  9. const WMP = new Cesium.WebMercatorProjection()
  10. const DEF_OPTS = {
  11. radius: 30,
  12. height: 0,
  13. gradient: undefined
  14. }
  15. class HeatLayer extends Layer {
  16. constructor(id, options = {}) {
  17. super(id)
  18. this._options = {
  19. ...DEF_OPTS,
  20. ...options
  21. }
  22. this._canvas = document.createElement('canvas')
  23. this._canvas.setAttribute('id', id)
  24. this._heat = undefined
  25. this._mRect = undefined
  26. this._rect = new Cesium.Rectangle()
  27. this._delegate = new Cesium.PrimitiveCollection()
  28. this._primitive = this._delegate.add(
  29. new Cesium.Primitive({
  30. geometryInstances: new Cesium.GeometryInstance({
  31. geometry: {}
  32. })
  33. })
  34. )
  35. this._scale = 1
  36. this._points = []
  37. this._positions = []
  38. this._state = State.INITIALIZED
  39. }
  40. get type() {
  41. return Layer.getLayerType('heat')
  42. }
  43. /**
  44. *
  45. * @private
  46. */
  47. _addedHook() {
  48. this._canvas.style.cssText = `
  49. visibility:hidden;
  50. width:${this._viewer.canvas.width}px;
  51. height:${this._viewer.canvas.height}px;
  52. `
  53. this._viewer.dcContainer.appendChild(this._canvas)
  54. }
  55. /**
  56. *
  57. * @returns {string|undefined}
  58. * @private
  59. */
  60. _createGradientTexture() {
  61. if (!this._options.gradient) {
  62. return undefined
  63. }
  64. let canvas = document.createElement('canvas')
  65. canvas.width = 200
  66. canvas.height = 10
  67. let ctx = canvas.getContext('2d')
  68. let grd = ctx.createLinearGradient(0, 0, 200, 0)
  69. for (let key in this._options.gradient) {
  70. grd.addColorStop(+key, this._options.gradient[+key])
  71. }
  72. ctx.fillStyle = grd
  73. ctx.fillRect(0, 0, 200, 10)
  74. return canvas.toDataURL()
  75. }
  76. /**
  77. *
  78. * @param position
  79. * @returns {{intensity: number, size: (*|number), x: number, y: number}}
  80. * @private
  81. */
  82. _parsePosition(position) {
  83. let point = WMP.project(
  84. Cesium.Cartographic.fromDegrees(position.lng, position.lat)
  85. )
  86. return {
  87. x: (point.x - this._mRect.west) / this._scale,
  88. y: (point.y - this._mRect.south) / this._scale,
  89. size: this._options.radius,
  90. intensity: position.value || Math.random()
  91. }
  92. }
  93. /**
  94. *
  95. * @param positions
  96. * @returns {*}
  97. * @private
  98. */
  99. _parsePositions(positions) {
  100. return positions.map(this._parsePosition.bind(this))
  101. }
  102. /**
  103. *
  104. * @private
  105. */
  106. _setRect() {
  107. Cesium.Rectangle.fromCartographicArray(
  108. this._positions.map(item =>
  109. Cesium.Cartographic.fromDegrees(item.lng, item.lat)
  110. ),
  111. this._rect
  112. )
  113. }
  114. /**
  115. *
  116. * @returns {{east, south, north, west}}
  117. * @private
  118. */
  119. _getMRect() {
  120. let mSouthwest = WMP.project(Cesium.Rectangle.southwest(this._rect))
  121. let mNortheast = WMP.project(Cesium.Rectangle.northeast(this._rect))
  122. return {
  123. west: mSouthwest.x,
  124. south: mSouthwest.y,
  125. east: mNortheast.x,
  126. north: mNortheast.y
  127. }
  128. }
  129. /**
  130. *
  131. * @returns {boolean}
  132. * @private
  133. */
  134. _update() {
  135. if (!this._points || !this._points.length) {
  136. return false
  137. }
  138. this._heat.adjustSize()
  139. this._heat.update()
  140. this._heat.display()
  141. if (this._primitive && this._primitive.geometryInstances) {
  142. this._primitive.geometryInstances.geometry = new Cesium.RectangleGeometry(
  143. {
  144. rectangle: this._rect,
  145. height: this._options.height
  146. }
  147. )
  148. }
  149. this._primitive.appearance = new Cesium.MaterialAppearance({
  150. material: new Cesium.Material({
  151. fabric: {
  152. type: 'Heat-Image',
  153. uniforms: {
  154. image: this._canvas
  155. },
  156. source: `
  157. uniform sampler2D image;
  158. czm_material czm_getMaterial(czm_materialInput materialInput){
  159. czm_material material = czm_getDefaultMaterial(materialInput);
  160. vec2 st = materialInput.st;
  161. vec4 colorImage = texture2D(image,st);
  162. if(colorImage.rgb == vec3(1.0) || colorImage.rgb == vec3(0.0)){
  163. discard;
  164. }
  165. material.diffuse = colorImage.rgb;
  166. material.alpha = colorImage.a;
  167. return material;
  168. }
  169. `
  170. },
  171. translucent: function(material) {
  172. return true
  173. }
  174. }),
  175. flat: true
  176. })
  177. }
  178. /**
  179. *
  180. * @param positions
  181. */
  182. setPositions(positions) {
  183. this._positions = positions
  184. this._setRect()
  185. let mRect = this._getMRect()
  186. if (
  187. !this._mRect ||
  188. !mRect.west === this._mRect.west ||
  189. !mRect.south === this._mRect.south ||
  190. !mRect.east === this._mRect.east ||
  191. !mRect.north === this._mRect.north
  192. ) {
  193. this._mRect = mRect
  194. this._heat = createWebGLHeatmap({
  195. canvas: this._canvas,
  196. gradientTexture: this._createGradientTexture()
  197. })
  198. this._scale = Math.min(
  199. Math.abs(this._mRect.west - this._mRect.east) / this._canvas.width,
  200. Math.abs(this._mRect.north - this._mRect.south) / this._canvas.height
  201. )
  202. }
  203. this._points = this._parsePositions(this._positions)
  204. if (this._heat) {
  205. this._heat.blur()
  206. this._heat.addPoints(this._points)
  207. this._update()
  208. }
  209. return this
  210. }
  211. /**
  212. *
  213. * @param position
  214. */
  215. addPosition(position) {
  216. this._positions.push(position)
  217. this._setRect()
  218. let mRect = this._getMRect()
  219. if (
  220. !this._mRect ||
  221. !mRect.west === this._mRect.west ||
  222. !mRect.south === this._mRect.south ||
  223. !mRect.east === this._mRect.east ||
  224. !mRect.north === this._mRect.north
  225. ) {
  226. this._mRect = mRect
  227. this._heat = createWebGLHeatmap({
  228. canvas: this._canvas,
  229. gradientTexture: this._createGradientTexture()
  230. })
  231. this._scale = Math.min(
  232. Math.abs(this._mRect.west - this._mRect.east) / this._canvas.width,
  233. Math.abs(this._mRect.north - this._mRect.south) / this._canvas.height
  234. )
  235. this._heat.addPoints(this._points)
  236. }
  237. let point = this._parsePosition(position)
  238. this._points.push(point)
  239. if (this._heat) {
  240. this._heat.addPoint(point.x, point.y, point.size, point.intensity)
  241. this._update()
  242. }
  243. return this
  244. }
  245. }
  246. Layer.registerType('heat')
  247. export default HeatLayer