Skip to content
73 changes: 73 additions & 0 deletions src/layers/Heat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import {
setLayersOpacity,
makeHeatmapIntensity,
setLayersIntensity,
makeHeatmapRadius,
setLayersRadius,
} from '../utils/heat.js'
import { heatLayer } from '../utils/layers.js'
import Layer from './Layer.js'

class Heat extends Layer {
constructor(options) {
super(options)

this.createSource()
this.createLayers()
}

createLayers() {
const id = this.getId()
const { heatWeight, heatIntensity, heatColor, heatRadius, opacity } =
this.options
const isInteractive = false
const transformedIntensity = makeHeatmapIntensity(heatIntensity)
const transformedRadius = makeHeatmapRadius(heatRadius)

this.addLayer(
heatLayer({
id,
heatWeight,
heatIntensity: transformedIntensity,
heatColor,
heatRadius: transformedRadius,
opacity,
}),
{ isInteractive }
)
}

setOpacity(opacity) {
const mapgl = this.getMapGL()

if (mapgl) {
setLayersOpacity(mapgl, this.getId(), opacity)
}

this.options.opacity = opacity
}

setIntensity(heatIntensity) {
const mapgl = this.getMapGL()
const transformedIntensity = makeHeatmapIntensity(heatIntensity)

if (mapgl) {
setLayersIntensity(mapgl, this.getId(), transformedIntensity)
}

this.options.heatIntensity = transformedIntensity
}

setRadius(heatRadius) {
const mapgl = this.getMapGL()
const transformedRadius = makeHeatmapRadius(heatRadius)

if (mapgl) {
setLayersRadius(mapgl, this.getId(), transformedRadius)
}

this.options.heatRadius = heatRadius
}
}

export default Heat
2 changes: 2 additions & 0 deletions src/layers/layerTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import DonutCluster from './DonutCluster.js'
import EarthEngine from './EarthEngine.js'
import Events from './Events.js'
import GeoJson from './GeoJson.js'
import Heat from './Heat.js'
import LayerGroup from './LayerGroup.js'
import Markers from './Markers.js'
import ServerCluster from './ServerCluster.js'
Expand All @@ -24,6 +25,7 @@ export default {
events: Events, // event layer
geoJson: GeoJson, // tracked entity layer
group: LayerGroup, // tracked entity layer
heat: Heat, // event layer
markers: Markers, // facility layer
serverCluster: ServerCluster, // event layer
tileLayer: TileLayer, // basemap / external layer
Expand Down
38 changes: 38 additions & 0 deletions src/utils/heat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
export const setLayersOpacity = (mapgl, id, heatOpacity) => {
mapgl
.getStyle()
.layers.filter(layer => layer.id.startsWith(id))
.forEach(layer => {
mapgl.setPaintProperty(layer.id, 'heatmap-opacity', heatOpacity)
})
}

export const makeHeatmapIntensity = (i = 0.5) => Math.pow(i, 2) * 2

export const setLayersIntensity = (mapgl, id, heatIntensity) => {
mapgl
.getStyle()
.layers.filter(layer => layer.id.startsWith(id))
.forEach(layer => {
mapgl.setPaintProperty(layer.id, 'heatmap-intensity', heatIntensity)
})
}

export const makeHeatmapRadius = (r = 0.5) => [
'interpolate',
['linear'],
['zoom'],
7,
50 * r,
20,
1000 * r,
]

export const setLayersRadius = (mapgl, id, heatRadius) => {
mapgl
.getStyle()
.layers.filter(layer => layer.id.startsWith(id))
.forEach(layer => {
mapgl.setPaintProperty(layer.id, 'heatmap-radius', heatRadius)
})
}
30 changes: 30 additions & 0 deletions src/utils/layers.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,33 @@ export const clusterCountLayer = ({ id, color, opacity }) => ({
'text-opacity': opacity ?? textOpacity,
},
})

// Layer with heat surface
export const heatLayer = ({
id,
heatWeight = 1,
heatIntensity = 0.5,
heatColor,
heatRadius,
opacity = 1,
source,
}) => ({
id: `${id}-heat`,
type: 'heatmap',
source: source || id,
paint: {
// Increase the heatmap weight based on frequency and property magnitude
'heatmap-weight': heatWeight,
// Increase the heatmap color weight weight by zoom level
// heatmap-intensity is a multiplier on top of heatmap-weight
'heatmap-intensity': heatIntensity,
// Color ramp for heatmap. Domain is 0 (low) to 1 (high).
// Begin color ramp at 0-stop with a 0-transparency color
// to create a blur-like effect.
'heatmap-color': heatColor,
// Adjust the heatmap radius by zoom level
'heatmap-radius': heatRadius,
// Transition from heatmap to circle layer by zoom level
'heatmap-opacity': opacity,
},
})
Loading