Heatmaps in Cesium

2,084 views
Skip to first unread message

Manuel Nas

unread,
Jun 2, 2015, 7:26:14 AM6/2/15
to cesiu...@googlegroups.com
Hey Guys,

I've been looking for a library that adds heatmaps to Cesium and found that there aren't any. So I decided to create one myself: CesiumHeatmap on GitHub.

I decided to use heatmap.js as it's easy to use and fairly lightweight. A heatmap is created by calling CesiumHeatmap.create() and adding data to the returned instance.

Take a look and improve it if you want because it's far from perfect. Currently the main issue I have with it is that the resulting heatmaps on the globe don't fit well when the area (bounding box) is very big (for example the entire EU).

Regards
Manuel

Mike LP

unread,
Jun 3, 2015, 5:12:32 PM6/3/15
to cesiu...@googlegroups.com, drag...@gmail.com
Does it look fine when you are viewing the heatmap in 2D mode?  I'm wondering if it's a projection issue.

Manuel Nas

unread,
Jun 4, 2015, 4:05:39 AM6/4/15
to cesiu...@googlegroups.com, drag...@gmail.com
No, it looks the same.

Mike LP

unread,
Jun 4, 2015, 9:20:04 PM6/4/15
to cesiu...@googlegroups.com, drag...@gmail.com
can you post some code samples to show what the problem is exactly

Manuel Nas

unread,
Jun 5, 2015, 3:26:11 AM6/5/15
to cesiu...@googlegroups.com, drag...@gmail.com
Take a look at the GitHub Repository, it's not that much code and it's not very complicated. This is what it looks like:



The heatmap should be positioned on top of the circles, but for some reason it's positioned way south of them (the lines connect the positions that should be lined up). The further north or south you go the closer the heatmap is to the expected position (the circles). This leads me to believe something is wrong with the way Cesium streches it out over the rectangle and/or the way I draw it. 

This heatmap spans The Netherlands, Belgium, Germany, Luxembourg and France with this bounding box: {north: 54.86127, south: 42.3316, east: 14.99133, west: -4.579688}. The area you are looking at in the image is the westernmost part of France. 

Kevin Ring

unread,
Jun 5, 2015, 3:56:50 AM6/5/15
to cesiu...@googlegroups.com
Hi,

SingleTimeImageryProvider uses the GeographicTilingScheme by default, not WebMercatorTilingScheme.  Either pass an instance of WebMercatorTilingScheme with appropriate "rectangleSouthwestInMeters" and "rectangleNortheastInMeters" properties to the SingleTileImageryProvider constructor, or change your heatmap generator to use the geographic projection.

Kevin

--
You received this message because you are subscribed to the Google Groups "cesium-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cesium-dev+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--

Manuel Nas

unread,
Jun 5, 2015, 4:22:00 AM6/5/15
to cesiu...@googlegroups.com
Hey,

Changing the Tiling Scheme to WebMercatorTilingScheme seems like it would be the correct way to do this, but looking at the documentation for this class there doesn't seem to be a way for this to be passed on to the SingleTimeImageryProvider. It just states "The single image is assumed to use a GeographicTilingScheme". Do you know of a way I should do this?

Manuel

Kevin Ring

unread,
Jun 5, 2015, 4:29:58 AM6/5/15
to cesiu...@googlegroups.com
You're right, SingleTimeImageryProvider doesn't seem to support that.  I don't see any good reason for that, though.  It should be easy to create a fork of it that does the right thing, or perhaps even monkey patch it by overwriting the _tilingScheme property after it's constructed.

Manuel Nas

unread,
Jun 5, 2015, 5:11:54 AM6/5/15
to cesiu...@googlegroups.com
This works perfectly, thank you so much! :)

Now to find out a way to use the heatmap as a Entity's material as mramato suggested in the GitHub issues thread. If you have any insight please do tell.

Manuel Nas

unread,
Jun 5, 2015, 6:17:55 AM6/5/15
to cesiu...@googlegroups.com
I'm still not quite happy with the performance, but it works well enough for anyone interested to check it out on GitHub.

Mike LP

unread,
Jun 5, 2015, 11:23:05 AM6/5/15
to cesiu...@googlegroups.com, drag...@gmail.com
Have you added any profiling code to figure out where the bottleneck is?

Manuel Nas

unread,
Jun 8, 2015, 7:17:28 AM6/8/15
to cesiu...@googlegroups.com, drag...@gmail.com
I have checked and 95-99% of the time is spent on the setData call (line 2 of CHInstance.prototype.setData) and the adding of the layer itself (line 6 of CHInstance.prototype.updateLayer). Both of these calls are handled by outside code (setData in heatmap.js and updateLayer in Cesium.js).

Mike LP

unread,
Jun 10, 2015, 2:28:41 AM6/10/15
to cesiu...@googlegroups.com, drag...@gmail.com
For the update layer does the browser loading timeline show where the bottleneck is?  The Cesium imagery providers are generally very fast at getting the provider bootstrapped and ready to request tiles.

Manuel Nas

unread,
Jun 10, 2015, 5:13:00 AM6/10/15
to cesiu...@googlegroups.com, drag...@gmail.com
It looks like a lot of time is spent on this: instance._heatmap.getDataURL() (line 2 of CesiumHeatmap._getImageryProvider), which is the  heatmapInstance.getDataURL() call from the heatmap library.

Matthew Amato

unread,
Jun 10, 2015, 10:22:01 AM6/10/15
to cesiu...@googlegroups.com
You shouldn't need to call getDataURL, just pass the canvas directly.

Manuel Nas

