The Goal
I am trying to recreate what I created in ArcGIS online using the ArcGIS JS API. I have this webmap which uses a heatmap to visualize COVID numbers by country, with a time slider, as this is a time aware layer:
https://www.arcgis.com/home/webmap/viewer.html?webmap=3f2a6426b68247428618ce08bf5ac10b
I love the distribution of colors from the low end to the high end, and how it evolves over time.
What I've Tried
I am trying to code this from scratch using the api. I'm having a hard time. In order to get the map to show the right data according to the current timeslider timeextent, I followed the advice from this GIS stack exhange question , and the layer's definitionExpression is updated with each timeslider change:
timeSlider.watch('timeExtent', function (value) {
updateDefintionExpression(value);
});
function updateDefintionExpression(timeExtent) {
const start = toDateString(timeExtent.start);
const end = toDateString(timeExtent.end);
covidLayer.definitionExpression = `Date >= DATE '${start}' AND Date <= DATE '${end}'`;
}
I came up with a heatmap renderer from scratch, but it doesn't show off the low end as well as I'd like. Here is the renderer code:
renderer: {
type: 'heatmap',
field: 'Confirmed',
colorStops: [
{ ratio: 0, color: 'rgba(255, 255, 255, 0)' },
{ ratio: 0.06, color: 'rgba(255, 255, 255, 1)' },
{ ratio: 0.15, color: 'rgba(255, 255, 0, 1)' },
{ ratio: 0.25, color: 'rgba(255, 140, 0, 1)' },
{ ratio: 0.55, color: 'rgba(255, 0, 0, 1)' },
],
minPixelIntensity: 1,
maxPixelIntensity: 150000000,
blurRadius: 12,
},
You can see this in action here: https://codepen.io/slutske22/pen/poEdqEz
I played endlessly with the stops and the pixelIntensities, and I couldn't get a good range across the low end and high end (low numbers in the data vs high numbers in the data).
I looked into the JSON for the arcgis webmap I initially cereated, and this is the renderer it shows:
renderer: {
type: "heatmap",
blurRadius: 10,
colorStops: [
{
ratio: 0,
color: [212, 227, 245, 0]
},
{
ratio: 0.01,
color: [212, 227, 245, 0]
},
// ... more color stops
{
ratio: 0.9175000000000001,
color: [204, 211, 51, 255]
},
{
ratio: 1,
color: [255, 255, 0, 255]
}
],
maxPixelIntensity: 9566880,
minPixelIntensity: 0,
field: "Confirmed"
}
Using that, I get this result: https://codepen.io/slutske22/pen/eYdebdp
Also not quite right - the low end looks nice, but the high end looks blown out, like the heatmap is overflowing against an invisible square border. Take a look - here is my goal:
But here is what I'm getting with the JS API:
I'm not sure why in my handcoded app, the heatmap looks "cut off"...if I can fix this, then the renderer from JSON will probably work just fine. (And how to get that nice fade-out effect?)
I also tried using the smartmapping heatmap renderer:
timeSlider.watch("timeExtent", function (value) {
updateDefintionExpression(value);
const params = {
layer: covidLayer,
view,
field: "Confirmed",
fadeToTransparent: true,
minRatio: 0.05
}
heatmapRendererCreator.createRenderer(params)
.then(result => {
covidLayer.renderer = result.renderer
console.log(result.renderer)
})
});
You can see the result here: https://codepen.io/slutske22/pen/VwKrqKr
This is also not correct. This seems to re-evaluate the total range of values on each timeslider update, and distribute the heatmap accordingly, making each timestep look very similar.
How can I achieve the effect that I have in the arcgis online web map, using the JS API? I feel I am close but struggling to see the right way.