├── .env ├── .gitignore ├── README.md ├── craco.config.js ├── dist ├── cesium-heatmap-es6.umd.js ├── cesiumHeatmap.js ├── heatmap.js └── index.js ├── docs ├── .nojekyll ├── assets │ ├── highlight.css │ ├── icons.css │ ├── icons.png │ ├── icons@2x.png │ ├── main.js │ ├── search.js │ ├── style.css │ ├── widgets.png │ └── widgets@2x.png ├── classes │ └── CesiumHeatmap.html ├── index.html ├── interfaces │ ├── BaseHeatmapConfiguration.html │ ├── CesiumHeatmapOption.html │ ├── HeatmapConfiguration.html │ ├── HeatmapDataOption.html │ └── HeatmapPoint.html └── modules.html ├── lib ├── cesiumHeatmap.d.ts └── index.d.ts ├── package-lock.json ├── package.json ├── public ├── CesiumHeatmap │ ├── dist │ │ └── cesium-heatmap-es6.umd.js │ ├── docs │ │ ├── .nojekyll │ │ ├── assets │ │ │ ├── highlight.css │ │ │ ├── icons.css │ │ │ ├── icons.png │ │ │ ├── icons@2x.png │ │ │ ├── main.js │ │ │ ├── search.js │ │ │ ├── style.css │ │ │ ├── widgets.png │ │ │ └── widgets@2x.png │ │ ├── classes │ │ │ └── CesiumHeatmap.html │ │ ├── index.html │ │ ├── interfaces │ │ │ ├── BaseHeatmapConfiguration.html │ │ │ ├── CesiumHeatmapOption.html │ │ │ ├── HeatmapConfiguration.html │ │ │ ├── HeatmapDataOption.html │ │ │ └── HeatmapPoint.html │ │ └── modules.html │ └── lib │ │ ├── cesiumHeatmap.d.ts │ │ └── index.d.ts ├── datas │ └── geojson │ │ ├── busstop2016.geojson │ │ └── test.geojson ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json ├── robots.txt └── testumd.html ├── src ├── App.less ├── App.test.tsx ├── App.tsx ├── imgs │ ├── effect.png │ └── effect2.png ├── index.tsx ├── logo.svg ├── page │ └── index.tsx ├── react-app-env.d.ts ├── reportWebVitals.ts ├── setupTests.ts ├── source │ ├── cesiumHeatmap.ts │ ├── heatmap.js │ └── index.ts └── webRoutes.tsx ├── tsconfig.json ├── webapck-plugin-copy.js ├── webpack.config.copyjs.js ├── webpack.config.release.js └── yarn.lock /.env: -------------------------------------------------------------------------------- 1 | SKIP_PREFLIGHT_CHECK=true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /public/Cesium 6 | /public/CesiumPoup 7 | /.pnp 8 | .pnp.js 9 | 10 | # testing 11 | /coverage 12 | 13 | # production 14 | /build 15 | 16 | # misc 17 | .DS_Store 18 | .env.local 19 | .env.development.local 20 | .env.test.local 21 | .env.production.local 22 | 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 参考源码 2 | 1.[《117颗星 manuelnas/CesiumHeatmap》](https://github.com/manuelnas/CesiumHeatmap) 3 | 基于heatmap.min.js,通过绘制Entity(矩形)实体实现,364行代码,有三维效果 4 | 2. [《32颗星 postor/cesiumjs-heat 》](https://github.com/postor/cesiumjs-heat) 5 | 基于heatmap.min.js,使用SingleTileImageryProvider图层实现,根据镜头移动具有重绘功能,239行代码,无三维效果 6 | 3. [《16颗星 wangzhongliang/CesiumHeatmap》](https://github.com/wangzhongliang/CesiumHeatmap) 7 | 使用Primitive图元实现,提供了两种方式,优点在于计算范围的方法。 8 | 方式一基于heatmap.min.js,157行代码,无三维效果; 9 | 方式二基于webgl-heatmap.js,128行代码,无三维效果; 10 | 11 | # 特点 12 | 1. 提供三种绘制方式,实体(可贴模型,有三维效果)、图元、图层 13 | 2. 提供重绘,通过摄像头的高度进行重绘 14 | 3. 提供heatmap.js的所有配置参数入口 15 | 4. 源码ts编写,发布支持es6和umd两种模式 16 | 5. [支持npm安装](https://www.npmjs.com/package/cesium-heatmap-es6) 17 | 18 | # 效果图 19 | 20 | ![效果图](https://img-blog.csdnimg.cn/d6f7e8f5cc8c459db86fd54a4462b3df.gif#pic_center) 21 | 22 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/3717eb863969431885152b3ab67dfd2f.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAT05FR0lTRVIoWlBDKQ==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center) 23 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/9f76a7f833bb400b867d6612eebe0d70.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAT05FR0lTRVIoWlBDKQ==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center) 24 | 25 | # 插件使用方法 26 | 27 | ## 安装 28 | `npm install cesium-heatmap-es6` 29 | 30 | ## 文档 31 | 32 | 自行打开docs文件夹 33 | ## umd模式 34 | 35 | ```javascript 36 | 37 | const defaultDataValue = [10, 500] 38 | const defaultOpacityValue = [0, 1] 39 | const points = [] 40 | fetch("/datas/geojson/busstop2016.geojson", { 41 | method: 'GET', 42 | headers: { 43 | 'Content-Type': 'application/json' 44 | }, 45 | }).then((response) => { 46 | response.json().then((data) => { 47 | if (data) 48 | data.features.forEach(function (feature) { 49 | const lon = feature.geometry.coordinates[0] 50 | const lat = feature.geometry.coordinates[1] 51 | points.push({ 52 | x: lon, 53 | y: lat, 54 | value: 100 * Math.random() 55 | }) 56 | }) 57 | const earthHeatMap = new CesiumHeatmap(viewer, 58 | { 59 | zoomToLayer: true, 60 | points, 61 | heatmapDataOptions: { max: defaultDataValue[1], min: defaultDataValue[0] }, 62 | heatmapOptions: { 63 | maxOpacity: defaultOpacityValue[1], 64 | minOpacity: defaultOpacityValue[0] 65 | } 66 | } 67 | ) 68 | }) 69 | }) 70 | ``` 71 | 72 | ## es6模式 73 | ```javascript 74 | const defaultDataValue = [10, 500] 75 | const defaultOpacityValue = [0, 1] 76 | import { CesiumHeatmap, HeatmapPoint } from "cesium-heatmap-es6" 77 | 78 | const points: HeatmapPoint[] = [] 79 | fetch("/datas/geojson/busstop2016.geojson", { 80 | method: 'GET', 81 | headers: { 82 | 'Content-Type': 'application/json' 83 | }, 84 | }).then((response) => { 85 | response.json().then((data) => { 86 | if (data) 87 | data.features.forEach(function (feature) { 88 | const lon = feature.geometry.coordinates[0] 89 | const lat = feature.geometry.coordinates[1] 90 | points.push({ 91 | x: lon - 0.05, 92 | y: lat - 0.04, 93 | value: 100 * Math.random() 94 | }) 95 | }) 96 | cesiumHeatmap = new CesiumHeatmap(viewer, 97 | { 98 | zoomToLayer: true, 99 | points, 100 | heatmapDataOptions: { max: defaultDataValue[1], min: defaultDataValue[0] }, 101 | heatmapOptions: { 102 | maxOpacity: defaultOpacityValue[1], 103 | minOpacity: defaultOpacityValue[0] 104 | } 105 | } 106 | ) 107 | }) 108 | }) 109 | ``` 110 | 111 | # 源码使用方法 112 | ## 依赖安装 113 | `npm run a` 114 | 115 | ## 项目运行 116 | `npm start` 117 | 118 | ## 项目打包 119 | `npm run build` 120 | 121 | ## 发布 122 | `npm run release` -------------------------------------------------------------------------------- /craco.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const CracoLessPlugin = require('craco-less'); 3 | const isEnvProduction = process.env.NODE_ENV === "production"; 4 | const CompressionWebpackPlugin = require("compression-webpack-plugin"); 5 | // const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer") 6 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 7 | 8 | const TerserPlugin = require('terser-webpack-plugin'); 9 | const plugins = [ 10 | new webpack.DefinePlugin({ 11 | CESIUM_BASE_URL: JSON.stringify('./Cesium/') 12 | })] 13 | if (isEnvProduction) { 14 | plugins.push(new CompressionWebpackPlugin({ 15 | test: /\.(css|js)$/, 16 | // 只处理比1kb大的资源 17 | threshold: 1024, 18 | // 只处理压缩率低于90%的文件 19 | minRatio: 0.9 20 | })) 21 | } else { 22 | // plugins.push(new BundleAnalyzerPlugin()) 23 | plugins.push(new CopyWebpackPlugin({ 24 | patterns: [ 25 | { from: 'node_modules/cesium/Build/Cesium', to: 'Cesium' }, 26 | ], 27 | })) 28 | } 29 | module.exports = { 30 | webpack: { 31 | plugins, 32 | configure: (config) => { 33 | config.entry = ['./src/index.tsx'] 34 | const markdown = { 35 | test: /\.md$/, 36 | use: [ 37 | { 38 | loader: require.resolve("html-loader") 39 | }, 40 | { 41 | loader: require.resolve('markdown-loader'), 42 | }] 43 | } 44 | config.module.rules[1].oneOf.unshift(markdown) 45 | //移除cesium警告 46 | config.module.unknownContextCritical = false 47 | config.module.unknownContextRegExp = /\/cesium\/cesium\/Source\/Core\/buildModuleUrl\.js/ 48 | config.externals = [{ 49 | 'cesium': 'Cesium', 50 | },] 51 | config.optimization = { 52 | minimizer: [new TerserPlugin({ 53 | extractComments: false, 54 | })], 55 | } 56 | return config 57 | } 58 | }, 59 | devServer: (devServerConfig) => { 60 | devServerConfig.proxy = { 61 | '/3dtiles': { target: 'https://data1.mars3d.cn', secure: false, changeOrigin: true, }, 62 | '/terrain': { target: 'http://data.marsgis.cn', secure: false, changeOrigin: true, }, 63 | '/realspace/services/': { target: 'http://www.supermapol.com', secure: false, changeOrigin: true, }, 64 | '/iserver/services/': { target: 'http://support.supermap.com.cn:8090', secure: false, changeOrigin: true, }, 65 | } 66 | return devServerConfig; 67 | }, 68 | plugins: [{ 69 | plugin: CracoLessPlugin, 70 | options: { 71 | lessLoaderOptions: { 72 | lessOptions: { 73 | modifyVars: { 74 | // '@primary-color': '#73ffff' 75 | '@font-size-base': '16px' 76 | }, 77 | javascriptEnabled: true, 78 | }, 79 | }, 80 | }, 81 | }], 82 | }; -------------------------------------------------------------------------------- /dist/cesium-heatmap-es6.umd.js: -------------------------------------------------------------------------------- 1 | /*! cesium-heatmap-es6 v0.7.0 - cesium-heatmap-es6.umd.js, e4faef7769bd6e9cbc39, Tue Mar 28 2023 00:26:23 GMT+0800 (中国标准时间) */ 2 | !function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e(require("Cesium"));else if("function"==typeof define&&define.amd)define(["Cesium"],e);else{var i="object"==typeof exports?e(require("Cesium")):e(t.Cesium);for(var a in i)("object"==typeof exports?exports:t)[a]=i[a]}}(window,(function(t){return function(t){var e={};function i(a){if(e[a])return e[a].exports;var r=e[a]={i:a,l:!1,exports:{}};return t[a].call(r.exports,r,r.exports,i),r.l=!0,r.exports}return i.m=t,i.c=e,i.d=function(t,e,a){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:a})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(t,e){if(1&e&&(t=i(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var a=Object.create(null);if(i.r(a),Object.defineProperty(a,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)i.d(a,r,function(e){return t[e]}.bind(null,r));return a},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=1)}([function(e,i){e.exports=t},function(t,e,i){"use strict";i.r(e),i.d(e,"CesiumHeatmap",(function(){return c}));var a,r=i(0),n={defaultRadius:40,defaultRenderer:"canvas2d",defaultGradient:{.25:"rgb(0,0,255)",.55:"rgb(0,255,0)",.85:"yellow",1:"rgb(255,0,0)"},defaultMaxOpacity:1,defaultMinOpacity:0,defaultBlur:.85,defaultXField:"x",defaultYField:"y",defaultValueField:"value",plugins:{}},s=function(){var t=function(t){this._coordinator={},this._data=[],this._radi=[],this._min=0,this._max=1,this._xField=t.xField||t.defaultXField,this._yField=t.yField||t.defaultYField,this._valueField=t.valueField||t.defaultValueField,t.radius&&(this._cfgRadius=t.radius)},e=n.defaultRadius;return t.prototype={_organiseData:function(t,i){var a=t[this._xField],r=t[this._yField],n=this._radi,s=this._data,o=this._max,h=this._min,d=t[this._valueField]||1,u=t.radius||this._cfgRadius||e;return s[a]||(s[a]=[],n[a]=[]),s[a][r]?s[a][r]+=d:(s[a][r]=d,n[a][r]=u),s[a][r]>o?(i?this.setDataMax(s[a][r]):this._max=s[a][r],!1):{x:a,y:r,value:d,radius:u,min:h,max:o}},_unOrganizeData:function(){var t=[],e=this._data,i=this._radi;for(var a in e)for(var r in e[a])t.push({x:a,y:r,radius:i[a][r],value:e[a][r]});return{min:this._min,max:this._max,data:t}},_onExtremaChange:function(){this._coordinator.emit("extremachange",{min:this._min,max:this._max})},addData:function(){if(arguments[0].length>0)for(var t=arguments[0],e=t.length;e--;)this.addData.call(this,t[e]);else{var i=this._organiseData(arguments[0],!0);i&&this._coordinator.emit("renderpartial",{min:this._min,max:this._max,data:[i]})}return this},setData:function(t){var e=t.data,i=e.length;this._data=[],this._radi=[];for(var a=0;athis._renderBoundaries[2]&&(this._renderBoundaries[2]=c+2*u),p+2*u>this._renderBoundaries[3]&&(this._renderBoundaries[3]=p+2*u)}},_colorize:function(){var t=this._renderBoundaries[0],e=this._renderBoundaries[1],i=this._renderBoundaries[2]-t,a=this._renderBoundaries[3]-e,r=this._width,n=this._height,s=this._opacity,o=this._maxOpacity,h=this._minOpacity,d=this._useGradientOpacity;t<0&&(t=0),e<0&&(e=0),t+i>r&&(i=r-t),e+a>n&&(a=n-e);for(var u=this.shadowCtx.getImageData(t,e,i,a),l=u.data,c=l.length,p=this._palette,m=3;m0?s:f>0},getDataURL:function(){return this.canvas.toDataURL()}},i}(),h=(a=!1,"canvas2d"===n.defaultRenderer&&(a=o),a),d=function(){for(var t={},e=arguments.length,i=0;i1e5?(t=>{let e=t.length,i=1/0;for(;e--;)i=t[e]1e5?(t=>{let e=t.length,i=-1/0;for(;e--;)i=t[e]>i?t[e]:i;return i})(h):Math.max(...h);if(null===(a=this.initOptions)||void 0===a?void 0:a.heatmapDataOptions){const{min:t,max:e}=this.initOptions.heatmapDataOptions;"number"==typeof t&&(d=t),"number"==typeof e&&(u=e)}this.heatmapDataOptions={min:d,max:u};const c={max:u,min:d,data:o},p={maxOpacity:.9,minOpacity:.1,gradient:{".3":"blue",".5":"green",".7":"yellow",".95":"red"}},m=this.initOptions.heatmapOptions?Object.assign(Object.assign({},p),this.initOptions.heatmapOptions):p;(null===(n=this.heatmapOptions)||void 0===n?void 0:n.radius)&&(this.initRadius=this.heatmapOptions.radius),this.heatmapOptions=Object.assign({},m);const g=Object.assign(Object.assign({},m),{container:e});this.heatmap=l.create(g),this.heatmap.setData(c),this.createLayer(),this.initOptions.noLisenerCamera||this.addLisener(),this.initOptions.zoomToLayer&&t&&this.viewer.camera.flyTo({destination:r.Rectangle.fromDegrees(...t)})}}updateHeatMapMaxMin(t){const{min:e,max:i}=t;this.heatmap&&("number"==typeof e&&(this.heatmap.setDataMin(e),this.heatmapDataOptions&&(this.heatmapDataOptions.min=e)),"number"==typeof i&&(this.heatmap.setDataMax(i),this.heatmapDataOptions&&(this.heatmapDataOptions.max=i))),this.updateLayer()}updateHeatmap(t){const{heatmapOptions:e}=this;this.heatmap.configure(Object.assign(Object.assign({},e),t)),this.updateLayer()}updateRadius(t){var e;const{heatmapOptions:i}=this,a=this.heatmap.getData();if(null==a?void 0:a.data)for(let e in a.data){a.data[e].radius=t}this.heatmap.setData(a),this.heatmapOptions=Object.assign(Object.assign({},i),{radius:t}),this.updateLayer(),(null===(e=this.initOptions)||void 0===e?void 0:e.onRadiusChange)&&this.initOptions.onRadiusChange(t)}remove(){this.element&&(document.body.removeChild(this.element),this.element=void 0,this.provider instanceof r.ImageryLayer?(this.provider&&this.viewer.imageryLayers.remove(this.provider),this.createSingleTileImageryLayer()):this.provider instanceof r.Primitive?this.viewer.scene.primitives.remove(this.provider):this.provider instanceof r.Entity&&this.viewer.entities.remove(this.provider),this.cameraMoveEnd&&(this.viewer.camera.moveEnd.removeEventListener(this.cameraMoveEnd),this.cameraMoveEnd=void 0))}createLayer(){"primitive"===this.initOptions.renderType?this.createPrimitive():"imagery"===this.initOptions.renderType?this.createSingleTileImageryLayer():this.createEntity()}createPrimitive(){const t=this.heatmap.getDataURL();this.provider=this.viewer.scene.primitives.add(new r.Primitive({geometryInstances:new r.GeometryInstance({geometry:new r.RectangleGeometry({rectangle:r.Rectangle.fromDegrees(...this.bounds),vertexFormat:r.EllipsoidSurfaceAppearance.VERTEX_FORMAT})}),appearance:new r.EllipsoidSurfaceAppearance({aboveGround:!1}),show:!0})),this.provider&&(this.provider.appearance.material=new r.Material({fabric:{type:"Image",uniforms:{image:t}}}))}createSingleTileImageryLayer(){const t=this.heatmap.getDataURL();this.provider=this.viewer.imageryLayers.addImageryProvider(new r.SingleTileImageryProvider({url:t,rectangle:r.Rectangle.fromDegrees(...this.bounds)}))}getImageMaterialProperty(){const t=this.heatmap.getDataURL();return new r.ImageMaterialProperty({image:t})}createEntity(){this.provider=this.viewer.entities.add({show:!0,rectangle:{coordinates:r.Rectangle.fromDegrees(...this.bounds),material:this.getImageMaterialProperty()}})}updateLayer(){const t=this.heatmap.getDataURL();this.provider instanceof r.ImageryLayer?(this.provider&&this.viewer.imageryLayers.remove(this.provider),this.createSingleTileImageryLayer()):this.provider instanceof r.Primitive?this.provider.appearance.material.uniforms.image=t:this.provider instanceof r.Entity&&this.provider.rectangle&&(this.provider.rectangle.material=this.getImageMaterialProperty())}addLisener(){const t=6375e3;this.cameraMoveEnd=()=>{var e;if(this.heatmapOptions&&this.heatmap&&this.heatmapDataOptions){const i=this.viewer.camera.getMagnitude(),a=(null===(e=null==this?void 0:this.initOptions)||void 0===e?void 0:e.cameraHeightDistance)?this.initOptions.cameraHeightDistance:1e3;if(Math.abs(i-this.lastCameraHeight)>a){this.lastCameraHeight=i;{const e=parseInt((this.initRadius+(100-this.initRadius)*(i-t)/3625e3).toFixed(0));e&&this.updateRadius(e)}}}},this.viewer.camera.moveEnd.addEventListener(this.cameraMoveEnd)}getBounds(t){if(t){let e=180,i=-180,a=90,r=-180;t.forEach((function(t){const{x:n,y:s}=t;e=ni?n:i,r=s>r?s:r}));const n=i-e?i-e:1,s=r-a?r-a:1;return[e-n/10,a-s/10,i+n/10,r+s/10]}return[0,0,0,0]}createContainer(t){const e=document.createElement("div"),i=parseInt((1e3/(t[2]-t[0])*(t[3]-t[1])).toFixed(0));return e.setAttribute("style",`width:1000px;height:${i}px;display:none;`),document.body.appendChild(e),{container:e,width:1e3,height:i}}}}])})); -------------------------------------------------------------------------------- /dist/cesiumHeatmap.js: -------------------------------------------------------------------------------- 1 | import { EllipsoidSurfaceAppearance, GeometryInstance, Material, Primitive, Rectangle, RectangleGeometry, SingleTileImageryProvider, ImageryLayer, ImageMaterialProperty, Entity } from "cesium"; 2 | import h337 from './heatmap.js'; //只能使用2.0.0版本,高版本热度图有出不来的情况,并且2.0.0 npm包有问题,只能通过修改使用这个js 3 | const Max = (arr) => { 4 | let len = arr.length; 5 | let max = -Infinity; 6 | while (len--) { 7 | max = arr[len] > max ? arr[len] : max; 8 | } 9 | return max; 10 | }; 11 | const Min = (arr) => { 12 | let len = arr.length; 13 | let min = Infinity; 14 | while (len--) { 15 | min = arr[len] < min ? arr[len] : min; 16 | } 17 | return min; 18 | }; 19 | /** 20 | * 热度图 21 | */ 22 | export class CesiumHeatmap { 23 | constructor(viewer, options) { 24 | var _a, _b, _c; 25 | this.bounds = [0, 0, 0, 0]; 26 | this.lastCameraHeight = 0; 27 | this.initRadius = 10; 28 | this.viewer = viewer; 29 | this.initOptions = Object.assign({}, options); 30 | if ((_a = this.initOptions) === null || _a === void 0 ? void 0 : _a.points) { 31 | const bounds = this.getBounds(this.initOptions.points); 32 | this.bounds = bounds; 33 | const { container, width, height } = this.createContainer(bounds); 34 | this.element = container; 35 | const datas = []; 36 | const values = []; 37 | for (let i in this.initOptions.points) { 38 | const point = this.initOptions.points[i]; 39 | const x = ((point.x - bounds[0]) / (bounds[2] - bounds[0])) * width; //屏幕坐标x 40 | const y = ((bounds[3] - point.y) / (bounds[3] - bounds[1])) * height; //屏幕坐标y 41 | const dataPoint = { 42 | x: x, 43 | y: y, 44 | value: point.value, 45 | }; 46 | if (typeof point.value === "number") 47 | values.push(point.value); 48 | datas.push(dataPoint); 49 | } 50 | //数据的最大值和最小值 51 | let _min = values.length > 100000 ? Min(values) : Math.min(...values); 52 | let _max = values.length > 100000 ? Max(values) : Math.max(...values); 53 | if ((_b = this.initOptions) === null || _b === void 0 ? void 0 : _b.heatmapDataOptions) { 54 | const { min, max } = this.initOptions.heatmapDataOptions; 55 | if (typeof min === "number") { 56 | _min = min; 57 | } 58 | if (typeof max === "number") { 59 | _max = max; 60 | } 61 | } 62 | this.heatmapDataOptions = { min: _min, max: _max }; 63 | const data = { 64 | max: _max, 65 | min: _min, 66 | data: datas, 67 | }; 68 | const defaultOptions = { 69 | maxOpacity: 0.9, 70 | // radius: minRadius, 71 | // minimum opacity. any value > 0 will produce 72 | // no transparent gradient transition 73 | minOpacity: 0.1, 74 | gradient: { 75 | // enter n keys between 0 and 1 here 76 | // for gradient color customization 77 | ".3": "blue", 78 | ".5": "green", 79 | ".7": "yellow", 80 | ".95": "red", 81 | }, 82 | }; 83 | const _options = this.initOptions.heatmapOptions 84 | ? Object.assign(Object.assign({}, defaultOptions), this.initOptions.heatmapOptions) : defaultOptions; 85 | //初始化半径 86 | if ((_c = this.heatmapOptions) === null || _c === void 0 ? void 0 : _c.radius) { 87 | this.initRadius = this.heatmapOptions.radius; 88 | } 89 | this.heatmapOptions = Object.assign({}, _options); 90 | const options = Object.assign(Object.assign({}, _options), { container }); 91 | this.heatmap = h337.create(options); 92 | this.heatmap.setData(data); 93 | this.createLayer(); 94 | if (!this.initOptions.noLisenerCamera) { 95 | this.addLisener(); 96 | } 97 | if (this.initOptions.zoomToLayer && bounds) { 98 | this.viewer.camera.flyTo({ 99 | destination: Rectangle.fromDegrees(...bounds), 100 | }); 101 | } 102 | } 103 | } 104 | /** 105 | * 设置数据的最大最小值 106 | * @param dataOption 107 | */ 108 | updateHeatMapMaxMin(dataOption) { 109 | const { min, max } = dataOption; 110 | if (this.heatmap) { 111 | if (typeof min === "number") { 112 | this.heatmap.setDataMin(min); 113 | if (this.heatmapDataOptions) 114 | this.heatmapDataOptions.min = min; 115 | } 116 | if (typeof max === "number") { 117 | this.heatmap.setDataMax(max); 118 | if (this.heatmapDataOptions) 119 | this.heatmapDataOptions.max = max; 120 | } 121 | } 122 | this.updateLayer(); 123 | } 124 | /** 125 | * 更新热度图配置 126 | * @param options 127 | */ 128 | updateHeatmap(options) { 129 | const { heatmapOptions } = this; 130 | this.heatmap.configure(Object.assign(Object.assign({}, heatmapOptions), options)); 131 | this.updateLayer(); 132 | } 133 | /** 134 | * 更新半径 135 | * @param radius 136 | */ 137 | updateRadius(radius) { 138 | var _a; 139 | const { heatmapOptions } = this; 140 | const currentData = this.heatmap.getData(); 141 | if (currentData === null || currentData === void 0 ? void 0 : currentData.data) { 142 | for (let i in currentData.data) { 143 | const data = currentData.data[i]; 144 | data.radius = radius; 145 | } 146 | } 147 | this.heatmap.setData(currentData); 148 | this.heatmapOptions = Object.assign(Object.assign({}, heatmapOptions), { radius }); 149 | this.updateLayer(); 150 | if ((_a = this.initOptions) === null || _a === void 0 ? void 0 : _a.onRadiusChange) { 151 | this.initOptions.onRadiusChange(radius); 152 | } 153 | } 154 | /** 155 | * 移除 156 | */ 157 | remove() { 158 | if (this.element) { 159 | document.body.removeChild(this.element); 160 | this.element = undefined; 161 | if (this.provider instanceof ImageryLayer) { 162 | if (this.provider) 163 | this.viewer.imageryLayers.remove(this.provider); 164 | this.createSingleTileImageryLayer(); 165 | } 166 | else if (this.provider instanceof Primitive) { 167 | this.viewer.scene.primitives.remove(this.provider); 168 | } 169 | else if (this.provider instanceof Entity) { 170 | this.viewer.entities.remove(this.provider); 171 | } 172 | if (this.cameraMoveEnd) { 173 | this.viewer.camera.moveEnd.removeEventListener(this.cameraMoveEnd); 174 | this.cameraMoveEnd = undefined; 175 | } 176 | } 177 | } 178 | createLayer() { 179 | if (this.initOptions.renderType === "primitive") { 180 | this.createPrimitive(); 181 | } 182 | else if (this.initOptions.renderType === "imagery") { 183 | this.createSingleTileImageryLayer(); 184 | } 185 | else { 186 | this.createEntity(); 187 | } 188 | } 189 | createPrimitive() { 190 | const url = this.heatmap.getDataURL(); 191 | this.provider = this.viewer.scene.primitives.add(new Primitive({ 192 | geometryInstances: new GeometryInstance({ 193 | geometry: new RectangleGeometry({ 194 | rectangle: Rectangle.fromDegrees(...this.bounds), 195 | vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT, 196 | }), 197 | }), 198 | appearance: new EllipsoidSurfaceAppearance({ 199 | aboveGround: false, 200 | }), 201 | show: true, 202 | })); 203 | if (this.provider) { 204 | this.provider.appearance.material = new Material({ 205 | fabric: { 206 | type: "Image", 207 | uniforms: { 208 | image: url, 209 | }, 210 | }, 211 | }); 212 | } 213 | } 214 | createSingleTileImageryLayer() { 215 | const url = this.heatmap.getDataURL(); 216 | this.provider = this.viewer.imageryLayers.addImageryProvider(new SingleTileImageryProvider({ 217 | url: url, 218 | rectangle: Rectangle.fromDegrees(...this.bounds), 219 | })); 220 | } 221 | getImageMaterialProperty() { 222 | const url = this.heatmap.getDataURL(); 223 | const material = new ImageMaterialProperty({ 224 | image: url, 225 | }); 226 | return material; 227 | } 228 | createEntity() { 229 | this.provider = this.viewer.entities.add({ 230 | show: true, 231 | rectangle: { 232 | coordinates: Rectangle.fromDegrees(...this.bounds), 233 | material: this.getImageMaterialProperty(), 234 | }, 235 | }); 236 | } 237 | updateLayer() { 238 | const src = this.heatmap.getDataURL(); 239 | if (this.provider instanceof ImageryLayer) { 240 | if (this.provider) 241 | this.viewer.imageryLayers.remove(this.provider); 242 | this.createSingleTileImageryLayer(); 243 | } 244 | else if (this.provider instanceof Primitive) { 245 | this.provider.appearance.material.uniforms.image = src; 246 | } 247 | else if (this.provider instanceof Entity) { 248 | if (this.provider.rectangle) 249 | this.provider.rectangle.material = this.getImageMaterialProperty(); 250 | } 251 | } 252 | /** 253 | * 添加相机的监听 254 | */ 255 | addLisener() { 256 | const maxRadius = 100; 257 | const min = 6375000; 258 | const max = 10000000; 259 | this.cameraMoveEnd = () => { 260 | var _a; 261 | if (this.heatmapOptions && this.heatmap && this.heatmapDataOptions) { 262 | const h = this.viewer.camera.getMagnitude(); 263 | const distance = ((_a = this === null || this === void 0 ? void 0 : this.initOptions) === null || _a === void 0 ? void 0 : _a.cameraHeightDistance) 264 | ? this.initOptions.cameraHeightDistance 265 | : 1000; 266 | if (Math.abs(h - this.lastCameraHeight) > distance) { 267 | this.lastCameraHeight = h; 268 | if (typeof min === "number" && typeof max === "number") { 269 | const radius = parseInt((this.initRadius + 270 | ((maxRadius - this.initRadius) * (h - min)) / (max - min)).toFixed(0)); 271 | if (radius) { 272 | this.updateRadius(radius); 273 | } 274 | } 275 | } 276 | } 277 | }; 278 | this.viewer.camera.moveEnd.addEventListener(this.cameraMoveEnd); 279 | } 280 | /** 281 | * 282 | * @param points 283 | * @param expand 284 | * @returns 285 | */ 286 | getBounds(points) { 287 | if (points) { 288 | let lonMin = 180; 289 | let lonMax = -180; 290 | let latMin = 90; 291 | let latMax = -180; 292 | points.forEach(function (point) { 293 | const { x: longitude, y: latitude } = point; 294 | lonMin = longitude < lonMin ? longitude : lonMin; 295 | latMin = latitude < latMin ? latitude : latMin; 296 | lonMax = longitude > lonMax ? longitude : lonMax; 297 | latMax = latitude > latMax ? latitude : latMax; 298 | }); 299 | const xRange = lonMax - lonMin ? lonMax - lonMin : 1; 300 | const yRange = latMax - latMin ? latMax - latMin : 1; 301 | return [ 302 | lonMin - xRange / 10, 303 | latMin - yRange / 10, 304 | lonMax + xRange / 10, 305 | latMax + yRange / 10, 306 | ]; 307 | } 308 | return [0, 0, 0, 0]; 309 | } 310 | createContainer(bounds) { 311 | const container = document.createElement("div"); 312 | const width = 1000; 313 | const height = parseInt(((1000 / (bounds[2] - bounds[0])) * (bounds[3] - bounds[1])).toFixed(0)); 314 | container.setAttribute("style", `width:${width}px;height:${height}px;display:none;`); 315 | document.body.appendChild(container); 316 | return { container, width, height }; 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | export * from "./cesiumHeatmap"; 2 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. -------------------------------------------------------------------------------- /docs/assets/highlight.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --light-hl-0: #800000; 3 | --dark-hl-0: #808080; 4 | --light-hl-1: #800000; 5 | --dark-hl-1: #569CD6; 6 | --light-hl-2: #000000; 7 | --dark-hl-2: #D4D4D4; 8 | --light-hl-3: #FF0000; 9 | --dark-hl-3: #9CDCFE; 10 | --light-hl-4: #A31515; 11 | --dark-hl-4: #CE9178; 12 | --light-hl-5: #0000FF; 13 | --dark-hl-5: #569CD6; 14 | --light-hl-6: #0070C1; 15 | --dark-hl-6: #4FC1FF; 16 | --light-hl-7: #098658; 17 | --dark-hl-7: #B5CEA8; 18 | --light-hl-8: #795E26; 19 | --dark-hl-8: #DCDCAA; 20 | --light-hl-9: #001080; 21 | --dark-hl-9: #9CDCFE; 22 | --light-hl-10: #AF00DB; 23 | --dark-hl-10: #C586C0; 24 | --light-hl-11: #267F99; 25 | --dark-hl-11: #4EC9B0; 26 | --light-code-background: #F5F5F5; 27 | --dark-code-background: #1E1E1E; 28 | } 29 | 30 | @media (prefers-color-scheme: light) { :root { 31 | --hl-0: var(--light-hl-0); 32 | --hl-1: var(--light-hl-1); 33 | --hl-2: var(--light-hl-2); 34 | --hl-3: var(--light-hl-3); 35 | --hl-4: var(--light-hl-4); 36 | --hl-5: var(--light-hl-5); 37 | --hl-6: var(--light-hl-6); 38 | --hl-7: var(--light-hl-7); 39 | --hl-8: var(--light-hl-8); 40 | --hl-9: var(--light-hl-9); 41 | --hl-10: var(--light-hl-10); 42 | --hl-11: var(--light-hl-11); 43 | --code-background: var(--light-code-background); 44 | } } 45 | 46 | @media (prefers-color-scheme: dark) { :root { 47 | --hl-0: var(--dark-hl-0); 48 | --hl-1: var(--dark-hl-1); 49 | --hl-2: var(--dark-hl-2); 50 | --hl-3: var(--dark-hl-3); 51 | --hl-4: var(--dark-hl-4); 52 | --hl-5: var(--dark-hl-5); 53 | --hl-6: var(--dark-hl-6); 54 | --hl-7: var(--dark-hl-7); 55 | --hl-8: var(--dark-hl-8); 56 | --hl-9: var(--dark-hl-9); 57 | --hl-10: var(--dark-hl-10); 58 | --hl-11: var(--dark-hl-11); 59 | --code-background: var(--dark-code-background); 60 | } } 61 | 62 | body.light { 63 | --hl-0: var(--light-hl-0); 64 | --hl-1: var(--light-hl-1); 65 | --hl-2: var(--light-hl-2); 66 | --hl-3: var(--light-hl-3); 67 | --hl-4: var(--light-hl-4); 68 | --hl-5: var(--light-hl-5); 69 | --hl-6: var(--light-hl-6); 70 | --hl-7: var(--light-hl-7); 71 | --hl-8: var(--light-hl-8); 72 | --hl-9: var(--light-hl-9); 73 | --hl-10: var(--light-hl-10); 74 | --hl-11: var(--light-hl-11); 75 | --code-background: var(--light-code-background); 76 | } 77 | 78 | body.dark { 79 | --hl-0: var(--dark-hl-0); 80 | --hl-1: var(--dark-hl-1); 81 | --hl-2: var(--dark-hl-2); 82 | --hl-3: var(--dark-hl-3); 83 | --hl-4: var(--dark-hl-4); 84 | --hl-5: var(--dark-hl-5); 85 | --hl-6: var(--dark-hl-6); 86 | --hl-7: var(--dark-hl-7); 87 | --hl-8: var(--dark-hl-8); 88 | --hl-9: var(--dark-hl-9); 89 | --hl-10: var(--dark-hl-10); 90 | --hl-11: var(--dark-hl-11); 91 | --code-background: var(--dark-code-background); 92 | } 93 | 94 | .hl-0 { color: var(--hl-0); } 95 | .hl-1 { color: var(--hl-1); } 96 | .hl-2 { color: var(--hl-2); } 97 | .hl-3 { color: var(--hl-3); } 98 | .hl-4 { color: var(--hl-4); } 99 | .hl-5 { color: var(--hl-5); } 100 | .hl-6 { color: var(--hl-6); } 101 | .hl-7 { color: var(--hl-7); } 102 | .hl-8 { color: var(--hl-8); } 103 | .hl-9 { color: var(--hl-9); } 104 | .hl-10 { color: var(--hl-10); } 105 | .hl-11 { color: var(--hl-11); } 106 | pre, code { background: var(--code-background); } 107 | -------------------------------------------------------------------------------- /docs/assets/icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesium-plugin/cesium-heatmap-es6/8721e879aafa0845f4cde4a41c0f13d37ec9d51b/docs/assets/icons.png -------------------------------------------------------------------------------- /docs/assets/icons@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesium-plugin/cesium-heatmap-es6/8721e879aafa0845f4cde4a41c0f13d37ec9d51b/docs/assets/icons@2x.png -------------------------------------------------------------------------------- /docs/assets/widgets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesium-plugin/cesium-heatmap-es6/8721e879aafa0845f4cde4a41c0f13d37ec9d51b/docs/assets/widgets.png -------------------------------------------------------------------------------- /docs/assets/widgets@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesium-plugin/cesium-heatmap-es6/8721e879aafa0845f4cde4a41c0f13d37ec9d51b/docs/assets/widgets@2x.png -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | cesium-heatmap-es6
Options
All
  • Public
  • Public/Protected
  • All
