The aggregation systems provide high-performance data processing capabilities for all aggregation layers. The package includes both GPU-accelerated (WebGLAggregator) and CPU-based (CPUAggregator) implementations, enabling optimal performance across different data sizes and hardware capabilities.
GPU-based aggregation implementation using WebGL compute shaders for high-performance processing of large datasets.
/**
* GPU-based aggregation implementation using WebGL compute shaders
* @param props - Configuration properties for WebGL aggregation
*/
class WebGLAggregator implements Aggregator {
constructor(props: WebGLAggregatorProps);
/** Check if WebGL aggregation is supported on the current device */
static isSupported(device: Device): boolean;
/** Update aggregator properties */
setProps(props: Partial<AggregationProps>): void;
/** Mark aggregator as needing update for specific channel */
setNeedsUpdate(channel?: number): void;
/** Execute the aggregation computation */
update(): void;
/** Prepare for rendering (called before draw) */
preDraw(): void;
/** Clean up resources */
destroy(): void;
/** Get aggregated bin data as binary attribute */
getBins(): BinaryAttribute | null;
/** Get aggregation result for specific channel */
getResult(channel: number): BinaryAttribute | null;
/** Get the value domain [min, max] for specific channel */
getResultDomain(channel: number): [min: number, max: number];
/** Get individual bin data by index */
getBin(index: number): AggregatedBin | null;
}
interface WebGLAggregatorProps extends AggregationProps {
/** Number of dimensions (1 for screen-grid, 2 for hexagon/grid) */
dimensions: 1 | 2;
/** Number of output channels (1-3) */
channelCount: 1 | 2 | 3;
/** Buffer layout for input data */
bufferLayout?: BufferLayout[];
/** Vertex shader source code */
vs: string;
/** Additional shader modules to include */
modules?: ShaderModule[];
/** Transform feedback varyings */
varyings?: string[];
/** Custom uniforms for the shader */
uniforms?: Record<string, any>;
/** Number of bins in each dimension */
binIdxToOrd?: number[];
/** Bin sorting configuration */
binSort?: boolean;
}CPU-based aggregation implementation providing full control and debugging capabilities.
/**
* CPU-based aggregation implementation
* @param props - Configuration properties for CPU aggregation
*/
class CPUAggregator implements Aggregator {
constructor(props: CPUAggregatorProps);
/** Update aggregator properties */
setProps(props: Partial<AggregationProps>): void;
/** Mark aggregator as needing update for specific channel */
setNeedsUpdate(channel?: number): void;
/** Execute the aggregation computation */
update(): void;
/** Prepare for rendering (called before draw) */
preDraw(): void;
/** Clean up resources */
destroy(): void;
/** Get aggregated bin data as binary attribute */
getBins(): BinaryAttribute | null;
/** Get aggregation result for specific channel */
getResult(channel: number): BinaryAttribute | null;
/** Get the value domain [min, max] for specific channel */
getResultDomain(channel: number): [min: number, max: number];
/** Get individual bin data by index */
getBin(index: number): AggregatedBin | null;
}
interface CPUAggregatorProps extends AggregationProps {
/** Number of dimensions for binning */
dimensions: number;
/** Function to extract bin coordinates from data */
getBin: VertexAccessor<number[] | null, any>;
/** Array of functions to extract values for each channel */
getValue: VertexAccessor<number>[];
/** Aggregation operations for each channel */
operations?: AggregationOperation[];
/** Whether to track point indices in bins (for picking) */
pointIndices?: boolean;
}Base interface implemented by both WebGL and CPU aggregators.
/**
* Core aggregator interface for data processing
*/
interface Aggregator {
/** Update aggregator properties */
setProps(props: Partial<AggregationProps>): void;
/** Mark aggregator as needing update for specific channel */
setNeedsUpdate(channel?: number): void;
/** Execute the aggregation computation */
update(): void;
/** Prepare for rendering (called before draw) */
preDraw(): void;
/** Clean up resources */
destroy(): void;
/** Get aggregated bin data as binary attribute */
getBins(): BinaryAttribute | null;
/** Get aggregation result for specific channel */
getResult(channel: number): BinaryAttribute | null;
/** Get the value domain [min, max] for specific channel */
getResultDomain(channel: number): [min: number, max: number];
/** Get individual bin data by index */
getBin(index: number): AggregatedBin | null;
}
interface AggregationProps {
/** Input data array */
data: any[];
/** Accessor function to get position from data */
getPosition: VertexAccessor<number[]>;
/** Array of accessor functions for value extraction */
getWeight?: VertexAccessor<number>[];
/** Aggregation operations to apply */
operations?: AggregationOperation[];
/** Bin configuration parameters */
binOptions?: BinOptions;
/** Whether aggregation needs update */
needsUpdate?: boolean;
/** Data change triggers */
dataChanged?: boolean;
/** Transform change triggers */
changeFlags?: number;
}
interface AggregatedBin {
/** Unique bin identifier coordinates */
id: number[];
/** Aggregated values for each channel */
value: number[];
/** Number of data points in this bin */
count: number;
/** Indices of data points in this bin (CPU aggregation only) */
pointIndices?: number[];
}Built-in aggregation operations supported by both aggregators.
/** Available aggregation operations */
type AggregationOperation = 'SUM' | 'MEAN' | 'MIN' | 'MAX' | 'COUNT';
/** Aggregation function signature */
type AggregationFunc = (values: number[]) => number;
/** Built-in aggregation operation implementations */
const BUILT_IN_OPERATIONS: Record<AggregationOperation, AggregationFunc>;
// Operation implementations
const SUM: AggregationFunc = (values) => values.reduce((a, b) => a + b, 0);
const MEAN: AggregationFunc = (values) => values.length ? SUM(values) / values.length : 0;
const MIN: AggregationFunc = (values) => Math.min(...values);
const MAX: AggregationFunc = (values) => Math.max(...values);
const COUNT: AggregationFunc = (values) => values.length;GPU Aggregation (WebGLAggregator):
CPU Aggregation (CPUAggregator):
// Performance comparison example
const useGPU = data.length > 100000 && WebGLAggregator.isSupported(device);
const aggregator = useGPU
? new WebGLAggregator(gpuProps)
: new CPUAggregator(cpuProps);import { WebGLAggregator, CPUAggregator } from "@deck.gl/aggregation-layers";
// GPU aggregation for large dataset
const gpuAggregator = new WebGLAggregator({
dimensions: 2, // 2D hexagon binning
channelCount: 2, // Color and elevation channels
vs: hexagonVertexShader,
modules: [aggregationModule],
bufferLayout: [
{ name: 'positions', format: 'float32x2' },
{ name: 'weights', format: 'float32x2' }
]
});
// CPU aggregation with point tracking
const cpuAggregator = new CPUAggregator({
dimensions: 2,
getBin: (point) => [
Math.floor(point[0] / cellSize),
Math.floor(point[1] / cellSize)
],
getValue: [
(point) => point.colorWeight,
(point) => point.elevationWeight
],
operations: ['SUM', 'MEAN'],
pointIndices: true // Enable for picking support
});
// Configuration and execution
aggregator.setProps({
data: myData,
getPosition: (d) => [d.lng, d.lat],
getWeight: [(d) => d.value1, (d) => d.value2],
operations: ['SUM', 'SUM']
});
aggregator.update();
const results = aggregator.getResult(0); // Get first channel results
const domain = aggregator.getResultDomain(0); // Get value rangeBoth aggregators provide bin-level access for detailed analysis and picking.
/** Get individual bin information */
interface BinAccessor {
/** Get bin by index */
getBin(index: number): AggregatedBin | null;
/** Get all bins as binary attribute */
getBins(): BinaryAttribute | null;
/** Get sorted bin indices */
getBinIds(): number[] | null;
}
// Usage example
const bin = aggregator.getBin(selectedIndex);
if (bin) {
console.log(`Bin [${bin.id.join(',')}]: ${bin.count} points, values: [${bin.value.join(',')}]`);
// CPU aggregator provides point indices
if (bin.pointIndices) {
const originalPoints = bin.pointIndices.map(i => data[i]);
console.log('Original data points:', originalPoints);
}
}Both aggregators support custom aggregation functions:
// Custom aggregation operation
const customOperation: AggregationFunc = (values: number[]) => {
// Custom logic, e.g., geometric mean
const product = values.reduce((a, b) => a * b, 1);
return Math.pow(product, 1 / values.length);
};
// Register custom operation
const customAggregator = new CPUAggregator({
dimensions: 2,
getBin: binFunction,
getValue: [weightFunction],
operations: [customOperation] // Use custom function
});Proper resource management is crucial for aggregators:
// Lifecycle management
class AggregationLayerManager {
private aggregator: Aggregator;
constructor(useGPU: boolean) {
this.aggregator = useGPU
? new WebGLAggregator(gpuConfig)
: new CPUAggregator(cpuConfig);
}
updateData(newData: any[]) {
this.aggregator.setProps({ data: newData });
this.aggregator.setNeedsUpdate(); // Mark for update
}
render() {
this.aggregator.update(); // Process data
this.aggregator.preDraw(); // Prepare for rendering
// ... render layer geometry
}
cleanup() {
this.aggregator.destroy(); // Clean up GPU resources
}
}Aggregators provide error handling and fallback mechanisms:
// Robust aggregator selection
function createAggregator(data: any[], device: Device): Aggregator {
// Try GPU first for large datasets
if (data.length > 50000 && WebGLAggregator.isSupported(device)) {
try {
return new WebGLAggregator(gpuConfig);
} catch (error) {
console.warn('GPU aggregation failed, falling back to CPU:', error);
}
}
// Fallback to CPU aggregation
return new CPUAggregator(cpuConfig);
}
// Handle aggregation errors
try {
aggregator.update();
} catch (error) {
console.error('Aggregation failed:', error);
// Handle gracefully, possibly with reduced data or different settings
}Aggregators are typically used internally by layer implementations:
// Example layer integration
class CustomAggregationLayer extends AggregationLayer {
getAggregatorType(): string {
return this.props.gpuAggregation && this.context.device.features.has('webgl2')
? 'webgl' : 'cpu';
}
createAggregator(type: string): Aggregator {
const commonProps = {
data: this.props.data,
getPosition: this.props.getPosition,
getWeight: this.props.getWeight ? [this.props.getWeight] : [],
operations: [this.props.aggregation || 'SUM']
};
return type === 'webgl'
? new WebGLAggregator({ ...commonProps, ...this.getWebGLProps() })
: new CPUAggregator({ ...commonProps, ...this.getCPUProps() });
}
}