unread,
Jun 11, 2015, 4:39:58 AM6/11/15
to cesiu...@googlegroups.com
When I do that I get the following error:

Cesium.js:21202 : An error occurred in "": Failed to load image [object HTMLCanvasElement].

I've tried:

url: instance._container.childNodes[0]
url: instance._container.children[0]
url: instance._heatmap._renderer.canvas
url: instance._heatmap._renderer.ctx

The bottom one points to the CanvasRenderingContext2D the rest points to the canvas on which the heatmap is drawn. This canvas is hidden by way of setting 'display: none', but removing that doesn't seem to make a difference.

I'm not quite sure how to pass on a canvas in stead of a url to this function.

Matthew Amato

unread,
Jun 11, 2015, 9:29:32 AM6/11/15
to cesiu...@googlegroups.com
Is that error when using the Rectangle.material?  Or a SingleTileImageryProvider?  I expect it to work with the former, I'm not sure about the latter.

Kevin Ring

unread,
Jun 11, 2015, 10:03:42 AM6/11/15
to cesiu...@googlegroups.com
SingleTileImageryProvider needs a URL - not a Canvas - but imagery providers in general can return a Canvas from requestImage.  You're probably getting to the point where you should write your own ImageryProvider instead of trying to use SingleTileImageryProvider.  If you want to continue monkey patching, though, do this:

1. Construct the SingleTileImageryProvider with an invalid URL.
2. Set its _image property to your Canvas.  Also set _tileWidth and _tileHeight to the dimensions of your canvas.

Hacktastic, but it should work.

Writing an imagery provider is pretty easy.  If this works for you, you should do that.

I don't want to discourage you from using a Rectangle.material as Matt has been suggesting, though.  It might be a better choice.

Kevin

Manuel Nas

unread,
Jun 11, 2015, 10:55:27 AM6/11/15
to cesiu...@googlegroups.com
That error is from using it with SingleTileImageryProvider.url.

It kind of works when I use Rectangle.material, but there are some issues:

- I'm back to using the WGS84 view instead of Mercator (that's what I set on line 12 of CesiumHeatmap._getImageryProvider) which distorts the heatmap to not fit (see my third message in this thread).
- The Entity also seems to only use the first heatmap canvas it can find, in stead of using the one I supply to it. Maybe it's getting the image by doing a getElementsByClassName() and using the first one it finds?

Manuel Nas

unread,
Jun 11, 2015, 10:56:43 AM6/11/15
to cesiu...@googlegroups.com
I've actually been thinking about creating my own ImageryProvider. I'll look into this if the Entity option doesn't pan out.

Alberto Acevedo

unread,
Jun 11, 2015, 11:59:51 AM6/11/15
to cesiu...@googlegroups.com
Manuel,

There is an issue with the rectangle material and canvas getting cached. The issue is described in https://github.com/AnalyticalGraphicsInc/cesium/pull/2633

Alberto

Manuel Nas

unread,
Jun 12, 2015, 3:46:03 AM6/12/15
to cesiu...@googlegroups.com
Alright, thanks for telling me this. It seems that I'll have to wait until 1.11 comes to use Rectangles.

Manuel Nas

unread,
Jul 22, 2015, 8:45:11 AM7/22/15
to cesium-dev
I've created a ImageryProvider version (HeatmapImageryProvider) and added it to the repository (https://github.com/dragon112/CesiumHeatmap).

It's almost perfect, the only issue I see so far is that the underlying map data doesn't update, does anyone have an idea how to fix this?

vdiwakar...@gmail.com

unread,
Mar 16, 2016, 5:51:44 AM3/16/16
to cesium-dev
On Wednesday, July 22, 2015 at 6:15:11 PM UTC+5:30, Manuel Nas wrote:
> I've created a ImageryProvider version (HeatmapImageryProvider) and added it to the repository (https://github.com/dragon112/CesiumHeatmap).
>
>
> It's almost perfect, the only issue I see so far is that the underlying map data doesn't update, does anyone have an idea how to fix this?

Hi Manuel,

I tried to use heatmap sample with Cesium 1.16 and noticed it is not working as expected. The same sample is working with Cesium 1.14. Could you please help me with it.

Thanks in advance.

Regards,
Diwakar

par...@vizexperts.com

unread,
Apr 16, 2018, 5:23:27 AM4/16/18
to cesium-dev
Hi Manuel,

I tried to use heatmap and i am facing a error h337 is not defined in this line this._heatmap = h337.create(this._options);
Any idea what is wrong?

Thanks in advance.

Regards,
Paras

Jody Robert Ford

unread,
Sep 3, 2018, 9:40:46 PM9/3/18
to cesium-dev
Manuel,
Can you add a usage license to the code, please?

Jody

On Tuesday, June 2, 2015 at 7:26:14 AM UTC-4, Manuel Nas wrote:

j...@intelesense.net

unread,
Mar 5, 2019, 3:58:59 PM3/5/19
to cesium-dev
Hi Manuel, thanks for making this! I just came across the need to use this and tried your library and it works great! I even have it hooked into the clock.onTick event so it can be dynamic and change over time as the data changes.

The only thing I am stuck on is the zoom level. I can use the bounds to show global data zoomed out. I could alternatively use the bounds to zoom into just a city and show that data. However, I would like it to be able to change the bounds as I zoom. That way, I could say start with a heat map of the united states that may have a big red blob over Chicago. However, as I zoom into Chicago, I would like to see the blobs spread out to show the intensity in the different parts of the city. Do you know of a way to do this or would I have to destroy and recreate the heatmap each time I zoom?
Reply all
Reply to author
Forward
0 new messages