Some visualizations animate, pulse, and flash. If you're sensitive to motion or flashing, turn on Reduce motion in your system settings.

poopdeck.gl
deck.gl Layers

AnimatedHexagonLayer

The AnimatedHexagonLayer renders temporal point data as an animated, extruded hexbin — the discrete, pickable analog of the smooth AnimatedHeatmapLayer. It is a composite over the canonical deck.gl HexagonLayer (@deck.gl/aggregation-layers): instead of splatting points into a density texture, every visible point is binned into hexagonal cells at runtime (on the GPU by default), and each cell is coloured — and optionally extruded — by its aggregated weight, giving the iconic deck.gl hexagon look.

Data feed. The point feed is identical to AnimatedHeatmapLayer: every visible tile's points are consolidated into one binary buffer set, cached by the visible-tile-set key so it rebuilds only when that set (or the weight config) changes, never per frame. The single consolidated weight buffer is aliased to both of HexagonLayer's weight accessors (getColorWeight and getElevationWeight), so one weight column drives both colour and elevation.

Time animation. The canonical HexagonLayer has no notion of time, so the window is driven by @deck.gl/extensions' DataFilterExtension: each point carries its start time as getFilterValue, and the filterRange (the window around the play head) is recomputed each render. Cells genuinely appear, disappear and re-colour as the window slides — the bin sorter re-runs, it is not a cross-fade. The re-aggregation cadence is capped at ~30 Hz, independently of tile loading. Because DataFilterExtension is a GPU-shader construct, the window only works on the GPU aggregation path.

It extends SpatioTemporalLayer and reuses all of its archive/tileset plumbing.

Installation#

import { AnimatedHexagonLayer } from '@poopdeck.gl/layers';

Usage#

import { AnimatedHexagonLayer } from '@poopdeck.gl/layers';
const layer = new AnimatedHexagonLayer({
id: 'pickup-hexbin',
data: '/data/nyc-taxi/manifest.json',
currentTime,
timeWindow: 30 * 60 * 1000, // 30 min window around the play head
radius: 500, // hex bin radius, meters
extruded: true,
elevationScale: 20,
elevationRange: [0, 3000],
weightProperty: 'passengers', // unset → a pure COUNT hexbin
hexagonAggregation: 'SUM',
});

Pair it with a raw-tier layer for a zoom-dependent stack, or use any animated layer with tier: 'auto' (the base default) to dispatch tiers automatically.

Properties#

Inherits all properties from SpatioTemporalLayer.

Binning#

PropertyTypeDefaultDescription
radiusnumber1000Radius of a hexagon bin, in meters.
coveragenumber1Cell size multiplier, clamped 01. Lower values leave gaps between adjacent hexes.

Colour#

PropertyTypeDefaultDescription
colorRangeColor[]6-class YlOrRdCell colour ramp (low → high aggregated weight).
colorDomain[number, number] | nullnullPinned colour scale domain. null → the canonical layer auto-ranges against the current window's aggregated weights.
colorScaleType'quantize' | 'linear' | 'quantile' | 'ordinal''quantize'Colour scale function.
upperPercentilenumber100Hide cells above this colour percentile (0100).
lowerPercentilenumber0Hide cells below this colour percentile (0100).
onSetColorDomain((domain: [number, number]) => void) | nullnullFired when the canonical HexagonLayer computes an auto-ranged colour domain (HexagonLayer pass-through) — the way to read the domain back when colorDomain is left null.

Elevation#

PropertyTypeDefaultDescription
extrudedbooleantrueWhether to extrude cells by their aggregated weight.
elevationScalenumber1Cell elevation multiplier.
elevationRange[number, number][0, 1000]Elevation scale output range.
elevationDomain[number, number] | nullnullPinned elevation scale input domain. null → auto-range against the current window's aggregated weights.
elevationScaleType'linear' | 'quantile''linear'Elevation scale function.
elevationUpperPercentilenumber100Hide cells above this elevation percentile (0100).
elevationLowerPercentilenumber0Hide cells below this elevation percentile (0100).
materialMaterial | booleantrueLighting material (applies when extruded).
onSetElevationDomain((domain: [number, number]) => void) | nullnullFired when the canonical HexagonLayer computes an auto-ranged elevation domain (HexagonLayer pass-through) — the way to read the domain back when elevationDomain is left null.

Aggregation#

PropertyTypeDefaultDescription
hexagonAggregation'SUM' | 'MEAN' | 'MIN' | 'MAX' | 'COUNT''SUM'Aggregation operation used for both colour and elevation, unless colorAggregation / elevationAggregation overrides it.
colorAggregation'SUM' | 'MEAN' | 'MIN' | 'MAX' | 'COUNT' | nullnullColour aggregation operation. null → inherit hexagonAggregation.
elevationAggregation'SUM' | 'MEAN' | 'MIN' | 'MAX' | 'COUNT' | nullnullElevation aggregation operation. null → inherit hexagonAggregation.
gpuAggregationbooleantruePerform binning on the GPU when possible. Setting it false warns once and is forced back to true: HexagonLayer's CPU aggregator ignores the shader-side time filter. Devices without float-texture support still fall back to CPU inside HexagonLayer, where the window has no effect.

Weight column#

The weight is a baked property-column name (not a per-feature function accessor — binary tiles cannot run per-feature JS; a function-valued alias warns once and falls back). One weight column drives both colour and elevation.

PropertyTypeDefaultDescription
getColorWeightstring | nullnullUpstream-vocabulary alias for the colour weight column name. Wins over getElevationWeight and weightProperty.
getElevationWeightstring | nullnullUpstream-vocabulary alias for the elevation weight column name. Used when getColorWeight is unset.
weightPropertystring | nullnullLegacy weight column name. Unset → every point weighs 1.0 (a pure COUNT hexbin). getColorWeight / getElevationWeight win over it.

Behavior notes#

  • Picking: pickable is inherited, like every sibling STT layer — pass pickable: true to pick cells. Discrete cells have feature identity to pick, unlike the heatmap's density pixels, which are forced non-pickable.
  • The sublayer short id for _subLayerProps overrides is hexbin: _subLayerProps: { hexbin: { type: MyLayer, ... } } swaps the sublayer class or overrides sublayer props.

Source#

packages/layers/src/layers/summary/animated-hexagon-layer.ts