Complete reference documentation for all public APIs in ScreenGrid Library.
- ScreenGridLayerGL
- Configuration Options
- GlyphUtilities
- ConfigManager
- Aggregator
- Projector
- CellQueryEngine
- Legend
- CanvasManager
- Renderer
- EventBinder
- EventHandlers
- Data Normalization and Aggregation Procedure
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);- Type:
string - Description: Unique identifier for the layer
- Default:
"screen-grid-layer"
- Type:
string - Description: Always returns
"custom"(required by MapLibre GL)
- Type:
string - Description: Always returns
"2d"(indicates Canvas 2D rendering)
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 context
Returns: void
Called automatically before each render. Projects points to screen space.
Returns: void
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.
Called automatically when the layer is removed from the map. Cleans up event bindings and canvas.
Returns: void
Updates the data source for the layer.
Parameters:
newData(Array) - New array of data points
Returns: void
Example:
layer.setData(updatedData);Note: Automatically re-projects points after updating data.
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.
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`);
}
});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}`);
});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().
- Type:
string - Default:
"screen-grid-layer" - Description: Unique identifier for the layer
- Type:
Array - Default:
[] - Description: Array of data points to aggregate
- Type:
Function - Default:
(d) => d.coordinates - Description: Function to extract
[lng, lat]coordinates from a data point - Parameters:
(dataPoint) => [lng, lat]
Example:
getPosition: (d) => [d.longitude, d.latitude]
// or
getPosition: (d) => d.location- Type:
Function - Default:
() => 1 - Description: Function to extract weight/value from a data point
- Parameters:
(dataPoint) => number
Example:
getWeight: (d) => d.population
// or
getWeight: (d) => d.count || 1- Type:
number - Default:
50 - Description: Size of each grid cell in pixels
- Type:
Function - Default:
(v) => [255 * v, 100, 200, 200] - Description: Color scale function that maps normalized value (0-1) to RGBA color
- Parameters:
(normalizedValue: number) => [r, g, b, a]normalizedValue: Value between 0 and 1- Returns: Array of
[red, green, blue, alpha]where each component is 0-255
Example:
// 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];
}- Type:
boolean - Default:
false - Description: Enable glyph-based rendering instead of color-based rendering
- Type:
Function|null - Default:
null - Description: Callback function for custom glyph drawing
- Parameters:
(ctx, x, y, normVal, cellInfo) => voidctx: 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();
}
- Type:
number - Default:
0.8 - Description: Size of glyphs relative to cell size (0-1). Multiplied by cell size to get glyph radius.
- Type:
Function|null - Default:
null - Description: Callback for post-aggregation calculations. Executed once per cell with data. Result is passed to
onDrawCellascellInfo.customData. - Parameters:
(cellData, aggregatedValue, index, grid) => anycellData: 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 values
Example (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
};
}- Type:
boolean - Default:
false - Description: Enable adaptive cell sizing (not yet fully implemented)
- Type:
number - Default:
20 - Description: Minimum cell size in pixels (used with
zoomBasedSize)
- Type:
number - Default:
100 - Description: Maximum cell size in pixels (used with
zoomBasedSize)
- Type:
boolean - Default:
false - Description: Adjust cell size based on zoom level. Cells shrink as you zoom in.
- Type:
Function|null - Default:
null - Description: Callback when grid is aggregated
- Parameters:
(gridData) => void
gridData 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)}`);
}- Type:
Function|null - Default:
null - Description: Callback when hovering over a grid cell
- Parameters:
({cell, event}) => voidcell: Cell information object (same asgetCellAtreturn value)event: MapLibre mouse event
Example:
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`);
}
}- Type:
Function|null - Default:
null - Description: Callback when clicking a grid cell
- Parameters:
({cell, event}) => void(same asonHover)
Example:
onClick: ({ cell, event }) => {
if (cell) {
showDetailsModal(cell.cellData);
}
}- Type:
boolean - Default:
true - Description: Whether the layer is enabled (rendered)
These options allow you to use non-point geometries (Polygon, LineString, etc.) instead of point data.
- Type:
GeoJSON.FeatureCollection | GeoJSON.Feature[] | null - Default:
null - Description: GeoJSON source data with non-point geometries. Mutually exclusive with
dataoption. - Supported Geometry Types: Point, MultiPoint, LineString, MultiLineString, Polygon, MultiPolygon
Example:
const layer = new ScreenGridLayerGL({
source: geojsonData, // GeoJSON FeatureCollection
placement: { strategy: 'centroid' },
renderMode: 'feature-anchors'
});- Type:
Object | null - Default:
null - Description: Configuration for converting geometries to anchor points. Required when using
source.
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
}- Type:
'screen-grid' | 'feature-anchors' - Default:
'screen-grid' - Description: Rendering mode for geometry input.
'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- Type:
number - Default:
auto(calculated fromcellSizePixels * glyphSize * 0.9) - Description: Size of glyphs in pixels when using
renderMode: 'feature-anchors'.
Example:
anchorSizePixels: 18 // Fixed glyph size in pixelsThese options allow you to use non-point geometries (Polygon, LineString, etc.) instead of point data.
- Type:
GeoJSON.FeatureCollection | GeoJSON.Feature[] | null - Default:
null - Description: GeoJSON source data with non-point geometries. Mutually exclusive with
dataoption. - Supported Geometry Types: Point, MultiPoint, LineString, MultiLineString, Polygon, MultiPolygon
Example:
const layer = new ScreenGridLayerGL({
source: geojsonData, // GeoJSON FeatureCollection
placement: { strategy: 'centroid' },
renderMode: 'feature-anchors'
});- Type:
Object | null - Default:
null - Description: Configuration for converting geometries to anchor points. Required when using
source.
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
}- Type:
'screen-grid' | 'feature-anchors' - Default:
'screen-grid' - Description: Rendering mode for geometry input.
'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- Type:
number - Default:
auto(calculated fromcellSizePixels * glyphSize * 0.9) - Description: Size of glyphs in pixels when using
renderMode: 'feature-anchors'.
Example:
anchorSizePixels: 18 // Fixed glyph size in pixelsStatic utility class for drawing common glyph types. Can be imported directly or accessed via ScreenGridLayerGL static methods.
import { GlyphUtilities } from 'screengrid';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.8
Returns: void
Example:
GlyphUtilities.drawCircleGlyph(ctx, 100, 100, 20, '#3498db', 0.8);Draw a horizontal bar chart glyph showing multiple values.
Parameters:
ctx(CanvasRenderingContext2D) - Canvas contextx(number) - Center X coordinatey(number) - Center Y coordinatevalues(Array) - Array of numeric values to displaymaxValue(number) - Maximum value for scalingcellSize(number) - Cell size in pixelscolors(Array, optional) - Array of colors for bars. Default:['#ff6b6b', '#4ecdc4', '#45b7d1']
Returns: void
Example:
GlyphUtilities.drawBarGlyph(
ctx, x, y,
[10, 25, 15], // values
30, // maxValue
50, // cellSize
['#e74c3c', '#3498db', '#2ecc71'] // colors
);Draw a pie chart glyph showing proportions.
Parameters:
ctx(CanvasRenderingContext2D) - Canvas contextx(number) - Center X coordinatey(number) - Center Y coordinatevalues(Array) - Array of numeric values for slicesradius(number) - Pie radius in pixelscolors(Array, optional) - Array of colors for slices. Default:['#ff6b6b', '#4ecdc4', '#45b7d1']
Returns: void
Example:
GlyphUtilities.drawPieGlyph(
ctx, x, y,
[30, 20, 10], // values
15, // radius
['#e74c3c', '#3498db', '#2ecc71'] // colors
);Draw a donut chart glyph (pie chart with central hole).
Parameters:
ctx(CanvasRenderingContext2D) - Canvas contextx(number) - Center X coordinatey(number) - Center Y coordinatevalues(Array) - Array of numeric valuesouterRadius(number) - Outer radius in pixelsinnerRadius(number) - Inner radius (hole size) in pixelscolors(Array, optional) - Array of colors. Default:['#ff6b6b', '#4ecdc4', '#45b7d1']
Returns: void
Example:
GlyphUtilities.drawDonutGlyph(
ctx, x, y,
[30, 20, 10], // values
20, // outerRadius
10, // innerRadius
['#e74c3c', '#3498db', '#2ecc71']
);Draw a scatter plot glyph showing individual data points.
Parameters:
ctx(CanvasRenderingContext2D) - Canvas contextx(number) - Center X coordinatey(number) - Center Y coordinatepoints(Array) - Array of point objects withweightpropertycellSize(number) - Cell size in pixelscolor(string, optional) - Point color. Default:'#ff0000'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) => stringctx(CanvasRenderingContext2D) - Canvas contextx(number) - Center X coordinatey(number) - Center Y coordinatevalues(Array) - Array of valuesmaxValue(number) - Maximum value for scalingmaxRadius(number) - Maximum bar length (radius)color(string, optional) - Bar color. Default:'#ff0000'ctx(CanvasRenderingContext2D) - Canvas contextx(number) - Center X coordinatey(number) - Center Y coordinatetimeSeriesData(Array) - Array of{year: number, value: number}objects, sorted by yearcellSize(number) - Cell size in pixelsoptions(Object, optional) - Configuration optionsoptions(Object, optional) - User-provided configuration optionsconfig(Object) - Current configurationupdates(Object) - Partial configuration updatesconfig(Object) - Configuration to validateprojectedPoints(Array) - Array of projected points:{x: number, y: number, w: number}originalData(Array) - Original data array for referencewidth(number) - Canvas width in pixelsheight(number) - Canvas height in pixelscellSizePixels(number) - Size of each grid cellaggregationResult(Object) - Result fromaggregate()methoddata(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 instancemap(Object, optional) - MapLibre GL map instancemap(Object) - MapLibre GL map instancedata(Array) - Data points to projectgetPosition(Function) - Position extractor:(d) => [lng, lat]getWeight(Function) - Weight extractor:(d) => numberaggregationResult(Object) - Result fromAggregator.aggregate()point(Object) - Point coordinates:{x: number, y: number}aggregationResult(Object) - Aggregation resultbounds(Object) - Bounding rectangle:{minX: number, minY: number, maxX: number, maxY: number}aggregationResult(Object) - Aggregation resultthreshold(number) - Minimum valueaggregationResult(Object, optional) - Initial aggregation resultaggregationResult(Object) - Aggregation resultpoint(Object) -{x: number, y: number}bounds(Object) - Bounding rectanglethreshold(number) - Threshold valuegetCentroid(geometry)- Get centroid of geometrysampleLine(geometry, spacing)- Sample points along linegridPolygon(geometry, spacing)- Create grid within polygonoptions(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)
gridData(Object) - Aggregation result from ScreenGridLayerGLconfig(Object) - ScreenGridLayerGL configposition(string) - New position:'top-left','top-right','bottom-left','bottom-right'title(string) - New titlemap(Object) - MapLibre GL map instanceaggregationResult(Object) - Result fromAggregator.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 factor
aggregationResult(Object) - Aggregation resultctx(CanvasRenderingContext2D) - Canvas contextonDrawCell(Function) - Glyph drawing callbackglyphSize(number, optional) - Glyph size (0-1). Default:0.8aggregationResult(Object) - Aggregation resultctx(CanvasRenderingContext2D) - Canvas contextcolorScale(Function) - Color scale functionmap(Object) - MapLibre map instanceeventHandlers(Object) - Object with handler methods:handleHover(Function) - Hover handlerhandleClick(Function) - Click handlerhandleZoom(Function) - Zoom handlerhandleMove(Function) - Move handler
eventName(string) - Event name (e.g.,'mousemove','click')handler(Function) - Handler functioneventName(string) - Event nameevent(Object) - MapLibre mouse eventcellQueryEngine(CellQueryEngine) - CellQueryEngine instanceonHover(Function) - Hover callback from configevent(Object) - MapLibre click eventcellQueryEngine(CellQueryEngine) - CellQueryEngine instanceonClick(Function) - Click callback from configmap(Object) - MapLibre map instanceconfig(Object) - Layer configurationonZoom(Function) - Callback after zoom handlingonMove(Function) - Callback when map moves- Projection: Geographic coordinates → Screen coordinates
- Aggregation: Screen points → Grid cells (summing weights)
- Normalization: Raw cell values → Normalized values (0-1) for rendering
- Uses MapLibre's
map.project()method - Screen coordinates update automatically when map moves/zooms
- Each point retains its weight value (
w) -
Calculate Grid Dimensions:
const cols = Math.ceil(canvasWidth / cellSizePixels); const rows = Math.ceil(canvasHeight / cellSizePixels); // Example: 800px width, 50px cells → 16 columns
-
Determine Cell Assignment:
// For each projected point {x, y, w}: const col = Math.floor(x / cellSizePixels); const row = Math.floor(y / cellSizePixels); const cellIndex = row * cols + col;
-
Sum Weights:
// 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 });
- Canvas: 800×600 pixels
- Cell size: 50 pixels
- Grid: 16 columns × 12 rows
- Intuitive for counts, populations, totals
- Preserves magnitude information
- Works well with weighted data
-
Pre-process data before passing to ScreenGrid:
// Convert to per-cell data const aggregatedData = preAggregate(data); // Then use getWeight to return 1 for each aggregated cell
-
Post-process in
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 }
-
Find Maximum Value:
const maxValue = Math.max(...grid); // Example: grid = [0, 5, 10, 15, 20, 0, ...] // maxValue = 20
-
Normalize Each Cell:
// 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
-
Color Rendering:
// colorScale receives normalized value (0-1) const [r, g, b, a] = colorScale(normalizedValue); // Example: normalizedValue = 0.5 → colorScale(0.5) → [127, 50, 100, 200]
-
Glyph Rendering:
// onDrawCell receives normalized value onDrawCell: (ctx, x, y, normalizedValue, cellInfo) => { // Use normalizedValue for size, opacity, etc. const radius = glyphRadius * normalizedValue; }
-
Projection (geographic → screen):
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} -
Aggregation (assign to cells):
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 -
Normalization (for rendering):
maxValue = Math.max(1500, 2000) = 2000 Cell [8, 6]: normalizedValue = 1500 / 2000 = 0.75 Cell [9, 7]: normalizedValue = 2000 / 2000 = 1.0 -
Rendering:
// Cell [8, 6]: colorScale(0.75) → [191, 25, 50, 200] // Example color // Cell [9, 7]: colorScale(1.0) → [255, 100, 200, 200] // Maximum intensity
0.0= Minimum non-zero value (or empty cell, not rendered)1.0= Maximum value in current grid0.5= Half of maximum value-
Grid Size:
- Larger cells → fewer cells → faster aggregation
- Smaller cells → more cells → slower but more detailed
-
Data Size:
- More points → longer projection/aggregation time
- Consider filtering data based on zoom level
-
Normalization:
- Calculated once per render
- Requires finding max value:
O(n)where n = number of cells
- Quick Reference Guide - Brief API snippets and patterns
- Architecture Guide - Detailed module architecture
- Glyph Drawing Guide - Comprehensive glyph visualization guide
- Usage Guide - Development and troubleshooting
- Spatio-Temporal Guide - Time series visualization patterns
- Geometry Input & Placement Guide - Non-point geometry workflows
- Placement Config Reference - Formal placement configuration schema
- Plugin Glyph Ecosystem - Plugin system documentation
- Data Utilities Guide - Utility functions for data processing
- Cartography & Multivariate Design - Design patterns
Returns: void
Example:
GlyphUtilities.drawScatterGlyph(
ctx, x, y,
cellData, // Array of {data, weight, ...} objects
50, // cellSize
'#e74c3c' // color
);Draw a heatmap-style glyph with color intensity based on normalized value.
Parameters:
Returns: void
Example:
GlyphUtilities.drawHeatmapGlyph(
ctx, x, y,
15, // radius
0.75, // normalizedValue
(v) => `hsl(${v * 240}, 70%, 50%)` // colorScale
);Draw a radial bar glyph (bars radiating from center, like a radar chart).
Parameters:
Returns: void
Example:
GlyphUtilities.drawRadialBarGlyph(
ctx, x, y,
[10, 20, 15, 25], // values
30, // maxValue
20, // maxRadius
'#3498db' // color
);Draw a time series line chart glyph showing temporal trends.
Parameters:
Options 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 configuration from user options merged with defaults.
Parameters:
Returns: Object - Merged configuration object
Example:
const config = ConfigManager.create({
data: myData,
cellSizePixels: 60
});
// config now has all defaults plus user optionsUpdate configuration with partial options.
Parameters:
Returns: Object - Updated configuration object
Example:
const updatedConfig = ConfigManager.update(config, {
cellSizePixels: 80,
enableGlyphs: true
});Validate configuration structure.
Parameters:
Returns: 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 projected points into a grid.
Parameters:
Returns: 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
);Get statistics about a grid aggregation.
Parameters:
Returns: 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}`);Instance method that calls the static method. Same parameters and return value.
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';Project geographic coordinates to screen space.
Parameters:
Returns: 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
);Create a new Projector instance.
Parameters:
Set the map reference.
Parameters:
Project points using stored map reference.
Parameters:
Returns: 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';Get cell information at a specific point.
Parameters:
Returns: Object|null - Cell information object (see ScreenGridLayerGL.getCellAt)
Get all cells with data in a rectangular region.
Parameters:
Returns: Array<Object> - Array of cell information objects
Get all cells with values above a threshold.
Parameters:
Returns: Array<Object> - Array of cell information objects
Create a new CellQueryEngine instance.
Parameters:
Set the aggregation result for queries.
Parameters:
Query cell at point using stored result.
Parameters:
Returns: Object|null - Cell information
Query cells in bounds using stored result.
Parameters:
Returns: Array<Object> - Cells in bounds
Query cells above threshold using stored result.
Parameters:
Returns: 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:
Main Legend class for rendering data-driven legends.
import { Legend } from 'screengrid';new Legend(options)Parameters:
Returns: Legend instance
Example:
const legend = new Legend({
layer: gridLayer,
type: 'auto',
position: 'bottom-right',
title: 'Data Legend'
});Update legend with new data.
Parameters:
Returns: void
Show the legend.
Returns: void
Hide the legend.
Returns: void
Remove the legend from DOM.
Returns: void
Update legend position.
Parameters:
Returns: void
Update legend title.
Parameters:
Returns: void
Manages canvas creation, sizing, and cleanup. Typically used internally by ScreenGridLayerGL.
import { CanvasManager } from 'screengrid';Initialize the canvas overlay.
Parameters:
Throws: Error if canvas cannot be initialized
Returns: void
Get the 2D rendering context.
Returns: CanvasRenderingContext2D
Get the overlay canvas element.
Returns: HTMLCanvasElement
Resize canvas to match map canvas with DPI scaling.
Returns: void
Clear the canvas.
Returns: void
Get canvas dimensions in CSS pixels.
Returns: Object - {width: number, height: number}
Clean up resources.
Returns: void
Canvas drawing logic for grid cells. Typically used internally by ScreenGridLayerGL.
import { Renderer } from 'screengrid';Render grid cells to canvas.
Parameters:
Returns: void
Render with glyph mode enabled.
Parameters:
Returns: void
Render with color mode enabled.
Parameters:
Returns: void
Manages event binding and unbinding. Typically used internally by ScreenGridLayerGL.
import { EventBinder } from 'screengrid';Bind events to the map.
Parameters:
Returns: void
Unbind events from the map.
Returns: void
Bind a specific event.
Parameters:
Returns: void
Unbind a specific event.
Parameters:
Returns: void
Event handler implementations. Typically used internally by ScreenGridLayerGL.
import { EventHandlers } from 'screengrid';Handle hover events.
Parameters:
Returns: void
Handle click events.
Parameters:
Returns: void
Handle zoom events.
Parameters:
Returns: void
Handle move events.
Parameters:
Returns: 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:
Purpose: Assign projected points to grid cells and sum their weights.
Algorithm:
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:
Purpose: Convert raw aggregated cell values to normalized range (0-1) for consistent rendering.
Process:
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:
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:
Cells with no data points have value = 0 and are not rendered.
// Cell contains no points
grid[index] = 0 // Not drawn, skipped in render loopWhen 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 = 30Normalized values are always in range [0, 1]:
Important: 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 pointsFor 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+