Menu

cesium-heatmap-es6

2 | 3 |

参考源码

4 |
5 |

1.《117颗星 manuelnas/CesiumHeatmap》 6 | 基于heatmap.min.js,通过绘制Entity(矩形)实体实现,364行代码,有三维效果 7 | 2. 《32颗星 postor/cesiumjs-heat 》 8 | 基于heatmap.min.js,使用SingleTileImageryProvider图层实现,根据镜头移动具有重绘功能,239行代码,无三维效果 9 | 3. 《16颗星 wangzhongliang/CesiumHeatmap》 10 | 使用Primitive图元实现,提供了两种方式,优点在于计算范围的方法。 11 | 方式一基于heatmap.min.js,157行代码,无三维效果; 12 | 方式二基于webgl-heatmap.js,128行代码,无三维效果;

13 | 14 | 15 |

特点

16 |
17 |
    18 |
  1. 提供三种绘制方式,实体(可贴模型,有三维效果)、图元、图层
  2. 19 |
  3. 提供重绘,通过摄像头的高度进行重绘
  4. 20 |
  5. 提供heatmap.js的所有配置参数入口
  6. 21 |
  7. 源码ts编写,发布支持es6和umd两种模式
  8. 22 |
  9. 支持npm安装
  10. 23 |
24 | 25 | 26 |

