Use deck.gl layers as custom mapbox-gl-js layers, enabling seamless interleaving of mapbox and deck.gl layers
npx @tessl/cli install tessl/npm-deck-gl--mapbox@9.1.0@deck.gl/mapbox provides seamless integration between deck.gl WebGL-powered visualization layers and Mapbox GL JS maps, enabling interleaving of mapbox and deck.gl layers. It offers two integration modes: overlaid rendering (deck.gl on top of map) and interleaved rendering (deck.gl layers as custom Mapbox layers).
npm install @deck.gl/mapbox @deck.gl/core @luma.gl/coreimport { MapboxOverlay } from "@deck.gl/mapbox";
import type { MapboxOverlayProps } from "@deck.gl/mapbox";
import type { Deck } from "@deck.gl/core";For CommonJS:
const { MapboxOverlay } = require("@deck.gl/mapbox");Dependencies Required:
@deck.gl/core (peer dependency)@luma.gl/core (peer dependency)mapbox-gl or maplibre-gl (map library)import { MapboxOverlay } from "@deck.gl/mapbox";
import { ScatterplotLayer } from "@deck.gl/layers";
import mapboxgl from "mapbox-gl";
// Create map
const map = new mapboxgl.Map({
container: "map",
style: "mapbox://styles/mapbox/light-v9",
center: [-122.45, 37.78],
zoom: 12
});
// Create overlay with deck.gl layers
const overlay = new MapboxOverlay({
layers: [
new ScatterplotLayer({
id: "scatter",
data: [
{ position: [-122.45, 37.78], size: 100, color: [255, 0, 0] }
],
getPosition: d => d.position,
getRadius: d => d.size,
getFillColor: d => d.color
})
]
});
// Add to map
map.addControl(overlay);@deck.gl/mapbox is built around several key components:
Primary integration component that renders deck.gl layers over Mapbox maps with automatic view state synchronization.
/**
* Implements Mapbox IControl interface for rendering deck.gl layers
* Supports both overlaid and interleaved rendering modes
*/
class MapboxOverlay implements IControl {
constructor(props: MapboxOverlayProps);
/** Update overlay properties including layers */
setProps(props: MapboxOverlayProps): void;
/** Called when control is added to map (IControl interface) */
onAdd(map: unknown): HTMLDivElement;
/** Called when control is removed from map (IControl interface) */
onRemove(): void;
/** Get default position for map control */
getDefaultPosition(): ControlPosition;
/** Pick object at screen coordinate (forwards to Deck.pickObject) */
pickObject(params: Parameters<Deck['pickObject']>[0]): ReturnType<Deck['pickObject']>;
/** Pick multiple objects at screen coordinate (forwards to Deck.pickMultipleObjects) */
pickMultipleObjects(params: Parameters<Deck['pickMultipleObjects']>[0]): ReturnType<Deck['pickMultipleObjects']>;
/** Pick all objects in rectangle or radius (forwards to Deck.pickObjects) */
pickObjects(params: Parameters<Deck['pickObjects']>[0]): ReturnType<Deck['pickObjects']>;
/** Remove from map and release all resources */
finalize(): void;
/** Get the rendering canvas */
getCanvas(): HTMLCanvasElement | null;
}Configuration interface for MapboxOverlay with rendering mode and deck.gl properties.
/**
* Configuration props for MapboxOverlay
* Extends most DeckProps except viewport and canvas-related properties
*/
type MapboxOverlayProps = Omit<
DeckProps,
| 'width'
| 'height'
| 'gl'
| 'parent'
| 'canvas'
| '_customRender'
| 'viewState'
| 'initialViewState'
| 'controller'
> & {
/** Enable interleaved rendering mode (deck layers as custom Mapbox layers) */
interleaved?: boolean;
};Object picking functionality forwards directly to the underlying Deck instance. The picking methods use the same parameters and return types as the corresponding methods on the Deck class from @deck.gl/core.
/**
* Note: Picking parameters and return types are defined by @deck.gl/core
* The MapboxOverlay picking methods forward directly to Deck methods
*
* Example picking usage:
* const info = overlay.pickObject({x: 100, y: 100, radius: 4});
* const objects = overlay.pickObjects({x: 100, y: 100, width: 50, height: 50});
*/TypeScript interfaces for Mapbox/MapLibre compatibility, providing minimal type definitions.
/**
* Minimal map interface compatible with Mapbox GL JS and MapLibre GL JS
*/
interface Map extends Evented {
/** Add a control to the map */
addControl(control: IControl, position?: ControlPosition): Map;
/** Remove a control from the map */
removeControl(control: IControl): Map;
/** Check if map has a specific control */
hasControl(control: IControl): boolean;
/** Resize the map */
resize(): Map;
/** Check if map style is loaded */
isStyleLoaded(): boolean | void;
/** Add a source to the map */
addSource(id: string, source: any): Map;
/** Remove a source from the map */
removeSource(id: string): Map;
/** Get a source by ID */
getSource(id: string): any;
/** Add a layer to the map */
addLayer(layer: any, before?: string): Map;
/** Move a layer in the layer stack */
moveLayer(id: string, beforeId?: string): Map;
/** Remove a layer from the map */
removeLayer(id: string): Map;
/** Get a layer by ID */
getLayer(id: string): any;
/** Get the map container element */
getContainer(): HTMLElement;
/** Get the map canvas element */
getCanvas(): HTMLCanvasElement;
/** Get the map center */
getCenter(): LngLat;
/** Get the map zoom level */
getZoom(): number;
/** Get the map bearing */
getBearing(): number;
/** Get the map pitch */
getPitch(): number;
/** Get the map padding */
getPadding(): PaddingOptions;
/** Get render world copies setting */
getRenderWorldCopies(): boolean;
/** Get terrain (mapbox v2+, maplibre v3+) */
getTerrain?(): any;
/** Get projection (mapbox v2+, maplibre v5+) */
getProjection?(): any;
/** Get free camera options (mapbox v2+) */
getFreeCameraOptions?(): FreeCameraOptions;
/** Remove the map and clean up */
remove(): void;
/** Trigger a repaint */
triggerRepaint(): void;
}
/**
* Control interface for map controls
*/
interface IControl {
/** Called when control is added to map */
onAdd(map: unknown): HTMLElement;
/** Called when control is removed from map */
onRemove(map: unknown): void;
/** Get default position for control */
getDefaultPosition?: (() => ControlPosition) | undefined;
}
/**
* Event handling interface
*/
interface Evented {
/** Add event listener */
on(type: string, listener: (event?: any) => any): Evented;
/** Remove event listener */
off(type: string, listener?: (event?: any) => any): Evented;
/** Add one-time event listener */
once(type: string, listener: (event?: any) => any): Evented;
}Core type definitions for geographic coordinates and UI positioning.
/**
* Screen coordinate point
*/
interface Point {
x: number;
y: number;
}
/**
* Geographic coordinate
*/
interface LngLat {
lng: number;
lat: number;
}
/**
* Map padding configuration
*/
interface PaddingOptions {
top: number;
bottom: number;
left: number;
right: number;
}
/**
* Free camera position (mapbox v2+)
*/
interface FreeCameraOptions {
position?: {
x: number;
y: number;
z: number;
};
}
/**
* Control position on map
*/
type ControlPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
/**
* Map mouse event
*/
interface MapMouseEvent {
type: string;
target: Map;
originalEvent: MouseEvent;
point: Point;
lngLat: LngLat;
}Renders deck.gl layers in a separate canvas overlaying the map:
import { MapboxOverlay } from "@deck.gl/mapbox";
import { HexagonLayer } from "@deck.gl/aggregation-layers";
const overlay = new MapboxOverlay({
layers: [
new HexagonLayer({
id: "hexagon-layer",
data: dataPoints,
getPosition: d => d.coordinates,
radius: 200,
elevationScale: 4
})
]
});
map.addControl(overlay);Renders deck.gl layers as custom Mapbox layers, allowing layer ordering with map layers:
import { MapboxOverlay } from "@deck.gl/mapbox";
import { GeoJsonLayer } from "@deck.gl/layers";
const overlay = new MapboxOverlay({
interleaved: true,
layers: [
new GeoJsonLayer({
id: "geojson-layer",
data: geoJsonData,
filled: true,
getFillColor: [255, 100, 100, 180]
})
]
});
map.addControl(overlay);Update layers dynamically using setProps:
// Initial setup
const overlay = new MapboxOverlay({
layers: [scatterplotLayer]
});
map.addControl(overlay);
// Later update
overlay.setProps({
layers: [
scatterplotLayer,
new ArcLayer({
id: "arc-layer",
data: connections,
getSourcePosition: d => d.from,
getTargetPosition: d => d.to,
getSourceColor: [255, 0, 0],
getTargetColor: [0, 255, 0]
})
]
});Interact with deck.gl layers through picking:
const overlay = new MapboxOverlay({
layers: [dataLayer]
});
map.addControl(overlay);
// Pick object on click
map.on("click", (event) => {
const pickInfo = overlay.pickObject({
x: event.point.x,
y: event.point.y,
radius: 4
});
if (pickInfo && pickInfo.object) {
console.log("Clicked object:", pickInfo.object);
}
});Always clean up resources when done:
// Remove from map and clean up
overlay.finalize();
// Or remove control normally
map.removeControl(overlay);