Hierarchical layer system for rendering data with base Layer class for direct GPU rendering and CompositeLayer for sublayer composition. Provides attribute management, lifecycle methods, and coordinate transformations.
Abstract base class for all deck.gl layers providing core functionality for data visualization.
/**
* Abstract base class for all deck.gl layers
* Provides attribute management, lifecycle methods, and rendering infrastructure
*/
abstract class Layer<PropsT = {}> {
/** Initialize layer with properties */
constructor(props: LayerProps<PropsT>);
/** Abstract method to initialize layer state - must be implemented by subclasses */
abstract initializeState(context: LayerContext): void;
/** Update layer state when props or data changes */
updateState(params: UpdateParameters<Layer>): void;
/** Clean up layer resources */
finalizeState(context: LayerContext): void;
/** Render the layer to WebGL context */
draw(opts: DrawLayerParameters): void;
/** Handle picking interactions and return picking info */
getPickingInfo(params: GetPickingInfoParams): PickingInfo;
/** Transform world coordinates to screen space */
project(xyz: [number, number, number]): [number, number, number];
/** Transform screen coordinates to world space */
unproject(xy: [number, number]): [number, number, number];
/** Update layer state (partial update) */
setState(partialState: any): void;
/** Mark layer as needing redraw */
setNeedsRedraw(): void;
/** Get number of data instances */
getNumInstances(): number;
/** Get attribute manager for this layer */
getAttributeManager(): AttributeManager;
/** Check if layer state needs update */
needsUpdate(): boolean;
/** Check if layer needs redraw */
needsRedraw(opts?: {clearRedrawFlags?: boolean}): boolean;
/** Get shader uniforms for this layer */
getShaders(): any;
/** Get loading options for data fetching */
getLoadOptions(): any;
/** Layer unique identifier */
readonly id: string;
/** Current layer properties */
readonly props: LayerProps<PropsT>;
/** Layer rendering context */
readonly context: LayerContext;
/** Internal layer state */
readonly state: any;
/** Whether this is a composite layer */
readonly isComposite: boolean;
/** Whether this layer renders directly to GPU */
readonly isDrawable: boolean;
}
interface LayerProps<PropsT = {}> {
/** Unique layer identifier */
id: string;
/** Layer data - array or data source */
data?: LayerData;
/** Whether layer is visible */
visible?: boolean;
/** Layer opacity (0-1) */
opacity?: number;
/** Whether layer objects can be picked */
pickable?: boolean;
/** Coordinate system for layer data */
coordinateSystem?: CoordinateSystem;
/** Origin for coordinate system */
coordinateOrigin?: [number, number, number];
/** Model matrix for transforming layer */
modelMatrix?: number[];
/** Position accessor function or constant */
getPosition?: Accessor<PropsT, Position>;
/** Layer extensions to apply */
extensions?: LayerExtension[];
/** Hover event handler */
onHover?: (info: PickingInfo, event: MjolnirEvent) => boolean | void;
/** Click event handler */
onClick?: (info: PickingInfo, event: MjolnirEvent) => boolean | void;
/** Data loading callback */
onDataLoad?: (data: any) => void;
/** Error handling callback */
onError?: (error: Error) => void;
/** Data transform function */
dataTransform?: (data: any) => any;
/** Data comparison function for change detection */
dataComparator?: (newData: any, oldData: any) => boolean;
/** Custom data fetching function */
fetch?: (url: string, opts: any) => Promise<any>;
/** Loaders for data parsing */
loaders?: any[];
/** Load options for data fetching */
loadOptions?: any;
/** Auto-highlighting configuration */
autoHighlight?: boolean;
/** Highlighted object index */
highlightedObjectIndex?: number;
/** Highlight color */
highlightColor?: Color;
/** Update triggers for attribute invalidation */
updateTriggers?: {[key: string]: any};
/** Animation parameters */
transitions?: {[key: string]: any};
/** Material properties for 3D rendering */
material?: Material;
/** Rendering operation type */
operation?: string;
}
interface UpdateParameters<LayerT extends Layer = Layer> {
/** Layer being updated */
layer: LayerT;
/** Previous props */
oldProps: LayerT['props'];
/** Current props */
props: LayerT['props'];
/** Context for rendering */
context: LayerContext;
/** Flags indicating what changed */
changeFlags: ChangeFlags;
/** Previous layer state */
oldState: any;
/** Current layer state */
state: any;
}
interface ChangeFlags {
/** Data changed */
dataChanged: boolean;
/** Props changed */
propsChanged: boolean;
/** View or projection changed */
viewportChanged: boolean;
/** Update triggers changed */
updateTriggersChanged: boolean;
/** Extensions changed */
extensionsChanged: boolean;
/** Anything changed */
somethingChanged: boolean;
}Usage Examples:
import { Layer, COORDINATE_SYSTEM } from "@deck.gl/core";
// Define a custom layer
class MyCustomLayer extends Layer {
static layerName = 'MyCustomLayer';
initializeState(context) {
// Initialize WebGL resources
const {device} = context;
this.state = {
model: this._createModel(device)
};
// Set up attribute manager
const attributeManager = this.getAttributeManager();
attributeManager.addInstanced({
instancePositions: {
size: 3,
accessor: 'getPosition'
},
instanceColors: {
size: 4,
type: 'uint8',
normalized: true,
accessor: 'getColor',
defaultValue: [255, 0, 0, 255]
}
});
}
updateState({props, oldProps, changeFlags}) {
// Handle prop changes
if (changeFlags.dataChanged) {
this.state.numInstances = props.data?.length || 0;
}
}
draw({uniforms}) {
const {model} = this.state;
model.draw(this.context.renderPass, {
uniforms: {
...uniforms,
opacity: this.props.opacity
}
});
}
getPickingInfo({info, mode}) {
// Customize picking info
if (info.object) {
info.customData = this.props.data[info.index];
}
return info;
}
_createModel(device) {
// Create WebGL model
// Implementation details...
}
}
// Use the custom layer
const layer = new MyCustomLayer({
id: 'my-layer',
data: myDataArray,
getPosition: d => d.coordinates,
getColor: d => d.color || [255, 0, 0, 255],
pickable: true,
coordinateSystem: COORDINATE_SYSTEM.LNGLAT
});Abstract base class for layers that render other sublayers rather than directly to WebGL, enabling complex layer composition.
/**
* Abstract base class for composite layers
* Enables layer composition by rendering sublayers instead of direct GPU rendering
*/
abstract class CompositeLayer<PropsT = {}> extends Layer<PropsT> {
/** Abstract method to define sublayers - must be implemented by subclasses */
abstract renderLayers(): Layer[] | Layer;
/** Get currently rendered sublayers */
getSubLayers(): Layer[];
/** Filter sublayers during rendering */
filterSubLayer(context: FilterContext): boolean;
/** Generate properties for sublayers */
getSubLayerProps(props: any): any;
/** Get sublayer constructor class */
getSubLayerClass(id: string, DefaultClass: any): any;
/** Whether this is a composite layer (always true) */
readonly isComposite: true;
/** Whether this layer renders directly (always false) */
readonly isDrawable: false;
}
interface FilterContext {
/** Current layer being filtered */
layer: Layer;
/** Viewport being rendered */
viewport: Viewport;
/** Render pass type */
renderPass: string;
/** Whether layer is selected for rendering */
isPicking: boolean;
}Usage Examples:
import { CompositeLayer, ScatterplotLayer, LineLayer } from "@deck.gl/core";
// Define a composite layer
class MultiDataLayer extends CompositeLayer {
static layerName = 'MultiDataLayer';
renderLayers() {
const {data, pointRadius, lineWidth} = this.props;
return [
// Render points
new ScatterplotLayer(
this.getSubLayerProps({
id: 'points',
data: data.points,
getPosition: d => d.coordinates,
getRadius: pointRadius,
getFillColor: [255, 0, 0]
})
),
// Render lines
new LineLayer(
this.getSubLayerProps({
id: 'lines',
data: data.lines,
getSourcePosition: d => d.start,
getTargetPosition: d => d.end,
getWidth: lineWidth,
getColor: [0, 255, 0]
})
)
];
}
}
// Use the composite layer
const compositeLayer = new MultiDataLayer({
id: 'multi-data',
data: {
points: pointsData,
lines: linesData
},
pointRadius: 100,
lineWidth: 5
});System for extending layer functionality through composable extensions.
/**
* Abstract base class for layer extensions
* Provides composable functionality that can be applied to any layer
*/
abstract class LayerExtension {
constructor(opts?: any);
/** Add/modify shader code */
getShaders(extension: this): any;
/** Initialize extension state */
initializeState(context: LayerContext, extension: this): void;
/** Update extension state */
updateState(params: UpdateParameters<Layer>, extension: this): void;
/** Modify drawing behavior */
draw(params: any, extension: this): void;
/** Extension identifier */
static extensionName: string;
}Usage Examples:
// Using extensions with layers
const layerWithExtensions = new ScatterplotLayer({
id: 'points-with-extensions',
data: myData,
getPosition: d => d.coordinates,
getRadius: 100,
extensions: [
new DataFilterExtension({filterSize: 2}),
new BrushingExtension()
]
});Type definitions for layer data handling and accessor functions.
// Data types
type LayerData<T = any> = T[] | LayerDataSource<T>;
interface LayerDataSource<T> {
length: number;
[key: number]: T;
}
// Accessor types
type Accessor<ObjectT, ValueT> = ValueT | AccessorFunction<ObjectT, ValueT>;
type AccessorFunction<ObjectT, ValueT> =
(object: ObjectT, context: AccessorContext<ObjectT>) => ValueT;
interface AccessorContext<ObjectT> {
/** Index of current object */
index: number;
/** Complete data array */
data: LayerData<ObjectT>;
/** Target array being populated */
target: any[];
}
// Common value types
type Position = [number, number] | [number, number, number];
type Color = [number, number, number] | [number, number, number, number];
// Material properties
interface Material {
/** Ambient reflection factor */
ambient?: number;
/** Diffuse reflection factor */
diffuse?: number;
/** Shininess for specular reflection */
shininess?: number;
/** Specular reflection color */
specularColor?: [number, number, number];
}Internal state management for layers.
interface LayerState {
/** Layer initialization complete */
initialized: boolean;
/** Attribute manager instance */
attributeManager: AttributeManager;
/** WebGL models for rendering */
models?: any[];
/** Number of data instances */
numInstances?: number;
/** Custom layer state */
[key: string]: any;
}
interface DrawLayerParameters {
/** Shader uniforms */
uniforms: any;
/** Render pass parameters */
parameters?: any;
/** Module settings */
moduleSettings?: any;
/** Context for rendering */
context: LayerContext;
}Usage Examples:
// Advanced layer with state management
class AdvancedLayer extends Layer {
initializeState(context) {
this.setState({
models: [],
uniformBuffer: null,
instanceCount: 0
});
// Initialize attribute manager
const attributeManager = this.getAttributeManager();
attributeManager.addInstanced({
positions: {size: 3, accessor: 'getPosition'},
colors: {size: 4, accessor: 'getColor'},
sizes: {size: 1, accessor: 'getSize'}
});
}
updateState({props, oldProps, changeFlags}) {
super.updateState({props, oldProps, changeFlags});
if (changeFlags.dataChanged) {
this.setState({
instanceCount: props.data?.length || 0
});
}
if (changeFlags.propsChanged) {
this.getAttributeManager().invalidateAll();
}
}
draw({uniforms}) {
const {models} = this.state;
const layerUniforms = {
...uniforms,
instanceCount: this.state.instanceCount
};
for (const model of models) {
model.draw(this.context.renderPass, {
uniforms: layerUniforms
});
}
}
}