效果图

27 |
28 |

效果图

29 |

在这里插入图片描述 30 | 在这里插入图片描述

31 | 32 | 33 |

插件使用方法

34 |
35 | 36 | 37 |

安装

38 |
39 |

npm install cesium-heatmap-es6

40 | 41 | 42 |

文档

43 |
44 |

自行打开docs文件夹

45 | 46 | 47 |

umd模式

48 |
49 |
<script type="text/javascript" src="./CesiumHeatmap/dist/cesium-heatmap-es6.umd.js"></script>
const defaultDataValue = [10, 500]
const defaultOpacityValue = [0, 1]
const points = []
fetch("/datas/geojson/busstop2016.geojson", {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
}).then((response) => {
response.json().then((data) => {
if (data)
data.features.forEach(function (feature) {
const lon = feature.geometry.coordinates[0]
const lat = feature.geometry.coordinates[1]
points.push({
x: lon,
y: lat,
value: 100 * Math.random()
})
})
const earthHeatMap = new CesiumHeatmap(viewer,
{
zoomToLayer: true,
points,
heatmapDataOptions: { max: defaultDataValue[1], min: defaultDataValue[0] },
heatmapOptions: {
maxOpacity: defaultOpacityValue[1],
minOpacity: defaultOpacityValue[0]
}
}
)
})
}) 50 |
51 | 52 | 53 |

