Essential utility functions for data processing, mathematical operations, development support, and performance optimization in deck.gl applications.
Create iterables from various data sources for efficient data processing.
/**
* Create iterable from various data sources
* Handles arrays, array-like objects, and iterables uniformly
* @param data - Data source to make iterable
* @param objectInfo - Additional metadata about objects
* @returns Iterable that can be used in for...of loops
*/
function createIterable<T>(data: any, objectInfo?: any): Iterable<T>;Usage Examples:
import { createIterable } from "@deck.gl/core";
// Works with arrays
const arrayData = [1, 2, 3, 4, 5];
for (const item of createIterable(arrayData)) {
console.log(item);
}
// Works with array-like objects
const arrayLike = {0: 'a', 1: 'b', 2: 'c', length: 3};
for (const item of createIterable(arrayLike)) {
console.log(item);
}
// Works with typed arrays
const typedArray = new Float32Array([1.1, 2.2, 3.3]);
for (const item of createIterable(typedArray)) {
console.log(item);
}
// Custom data source with metadata
const customIterable = createIterable(data, {
geometrySize: 3,
hasTimestamp: true
});Extract low part of 64-bit floating point for high-precision shader calculations.
/**
* Extract low part of 64-bit floating point number
* Used for high-precision calculations in WebGL shaders
* @param x - Input number
* @returns Low 32-bit part for shader precision
*/
function fp64LowPart(x: number): number;Usage Examples:
import { fp64LowPart } from "@deck.gl/core";
// High-precision coordinate handling
const processHighPrecisionCoords = (coordinates) => {
return coordinates.map(coord => ({
high: coord,
low: fp64LowPart(coord)
}));
};
// Custom layer with high-precision positions
class HighPrecisionLayer extends Layer {
initializeState() {
this.getAttributeManager().add({
positions: {
size: 3,
accessor: 'getPosition'
},
positions64Low: {
size: 3,
accessor: 'getPosition',
transform: (position) => position.map(fp64LowPart)
}
});
}
}Polygon tessellation for complex geometries and GPU rendering.
/**
* Polygon tessellation utility
* Converts complex polygons into triangles for GPU rendering
*/
class Tesselator {
/** Initialize tesselator with options */
constructor(opts?: TesselatorOptions);
/** Tessellate polygon data into triangles */
tesselate(opts: TesselateOptions): TesselationResult;
/** Get tessellation statistics */
getStats(): TesselationStats;
}
interface TesselatorOptions {
/** Winding order for triangles */
windingOrder?: 'CW' | 'CCW';
/** Whether to generate vertex normals */
generateNormals?: boolean;
/** Tolerance for tessellation */
tolerance?: number;
/** Whether to optimize output */
optimize?: boolean;
}
interface TesselateOptions {
/** Polygon data to tessellate */
data: any[];
/** Accessor for polygon coordinates */
getPolygon: (d: any) => number[][] | number[][][];
/** Accessor for polygon holes */
getHoles?: (d: any) => number[][][];
/** Number of dimensions (2 or 3) */
dimensions?: number;
/** Position format */
positionFormat?: 'XY' | 'XYZ';
/** Whether to normalize coordinates */
normalize?: boolean;
}
interface TesselationResult {
/** Tessellated vertex positions */
positions: Float32Array;
/** Triangle indices */
indices: Uint32Array;
/** Vertex normals (if generated) */
normals?: Float32Array;
/** Number of vertices */
vertexCount: number;
/** Number of triangles */
triangleCount: number;
/** Metadata for each polygon */
polygonMetadata: PolygonMetadata[];
}
interface PolygonMetadata {
/** Start index in vertex array */
startIndex: number;
/** Number of vertices for this polygon */
vertexCount: number;
/** Original polygon index */
polygonIndex: number;
}
interface TesselationStats {
/** Total polygons processed */
polygonCount: number;
/** Total vertices generated */
vertexCount: number;
/** Total triangles generated */
triangleCount: number;
/** Processing time in milliseconds */
processingTime: number;
}Usage Examples:
import { Tesselator } from "@deck.gl/core";
// Create tesselator for complex polygons
const tesselator = new Tesselator({
windingOrder: 'CCW',
generateNormals: true,
tolerance: 1e-6
});
// Tessellate building footprints
const buildingData = [
{
id: 1,
coordinates: [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]]],
holes: [[[2, 2], [8, 2], [8, 8], [2, 8], [2, 2]]]
}
];
const tessellationResult = tesselator.tesselate({
data: buildingData,
getPolygon: d => d.coordinates,
getHoles: d => d.holes,
dimensions: 2,
positionFormat: 'XY'
});
console.log(`Generated ${tessellationResult.triangleCount} triangles`);
// Use tessellated data in custom layer
class TessellatedPolygonLayer extends Layer {
initializeState() {
const {gl} = this.context;
const tessellationResult = tesselator.tesselate({
data: this.props.data,
getPolygon: this.props.getPolygon
});
this.setState({
model: new Model(gl, {
vs: vertexShader,
fs: fragmentShader,
geometry: new Geometry({
attributes: {
positions: tessellationResult.positions,
normals: tessellationResult.normals
},
indices: tessellationResult.indices
})
})
});
}
}Comprehensive logging system with levels and conditional logging.
/**
* Logging utility with multiple levels
* Provides conditional logging and performance tracking
*/
const log: {
/** Log info message */
info: (message: string, ...args: any[]) => void;
/** Log warning message */
warn: (message: string, ...args: any[]) => void;
/** Log error message */
error: (message: string, ...args: any[]) => void;
/** Log debug message (only in development) */
debug: (message: string, ...args: any[]) => void;
/** Create deprecated function warning */
deprecated: (oldUsage: string, newUsage: string) => () => void;
/** Time a code block */
time: (id: string) => void;
/** End timing and log result */
timeEnd: (id: string) => void;
/** Create performance probe */
probe: (id: string, message: string) => {
start: () => void;
end: () => void;
};
/** Set logging level */
level: number;
/** Enable/disable specific log types */
enable: (types: string[]) => void;
/** Disable specific log types */
disable: (types: string[]) => void;
};
// Log levels
const LOG_LEVELS = {
ERROR: 0,
WARN: 1,
INFO: 2,
DEBUG: 3
};Usage Examples:
import { log } from "@deck.gl/core";
// Basic logging
log.info('Layer initialized successfully');
log.warn('Large dataset detected, performance may be affected');
log.error('Failed to load data:', error);
// Performance timing
log.time('data-processing');
processLargeDataset(data);
log.timeEnd('data-processing');
// Performance probes
const renderProbe = log.probe('layer-render', 'Rendering layer');
renderProbe.start();
layer.draw();
renderProbe.end();
// Deprecation warnings
const deprecatedFunction = log.deprecated('oldFunction()', 'newFunction()');
const myOldFunction = () => {
deprecatedFunction();
// Function implementation
};
// Conditional logging based on environment
if (process.env.NODE_ENV === 'development') {
log.level = LOG_LEVELS.DEBUG;
log.debug('Debug information:', debugData);
} else {
log.level = LOG_LEVELS.WARN;
}Development-time assertion utility for validation.
/**
* Assertion utility for development-time validation
* Throws error if condition is false (only in development builds)
* @param condition - Condition to test
* @param message - Error message if assertion fails
*/
function assert(condition: any, message?: string): asserts condition;Usage Examples:
import { assert } from "@deck.gl/core";
// Parameter validation
const validateLayerProps = (props) => {
assert(props.data, 'Layer data is required');
assert(Array.isArray(props.data) || props.data.length !== undefined,
'Layer data must be array-like');
assert(typeof props.getPosition === 'function',
'getPosition accessor must be a function');
};
// Range validation
const validateCoordinates = (coords) => {
assert(coords.length >= 2, 'Coordinates must have at least 2 elements');
assert(coords[0] >= -180 && coords[0] <= 180, 'Longitude out of range');
assert(coords[1] >= -90 && coords[1] <= 90, 'Latitude out of range');
};
// Custom layer with assertions
class ValidatedLayer extends Layer {
updateState({props, oldProps}) {
assert(props.data, 'Data is required');
assert(props.data !== oldProps.data ||
JSON.stringify(props.updateTriggers) !== JSON.stringify(oldProps.updateTriggers),
'Props or update triggers must change to trigger update');
super.updateState({props, oldProps});
}
}/**
* Fill array with values efficiently
* @param array - Target array to fill
* @param value - Value or function to fill with
* @param start - Start index
* @param end - End index
*/
function _fillArray(
array: any[],
value: any | ((index: number) => any),
start?: number,
end?: number
): any[];
/**
* Flatten nested arrays
* @param array - Array to flatten
* @param depth - Depth to flatten (default: 1)
* @param filter - Optional filter function
*/
function _flatten<T>(
array: any[],
depth?: number,
filter?: (item: any) => boolean
): T[];/**
* Count data instances efficiently
* @param data - Data to count
* @param accessor - Optional accessor function
*/
function _count(data: any, accessor?: (item: any) => boolean): number;
/**
* Deep equality comparison
* @param a - First object to compare
* @param b - Second object to compare
* @param depth - Maximum depth to compare
*/
function _deepEqual(a: any, b: any, depth?: number): boolean;/**
* Memoize expensive function calls
* @param fn - Function to memoize
* @param getKey - Key generation function
*/
function _memoize<T extends (...args: any[]) => any>(
fn: T,
getKey?: (...args: Parameters<T>) => string
): T;
/**
* Merge shader code efficiently
* @param shaders - Array of shader objects to merge
*/
function _mergeShaders(shaders: any[]): any;
/**
* Compare props efficiently for updates
* @param newProps - New properties
* @param oldProps - Old properties
* @param compareKeys - Keys to compare
*/
function _compareProps(
newProps: any,
oldProps: any,
compareKeys?: string[]
): boolean;/**
* Apply CSS styles to DOM element
* @param element - Target DOM element
* @param styles - Styles to apply
*/
function _applyStyles(
element: HTMLElement,
styles: Partial<CSSStyleDeclaration>
): void;
/**
* Remove CSS styles from DOM element
* @param element - Target DOM element
* @param styleNames - Style names to remove
*/
function _removeStyles(
element: HTMLElement,
styleNames: string[]
): void;Usage Examples:
import {
_fillArray,
_flatten,
_count,
_deepEqual,
_memoize,
_compareProps
} from "@deck.gl/core";
// Efficient array operations
const positions = new Float32Array(1000 * 3);
_fillArray(positions, (i) => Math.random() * 100, 0, positions.length);
// Flatten nested coordinate arrays
const nestedCoords = [[[1, 2]], [[3, 4]], [[5, 6]]];
const flatCoords = _flatten(nestedCoords, 2); // [1, 2, 3, 4, 5, 6]
// Count filtered data
const validCount = _count(data, item => item.valid === true);
// Deep comparison for prop changes
const hasChanged = !_deepEqual(newProps, oldProps, 3);
// Memoize expensive calculations
const expensiveCalculation = _memoize((data, options) => {
// Complex calculation
return processData(data, options);
}, (data, options) => `${data.id}-${JSON.stringify(options)}`);
// Efficient prop comparison in layers
class OptimizedLayer extends Layer {
shouldUpdateState({props, oldProps, changeFlags}) {
return changeFlags.somethingChanged ||
!_compareProps(props, oldProps, ['data', 'getPosition', 'getColor']);
}
}
// DOM styling utilities
import { _applyStyles, _removeStyles } from "@deck.gl/core";
const canvas = deck.getCanvas();
_applyStyles(canvas, {
cursor: 'pointer',
borderRadius: '8px',
boxShadow: '0 4px 8px rgba(0,0,0,0.1)'
});
// Remove styles when done
_removeStyles(canvas, ['cursor', 'borderRadius', 'boxShadow']);Package version constant for compatibility checking.
/**
* Current package version string
* Used for compatibility checking and debugging
*/
const VERSION: string;Usage Examples:
import { VERSION } from "@deck.gl/core";
console.log(`Using @deck.gl/core version ${VERSION}`);
// Version compatibility checking
const checkCompatibility = (requiredVersion) => {
const [major, minor, patch] = VERSION.split('.').map(n => parseInt(n));
const [reqMajor, reqMinor, reqPatch] = requiredVersion.split('.').map(n => parseInt(n));
if (major > reqMajor) return true;
if (major === reqMajor && minor > reqMinor) return true;
if (major === reqMajor && minor === reqMinor && patch >= reqPatch) return true;
return false;
};
if (!checkCompatibility('9.0.0')) {
console.warn('This application requires @deck.gl/core version 9.0.0 or higher');
}Efficient memory management for large datasets.
interface TypedArrayManager {
/** Allocate typed array */
allocate(size: number, type: string): TypedArray;
/** Release typed array back to pool */
release(array: TypedArray): void;
/** Get memory usage statistics */
getStats(): {
totalAllocated: number;
totalReleased: number;
currentUsage: number;
poolSize: number;
};
}
interface TypedArrayManagerOptions {
/** Pool size for array reuse */
poolSize?: number;
/** Enable memory tracking */
trackMemory?: boolean;
/** Maximum total memory usage */
maxMemory?: number;
}Usage Examples:
// Efficient memory management for large datasets
const createOptimizedLayer = (data) => {
const typedArrayManager = new TypedArrayManager({
poolSize: 100,
trackMemory: true,
maxMemory: 1024 * 1024 * 512 // 512MB limit
});
return new ScatterplotLayer({
id: 'optimized-points',
data: data,
getPosition: d => d.coordinates,
// Custom attribute update with memory pooling
updateAttributes: ({props, oldProps}) => {
if (props.data !== oldProps.data) {
const positions = typedArrayManager.allocate(
props.data.length * 3,
'Float32Array'
);
// Fill positions array
props.data.forEach((d, i) => {
const pos = d.coordinates;
positions[i * 3] = pos[0];
positions[i * 3 + 1] = pos[1];
positions[i * 3 + 2] = pos[2] || 0;
});
return {positions};
}
}
});
};