Complete reference documentation for all public APIs in ScreenGrid Library.
Main orchestrator class that composes all modules. This is the primary interface for using the library.
new ScreenGridLayerGL(options)
Creates a new ScreenGrid layer instance.
Parameters:
options (Object, optional) - Configuration options. See Configuration Options for details.Returns: ScreenGridLayerGL instance
Example:
const layer = new ScreenGridLayerGL({
data: myData,
getPosition: (d) => d.coordinates,
getWeight: (d) => d.value,
cellSizePixels: 50
});
map.addLayer(layer);
id (getter)string"screen-grid-layer"type (getter)string"custom" (required by MapLibre GL)renderingMode (getter)string"2d" (indicates Canvas 2D rendering)onAdd(map, gl)Called automatically by MapLibre GL when the layer is added to the map. You typically don’t call this directly.
Parameters:
map (Object) - MapLibre GL map instancegl (WebGLRenderingContext) - WebGL contextReturns: void
prerender()Called automatically before each render. Projects points to screen space.
Returns: void
render()Renders the grid layer to the canvas. Called automatically by MapLibre GL render loop.
Returns: void
Note: This method performs aggregation and drawing. For performance, avoid calling manually unless necessary.
onRemove()Called automatically when the layer is removed from the map. Cleans up event bindings and canvas.
Returns: void
setData(newData)Updates the data source for the layer.
Parameters:
newData (Array) - New array of data pointsReturns: void
Example:
layer.setData(updatedData);
Note: Automatically re-projects points after updating data.
setConfig(updates)Updates layer configuration with partial options.
Parameters:
updates (Object) - Partial configuration object. Only include properties you want to change.Returns: void
Example:
layer.setConfig({
cellSizePixels: 80,
colorScale: (v) => [255 * v, 0, 0, 200],
enableGlyphs: true
});
Note: Automatically re-projects points after updating config.
getCellAt(point)Get cell information at a specific screen point.
Parameters:
point (Object) - Point coordinates: {x: number, y: number} (screen pixels)Returns: Object|null - Cell information object or null if no cell at point.
Cell Object Structure:
{
col: number, // Grid column index
row: number, // Grid row index
value: number, // Aggregated value
cellData: Array, // Array of original data points in this cell
x: number, // Screen X coordinate (top-left of cell)
y: number, // Screen Y coordinate (top-left of cell)
cellSize: number, // Cell size in pixels
index: number // Linear index in grid array
}
Example:
map.on('mousemove', (e) => {
const cell = layer.getCellAt({ x: e.point.x, y: e.point.y });
if (cell) {
console.log(`Cell [${cell.col}, ${cell.row}]: ${cell.value}`);
console.log(`Contains ${cell.cellData.length} data points`);
}
});
getCellsInBounds(bounds)Get all cells with data in a rectangular region.
Parameters:
bounds (Object) - Bounding rectangle: {minX: number, minY: number, maxX: number, maxY: number} (screen pixels)Returns: Array<Object> - Array of cell information objects (same structure as getCellAt)
Example:
const cells = layer.getCellsInBounds({
minX: 100,
minY: 100,
maxX: 500,
maxY: 400
});
console.log(`Found ${cells.length} cells in region`);
cells.forEach(cell => {
console.log(`Cell [${cell.col}, ${cell.row}]: ${cell.value}`);
});
getGridStats()Get statistics about the current grid aggregation.
Returns: Object|null - Statistics object or null if grid not yet aggregated.
Statistics Object:
{
totalCells: number, // Total number of cells in grid
cellsWithData: number, // Number of cells containing data
maxValue: number, // Maximum aggregated value
minValue: number, // Minimum aggregated value (excluding zeros)
avgValue: number, // Average value across cells with data
totalValue: number // Sum of all cell values
}
Example:
const stats = layer.getGridStats();
if (stats) {
console.log(`Grid: ${stats.cols}×${stats.rows} cells`);
console.log(`${stats.cellsWithData} cells contain data`);
console.log(`Value range: ${stats.minValue} - ${stats.maxValue}`);
}
These are convenience aliases to GlyphUtilities methods. See GlyphUtilities for detailed documentation.
ScreenGridLayerGL.drawCircleGlyph(ctx, x, y, radius, color, alpha)
ScreenGridLayerGL.drawBarGlyph(ctx, x, y, values, maxValue, cellSize, colors)
ScreenGridLayerGL.drawPieGlyph(ctx, x, y, values, radius, colors)
ScreenGridLayerGL.drawScatterGlyph(ctx, x, y, points, cellSize, color)
ScreenGridLayerGL.drawDonutGlyph(ctx, x, y, values, outerRadius, innerRadius, colors)
ScreenGridLayerGL.drawHeatmapGlyph(ctx, x, y, radius, normalizedValue, colorScale)
ScreenGridLayerGL.drawRadialBarGlyph(ctx, x, y, values, maxValue, maxRadius, color)
ScreenGridLayerGL.drawTimeSeriesGlyph(ctx, x, y, timeSeriesData, cellSize, options)
Options passed to ScreenGridLayerGL constructor or setConfig().
idstring"screen-grid-layer"dataArray[]getPositionFunction(d) => d.coordinates[lng, lat] coordinates from a data point(dataPoint) => [lng, lat]Example:
getPosition: (d) => [d.longitude, d.latitude]
// or
getPosition: (d) => d.location
getWeightFunction() => 1(dataPoint) => numberExample:
getWeight: (d) => d.population
// or
getWeight: (d) => d.count || 1
cellSizePixelsnumber50colorScaleFunction(v) => [255 * v, 100, 200, 200](normalizedValue: number) => [r, g, b, a]
normalizedValue: Value between 0 and 1[red, green, blue, alpha] where each component is 0-255Example:
// Heatmap (red to yellow)
colorScale: (v) => [255 * v, 200 * (1 - v), 50, 220]
// Blue scale
colorScale: (v) => [50, 100, 255 * v, 220]
// Custom gradient
colorScale: (v) => {
const r = Math.floor(255 * Math.sin(v * Math.PI));
const g = Math.floor(255 * Math.cos(v * Math.PI));
const b = Math.floor(255 * v);
return [r, g, b, 200];
}
enableGlyphsbooleanfalseonDrawCellFunction|nullnull(ctx, x, y, normVal, cellInfo) => void
ctx: Canvas 2D rendering contextx, y: Center coordinates of the cellnormVal: Normalized value (0-1)cellInfo: Object with cell information (see below)cellInfo Object:
{
cellData: Array, // Array of original data points in this cell
cellSize: number, // Size of the cell in pixels
glyphRadius: number, // Recommended radius for glyph drawing
normalizedValue: number, // Same as normVal
col: number, // Grid column index
row: number, // Grid row index
value: number, // Raw aggregated value
customData: any, // Result returned from onAfterAggregate for this cell
zoomLevel: number, // Current map zoom level
isHovered: boolean, // True if cell is currently hovered by mouse
grid: Array<number> // Full grid array for context
}
**Example:**
```javascript
onDrawCell: (ctx, x, y, normVal, cellInfo) => {
const { cellData, glyphRadius } = cellInfo;
const total = cellData.reduce((sum, item) => sum + item.data.value, 0);
ctx.fillStyle = `hsl(${normVal * 360}, 70%, 50%)`;
ctx.beginPath();
ctx.arc(x, y, glyphRadius, 0, 2 * Math.PI);
ctx.fill();
}
glyphSizenumber0.8onAfterAggregateFunction|nullnullonDrawCell as cellInfo.customData.(cellData, aggregatedValue, index, grid) => any
cellData: Array of points in the cellaggregatedValue: The result of the primary aggregation (e.g., sum)index: Linear index of the cell in the gridgrid: The full array of aggregated valuesExample (Multivariate Averages):
onAfterAggregate: (cellData) => {
const sumVal1 = cellData.reduce((s, p) => s + p.data.val1, 0);
const sumVal2 = cellData.reduce((s, p) => s + p.data.val2, 0);
return {
avgVal1: sumVal1 / cellData.length,
avgVal2: sumVal2 / cellData.length
};
}
adaptiveCellSizebooleanfalseminCellSizenumber20zoomBasedSize)maxCellSizenumber100zoomBasedSize)zoomBasedSizebooleanfalseonAggregateFunction|nullnull(gridData) => voidgridData Object:
{
grid: Array<number>, // Array of aggregated values
cellData: Array<Array>, // 2D array of original data points per cell
cols: number, // Number of columns
rows: number, // Number of rows
width: number, // Canvas width
height: number, // Canvas height
cellSizePixels: number // Cell size used
}
Example:
onAggregate: (gridData) => {
console.log(`Grid: ${gridData.cols}×${gridData.rows}`);
console.log(`Max value: ${Math.max(...gridData.grid)}`);
}
onHoverFunction|nullnull({cell, event}) => void
cell: Cell information object (same as getCellAt return value)event: MapLibre mouse eventExample:
onHover: ({ cell, event }) => {
if (cell) {
console.log(`Hovering over cell [${cell.col}, ${cell.row}]`);
console.log(`Value: ${cell.value}`);
console.log(`Contains ${cell.cellData.length} points`);
}
}
onClickFunction|nullnull({cell, event}) => void (same as onHover)Example:
onClick: ({ cell, event }) => {
if (cell) {
showDetailsModal(cell.cellData);
}
}
enabledbooleantrueThese options allow you to use non-point geometries (Polygon, LineString, etc.) instead of point data.
sourceGeoJSON.FeatureCollection | GeoJSON.Feature[] | nullnulldata option.Example:
const layer = new ScreenGridLayerGL({
source: geojsonData, // GeoJSON FeatureCollection
placement: { strategy: 'centroid' },
renderMode: 'feature-anchors'
});
placementObject | nullnullsource.Placement Config Structure:
{
strategy: 'centroid' | 'polylabel' | 'line-sample' | 'grid-geo' | 'grid-screen' | 'point',
spacing?: { meters: number } | { pixels: number },
partition?: 'union' | 'per-part',
maxPerFeature?: number,
minArea?: number,
minLength?: number,
jitterPixels?: number,
zoomAdaptive?: boolean
}
Example:
placement: {
strategy: 'line-sample',
spacing: { meters: 200 },
zoomAdaptive: true
}
renderMode'screen-grid' | 'feature-anchors''screen-grid''screen-grid': Aggregate anchors into screen-space grid cells (default)'feature-anchors': Draw glyphs directly at anchor positions (one glyph per anchor)Example:
renderMode: 'feature-anchors' // Draw one glyph per feature
anchorSizePixelsnumberauto (calculated from cellSizePixels * glyphSize * 0.9)renderMode: 'feature-anchors'.Example:
anchorSizePixels: 18 // Fixed glyph size in pixels
These options allow you to use non-point geometries (Polygon, LineString, etc.) instead of point data.
sourceGeoJSON.FeatureCollection | GeoJSON.Feature[] | nullnulldata option.Example:
const layer = new ScreenGridLayerGL({
source: geojsonData, // GeoJSON FeatureCollection
placement: { strategy: 'centroid' },
renderMode: 'feature-anchors'
});
placementObject | nullnullsource.Placement Config Structure:
{
strategy: 'centroid' | 'polylabel' | 'line-sample' | 'grid-geo' | 'grid-screen' | 'point',
spacing?: { meters: number } | { pixels: number },
partition?: 'union' | 'per-part',
maxPerFeature?: number,
minArea?: number,
minLength?: number,
jitterPixels?: number,
zoomAdaptive?: boolean
}
Example:
placement: {
strategy: 'line-sample',
spacing: { meters: 200 },
zoomAdaptive: true
}
renderMode'screen-grid' | 'feature-anchors''screen-grid''screen-grid': Aggregate anchors into screen-space grid cells (default)'feature-anchors': Draw glyphs directly at anchor positions (one glyph per anchor)Example:
renderMode: 'feature-anchors' // Draw one glyph per feature
anchorSizePixelsnumberauto (calculated from cellSizePixels * glyphSize * 0.9)renderMode: 'feature-anchors'.Example:
anchorSizePixels: 18 // Fixed glyph size in pixels
Static utility class for drawing common glyph types. Can be imported directly or accessed via ScreenGridLayerGL static methods.
import { GlyphUtilities } from 'screengrid';
drawCircleGlyph(ctx, x, y, radius, color, alpha)Draw a simple circle glyph.
Parameters:
ctx (CanvasRenderingContext2D) - Canvas 2D contextx (number) - Center X coordinatey (number) - Center Y coordinateradius (number) - Circle radius in pixelscolor (string, optional) - Fill color (CSS color string). Default: '#ff0000'alpha (number, optional) - Opacity (0-1). Default: 0.8Returns: void
Example:
GlyphUtilities.drawCircleGlyph(ctx, 100, 100, 20, '#3498db', 0.8);
drawBarGlyph(ctx, x, y, values, maxValue, cellSize, colors)Draw a horizontal bar chart glyph showing multiple values.
Parameters:
ctx (CanvasRenderingContext2D) - Canvas contextx (number) - Center X coordinatey (number) - Center Y coordinatevalues (ArraymaxValue (number) - Maximum value for scalingcellSize (number) - Cell size in pixelscolors (ArrayReturns: void
Example:
GlyphUtilities.drawBarGlyph(
ctx, x, y,
[10, 25, 15], // values
30, // maxValue
50, // cellSize
['#e74c3c', '#3498db', '#2ecc71'] // colors
);
drawPieGlyph(ctx, x, y, values, radius, colors)Draw a pie chart glyph showing proportions.
Parameters:
ctx (CanvasRenderingContext2D) - Canvas contextx (number) - Center X coordinatey (number) - Center Y coordinatevalues (Arrayradius (number) - Pie radius in pixelscolors (ArrayReturns: void
Example:
GlyphUtilities.drawPieGlyph(
ctx, x, y,
[30, 20, 10], // values
15, // radius
['#e74c3c', '#3498db', '#2ecc71'] // colors
);
drawDonutGlyph(ctx, x, y, values, outerRadius, innerRadius, colors)Draw a donut chart glyph (pie chart with central hole).
Parameters:
ctx (CanvasRenderingContext2D) - Canvas contextx (number) - Center X coordinatey (number) - Center Y coordinatevalues (ArrayouterRadius (number) - Outer radius in pixelsinnerRadius (number) - Inner radius (hole size) in pixelscolors (ArrayReturns: void
Example:
GlyphUtilities.drawDonutGlyph(
ctx, x, y,
[30, 20, 10], // values
20, // outerRadius
10, // innerRadius
['#e74c3c', '#3498db', '#2ecc71']
);
drawScatterGlyph(ctx, x, y, points, cellSize, color)Draw a scatter plot glyph showing individual data points.
Parameters:
ctx (CanvasRenderingContext2D) - Canvas contextx (number) - Center X coordinatey (number) - Center Y coordinatepoints (ArraycellSize (number) - Cell size in pixelscolor (string, optional) - Point color. Default: '#ff0000'Returns: void
Example:
GlyphUtilities.drawScatterGlyph(
ctx, x, y,
cellData, // Array of {data, weight, ...} objects
50, // cellSize
'#e74c3c' // color
);
drawHeatmapGlyph(ctx, x, y, radius, normalizedValue, colorScale)Draw a heatmap-style glyph with color intensity based on normalized value.
Parameters:
ctx (CanvasRenderingContext2D) - Canvas contextx (number) - Center X coordinatey (number) - Center Y coordinateradius (number) - Circle radius in pixelsnormalizedValue (number) - Normalized value (0-1)colorScale (Function) - Function that maps value to color: (value: number) => stringReturns: void
Example:
GlyphUtilities.drawHeatmapGlyph(
ctx, x, y,
15, // radius
0.75, // normalizedValue
(v) => `hsl(${v * 240}, 70%, 50%)` // colorScale
);
drawRadialBarGlyph(ctx, x, y, values, maxValue, maxRadius, color)Draw a radial bar glyph (bars radiating from center, like a radar chart).
Parameters:
ctx (CanvasRenderingContext2D) - Canvas contextx (number) - Center X coordinatey (number) - Center Y coordinatevalues (ArraymaxValue (number) - Maximum value for scalingmaxRadius (number) - Maximum bar length (radius)color (string, optional) - Bar color. Default: '#ff0000'Returns: void
Example:
GlyphUtilities.drawRadialBarGlyph(
ctx, x, y,
[10, 20, 15, 25], // values
30, // maxValue
20, // maxRadius
'#3498db' // color
);
drawTimeSeriesGlyph(ctx, x, y, timeSeriesData, cellSize, options)Draw a time series line chart glyph showing temporal trends.
Parameters:
ctx (CanvasRenderingContext2D) - Canvas contextx (number) - Center X coordinatey (number) - Center Y coordinatetimeSeriesData (ArraycellSize (number) - Cell size in pixelsoptions (Object, optional) - Configuration optionsOptions Object:
{
lineColor: string, // Line color. Default: '#3498db'
pointColor: string, // Data point color. Default: '#e74c3c'
lineWidth: number, // Line width. Default: 2
pointRadius: number, // Point radius. Default: 2
showPoints: boolean, // Show data points. Default: true
showArea: boolean, // Fill area under line. Default: false
areaColor: string, // Area fill color. Default: 'rgba(52, 152, 219, 0.2)'
padding: number // Padding as fraction of cellSize. Default: 0.1
}
Returns: void
Example:
const timeSeriesData = [
{ year: 2020, value: 10 },
{ year: 2021, value: 15 },
{ year: 2022, value: 12 },
{ year: 2023, value: 20 }
];
GlyphUtilities.drawTimeSeriesGlyph(
ctx, x, y,
timeSeriesData,
50, // cellSize
{
lineColor: '#2ecc71',
pointColor: '#27ae60',
lineWidth: 2,
showPoints: true,
showArea: true,
areaColor: 'rgba(46, 204, 113, 0.15)',
padding: 0.15
}
);
Static utility class for managing configuration with defaults and validation.
import { ConfigManager } from 'screengrid';
create(options)Create configuration from user options merged with defaults.
Parameters:
options (Object, optional) - User-provided configuration optionsReturns: Object - Merged configuration object
Example:
const config = ConfigManager.create({
data: myData,
cellSizePixels: 60
});
// config now has all defaults plus user options
update(config, updates)Update configuration with partial options.
Parameters:
config (Object) - Current configurationupdates (Object) - Partial configuration updatesReturns: Object - Updated configuration object
Example:
const updatedConfig = ConfigManager.update(config, {
cellSizePixels: 80,
enableGlyphs: true
});
isValid(config)Validate configuration structure.
Parameters:
config (Object) - Configuration to validateReturns: boolean - true if valid, false otherwise
Example:
if (ConfigManager.isValid(config)) {
// Configuration is valid
}
Pure business logic class for aggregating points into grid cells.
import { Aggregator } from 'screengrid';
aggregate(projectedPoints, originalData, width, height, cellSizePixels)Aggregate projected points into a grid.
Parameters:
projectedPoints (ArrayoriginalData (Array) - Original data array for referencewidth (number) - Canvas width in pixelsheight (number) - Canvas height in pixelscellSizePixels (number) - Size of each grid cellReturns: Object - Aggregation result:
{
grid: Array<number>, // Array of aggregated values
cellData: Array<Array>, // 2D array of original data points per cell
cols: number, // Number of columns
rows: number, // Number of rows
width: number, // Canvas width
height: number, // Canvas height
cellSizePixels: number // Cell size used
}
Example:
const projectedPoints = [
{ x: 100, y: 200, w: 1.5 },
{ x: 150, y: 250, w: 2.0 }
];
const result = Aggregator.aggregate(
projectedPoints,
originalData,
800, // width
600, // height
50 // cellSizePixels
);
getStats(aggregationResult)Get statistics about a grid aggregation.
Parameters:
aggregationResult (Object) - Result from aggregate() methodReturns: Object - Statistics:
{
totalCells: number, // Total number of cells
cellsWithData: number, // Number of cells with data
maxValue: number, // Maximum value
minValue: number, // Minimum value (excluding zeros)
avgValue: number, // Average value
totalValue: number // Sum of all values
}
Example:
const stats = Aggregator.getStats(result);
console.log(`Found ${stats.cellsWithData} cells with data`);
console.log(`Max value: ${stats.maxValue}`);
aggregate(projectedPoints, originalData, width, height, cellSizePixels)Instance method that calls the static method. Same parameters and return value.
getStats(aggregationResult)Instance method that calls the static method. Same parameters and return value.
Pure function class for projecting geographic coordinates to screen space.
import { Projector } from 'screengrid';
projectPoints(data, getPosition, getWeight, map)Project geographic coordinates to screen space.
Parameters:
data (Array) - Array of data pointsgetPosition (Function) - Function to extract [lng, lat] from data point: (d) => [lng, lat]getWeight (Function) - Function to extract weight from data point: (d) => numbermap (Object) - MapLibre GL map instanceReturns: Array<Object> - Array of projected points: {x: number, y: number, w: number}
Example:
const projected = Projector.projectPoints(
myData,
(d) => d.coordinates,
(d) => d.value,
map
);
constructor(map)Create a new Projector instance.
Parameters:
map (Object, optional) - MapLibre GL map instancesetMap(map)Set the map reference.
Parameters:
map (Object) - MapLibre GL map instanceproject(data, getPosition, getWeight)Project points using stored map reference.
Parameters:
data (Array) - Data points to projectgetPosition (Function) - Position extractor: (d) => [lng, lat]getWeight (Function) - Weight extractor: (d) => numberReturns: Array<Object> - Projected points
Example:
const projector = new Projector(map);
const projected = projector.project(
myData,
(d) => d.coordinates,
(d) => d.value
);
Query engine for finding and accessing grid cells.
import { CellQueryEngine } from 'screengrid';
getCellAt(aggregationResult, point)Get cell information at a specific point.
Parameters:
aggregationResult (Object) - Result from Aggregator.aggregate()point (Object) - Point coordinates: {x: number, y: number}Returns: Object|null - Cell information object (see ScreenGridLayerGL.getCellAt)
getCellsInBounds(aggregationResult, bounds)Get all cells with data in a rectangular region.
Parameters:
aggregationResult (Object) - Aggregation resultbounds (Object) - Bounding rectangle: {minX: number, minY: number, maxX: number, maxY: number}Returns: Array<Object> - Array of cell information objects
getCellsAboveThreshold(aggregationResult, threshold)Get all cells with values above a threshold.
Parameters:
aggregationResult (Object) - Aggregation resultthreshold (number) - Minimum valueReturns: Array<Object> - Array of cell information objects
constructor(aggregationResult)Create a new CellQueryEngine instance.
Parameters:
aggregationResult (Object, optional) - Initial aggregation resultsetAggregationResult(aggregationResult)Set the aggregation result for queries.
Parameters:
aggregationResult (Object) - Aggregation resultgetCellAt(point)Query cell at point using stored result.
Parameters:
point (Object) - {x: number, y: number}Returns: Object|null - Cell information
getCellsInBounds(bounds)Query cells in bounds using stored result.
Parameters:
bounds (Object) - Bounding rectangleReturns: Array<Object> - Cells in bounds
getCellsAboveThreshold(threshold)Query cells above threshold using stored result.
Parameters:
threshold (number) - Threshold valueReturns: Array<Object> - Cells above threshold
Modules for handling non-point geometries (Polygon, LineString, etc.) and converting them to anchor points.
Converts GeoJSON geometries to anchor points based on placement strategy.
Import:
import { PlacementEngine } from 'screengrid';
Usage:
const engine = new PlacementEngine(map);
const anchors = engine.processFeatures(features, placementConfig);
Validates placement configuration objects.
Import:
import { PlacementValidator } from 'screengrid';
Usage:
const isValid = PlacementValidator.validate(placementConfig);
Registry for placement strategies (centroid, line-sample, grid-geo, etc.).
Import:
import { PlacementStrategyRegistry } from 'screengrid';
Usage:
const strategy = PlacementStrategyRegistry.get('centroid');
Utility functions for geometry operations.
Import:
import { GeometryUtils } from 'screengrid';
Methods:
getCentroid(geometry) - Get centroid of geometrysampleLine(geometry, spacing) - Sample points along linegridPolygon(geometry, spacing) - Create grid within polygonMain Legend class for rendering data-driven legends.
import { Legend } from 'screengrid';
new Legend(options)
Parameters:
options (Object) - Configuration options:
layer (ScreenGridLayerGL) - ScreenGridLayerGL instance to connect totype (string, optional) - Legend type: 'color-scale', 'categorical', 'temporal', 'size-scale', 'auto', 'multi'. Default: 'auto'position (string, optional) - Position: 'top-left', 'top-right', 'bottom-left', 'bottom-right'. Default: 'bottom-right'title (string, optional) - Legend title. Default: 'Legend'container (HTMLElement, optional) - Custom container elementrenderOptions (Object, optional) - Options passed to rendererscategoryExtractor (Function, optional) - Function to extract category from data (for categorical)valueExtractor (Function, optional) - Function to extract value from datatimeExtractor (Function, optional) - Function to extract time/year from data (for temporal)sizeExtractor (Function, optional) - Function to extract size from data (for size-scale)Returns: Legend instance
Example:
const legend = new Legend({
layer: gridLayer,
type: 'auto',
position: 'bottom-right',
title: 'Data Legend'
});
update(gridData, config)Update legend with new data.
Parameters:
gridData (Object) - Aggregation result from ScreenGridLayerGLconfig (Object) - ScreenGridLayerGL configReturns: void
show()Show the legend.
Returns: void
hide()Hide the legend.
Returns: void
remove()Remove the legend from DOM.
Returns: void
setPosition(position)Update legend position.
Parameters:
position (string) - New position: 'top-left', 'top-right', 'bottom-left', 'bottom-right'Returns: void
setTitle(title)Update legend title.
Parameters:
title (string) - New titleReturns: void
Manages canvas creation, sizing, and cleanup. Typically used internally by ScreenGridLayerGL.
import { CanvasManager } from 'screengrid';
init(map)Initialize the canvas overlay.
Parameters:
map (Object) - MapLibre GL map instanceThrows: Error if canvas cannot be initialized
Returns: void
getContext()Get the 2D rendering context.
Returns: CanvasRenderingContext2D
getCanvas()Get the overlay canvas element.
Returns: HTMLCanvasElement
resize()Resize canvas to match map canvas with DPI scaling.
Returns: void
clear()Clear the canvas.
Returns: void
getDisplaySize()Get canvas dimensions in CSS pixels.
Returns: Object - {width: number, height: number}
cleanup()Clean up resources.
Returns: void
Canvas drawing logic for grid cells. Typically used internally by ScreenGridLayerGL.
import { Renderer } from 'screengrid';
render(aggregationResult, ctx, config)Render grid cells to canvas.
Parameters:
aggregationResult (Object) - Result from Aggregator.aggregate()ctx (CanvasRenderingContext2D) - Canvas 2D contextconfig (Object) - Configuration:
colorScale (Function) - Color function: (normalizedValue) => [r, g, b, a]enableGlyphs (boolean) - Enable glyph renderingonDrawCell (Function) - Custom glyph drawing callbackglyphSize (number) - Glyph size factorReturns: void
renderGlyphs(aggregationResult, ctx, onDrawCell, glyphSize)Render with glyph mode enabled.
Parameters:
aggregationResult (Object) - Aggregation resultctx (CanvasRenderingContext2D) - Canvas contextonDrawCell (Function) - Glyph drawing callbackglyphSize (number, optional) - Glyph size (0-1). Default: 0.8Returns: void
renderColors(aggregationResult, ctx, colorScale)Render with color mode enabled.
Parameters:
aggregationResult (Object) - Aggregation resultctx (CanvasRenderingContext2D) - Canvas contextcolorScale (Function) - Color scale functionReturns: void
Manages event binding and unbinding. Typically used internally by ScreenGridLayerGL.
import { EventBinder } from 'screengrid';
bind(map, eventHandlers)Bind events to the map.
Parameters:
map (Object) - MapLibre map instanceeventHandlers (Object) - Object with handler methods:
handleHover (Function) - Hover handlerhandleClick (Function) - Click handlerhandleZoom (Function) - Zoom handlerhandleMove (Function) - Move handlerReturns: void
unbind()Unbind events from the map.
Returns: void
bindEvent(eventName, handler)Bind a specific event.
Parameters:
eventName (string) - Event name (e.g., 'mousemove', 'click')handler (Function) - Handler functionReturns: void
unbindEvent(eventName)Unbind a specific event.
Parameters:
eventName (string) - Event nameReturns: void
Event handler implementations. Typically used internally by ScreenGridLayerGL.
import { EventHandlers } from 'screengrid';
handleHover(event, cellQueryEngine, onHover)Handle hover events.
Parameters:
event (Object) - MapLibre mouse eventcellQueryEngine (CellQueryEngine) - CellQueryEngine instanceonHover (Function) - Hover callback from configReturns: void
handleClick(event, cellQueryEngine, onClick)Handle click events.
Parameters:
event (Object) - MapLibre click eventcellQueryEngine (CellQueryEngine) - CellQueryEngine instanceonClick (Function) - Click callback from configReturns: void
handleZoom(map, config, onZoom)Handle zoom events.
Parameters:
map (Object) - MapLibre map instanceconfig (Object) - Layer configurationonZoom (Function) - Callback after zoom handlingReturns: void
handleMove(onMove)Handle move events.
Parameters:
onMove (Function) - Callback when map movesReturns: void
Understanding how ScreenGrid processes data is crucial for effective visualization. This section explains the complete pipeline from raw data to rendered cells.
The library processes data through three main stages:
Purpose: Transform geographic coordinates [lng, lat] to screen pixel coordinates {x, y}.
Process:
// For each data point:
const [lng, lat] = getPosition(dataPoint);
const screenPoint = map.project([lng, lat]);
const weight = getWeight(dataPoint);
// Result: {x: screenPoint.x, y: screenPoint.y, w: weight}
Example:
// Input data:
[
{ coordinates: [-122.4, 37.74], population: 1000 },
{ coordinates: [-122.5, 37.75], population: 2000 }
]
// After projection (example screen coordinates):
[
{ x: 400, y: 300, w: 1000 },
{ x: 450, y: 350, w: 2000 }
]
Key Points:
map.project() methodw)Purpose: Assign projected points to grid cells and sum their weights.
Algorithm:
const cols = Math.ceil(canvasWidth / cellSizePixels);
const rows = Math.ceil(canvasHeight / cellSizePixels);
// Example: 800px width, 50px cells → 16 columns
// For each projected point {x, y, w}:
const col = Math.floor(x / cellSizePixels);
const row = Math.floor(y / cellSizePixels);
const cellIndex = row * cols + col;
// All points in the same cell have their weights summed:
grid[cellIndex] += weight;
// Original data is also stored:
cellData[cellIndex].push({
data: originalDataPoint,
weight: weight,
projectedX: x,
projectedY: y
});
Mathematical Example:
Given:
Projected points:
Point A: {x: 75, y: 125, w: 10} → Cell [1, 2]
Point B: {x: 80, y: 130, w: 5} → Cell [1, 2] (same cell!)
Point C: {x: 200, y: 300, w: 20} → Cell [4, 6]
Result:
grid[1 * 16 + 2] = 10 + 5 = 15 // Cell [1, 2]
grid[4 * 16 + 6] = 20 // Cell [4, 6]
Aggregation Function:
The library uses summation as the aggregation function:
cellValue = Σ(weights of all points in cell)
Why Summation?
Custom Aggregation:
If you need different aggregation (average, max, etc.), you can:
// Convert to per-cell data
const aggregatedData = preAggregate(data);
// Then use getWeight to return 1 for each aggregated cell
onDrawCell:
onDrawCell: (ctx, x, y, normVal, cellInfo) => {
const { cellData } = cellInfo;
// Calculate average instead of sum
const avg = cellData.reduce((sum, item) => sum + item.data.value, 0)
/ cellData.length;
// Use avg for visualization
}
Purpose: Convert raw aggregated cell values to normalized range (0-1) for consistent rendering.
Process:
const maxValue = Math.max(...grid);
// Example: grid = [0, 5, 10, 15, 20, 0, ...]
// maxValue = 20
// For each cell with value > 0:
const normalizedValue = cellValue / maxValue;
// Cell with value 20 → normalizedValue = 1.0
// Cell with value 10 → normalizedValue = 0.5
// Cell with value 5 → normalizedValue = 0.25
Important: Only cells with value > 0 are normalized. Empty cells (value = 0) are not rendered.
Example Normalization:
Raw Grid Values:
[0, 5, 10, 15, 20, 0, 8, 12]
Max Value: 20
Normalized Values:
[0, 0.25, 0.5, 0.75, 1.0, 0, 0.4, 0.6]
Where Normalization is Used:
// colorScale receives normalized value (0-1)
const [r, g, b, a] = colorScale(normalizedValue);
// Example: normalizedValue = 0.5 → colorScale(0.5) → [127, 50, 100, 200]
// onDrawCell receives normalized value
onDrawCell: (ctx, x, y, normalizedValue, cellInfo) => {
// Use normalizedValue for size, opacity, etc.
const radius = glyphRadius * normalizedValue;
}
Let’s trace a complete example from data to rendering:
Input Data:
const data = [
{ coordinates: [-122.4, 37.74], population: 1000 },
{ coordinates: [-122.4, 37.74], population: 500 }, // Same location
{ coordinates: [-122.5, 37.75], population: 2000 }
];
Configuration:
const layer = new ScreenGridLayerGL({
data: data,
getPosition: (d) => d.coordinates,
getWeight: (d) => d.population,
cellSizePixels: 50
});
Step-by-Step Processing:
Point 1: [-122.4, 37.74] → {x: 400, y: 300, w: 1000}
Point 2: [-122.4, 37.74] → {x: 400, y: 300, w: 500} // Same screen position
Point 3: [-122.5, 37.75] → {x: 450, y: 350, w: 2000}
Canvas: 800×600px, Cell size: 50px
Grid: 16×12 cells
Point 1: {x: 400, y: 300} → Cell [8, 6]
Point 2: {x: 400, y: 300} → Cell [8, 6] // Same cell!
Point 3: {x: 450, y: 350} → Cell [9, 7]
grid[8 * 16 + 6] = 1000 + 500 = 1500
grid[9 * 16 + 7] = 2000
maxValue = Math.max(1500, 2000) = 2000
Cell [8, 6]: normalizedValue = 1500 / 2000 = 0.75
Cell [9, 7]: normalizedValue = 2000 / 2000 = 1.0
// Cell [8, 6]:
colorScale(0.75) → [191, 25, 50, 200] // Example color
// Cell [9, 7]:
colorScale(1.0) → [255, 100, 200, 200] // Maximum intensity
Cells with no data points have value = 0 and are not rendered.
// Cell contains no points
grid[index] = 0 // Not drawn, skipped in render loop
When multiple points fall in the same cell, their weights are summed:
// 3 points in same cell with weights [10, 5, 15]
cellValue = 10 + 5 + 15 = 30
Normalized values are always in range [0, 1]:
0.0 = Minimum non-zero value (or empty cell, not rendered)1.0 = Maximum value in current grid0.5 = Half of maximum valueImportant: The normalization is relative to the current grid, not global data. When you zoom or filter data, the maximum may change, and normalization adjusts accordingly.
The getWeight function directly affects aggregation:
// Different weight functions produce different aggregations:
// Sum of values
getWeight: (d) => d.value
// Result: Cell value = sum of all values in cell
// Count (each point = 1)
getWeight: () => 1
// Result: Cell value = number of points in cell
// Custom calculation
getWeight: (d) => d.population * d.density
// Result: Cell value = sum of (population × density) for all points
O(n) where n = number of cellsFor custom normalization strategies, you can override in onDrawCell:
onDrawCell: (ctx, x, y, normVal, cellInfo) => {
const { cellData, value } = cellInfo;
// Use raw value instead of normalized
const customNormalized = value / customMaxValue;
// Or use percentile-based normalization
const percentile = calculatePercentile(value, allValues);
// Then use for visualization
}
This API reference is for ScreenGrid Library v2.2.0+