es6模式

54 |
55 |
 const defaultDataValue = [10, 500]
const defaultOpacityValue = [0, 1]
import { CesiumHeatmap, HeatmapPoint } from "cesium-heatmap-es6"

const points: HeatmapPoint[] = []
fetch("/datas/geojson/busstop2016.geojson", {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
}).then((response) => {
response.json().then((data) => {
if (data)
data.features.forEach(function (feature) {
const lon = feature.geometry.coordinates[0]
const lat = feature.geometry.coordinates[1]
points.push({
x: lon - 0.05,
y: lat - 0.04,
value: 100 * Math.random()
})
})
cesiumHeatmap = new CesiumHeatmap(viewer,
{
zoomToLayer: true,
points,
heatmapDataOptions: { max: defaultDataValue[1], min: defaultDataValue[0] },
heatmapOptions: {
maxOpacity: defaultOpacityValue[1],
minOpacity: defaultOpacityValue[0]
}
}
)
})
}) 56 |
57 | 58 | 59 |

源码使用方法

60 |
61 | 62 | 63 |

依赖安装

64 |
65 |

npm run a

66 | 67 | 68 |

项目运行

69 |
70 |

npm start

71 | 72 | 73 |

项目打包

74 |
75 |

npm run build

76 | 77 | 78 |

发布

79 |
80 |

npm run release

81 |

Legend

  • Property
  • Method
  • Constructor
  • Method
  • Private property
  • Private method

Settings

Theme

Generated using TypeDoc

-------------------------------------------------------------------------------- /docs/interfaces/CesiumHeatmapOption.html: -------------------------------------------------------------------------------- 1 | CesiumHeatmapOption | cesium-heatmap-es6
Options
All
  • Public
  • Public/Protected
  • All
Menu

Interface CesiumHeatmapOption

Hierarchy

  • CesiumHeatmapOption

Index

Properties

bounds?: number[]
cameraHeightDistance?: number
heatmapDataOptions?: HeatmapDataOption
heatmapOptions?: BaseHeatmapConfiguration
noLisenerCamera?: boolean
points: HeatmapPoint[]
renderType?: RenderType
zoomToLayer?: boolean

Methods

  • onRadiusChange(radius: number): void

Legend

  • Property
  • Method
  • Constructor
  • Method
  • Private property
  • Private method

Settings

Theme

Generated using TypeDoc

-------------------------------------------------------------------------------- /docs/interfaces/HeatmapDataOption.html: -------------------------------------------------------------------------------- 1 | HeatmapDataOption | cesium-heatmap-es6
Options
All
  • Public
  • Public/Protected
  • All
Menu

Interface HeatmapDataOption

Hierarchy

  • HeatmapDataOption

Index

Properties

Properties

max?: number
min?: number

Legend

  • Property
  • Method
  • Constructor
  • Method
  • Private property
  • Private method

Settings

Theme

Generated using TypeDoc

-------------------------------------------------------------------------------- /docs/interfaces/HeatmapPoint.html: -------------------------------------------------------------------------------- 1 | HeatmapPoint | cesium-heatmap-es6
Options
All
  • Public
  • Public/Protected
  • All
Menu

Interface HeatmapPoint

Hierarchy

  • HeatmapPoint

Index

Properties

Properties

value?: number
x: number
y: number

Legend

  • Property
  • Method
  • Constructor
  • Method
  • Private property
  • Private method

Settings

Theme

Generated using TypeDoc

-------------------------------------------------------------------------------- /docs/modules.html: -------------------------------------------------------------------------------- 1 | cesium-heatmap-es6
Options
All
  • Public
  • Public/Protected
  • All
Menu

cesium-heatmap-es6

Legend

  • Property
  • Method
  • Constructor
  • Method
  • Private property
  • Private method

Settings

Theme

Generated using TypeDoc

-------------------------------------------------------------------------------- /lib/cesiumHeatmap.d.ts: -------------------------------------------------------------------------------- 1 | import { Viewer } from "cesium"; 2 | export interface BaseHeatmapConfiguration { 3 | /** 4 | * A background color string in form of hexcode, color name, or rgb(a) 5 | */ 6 | backgroundColor?: string | undefined; 7 | /** 8 | * The blur factor that will be applied to all datapoints. The higher the 9 | * blur factor is, the smoother the gradients will be 10 | * Default value: 0.85 11 | */ 12 | blur?: number | undefined; 13 | /** 14 | * An object that represents the gradient. 15 | * Syntax: {[key: number in range [0,1]]: color} 16 | */ 17 | gradient?: { 18 | [key: string]: string; 19 | } | undefined; 20 | /** 21 | * The maximal opacity the highest value in the heatmap will have. (will be 22 | * overridden if opacity set) 23 | * Default value: 0.6 24 | */ 25 | maxOpacity?: number | undefined; 26 | /** 27 | * The minimum opacity the lowest value in the heatmap will have (will be 28 | * overridden if opacity set) 29 | */ 30 | minOpacity?: number | undefined; 31 | /** 32 | * A global opacity for the whole heatmap. This overrides maxOpacity and 33 | * minOpacity if set 34 | * Default value: 0.6 35 | */ 36 | opacity?: number | undefined; 37 | /** 38 | * The radius each datapoint will have (if not specified on the datapoint 39 | * itself) 40 | */ 41 | radius?: number | undefined; 42 | /** 43 | * The property name of the value/weight in a datapoint 44 | * Default value: 'value' 45 | */ 46 | valueField?: undefined; 47 | /** 48 | * Pass a callback to receive extrema change updates. Useful for DOM 49 | * legends. 50 | */ 51 | onExtremaChange?: (() => void) | undefined; 52 | /** 53 | * Indicate whether the heatmap should use a global extrema or a local 54 | * extrema (the maximum and minimum of the currently displayed viewport) 55 | */ 56 | useLocalExtrema?: boolean | undefined; 57 | } 58 | export interface HeatmapPoint { 59 | x: number; 60 | y: number; 61 | value?: number; 62 | } 63 | export interface HeatmapConfiguration extends BaseHeatmapConfiguration { 64 | } 65 | export interface HeatmapDataOption { 66 | max?: number; 67 | min?: number; 68 | } 69 | export declare type RenderType = "primitive" | "imagery" | "entity"; 70 | export interface CesiumHeatmapOption { 71 | noLisenerCamera?: boolean; 72 | cameraHeightDistance?: number; 73 | renderType?: RenderType; 74 | points: HeatmapPoint[]; 75 | bounds?: number[]; 76 | heatmapOptions?: BaseHeatmapConfiguration; 77 | heatmapDataOptions?: HeatmapDataOption; 78 | zoomToLayer?: boolean; 79 | onRadiusChange?: (radius: number) => void; 80 | } 81 | export declare type Bounds = [number, number, number, number]; 82 | /** 83 | * 热度图 84 | */ 85 | export declare class CesiumHeatmap { 86 | private viewer; 87 | private element?; 88 | private initOptions; 89 | private heatmapOptions?; 90 | private heatmapDataOptions?; 91 | private provider?; 92 | private heatmap?; 93 | private cameraMoveEnd?; 94 | private bounds; 95 | private lastCameraHeight; 96 | private initRadius; 97 | constructor(viewer: Viewer, options: CesiumHeatmapOption); 98 | /** 99 | * 设置数据的最大最小值 100 | * @param dataOption 101 | */ 102 | updateHeatMapMaxMin(dataOption: HeatmapDataOption): void; 103 | /** 104 | * 更新热度图配置 105 | * @param options 106 | */ 107 | updateHeatmap(options: HeatmapConfiguration): void; 108 | /** 109 | * 更新半径 110 | * @param radius 111 | */ 112 | updateRadius(radius: number): void; 113 | /** 114 | * 移除 115 | */ 116 | remove(): void; 117 | private createLayer; 118 | private createPrimitive; 119 | private createSingleTileImageryLayer; 120 | private getImageMaterialProperty; 121 | private createEntity; 122 | private updateLayer; 123 | /** 124 | * 添加相机的监听 125 | */ 126 | private addLisener; 127 | /** 128 | * 129 | * @param points 130 | * @param expand 131 | * @returns 132 | */ 133 | private getBounds; 134 | private createContainer; 135 | } 136 | -------------------------------------------------------------------------------- /lib/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from "./cesiumHeatmap"; 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cesium-heatmap-es6", 3 | "main": "dist/cesium-heatmap-es6.umd.js", 4 | "module": "dist/index.js", 5 | "typings": "lib/index.d.ts", 6 | "version": "0.8.0", 7 | "private": false, 8 | "dependencies": { 9 | "cesium": "^1.102.0" 10 | }, 11 | "files": [ 12 | "dist", 13 | "docs", 14 | "lib", 15 | "README.md", 16 | "package.json", 17 | "LICENSE", 18 | "CHANGELOG.md" 19 | ], 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/cesium-plugin/cesium-heatmap-es6.git" 23 | }, 24 | "bugs": { 25 | "url": "https://github.com/cesium-plugin/cesium-heatmap-es6/issues" 26 | }, 27 | "scripts": { 28 | "test": "react-scripts test", 29 | "eject": "react-scripts eject", 30 | "a": "npm install --registry https://registry.npm.taobao.org", 31 | "start": "node --max-old-space-size=6000 node_modules/cross-env/src/bin/cross-env.js PORT=5557 craco start", 32 | "build": "rimraf ./build && cross-env GENERATE_SOURCEMAP=false craco build", 33 | "ts2js": "tsc ./src/source/index.ts --target es2016", 34 | "release": "npm run doc & webpack --config ./webpack.config.release.js & npm run copyjs", 35 | "copyjs": "npm run ts2js & webpack --config ./webpack.config.copyjs.js", 36 | "doc": "npx typedoc ./src/source/index.ts" 37 | }, 38 | "eslintConfig": { 39 | "extends": [ 40 | "react-app", 41 | "react-app/jest" 42 | ] 43 | }, 44 | "browserslist": { 45 | "production": [ 46 | ">0.2%", 47 | "not dead", 48 | "not op_mini all" 49 | ], 50 | "development": [ 51 | "last 1 chrome version", 52 | "last 1 firefox version", 53 | "last 1 safari version" 54 | ] 55 | }, 56 | "devDependencies": { 57 | "@babel/preset-env": "^7.14.8", 58 | "@babel/preset-react": "^7.14.5", 59 | "@craco/craco": "6.2.0", 60 | "@testing-library/jest-dom": "^5.11.4", 61 | "@testing-library/react": "^11.1.0", 62 | "@testing-library/user-event": "^12.1.10", 63 | "@types/jest": "^26.0.15", 64 | "@types/jquery": "^3.5.5", 65 | "@types/js-md5": "^0.4.2", 66 | "@types/node": "^12.0.0", 67 | "@types/react": "^17.0.3", 68 | "@types/react-dom": "^17.0.3", 69 | "@types/react-router-dom": "^5.1.7", 70 | "@types/sortablejs": "^1.10.7", 71 | "@types/uuid": "^8.3.1", 72 | "antd": "^4.18.2", 73 | "awesome-typescript-loader": "3.5.0", 74 | "babel-loader": "^8.2.2", 75 | "babel-plugin-import": "^1.13.3", 76 | "browser-sync": "^2.18.11", 77 | "browser-sync-spa": "^1.0.3", 78 | "clean-webpack-plugin": "^4.0.0", 79 | "compression-webpack-plugin": "^5.0.1", 80 | "copy-webpack-plugin": "6.4.1", 81 | "craco-less": "^1.18.0", 82 | "cross-env": "^7.0.3", 83 | "gulp": "^4.0.2", 84 | "gutil": "^1.6.4", 85 | "html-loader": "0.5.5", 86 | "less": "^4.1.1", 87 | "markdown-loader": "5.1.0", 88 | "mv": "^2.1.1", 89 | "react": "^17.0.2", 90 | "react-dom": "^17.0.2", 91 | "react-error-overlay": "6.0.9", 92 | "react-router-dom": "^5.2.1", 93 | "react-scripts": "4.0.3", 94 | "typedoc": "^0.22.11", 95 | "typescript": "4.5.4", 96 | "uglifyjs-webpack-plugin": "^1.3.0", 97 | "web-vitals": "^1.0.1", 98 | "webpack-bundle-analyzer": "^4.4.2", 99 | "webpack-cli": "^4.9.1" 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /public/CesiumHeatmap/dist/cesium-heatmap-es6.umd.js: -------------------------------------------------------------------------------- 1 | /*! cesium-heatmap-es6 v0.7.0 - cesium-heatmap-es6.umd.js, e4faef7769bd6e9cbc39, Tue Mar 28 2023 00:26:23 GMT+0800 (中国标准时间) */ 2 | !function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e(require("Cesium"));else if("function"==typeof define&&define.amd)define(["Cesium"],e);else{var i="object"==typeof exports?e(require("Cesium")):e(t.Cesium);for(var a in i)("object"==typeof exports?exports:t)[a]=i[a]}}(window,(function(t){return function(t){var e={};function i(a){if(e[a])return e[a].exports;var r=e[a]={i:a,l:!1,exports:{}};return t[a].call(r.exports,r,r.exports,i),r.l=!0,r.exports}return i.m=t,i.c=e,i.d=function(t,e,a){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:a})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(t,e){if(1&e&&(t=i(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var a=Object.create(null);if(i.r(a),Object.defineProperty(a,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)i.d(a,r,function(e){return t[e]}.bind(null,r));return a},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=1)}([function(e,i){e.exports=t},function(t,e,i){"use strict";i.r(e),i.d(e,"CesiumHeatmap",(function(){return c}));var a,r=i(0),n={defaultRadius:40,defaultRenderer:"canvas2d",defaultGradient:{.25:"rgb(0,0,255)",.55:"rgb(0,255,0)",.85:"yellow",1:"rgb(255,0,0)"},defaultMaxOpacity:1,defaultMinOpacity:0,defaultBlur:.85,defaultXField:"x",defaultYField:"y",defaultValueField:"value",plugins:{}},s=function(){var t=function(t){this._coordinator={},this._data=[],this._radi=[],this._min=0,this._max=1,this._xField=t.xField||t.defaultXField,this._yField=t.yField||t.defaultYField,this._valueField=t.valueField||t.defaultValueField,t.radius&&(this._cfgRadius=t.radius)},e=n.defaultRadius;return t.prototype={_organiseData:function(t,i){var a=t[this._xField],r=t[this._yField],n=this._radi,s=this._data,o=this._max,h=this._min,d=t[this._valueField]||1,u=t.radius||this._cfgRadius||e;return s[a]||(s[a]=[],n[a]=[]),s[a][r]?s[a][r]+=d:(s[a][r]=d,n[a][r]=u),s[a][r]>o?(i?this.setDataMax(s[a][r]):this._max=s[a][r],!1):{x:a,y:r,value:d,radius:u,min:h,max:o}},_unOrganizeData:function(){var t=[],e=this._data,i=this._radi;for(var a in e)for(var r in e[a])t.push({x:a,y:r,radius:i[a][r],value:e[a][r]});return{min:this._min,max:this._max,data:t}},_onExtremaChange:function(){this._coordinator.emit("extremachange",{min:this._min,max:this._max})},addData:function(){if(arguments[0].length>0)for(var t=arguments[0],e=t.length;e--;)this.addData.call(this,t[e]);else{var i=this._organiseData(arguments[0],!0);i&&this._coordinator.emit("renderpartial",{min:this._min,max:this._max,data:[i]})}return this},setData:function(t){var e=t.data,i=e.length;this._data=[],this._radi=[];for(var a=0;athis._renderBoundaries[2]&&(this._renderBoundaries[2]=c+2*u),p+2*u>this._renderBoundaries[3]&&(this._renderBoundaries[3]=p+2*u)}},_colorize:function(){var t=this._renderBoundaries[0],e=this._renderBoundaries[1],i=this._renderBoundaries[2]-t,a=this._renderBoundaries[3]-e,r=this._width,n=this._height,s=this._opacity,o=this._maxOpacity,h=this._minOpacity,d=this._useGradientOpacity;t<0&&(t=0),e<0&&(e=0),t+i>r&&(i=r-t),e+a>n&&(a=n-e);for(var u=this.shadowCtx.getImageData(t,e,i,a),l=u.data,c=l.length,p=this._palette,m=3;m0?s:f>0},getDataURL:function(){return this.canvas.toDataURL()}},i}(),h=(a=!1,"canvas2d"===n.defaultRenderer&&(a=o),a),d=function(){for(var t={},e=arguments.length,i=0;i1e5?(t=>{let e=t.length,i=1/0;for(;e--;)i=t[e]1e5?(t=>{let e=t.length,i=-1/0;for(;e--;)i=t[e]>i?t[e]:i;return i})(h):Math.max(...h);if(null===(a=this.initOptions)||void 0===a?void 0:a.heatmapDataOptions){const{min:t,max:e}=this.initOptions.heatmapDataOptions;"number"==typeof t&&(d=t),"number"==typeof e&&(u=e)}this.heatmapDataOptions={min:d,max:u};const c={max:u,min:d,data:o},p={maxOpacity:.9,minOpacity:.1,gradient:{".3":"blue",".5":"green",".7":"yellow",".95":"red"}},m=this.initOptions.heatmapOptions?Object.assign(Object.assign({},p),this.initOptions.heatmapOptions):p;(null===(n=this.heatmapOptions)||void 0===n?void 0:n.radius)&&(this.initRadius=this.heatmapOptions.radius),this.heatmapOptions=Object.assign({},m);const g=Object.assign(Object.assign({},m),{container:e});this.heatmap=l.create(g),this.heatmap.setData(c),this.createLayer(),this.initOptions.noLisenerCamera||this.addLisener(),this.initOptions.zoomToLayer&&t&&this.viewer.camera.flyTo({destination:r.Rectangle.fromDegrees(...t)})}}updateHeatMapMaxMin(t){const{min:e,max:i}=t;this.heatmap&&("number"==typeof e&&(this.heatmap.setDataMin(e),this.heatmapDataOptions&&(this.heatmapDataOptions.min=e)),"number"==typeof i&&(this.heatmap.setDataMax(i),this.heatmapDataOptions&&(this.heatmapDataOptions.max=i))),this.updateLayer()}updateHeatmap(t){const{heatmapOptions:e}=this;this.heatmap.configure(Object.assign(Object.assign({},e),t)),this.updateLayer()}updateRadius(t){var e;const{heatmapOptions:i}=this,a=this.heatmap.getData();if(null==a?void 0:a.data)for(let e in a.data){a.data[e].radius=t}this.heatmap.setData(a),this.heatmapOptions=Object.assign(Object.assign({},i),{radius:t}),this.updateLayer(),(null===(e=this.initOptions)||void 0===e?void 0:e.onRadiusChange)&&this.initOptions.onRadiusChange(t)}remove(){this.element&&(document.body.removeChild(this.element),this.element=void 0,this.provider instanceof r.ImageryLayer?(this.provider&&this.viewer.imageryLayers.remove(this.provider),this.createSingleTileImageryLayer()):this.provider instanceof r.Primitive?this.viewer.scene.primitives.remove(this.provider):this.provider instanceof r.Entity&&this.viewer.entities.remove(this.provider),this.cameraMoveEnd&&(this.viewer.camera.moveEnd.removeEventListener(this.cameraMoveEnd),this.cameraMoveEnd=void 0))}createLayer(){"primitive"===this.initOptions.renderType?this.createPrimitive():"imagery"===this.initOptions.renderType?this.createSingleTileImageryLayer():this.createEntity()}createPrimitive(){const t=this.heatmap.getDataURL();this.provider=this.viewer.scene.primitives.add(new r.Primitive({geometryInstances:new r.GeometryInstance({geometry:new r.RectangleGeometry({rectangle:r.Rectangle.fromDegrees(...this.bounds),vertexFormat:r.EllipsoidSurfaceAppearance.VERTEX_FORMAT})}),appearance:new r.EllipsoidSurfaceAppearance({aboveGround:!1}),show:!0})),this.provider&&(this.provider.appearance.material=new r.Material({fabric:{type:"Image",uniforms:{image:t}}}))}createSingleTileImageryLayer(){const t=this.heatmap.getDataURL();this.provider=this.viewer.imageryLayers.addImageryProvider(new r.SingleTileImageryProvider({url:t,rectangle:r.Rectangle.fromDegrees(...this.bounds)}))}getImageMaterialProperty(){const t=this.heatmap.getDataURL();return new r.ImageMaterialProperty({image:t})}createEntity(){this.provider=this.viewer.entities.add({show:!0,rectangle:{coordinates:r.Rectangle.fromDegrees(...this.bounds),material:this.getImageMaterialProperty()}})}updateLayer(){const t=this.heatmap.getDataURL();this.provider instanceof r.ImageryLayer?(this.provider&&this.viewer.imageryLayers.remove(this.provider),this.createSingleTileImageryLayer()):this.provider instanceof r.Primitive?this.provider.appearance.material.uniforms.image=t:this.provider instanceof r.Entity&&this.provider.rectangle&&(this.provider.rectangle.material=this.getImageMaterialProperty())}addLisener(){const t=6375e3;this.cameraMoveEnd=()=>{var e;if(this.heatmapOptions&&this.heatmap&&this.heatmapDataOptions){const i=this.viewer.camera.getMagnitude(),a=(null===(e=null==this?void 0:this.initOptions)||void 0===e?void 0:e.cameraHeightDistance)?this.initOptions.cameraHeightDistance:1e3;if(Math.abs(i-this.lastCameraHeight)>a){this.lastCameraHeight=i;{const e=parseInt((this.initRadius+(100-this.initRadius)*(i-t)/3625e3).toFixed(0));e&&this.updateRadius(e)}}}},this.viewer.camera.moveEnd.addEventListener(this.cameraMoveEnd)}getBounds(t){if(t){let e=180,i=-180,a=90,r=-180;t.forEach((function(t){const{x:n,y:s}=t;e=ni?n:i,r=s>r?s:r}));const n=i-e?i-e:1,s=r-a?r-a:1;return[e-n/10,a-s/10,i+n/10,r+s/10]}return[0,0,0,0]}createContainer(t){const e=document.createElement("div"),i=parseInt((1e3/(t[2]-t[0])*(t[3]-t[1])).toFixed(0));return e.setAttribute("style",`width:1000px;height:${i}px;display:none;`),document.body.appendChild(e),{container:e,width:1e3,height:i}}}}])})); -------------------------------------------------------------------------------- /public/CesiumHeatmap/docs/.nojekyll: -------------------------------------------------------------------------------- 1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. -------------------------------------------------------------------------------- /public/CesiumHeatmap/docs/assets/highlight.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --light-hl-0: #800000; 3 | --dark-hl-0: #808080; 4 | --light-hl-1: #800000; 5 | --dark-hl-1: #569CD6; 6 | --light-hl-2: #000000; 7 | --dark-hl-2: #D4D4D4; 8 | --light-hl-3: #FF0000; 9 | --dark-hl-3: #9CDCFE; 10 | --light-hl-4: #A31515; 11 | --dark-hl-4: #CE9178; 12 | --light-hl-5: #0000FF; 13 | --dark-hl-5: #569CD6; 14 | --light-hl-6: #0070C1; 15 | --dark-hl-6: #4FC1FF; 16 | --light-hl-7: #098658; 17 | --dark-hl-7: #B5CEA8; 18 | --light-hl-8: #795E26; 19 | --dark-hl-8: #DCDCAA; 20 | --light-hl-9: #001080; 21 | --dark-hl-9: #9CDCFE; 22 | --light-hl-10: #AF00DB; 23 | --dark-hl-10: #C586C0; 24 | --light-hl-11: #267F99; 25 | --dark-hl-11: #4EC9B0; 26 | --light-code-background: #F5F5F5; 27 | --dark-code-background: #1E1E1E; 28 | } 29 | 30 | @media (prefers-color-scheme: light) { :root { 31 | --hl-0: var(--light-hl-0); 32 | --hl-1: var(--light-hl-1); 33 | --hl-2: var(--light-hl-2); 34 | --hl-3: var(--light-hl-3); 35 | --hl-4: var(--light-hl-4); 36 | --hl-5: var(--light-hl-5); 37 | --hl-6: var(--light-hl-6); 38 | --hl-7: var(--light-hl-7); 39 | --hl-8: var(--light-hl-8); 40 | --hl-9: var(--light-hl-9); 41 | --hl-10: var(--light-hl-10); 42 | --hl-11: var(--light-hl-11); 43 | --code-background: var(--light-code-background); 44 | } } 45 | 46 | @media (prefers-color-scheme: dark) { :root { 47 | --hl-0: var(--dark-hl-0); 48 | --hl-1: var(--dark-hl-1); 49 | --hl-2: var(--dark-hl-2); 50 | --hl-3: var(--dark-hl-3); 51 | --hl-4: var(--dark-hl-4); 52 | --hl-5: var(--dark-hl-5); 53 | --hl-6: var(--dark-hl-6); 54 | --hl-7: var(--dark-hl-7); 55 | --hl-8: var(--dark-hl-8); 56 | --hl-9: var(--dark-hl-9); 57 | --hl-10: var(--dark-hl-10); 58 | --hl-11: var(--dark-hl-11); 59 | --code-background: var(--dark-code-background); 60 | } } 61 | 62 | body.light { 63 | --hl-0: var(--light-hl-0); 64 | --hl-1: var(--light-hl-1); 65 | --hl-2: var(--light-hl-2); 66 | --hl-3: var(--light-hl-3); 67 | --hl-4: var(--light-hl-4); 68 | --hl-5: var(--light-hl-5); 69 | --hl-6: var(--light-hl-6); 70 | --hl-7: var(--light-hl-7); 71 | --hl-8: var(--light-hl-8); 72 | --hl-9: var(--light-hl-9); 73 | --hl-10: var(--light-hl-10); 74 | --hl-11: var(--light-hl-11); 75 | --code-background: var(--light-code-background); 76 | } 77 | 78 | body.dark { 79 | --hl-0: var(--dark-hl-0); 80 | --hl-1: var(--dark-hl-1); 81 | --hl-2: var(--dark-hl-2); 82 | --hl-3: var(--dark-hl-3); 83 | --hl-4: var(--dark-hl-4); 84 | --hl-5: var(--dark-hl-5); 85 | --hl-6: var(--dark-hl-6); 86 | --hl-7: var(--dark-hl-7); 87 | --hl-8: var(--dark-hl-8); 88 | --hl-9: var(--dark-hl-9); 89 | --hl-10: var(--dark-hl-10); 90 | --hl-11: var(--dark-hl-11); 91 | --code-background: var(--dark-code-background); 92 | } 93 | 94 | .hl-0 { color: var(--hl-0); } 95 | .hl-1 { color: var(--hl-1); } 96 | .hl-2 { color: var(--hl-2); } 97 | .hl-3 { color: var(--hl-3); } 98 | .hl-4 { color: var(--hl-4); } 99 | .hl-5 { color: var(--hl-5); } 100 | .hl-6 { color: var(--hl-6); } 101 | .hl-7 { color: var(--hl-7); } 102 | .hl-8 { color: var(--hl-8); } 103 | .hl-9 { color: var(--hl-9); } 104 | .hl-10 { color: var(--hl-10); } 105 | .hl-11 { color: var(--hl-11); } 106 | pre, code { background: var(--code-background); } 107 | -------------------------------------------------------------------------------- /public/CesiumHeatmap/docs/assets/icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesium-plugin/cesium-heatmap-es6/8721e879aafa0845f4cde4a41c0f13d37ec9d51b/public/CesiumHeatmap/docs/assets/icons.png -------------------------------------------------------------------------------- /public/CesiumHeatmap/docs/assets/icons@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesium-plugin/cesium-heatmap-es6/8721e879aafa0845f4cde4a41c0f13d37ec9d51b/public/CesiumHeatmap/docs/assets/icons@2x.png -------------------------------------------------------------------------------- /public/CesiumHeatmap/docs/assets/widgets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesium-plugin/cesium-heatmap-es6/8721e879aafa0845f4cde4a41c0f13d37ec9d51b/public/CesiumHeatmap/docs/assets/widgets.png -------------------------------------------------------------------------------- /public/CesiumHeatmap/docs/assets/widgets@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesium-plugin/cesium-heatmap-es6/8721e879aafa0845f4cde4a41c0f13d37ec9d51b/public/CesiumHeatmap/docs/assets/widgets@2x.png -------------------------------------------------------------------------------- /public/CesiumHeatmap/docs/interfaces/CesiumHeatmapOption.html: -------------------------------------------------------------------------------- 1 | CesiumHeatmapOption | cesium-heatmap-es6
Options
All
  • Public
  • Public/Protected
  • All
Menu

Interface CesiumHeatmapOption

Hierarchy

  • CesiumHeatmapOption

Index

Properties

bounds?: number[]
cameraHeightDistance?: number
heatmapDataOptions?: HeatmapDataOption
heatmapOptions?: BaseHeatmapConfiguration
noLisenerCamera?: boolean
points: HeatmapPoint[]
renderType?: RenderType
zoomToLayer?: boolean

Methods

  • onRadiusChange(radius: number): void

Legend

  • Property
  • Method
  • Constructor
  • Method
  • Private property
  • Private method

Settings

Theme

Generated using TypeDoc

-------------------------------------------------------------------------------- /public/CesiumHeatmap/docs/interfaces/HeatmapDataOption.html: -------------------------------------------------------------------------------- 1 | HeatmapDataOption | cesium-heatmap-es6
Options
All
  • Public
  • Public/Protected
  • All
Menu

Interface HeatmapDataOption

Hierarchy

  • HeatmapDataOption

Index

Properties

Properties

max?: number
min?: number

Legend

  • Property
  • Method
  • Constructor
  • Method
  • Private property
  • Private method

Settings

Theme

Generated using TypeDoc

-------------------------------------------------------------------------------- /public/CesiumHeatmap/docs/interfaces/HeatmapPoint.html: -------------------------------------------------------------------------------- 1 | HeatmapPoint | cesium-heatmap-es6
Options
All
  • Public
  • Public/Protected
  • All
Menu

Interface HeatmapPoint

Hierarchy

  • HeatmapPoint

Index

Properties

Properties

value?: number
x: number
y: number

Legend

  • Property
  • Method
  • Constructor
  • Method
  • Private property
  • Private method

Settings

Theme

Generated using TypeDoc

-------------------------------------------------------------------------------- /public/CesiumHeatmap/docs/modules.html: -------------------------------------------------------------------------------- 1 | cesium-heatmap-es6
Options
All
  • Public
  • Public/Protected
  • All
Menu

cesium-heatmap-es6

Legend

  • Property
  • Method
  • Constructor
  • Method
  • Private property
  • Private method

Settings

Theme

Generated using TypeDoc

-------------------------------------------------------------------------------- /public/CesiumHeatmap/lib/cesiumHeatmap.d.ts: -------------------------------------------------------------------------------- 1 | import { Viewer } from "cesium"; 2 | export interface BaseHeatmapConfiguration { 3 | /** 4 | * A background color string in form of hexcode, color name, or rgb(a) 5 | */ 6 | backgroundColor?: string | undefined; 7 | /** 8 | * The blur factor that will be applied to all datapoints. The higher the 9 | * blur factor is, the smoother the gradients will be 10 | * Default value: 0.85 11 | */ 12 | blur?: number | undefined; 13 | /** 14 | * An object that represents the gradient. 15 | * Syntax: {[key: number in range [0,1]]: color} 16 | */ 17 | gradient?: { 18 | [key: string]: string; 19 | } | undefined; 20 | /** 21 | * The maximal opacity the highest value in the heatmap will have. (will be 22 | * overridden if opacity set) 23 | * Default value: 0.6 24 | */ 25 | maxOpacity?: number | undefined; 26 | /** 27 | * The minimum opacity the lowest value in the heatmap will have (will be 28 | * overridden if opacity set) 29 | */ 30 | minOpacity?: number | undefined; 31 | /** 32 | * A global opacity for the whole heatmap. This overrides maxOpacity and 33 | * minOpacity if set 34 | * Default value: 0.6 35 | */ 36 | opacity?: number | undefined; 37 | /** 38 | * The radius each datapoint will have (if not specified on the datapoint 39 | * itself) 40 | */ 41 | radius?: number | undefined; 42 | /** 43 | * The property name of the value/weight in a datapoint 44 | * Default value: 'value' 45 | */ 46 | valueField?: undefined; 47 | /** 48 | * Pass a callback to receive extrema change updates. Useful for DOM 49 | * legends. 50 | */ 51 | onExtremaChange?: (() => void) | undefined; 52 | /** 53 | * Indicate whether the heatmap should use a global extrema or a local 54 | * extrema (the maximum and minimum of the currently displayed viewport) 55 | */ 56 | useLocalExtrema?: boolean | undefined; 57 | } 58 | export interface HeatmapPoint { 59 | x: number; 60 | y: number; 61 | value?: number; 62 | } 63 | export interface HeatmapConfiguration extends BaseHeatmapConfiguration { 64 | } 65 | export interface HeatmapDataOption { 66 | max?: number; 67 | min?: number; 68 | } 69 | export declare type RenderType = "primitive" | "imagery" | "entity"; 70 | export interface CesiumHeatmapOption { 71 | noLisenerCamera?: boolean; 72 | cameraHeightDistance?: number; 73 | renderType?: RenderType; 74 | points: HeatmapPoint[]; 75 | bounds?: number[]; 76 | heatmapOptions?: BaseHeatmapConfiguration; 77 | heatmapDataOptions?: HeatmapDataOption; 78 | zoomToLayer?: boolean; 79 | onRadiusChange?: (radius: number) => void; 80 | } 81 | export declare type Bounds = [number, number, number, number]; 82 | /** 83 | * 热度图 84 | */ 85 | export declare class CesiumHeatmap { 86 | private viewer; 87 | private element?; 88 | private initOptions; 89 | private heatmapOptions?; 90 | private heatmapDataOptions?; 91 | private provider?; 92 | private heatmap?; 93 | private cameraMoveEnd?; 94 | private bounds; 95 | private lastCameraHeight; 96 | private initRadius; 97 | constructor(viewer: Viewer, options: CesiumHeatmapOption); 98 | /** 99 | * 设置数据的最大最小值 100 | * @param dataOption 101 | */ 102 | updateHeatMapMaxMin(dataOption: HeatmapDataOption): void; 103 | /** 104 | * 更新热度图配置 105 | * @param options 106 | */ 107 | updateHeatmap(options: HeatmapConfiguration): void; 108 | /** 109 | * 更新半径 110 | * @param radius 111 | */ 112 | updateRadius(radius: number): void; 113 | /** 114 | * 移除 115 | */ 116 | remove(): void; 117 | private createLayer; 118 | private createPrimitive; 119 | private createSingleTileImageryLayer; 120 | private getImageMaterialProperty; 121 | private createEntity; 122 | private updateLayer; 123 | /** 124 | * 添加相机的监听 125 | */ 126 | private addLisener; 127 | /** 128 | * 129 | * @param points 130 | * @param expand 131 | * @returns 132 | */ 133 | private getBounds; 134 | private createContainer; 135 | } 136 | -------------------------------------------------------------------------------- /public/CesiumHeatmap/lib/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from "./cesiumHeatmap"; 2 | -------------------------------------------------------------------------------- /public/datas/geojson/test.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "crs": { 4 | "type": "name", 5 | "properties": { 6 | "name": "urn:ogc:def:crs:OGC:1.3:CRS84" 7 | } 8 | }, 9 | "features": [{ 10 | "geometry": { 11 | "type": "Point", 12 | "coordinates": [118.82298919453645, 32.02143208492404] 13 | } 14 | }, 15 | { 16 | "geometry": { 17 | "type": "Point", 18 | "coordinates": [118.82298919453645, 32.02143208492404] 19 | } 20 | }, 21 | { 22 | "geometry": { 23 | "type": "Point", 24 | "coordinates": [118.82058431751808, 32.021040777378516] 25 | } 26 | }, 27 | { 28 | "geometry": { 29 | "type": "Point", 30 | "coordinates": [118.82298919453645, 32.02143208492404] 31 | } 32 | }, 33 | { 34 | "geometry": { 35 | "type": "Point", 36 | "coordinates": [118.82298919453645, 32.02143208492404] 37 | } 38 | }, 39 | { 40 | "geometry": { 41 | "type": "Point", 42 | "coordinates": [118.82298919453645, 32.02143208492404] 43 | } 44 | }, 45 | { 46 | "geometry": { 47 | "type": "Point", 48 | "coordinates": [118.82182001002427, 32.021414183677045] 49 | } 50 | }, 51 | { 52 | "geometry": { 53 | "type": "Point", 54 | "coordinates": [118.82230914117798, 32.017125118773606] 55 | } 56 | }, 57 | { 58 | "geometry": { 59 | "type": "Point", 60 | "coordinates": [118.82182897304916, 32.02093209003145 ] 61 | } 62 | }, 63 | { 64 | "geometry": { 65 | "type": "Point", 66 | "coordinates": [118.82025760150296, 32.02128121930795] 67 | } 68 | } 69 | ] 70 | } -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesium-plugin/cesium-heatmap-es6/8721e879aafa0845f4cde4a41c0f13d37ec9d51b/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | CesiumHeatmap 19 | 20 | 21 | 22 | 23 |
24 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesium-plugin/cesium-heatmap-es6/8721e879aafa0845f4cde4a41c0f13d37ec9d51b/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesium-plugin/cesium-heatmap-es6/8721e879aafa0845f4cde4a41c0f13d37ec9d51b/public/logo512.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /public/testumd.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | CesiumHeatmap 14 | 15 | 16 | 17 | 18 |
19 |
20 | 21 |
22 |
23 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /src/App.less: -------------------------------------------------------------------------------- 1 | @import '~antd/dist/antd.less'; 2 | 3 | body { 4 | width: 100%; 5 | height: 100%; 6 | position: absolute; 7 | margin: 0; 8 | /* font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 9 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 10 | sans-serif; */ 11 | font-family: @font-family; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | #root { 17 | width: 100%; 18 | height: 100%; 19 | position: absolute; 20 | overflow: hidden; 21 | } -------------------------------------------------------------------------------- /src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, screen } from '@testing-library/react'; 3 | import App from './App'; 4 | 5 | test('renders learn react link', () => { 6 | render(); 7 | const linkElement = screen.getByText(/learn react/i); 8 | expect(linkElement).toBeInTheDocument(); 9 | }); 10 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import './App.less'; 2 | import { ConfigProvider, Spin } from 'antd'; 3 | import { Suspense } from 'react'; 4 | import zhCN from 'antd/lib/locale/zh_CN'; 5 | import { WebRoutes } from './webRoutes'; 6 | import "cesium/Build/Cesium/Widgets/widgets.css" 7 | 8 | function App() { 9 | return }> 10 | 11 | 12 | 13 | 14 | } 15 | 16 | export default App; 17 | -------------------------------------------------------------------------------- /src/imgs/effect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesium-plugin/cesium-heatmap-es6/8721e879aafa0845f4cde4a41c0f13d37ec9d51b/src/imgs/effect.png -------------------------------------------------------------------------------- /src/imgs/effect2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesium-plugin/cesium-heatmap-es6/8721e879aafa0845f4cde4a41c0f13d37ec9d51b/src/imgs/effect2.png -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | import reportWebVitals from './reportWebVitals'; 5 | ReactDOM.render( 6 | 7 | 8 | , 9 | document.getElementById("root") 10 | ); 11 | 12 | 13 | reportWebVitals(); 14 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/page/index.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Cartesian3, 3 | Cartographic, 4 | Cesium3DTileset, 5 | Matrix4, 6 | ScreenSpaceEventHandler, 7 | ScreenSpaceEventType, 8 | Viewer, 9 | Math as CesiumMath, 10 | ArcGisMapServerImageryProvider, 11 | ArcGISTiledElevationTerrainProvider, 12 | } from "cesium"; 13 | import { useEffect, useState } from "react"; 14 | import { CesiumHeatmap, HeatmapPoint } from "../source"; 15 | import { Button, Col, Row, Slider } from "antd"; 16 | 17 | let cesiumHeatmap: CesiumHeatmap; 18 | const defaultDataValue: [number, number] = [10, 200]; 19 | const defaultOpacityValue: [number, number] = [0, 1]; 20 | const defaultRadius = 20; 21 | const PHeatMap = (props: any) => { 22 | const [radius, setRadius] = useState(defaultRadius); 23 | 24 | useEffect(() => { 25 | const viewer: Viewer = new Viewer("map", { 26 | imageryProvider: new ArcGisMapServerImageryProvider({ 27 | url: "https://elevation3d.arcgis.com/arcgis/rest/services/World_Imagery/MapServer", 28 | }), 29 | terrainProvider: new ArcGISTiledElevationTerrainProvider({ 30 | url: "https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer", 31 | }), 32 | infoBox: false, 33 | selectionIndicator: false, 34 | animation: false, 35 | timeline: false, 36 | baseLayerPicker: false, 37 | }); 38 | 39 | const _3DTileset = new Cesium3DTileset({ 40 | url: "http://resource.dvgis.cn/data/3dtiles/ljz/tileset.json", 41 | }); 42 | _3DTileset.readyPromise.then(function (argument) { 43 | viewer.scene.primitives.add(_3DTileset); 44 | //贴地显示 45 | const height = 40; 46 | const cartographic = Cartographic.fromCartesian( 47 | _3DTileset.boundingSphere.center 48 | ); 49 | const surface = Cartesian3.fromRadians( 50 | cartographic.longitude, 51 | cartographic.latitude, 52 | cartographic.height 53 | ); 54 | const offset = Cartesian3.fromRadians( 55 | cartographic.longitude, 56 | cartographic.latitude, 57 | cartographic.height + height 58 | ); 59 | const translation = Cartesian3.subtract( 60 | offset, 61 | surface, 62 | new Cartesian3() 63 | ); 64 | _3DTileset.modelMatrix = Matrix4.fromTranslation(translation); 65 | // viewer.flyTo(_3DTileset) 66 | const mouseClickHandler = new ScreenSpaceEventHandler( 67 | viewer.scene.canvas 68 | ); 69 | mouseClickHandler.setInputAction((e) => { 70 | const { position } = e; 71 | const ray = viewer.camera.getPickRay(position); 72 | const cartesian3 = viewer.scene.globe.pick(ray, viewer.scene); 73 | const radians = 74 | viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian3); 75 | const lat = CesiumMath.toDegrees(radians.latitude); //弧度转度 76 | const lng = CesiumMath.toDegrees(radians.longitude); 77 | const alt = radians.height; 78 | console.log(`longitude:${lng},latitude:${lat},height:${alt}`); 79 | }, ScreenSpaceEventType.LEFT_CLICK); 80 | }); 81 | 82 | const points: HeatmapPoint[] = []; 83 | fetch("/datas/geojson/busstop2016.geojson", { 84 | method: "GET", 85 | headers: { 86 | "Content-Type": "application/json", 87 | }, 88 | }).then((response) => { 89 | response.json().then((data) => { 90 | if (data) { 91 | const values: number[] = []; 92 | // for (let i = 0; i < 22; i++) { 93 | data.features.forEach(function (feature) { 94 | const lon = feature.geometry.coordinates[0]; 95 | const lat = feature.geometry.coordinates[1]; 96 | const _value: number = 100 * Math.random(); 97 | values.push(_value); 98 | points.push({ 99 | x: lon, 100 | y: lat, 101 | value: _value, 102 | }); 103 | }); 104 | // } 105 | console.log(values); 106 | } 107 | 108 | cesiumHeatmap = new CesiumHeatmap(viewer, { 109 | zoomToLayer: true, 110 | points, 111 | heatmapDataOptions: { 112 | max: defaultDataValue[1], 113 | min: defaultDataValue[0], 114 | }, 115 | heatmapOptions: { 116 | maxOpacity: defaultOpacityValue[1], 117 | minOpacity: defaultOpacityValue[0], 118 | }, 119 | onRadiusChange: (radius) => { 120 | setRadius(radius); 121 | }, 122 | }); 123 | 124 | // for (let i in points) { 125 | // const point = points[i] 126 | // const cartesian3 = Cartesian3.fromDegrees(point.longitude, point.latitude, 0) 127 | // viewer.entities.add({ 128 | // position: cartesian3, 129 | // point: { 130 | // color: Color.RED, 131 | // pixelSize: 4 132 | // } 133 | // }) 134 | // } 135 | }); 136 | }); 137 | }, []); 138 | 139 | function onUpdate(value: [number, number]) { 140 | cesiumHeatmap.updateHeatMapMaxMin({ 141 | min: value[0], 142 | max: value[1], 143 | }); 144 | } 145 | 146 | function onUpdateOpacity(value: [number, number]) { 147 | cesiumHeatmap.updateHeatmap({ 148 | minOpacity: value[0], 149 | maxOpacity: value[1], 150 | } as any); 151 | } 152 | 153 | function onUpdateRadius(value: number) { 154 | cesiumHeatmap.updateRadius(value); 155 | } 156 | 157 | function remove() { 158 | cesiumHeatmap?.remove(); 159 | } 160 | 161 | return ( 162 |
163 |
164 | 173 | 174 | 更新数据的值域: 175 | 183 | 184 | 185 | 更新透明度: 186 | 195 | 196 | 197 | 更新半径: 198 | 206 | 207 | 208 | 211 | 212 | 213 | 221 | 222 | 223 |
224 | ); 225 | }; 226 | 227 | export default PHeatMap; 228 | -------------------------------------------------------------------------------- /src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare var Cesium: any; 4 | declare var ConfigurationExt: any; 5 | declare var CesiumNavigation: any; 6 | declare module "video-react" { 7 | export const Player, BigPlayButton 8 | } 9 | 10 | declare module 'cesium-navigation-es6' { 11 | const CesiumNavigation: any; 12 | export = CesiumNavigation; 13 | } 14 | 15 | declare module "*.md" { 16 | const content: string; 17 | export default content; 18 | } 19 | 20 | declare module 'coordtransform' 21 | 22 | declare module "uuid" 23 | //超图 24 | declare var SuperMapTerrainProvider: any 25 | declare module "s3m_parser_es6/S3MTiles/S3MTilesLayer" 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import { ReportHandler } from 'web-vitals'; 2 | 3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 6 | getCLS(onPerfEntry); 7 | getFID(onPerfEntry); 8 | getFCP(onPerfEntry); 9 | getLCP(onPerfEntry); 10 | getTTFB(onPerfEntry); 11 | }); 12 | } 13 | }; 14 | 15 | export default reportWebVitals; 16 | -------------------------------------------------------------------------------- /src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /src/source/cesiumHeatmap.ts: -------------------------------------------------------------------------------- 1 | import { EllipsoidSurfaceAppearance, GeometryInstance, Material, Primitive, Rectangle, RectangleGeometry, Viewer, Event, SingleTileImageryProvider, ImageryLayer, ImageMaterialProperty, Entity } from "cesium"; 2 | import h337 from './heatmap.js'//只能使用2.0.0版本,高版本热度图有出不来的情况,并且2.0.0 npm包有问题,只能通过修改使用这个js 3 | export interface BaseHeatmapConfiguration { 4 | /** 5 | * A background color string in form of hexcode, color name, or rgb(a) 6 | */ 7 | backgroundColor?: string | undefined; 8 | 9 | /** 10 | * The blur factor that will be applied to all datapoints. The higher the 11 | * blur factor is, the smoother the gradients will be 12 | * Default value: 0.85 13 | */ 14 | blur?: number | undefined; 15 | 16 | /** 17 | * An object that represents the gradient. 18 | * Syntax: {[key: number in range [0,1]]: color} 19 | */ 20 | gradient?: { [key: string]: string } | undefined; 21 | 22 | /** 23 | * The maximal opacity the highest value in the heatmap will have. (will be 24 | * overridden if opacity set) 25 | * Default value: 0.6 26 | */ 27 | maxOpacity?: number | undefined; 28 | 29 | /** 30 | * The minimum opacity the lowest value in the heatmap will have (will be 31 | * overridden if opacity set) 32 | */ 33 | minOpacity?: number | undefined; 34 | 35 | /** 36 | * A global opacity for the whole heatmap. This overrides maxOpacity and 37 | * minOpacity if set 38 | * Default value: 0.6 39 | */ 40 | opacity?: number | undefined; 41 | 42 | /** 43 | * The radius each datapoint will have (if not specified on the datapoint 44 | * itself) 45 | */ 46 | radius?: number | undefined; 47 | 48 | /** 49 | * The property name of the value/weight in a datapoint 50 | * Default value: 'value' 51 | */ 52 | valueField?: undefined; 53 | 54 | /** 55 | * Pass a callback to receive extrema change updates. Useful for DOM 56 | * legends. 57 | */ 58 | onExtremaChange?: (() => void) | undefined; 59 | 60 | /** 61 | * Indicate whether the heatmap should use a global extrema or a local 62 | * extrema (the maximum and minimum of the currently displayed viewport) 63 | */ 64 | useLocalExtrema?: boolean | undefined; 65 | } 66 | export interface HeatmapPoint { 67 | x: number; 68 | y: number; 69 | value?: number; 70 | } 71 | 72 | export interface HeatmapConfiguration extends BaseHeatmapConfiguration {} 73 | export interface HeatmapDataOption { 74 | max?: number; //数据最大值 75 | min?: number; //数据最小值 76 | } 77 | 78 | export type RenderType = "primitive" | "imagery" | "entity"; 79 | export interface CesiumHeatmapOption { 80 | noLisenerCamera?: boolean; //不监听相机 81 | cameraHeightDistance?: number; //相机高度的差值,大于这个值时重新渲染底图 82 | renderType?: RenderType; //渲染类型 83 | points: HeatmapPoint[]; 84 | bounds?: number[]; 85 | heatmapOptions?: BaseHeatmapConfiguration; 86 | heatmapDataOptions?: HeatmapDataOption; 87 | zoomToLayer?: boolean; 88 | onRadiusChange?: (radius: number) => void; 89 | } 90 | 91 | export type Bounds = [number, number, number, number]; 92 | 93 | const Max = (arr: number[]) => { 94 | let len = arr.length; 95 | let max = -Infinity; 96 | 97 | while (len--) { 98 | max = arr[len] > max ? arr[len] : max; 99 | } 100 | return max; 101 | }; 102 | 103 | const Min = (arr: number[]) => { 104 | let len = arr.length; 105 | let min = Infinity; 106 | 107 | while (len--) { 108 | min = arr[len] < min ? arr[len] : min; 109 | } 110 | return min; 111 | }; 112 | 113 | /** 114 | * 热度图 115 | */ 116 | export class CesiumHeatmap { 117 | private viewer: Viewer; 118 | private element?: HTMLElement; 119 | private initOptions: CesiumHeatmapOption; 120 | private heatmapOptions?: HeatmapConfiguration; 121 | private heatmapDataOptions?: HeatmapDataOption; 122 | private provider?: any; 123 | private heatmap?: any; 124 | private cameraMoveEnd?: Event.RemoveCallback; 125 | private bounds: Bounds = [0, 0, 0, 0]; 126 | private lastCameraHeight = 0; 127 | private initRadius = 10; 128 | constructor(viewer: Viewer, options: CesiumHeatmapOption) { 129 | this.viewer = viewer; 130 | this.initOptions = { ...options }; 131 | if (this.initOptions?.points) { 132 | const bounds: Bounds = this.getBounds(this.initOptions.points); 133 | this.bounds = bounds; 134 | const { container, width, height } = this.createContainer(bounds); 135 | this.element = container; 136 | const datas = []; 137 | const values: number[] = []; 138 | for (let i in this.initOptions.points) { 139 | const point = this.initOptions.points[i]; 140 | const x = ((point.x - bounds[0]) / (bounds[2] - bounds[0])) * width; //屏幕坐标x 141 | const y = ((bounds[3] - point.y) / (bounds[3] - bounds[1])) * height; //屏幕坐标y 142 | const dataPoint = { 143 | x: x, 144 | y: y, 145 | value: point.value, 146 | }; 147 | if (typeof point.value === "number") values.push(point.value); 148 | datas.push(dataPoint); 149 | } 150 | 151 | //数据的最大值和最小值 152 | let _min = values.length > 100000 ? Min(values) : Math.min(...values); 153 | let _max = values.length > 100000 ? Max(values) : Math.max(...values); 154 | if (this.initOptions?.heatmapDataOptions) { 155 | const { min, max } = this.initOptions.heatmapDataOptions; 156 | if (typeof min === "number") { 157 | _min = min; 158 | } 159 | if (typeof max === "number") { 160 | _max = max; 161 | } 162 | } 163 | this.heatmapDataOptions = { min: _min, max: _max }; 164 | 165 | const data = { 166 | max: _max, 167 | min: _min, 168 | data: datas, 169 | }; 170 | 171 | const defaultOptions = { 172 | maxOpacity: 0.9, 173 | // radius: minRadius, 174 | // minimum opacity. any value > 0 will produce 175 | // no transparent gradient transition 176 | minOpacity: 0.1, 177 | gradient: { 178 | // enter n keys between 0 and 1 here 179 | // for gradient color customization 180 | ".3": "blue", 181 | ".5": "green", 182 | ".7": "yellow", 183 | ".95": "red", 184 | }, 185 | }; 186 | const _options = this.initOptions.heatmapOptions 187 | ? { ...defaultOptions, ...this.initOptions.heatmapOptions } 188 | : defaultOptions; 189 | 190 | //初始化半径 191 | if (this.heatmapOptions?.radius) { 192 | this.initRadius = this.heatmapOptions.radius; 193 | } 194 | 195 | this.heatmapOptions = { ..._options }; 196 | const options = { 197 | ..._options, 198 | container, 199 | }; 200 | this.heatmap = h337.create(options); 201 | this.heatmap.setData(data as any); 202 | this.createLayer(); 203 | 204 | if (!this.initOptions.noLisenerCamera) { 205 | this.addLisener(); 206 | } 207 | 208 | if (this.initOptions.zoomToLayer && bounds) { 209 | this.viewer.camera.flyTo({ 210 | destination: Rectangle.fromDegrees(...bounds), 211 | }); 212 | } 213 | } 214 | } 215 | 216 | /** 217 | * 设置数据的最大最小值 218 | * @param dataOption 219 | */ 220 | updateHeatMapMaxMin(dataOption: HeatmapDataOption) { 221 | const { min, max } = dataOption; 222 | if (this.heatmap) { 223 | if (typeof min === "number") { 224 | this.heatmap.setDataMin(min); 225 | if (this.heatmapDataOptions) this.heatmapDataOptions.min = min; 226 | } 227 | if (typeof max === "number") { 228 | this.heatmap.setDataMax(max); 229 | if (this.heatmapDataOptions) this.heatmapDataOptions.max = max; 230 | } 231 | } 232 | this.updateLayer(); 233 | } 234 | 235 | /** 236 | * 更新热度图配置 237 | * @param options 238 | */ 239 | updateHeatmap(options: HeatmapConfiguration) { 240 | const { heatmapOptions } = this; 241 | this.heatmap.configure({ ...heatmapOptions, ...options }); 242 | this.updateLayer(); 243 | } 244 | 245 | /** 246 | * 更新半径 247 | * @param radius 248 | */ 249 | updateRadius(radius: number) { 250 | const { heatmapOptions } = this; 251 | const currentData = this.heatmap.getData(); 252 | if (currentData?.data) { 253 | for (let i in currentData.data) { 254 | const data = currentData.data[i]; 255 | data.radius = radius; 256 | } 257 | } 258 | this.heatmap.setData(currentData); 259 | this.heatmapOptions = { ...heatmapOptions, ...{ radius } }; 260 | this.updateLayer(); 261 | if (this.initOptions?.onRadiusChange) { 262 | this.initOptions.onRadiusChange(radius); 263 | } 264 | } 265 | 266 | /** 267 | * 移除 268 | */ 269 | remove() { 270 | if (this.element) { 271 | document.body.removeChild(this.element); 272 | this.element = undefined; 273 | if (this.provider instanceof ImageryLayer) { 274 | if (this.provider) this.viewer.imageryLayers.remove(this.provider); 275 | this.createSingleTileImageryLayer(); 276 | } else if (this.provider instanceof Primitive) { 277 | this.viewer.scene.primitives.remove(this.provider); 278 | } else if (this.provider instanceof Entity) { 279 | this.viewer.entities.remove(this.provider); 280 | } 281 | if (this.cameraMoveEnd) { 282 | this.viewer.camera.moveEnd.removeEventListener(this.cameraMoveEnd); 283 | this.cameraMoveEnd = undefined; 284 | } 285 | } 286 | } 287 | 288 | private createLayer() { 289 | if (this.initOptions.renderType === "primitive") { 290 | this.createPrimitive(); 291 | } else if (this.initOptions.renderType === "imagery") { 292 | this.createSingleTileImageryLayer(); 293 | } else { 294 | this.createEntity(); 295 | } 296 | } 297 | 298 | private createPrimitive() { 299 | const url = this.heatmap.getDataURL(); 300 | this.provider = this.viewer.scene.primitives.add( 301 | new Primitive({ 302 | geometryInstances: new GeometryInstance({ 303 | geometry: new RectangleGeometry({ 304 | rectangle: Rectangle.fromDegrees(...this.bounds), 305 | vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT, 306 | }), 307 | }), 308 | appearance: new EllipsoidSurfaceAppearance({ 309 | aboveGround: false, 310 | }), 311 | show: true, 312 | }) 313 | ); 314 | if (this.provider) { 315 | this.provider.appearance.material = new Material({ 316 | fabric: { 317 | type: "Image", 318 | uniforms: { 319 | image: url, 320 | }, 321 | }, 322 | }); 323 | } 324 | } 325 | 326 | private createSingleTileImageryLayer() { 327 | const url = this.heatmap.getDataURL(); 328 | this.provider = this.viewer.imageryLayers.addImageryProvider( 329 | new SingleTileImageryProvider({ 330 | url: url, 331 | rectangle: Rectangle.fromDegrees(...this.bounds), 332 | }) 333 | ); 334 | } 335 | 336 | private getImageMaterialProperty() { 337 | const url = this.heatmap.getDataURL(); 338 | const material = new ImageMaterialProperty({ 339 | image: url, 340 | }); 341 | return material; 342 | } 343 | 344 | private createEntity() { 345 | this.provider = this.viewer.entities.add({ 346 | show: true, 347 | rectangle: { 348 | coordinates: Rectangle.fromDegrees(...this.bounds), 349 | material: this.getImageMaterialProperty(), 350 | }, 351 | }); 352 | } 353 | 354 | private updateLayer() { 355 | const src = this.heatmap.getDataURL(); 356 | if (this.provider instanceof ImageryLayer) { 357 | if (this.provider) this.viewer.imageryLayers.remove(this.provider); 358 | this.createSingleTileImageryLayer(); 359 | } else if (this.provider instanceof Primitive) { 360 | this.provider.appearance.material.uniforms.image = src; 361 | } else if (this.provider instanceof Entity) { 362 | if (this.provider.rectangle) 363 | this.provider.rectangle.material = this.getImageMaterialProperty(); 364 | } 365 | } 366 | 367 | /** 368 | * 添加相机的监听 369 | */ 370 | private addLisener() { 371 | const maxRadius = 100; 372 | const min = 6375000; 373 | const max = 10000000; 374 | this.cameraMoveEnd = () => { 375 | if (this.heatmapOptions && this.heatmap && this.heatmapDataOptions) { 376 | const h = this.viewer.camera.getMagnitude(); 377 | const distance = this?.initOptions?.cameraHeightDistance 378 | ? this.initOptions.cameraHeightDistance 379 | : 1000; 380 | if (Math.abs(h - this.lastCameraHeight) > distance) { 381 | this.lastCameraHeight = h; 382 | if (typeof min === "number" && typeof max === "number") { 383 | const radius = parseInt( 384 | ( 385 | this.initRadius + 386 | ((maxRadius - this.initRadius) * (h - min)) / (max - min) 387 | ).toFixed(0) 388 | ); 389 | if (radius) { 390 | this.updateRadius(radius); 391 | } 392 | } 393 | } 394 | } 395 | }; 396 | this.viewer.camera.moveEnd.addEventListener(this.cameraMoveEnd); 397 | } 398 | 399 | /** 400 | * 401 | * @param points 402 | * @param expand 403 | * @returns 404 | */ 405 | private getBounds(points: HeatmapPoint[]) { 406 | if (points) { 407 | let lonMin = 180; 408 | let lonMax = -180; 409 | let latMin = 90; 410 | let latMax = -180; 411 | points.forEach(function (point) { 412 | const { x: longitude, y: latitude } = point; 413 | lonMin = longitude < lonMin ? longitude : lonMin; 414 | latMin = latitude < latMin ? latitude : latMin; 415 | lonMax = longitude > lonMax ? longitude : lonMax; 416 | latMax = latitude > latMax ? latitude : latMax; 417 | }); 418 | const xRange = lonMax - lonMin ? lonMax - lonMin : 1; 419 | const yRange = latMax - latMin ? latMax - latMin : 1; 420 | return [ 421 | lonMin - xRange / 10, 422 | latMin - yRange / 10, 423 | lonMax + xRange / 10, 424 | latMax + yRange / 10, 425 | ] as Bounds; 426 | } 427 | return [0, 0, 0, 0] as Bounds; 428 | } 429 | 430 | private createContainer(bounds: number[]) { 431 | const container = document.createElement("div"); 432 | const width = 1000; 433 | const height = parseInt( 434 | ((1000 / (bounds[2] - bounds[0])) * (bounds[3] - bounds[1])).toFixed(0) 435 | ); 436 | container.setAttribute( 437 | "style", 438 | `width:${width}px;height:${height}px;display:none;` 439 | ); 440 | document.body.appendChild(container); 441 | return { container, width, height }; 442 | } 443 | } 444 | -------------------------------------------------------------------------------- /src/source/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./cesiumHeatmap" -------------------------------------------------------------------------------- /src/webRoutes.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { BrowserRouter as Router, Route, Switch } from "react-router-dom"; 3 | import PPopup from "./page" 4 | export function WebRoutes() { 5 | return 6 | 7 | 8 | 9 | 10 | 11 | 12 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", 4 | "module": "esnext", 5 | "forceConsistentCasingInFileNames": true, 6 | "strict": true, 7 | "skipLibCheck": true, 8 | "lib": [ 9 | "dom", 10 | "dom.iterable", 11 | "esnext" 12 | ], 13 | "allowJs": true, 14 | "esModuleInterop": true, 15 | "allowSyntheticDefaultImports": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src/source" 25 | ], 26 | "exclude": [ 27 | "node_modules" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /webapck-plugin-copy.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs-extra"); 2 | 3 | let paths = [] 4 | class CopyDirWebpackPlugin { 5 | constructor(options) { 6 | if (!Array.isArray(options)) { 7 | options = [options]; 8 | } 9 | this.options = options; 10 | } 11 | 12 | getOptions(skipts) { 13 | if (skipts) { 14 | return { 15 | filter: (src) => { 16 | if (fs.lstatSync(src).isDirectory()) { 17 | return true; 18 | } else { 19 | paths.push(src) 20 | return src.indexOf(".ts") < 0 21 | } 22 | } 23 | } 24 | } else { 25 | return {} 26 | } 27 | } 28 | 29 | apply(compiler) { 30 | const opts = this.options; 31 | compiler.hooks.done.tap( 32 | 'Copy Plugin', 33 | ( 34 | stats /* stats is passed as an argument when done hook is tapped. */ 35 | ) => { 36 | opts.forEach(opt => { 37 | fs.copy( 38 | opt.from, 39 | opt.to, 40 | this.getOptions(opt.skipts) 41 | ).then(res => { 42 | console.log(`完成 copy ${opt.from} to ${opt.to} ${JSON.stringify(res)}`); 43 | 44 | if (opt.skipts) { 45 | //把打包生成js删除 46 | paths.forEach((src) => { 47 | if (src.indexOf(".js") > -1) { 48 | //源码为js的跳过 49 | let find = false 50 | if (opt.skipjs) { 51 | find = opt.skipjs.find((str) => { 52 | return src.indexOf(str) > -1 53 | }) 54 | } 55 | if (!find) 56 | fs.remove(src, err => { 57 | if (err) return console.error(err) 58 | console.log(src, 'remove success!') 59 | }) 60 | } 61 | }) 62 | paths = [] 63 | } 64 | }) 65 | }) 66 | } 67 | ); 68 | } 69 | } 70 | module.exports = CopyDirWebpackPlugin; 71 | 72 | -------------------------------------------------------------------------------- /webpack.config.copyjs.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const CopyDirWebpackPlugin = require('./webapck-plugin-copy'); 3 | const config = require('./package.json'); 4 | const Webpack = require('webpack'); 5 | 6 | const plugins = [ 7 | new Webpack.BannerPlugin({ 8 | banner: `${config.name} v${config.version} - [filebase], [hash], ${new Date()}` 9 | }), 10 | new CopyDirWebpackPlugin([ 11 | { 12 | from: path.resolve(__dirname, `./src/source`), 13 | to: path.resolve('./dist'), 14 | skipts: true,//跳过ts 15 | skipjs: ["heatmap.js"] 16 | }, 17 | ]), 18 | ] 19 | 20 | module.exports = { 21 | mode: "production", 22 | plugins, 23 | }; -------------------------------------------------------------------------------- /webpack.config.release.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const { CleanWebpackPlugin } = require('clean-webpack-plugin') 3 | const TerserPlugin = require("terser-webpack-plugin"); 4 | const CopyDirWebpackPlugin = require('./webapck-plugin-copy'); 5 | const config = require('./package.json'); 6 | const Webpack = require('webpack'); 7 | const rootPath = "./dist"; 8 | 9 | const p = new CleanWebpackPlugin() 10 | p.removeFiles(["dist", "lib", "public/CesiumHeatmap"]) 11 | const plugins = [ 12 | new Webpack.BannerPlugin({ 13 | banner: `${config.name} v${config.version} - [filebase], [hash], ${new Date()}` 14 | }), 15 | new CopyDirWebpackPlugin([ 16 | { from: path.resolve(__dirname, `${rootPath}`), to: path.resolve('./public/CesiumHeatmap/dist') }, 17 | { from: path.resolve(__dirname, `./lib`), to: path.resolve('./public/CesiumHeatmap/lib') },//拷贝至静态目录测试umd 18 | { from: path.resolve(__dirname, `./docs`), to: path.resolve('./public/CesiumHeatmap/docs') }, 19 | ]), 20 | ] 21 | const entry = {} 22 | entry[`${config.name}.umd`] = "./src/source/index.ts" 23 | module.exports = { 24 | mode: "production", 25 | // mode: "development", 26 | // devtool:"eval", 27 | entry, 28 | output: { 29 | path: path.resolve(__dirname, rootPath), 30 | filename: `[name].js`, 31 | chunkFilename: '[name].[chunkhash].js', 32 | libraryTarget: "umd" 33 | }, 34 | resolve: { 35 | extensions: [ 36 | '.js', 37 | '.jsx', 38 | '.ts', 39 | '.tsx' 40 | ], 41 | }, 42 | module: { 43 | rules: [ 44 | { test: /\.tsx?$/, use: 'awesome-typescript-loader?silent=true&declaration=true&declarationDir=lib' }, 45 | { 46 | test: /\.css$/, 47 | use: ['style-loader', 'css-loader'], 48 | }, 49 | { 50 | test: /\.less$/, 51 | use: ['style-loader', 'css-loader', 'less-loader'], 52 | }, 53 | { 54 | test: /\.js$/, 55 | use: [ 56 | { 57 | loader: 'babel-loader', 58 | } 59 | ] 60 | }, 61 | { test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' } 62 | ] 63 | }, 64 | plugins, 65 | externals: { 66 | "cesium": "Cesium" 67 | }, 68 | optimization: { 69 | minimize: true, 70 | minimizer: [ 71 | new TerserPlugin({ 72 | extractComments: false,//去掉license 73 | }), 74 | ], 75 | } 76 | }; --------------------------------------------------------------------------------