Skip to content

Latest commit

 

History

History
1998 lines (1440 loc) · 47.3 KB

File metadata and controls

1998 lines (1440 loc) · 47.3 KB

API Reference

Complete reference documentation for all public APIs in ScreenGrid Library.

Table of Contents


ScreenGridLayerGL

Main orchestrator class that composes all modules. This is the primary interface for using the library.

Constructor

new ScreenGridLayerGL(options)

Creates a new ScreenGrid layer instance.

Parameters:

Returns: ScreenGridLayerGL instance

Example:

const layer = new ScreenGridLayerGL({
  data: myData,
  getPosition: (d) => d.coordinates,
  getWeight: (d) => d.value,
  cellSizePixels: 50
});
map.addLayer(layer);

Properties

id (getter)

  • Type: string
  • Description: Unique identifier for the layer
  • Default: "screen-grid-layer"

type (getter)

  • Type: string
  • Description: Always returns "custom" (required by MapLibre GL)

renderingMode (getter)

  • Type: string
  • Description: Always returns "2d" (indicates Canvas 2D rendering)

Methods

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 instance
  • gl (WebGLRenderingContext) - WebGL context

Returns: 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 points

Returns: 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}`);
}

Static Methods (Glyph Utilities)

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)

Configuration Options

Options passed to ScreenGridLayerGL constructor or setConfig().

Basic Options

id

  • Type: string
  • Default: "screen-grid-layer"
  • Description: Unique identifier for the layer

data

  • Type: Array
  • Default: []
  • Description: Array of data points to aggregate

getPosition

  • 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

getWeight

  • 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

cellSizePixels

  • Type: number
  • Default: 50
  • Description: Size of each grid cell in pixels

colorScale

  • 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];
}

Glyph Options

enableGlyphs

  • Type: boolean
  • Default: false
  • Description: Enable glyph-based rendering instead of color-based rendering

onDrawCell

  • Type: Function|null
  • Default: null
  • Description: Callback function for custom glyph drawing
  • Parameters: (ctx, x, y, normVal, cellInfo) => void
    • ctx: Canvas 2D rendering context
    • x, y: Center coordinates of the cell
    • normVal: 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();
}

glyphSize

  • Type: number
  • Default: 0.8
  • Description: Size of glyphs relative to cell size (0-1). Multiplied by cell size to get glyph radius.

onAfterAggregate

  • Type: Function|null
  • Default: null
  • Description: Callback for post-aggregation calculations. Executed once per cell with data. Result is passed to onDrawCell as cellInfo.customData.
  • Parameters: (cellData, aggregatedValue, index, grid) => any
    • cellData: Array of points in the cell
    • aggregatedValue: The result of the primary aggregation (e.g., sum)
    • index: Linear index of the cell in the grid
    • grid: 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 
  };
}

Adaptive Sizing Options

adaptiveCellSize

  • Type: boolean
  • Default: false
  • Description: Enable adaptive cell sizing (not yet fully implemented)

minCellSize

  • Type: number
  • Default: 20
  • Description: Minimum cell size in pixels (used with zoomBasedSize)

maxCellSize

  • Type: number
  • Default: 100
  • Description: Maximum cell size in pixels (used with zoomBasedSize)

zoomBasedSize

  • Type: boolean
  • Default: false
  • Description: Adjust cell size based on zoom level. Cells shrink as you zoom in.

Event Callbacks

onAggregate

  • 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)}`);
}

onHover

  • Type: Function|null
  • Default: null
  • Description: Callback when hovering over a grid cell
  • Parameters: ({cell, event}) => void
    • cell: Cell information object (same as getCellAt return 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`);
  }
}

onClick

  • Type: Function|null
  • Default: null
  • Description: Callback when clicking a grid cell
  • Parameters: ({cell, event}) => void (same as onHover)

Example:

onClick: ({ cell, event }) => {
  if (cell) {
    showDetailsModal(cell.cellData);
  }
}

Other Options

enabled

  • Type: boolean
  • Default: true
  • Description: Whether the layer is enabled (rendered)

Geometry Input Options (v2.1.0+)

These options allow you to use non-point geometries (Polygon, LineString, etc.) instead of point data.

source

  • Type: GeoJSON.FeatureCollection | GeoJSON.Feature[] | null
  • Default: null
  • Description: GeoJSON source data with non-point geometries. Mutually exclusive with data option.
  • Supported Geometry Types: Point, MultiPoint, LineString, MultiLineString, Polygon, MultiPolygon

Example:

const layer = new ScreenGridLayerGL({
  source: geojsonData,  // GeoJSON FeatureCollection
  placement: { strategy: 'centroid' },
  renderMode: 'feature-anchors'
});

placement

  • 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
}

renderMode

  • 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

anchorSizePixels

  • Type: number
  • Default: auto (calculated from cellSizePixels * glyphSize * 0.9)
  • Description: Size of glyphs in pixels when using renderMode: 'feature-anchors'.

Example:

anchorSizePixels: 18  // Fixed glyph size in pixels

Geometry Input Options (v2.1.0+)

These options allow you to use non-point geometries (Polygon, LineString, etc.) instead of point data.

source

  • Type: GeoJSON.FeatureCollection | GeoJSON.Feature[] | null
  • Default: null
  • Description: GeoJSON source data with non-point geometries. Mutually exclusive with data option.
  • Supported Geometry Types: Point, MultiPoint, LineString, MultiLineString, Polygon, MultiPolygon

Example:

const layer = new ScreenGridLayerGL({
  source: geojsonData,  // GeoJSON FeatureCollection
  placement: { strategy: 'centroid' },
  renderMode: 'feature-anchors'
});

placement

  • 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
}

renderMode

  • 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

anchorSizePixels

  • Type: number
  • Default: auto (calculated from cellSizePixels * glyphSize * 0.9)
  • Description: Size of glyphs in pixels when using renderMode: 'feature-anchors'.

Example:

anchorSizePixels: 18  // Fixed glyph size in pixels

GlyphUtilities

Static utility class for drawing common glyph types. Can be imported directly or accessed via ScreenGridLayerGL static methods.

Import

import { GlyphUtilities } from 'screengrid';

Methods

drawCircleGlyph(ctx, x, y, radius, color, alpha)

Draw a simple circle glyph.

Parameters:

  • ctx (CanvasRenderingContext2D) - Canvas 2D context
  • x (number) - Center X coordinate
  • y (number) - Center Y coordinate
  • radius (number) - Circle radius in pixels
  • color (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);

drawBarGlyph(ctx, x, y, values, maxValue, cellSize, colors)

Draw a horizontal bar chart glyph showing multiple values.

Parameters:

  • ctx (CanvasRenderingContext2D) - Canvas context
  • x (number) - Center X coordinate
  • y (number) - Center Y coordinate
  • values (Array) - Array of numeric values to display
  • maxValue (number) - Maximum value for scaling
  • cellSize (number) - Cell size in pixels
  • colors (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
);

drawPieGlyph(ctx, x, y, values, radius, colors)

Draw a pie chart glyph showing proportions.

Parameters:

  • ctx (CanvasRenderingContext2D) - Canvas context
  • x (number) - Center X coordinate
  • y (number) - Center Y coordinate
  • values (Array) - Array of numeric values for slices
  • radius (number) - Pie radius in pixels
  • colors (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
);

drawDonutGlyph(ctx, x, y, values, outerRadius, innerRadius, colors)

Draw a donut chart glyph (pie chart with central hole).

Parameters:

  • ctx (CanvasRenderingContext2D) - Canvas context
  • x (number) - Center X coordinate
  • y (number) - Center Y coordinate
  • values (Array) - Array of numeric values
  • outerRadius (number) - Outer radius in pixels
  • innerRadius (number) - Inner radius (hole size) in pixels
  • colors (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']
);

drawScatterGlyph(ctx, x, y, points, cellSize, color)

Draw a scatter plot glyph showing individual data points.

Parameters:

  • ctx (CanvasRenderingContext2D) - Canvas context
  • x (number) - Center X coordinate
  • y (number) - Center Y coordinate
  • points (Array) - Array of point objects with weight property
  • cellSize (number) - Cell size in pixels
  • color (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 context
    • x (number) - Center X coordinate
    • y (number) - Center Y coordinate
    • radius (number) - Circle radius in pixels
    • normalizedValue (number) - Normalized value (0-1)
    • colorScale (Function) - Function that maps value to color: (value: number) => string

    Returns: 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 context
    • x (number) - Center X coordinate
    • y (number) - Center Y coordinate
    • values (Array) - Array of values
    • maxValue (number) - Maximum value for scaling
    • maxRadius (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 context
    • x (number) - Center X coordinate
    • y (number) - Center Y coordinate
    • timeSeriesData (Array) - Array of {year: number, value: number} objects, sorted by year
    • cellSize (number) - Cell size in pixels
    • options (Object, optional) - Configuration options
    • 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
        }
      );

      ConfigManager

      Static utility class for managing configuration with defaults and validation.

      Import

      import { ConfigManager } from 'screengrid';

      Methods

      create(options)

      Create configuration from user options merged with defaults.

      Parameters:

      • options (Object, optional) - User-provided configuration options

      Returns: 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 configuration
      • updates (Object) - Partial configuration updates

      Returns: Object - Updated configuration object

      Example:

      const updatedConfig = ConfigManager.update(config, {
        cellSizePixels: 80,
        enableGlyphs: true
      });

      isValid(config)

      Validate configuration structure.

      Parameters:

      • config (Object) - Configuration to validate

      Returns: boolean - true if valid, false otherwise

      Example:

      if (ConfigManager.isValid(config)) {
        // Configuration is valid
      }

      Aggregator

      Pure business logic class for aggregating points into grid cells.

      Import

      import { Aggregator } from 'screengrid';

      Static Methods

      aggregate(projectedPoints, originalData, width, height, cellSizePixels)

      Aggregate projected points into a grid.

      Parameters:

      • projectedPoints (Array) - Array of projected points: {x: number, y: number, w: number}
      • originalData (Array) - Original data array for reference
      • width (number) - Canvas width in pixels
      • height (number) - Canvas height in pixels
      • cellSizePixels (number) - Size of each grid cell
      • 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
        );

        getStats(aggregationResult)

        Get statistics about a grid aggregation.

        Parameters:

        • aggregationResult (Object) - Result from aggregate() method

        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 Methods

        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.


        Projector

        Pure function class for projecting geographic coordinates to screen space.

        Import

        import { Projector } from 'screengrid';

        Static Methods

        projectPoints(data, getPosition, getWeight, map)

        Project geographic coordinates to screen space.

        Parameters:

        • data (Array) - Array of data points
        • getPosition (Function) - Function to extract [lng, lat] from data point: (d) => [lng, lat]
        • getWeight (Function) - Function to extract weight from data point: (d) => number
        • map (Object) - MapLibre GL map instance

        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
        );

        Instance Methods

        constructor(map)

        Create a new Projector instance.

        Parameters:

        • map (Object, optional) - MapLibre GL map instance

        setMap(map)

        Set the map reference.

        Parameters:

        • map (Object) - MapLibre GL map instance

        project(data, getPosition, getWeight)

        Project points using stored map reference.

        Parameters:

        • data (Array) - Data points to project
        • getPosition (Function) - Position extractor: (d) => [lng, lat]
        • getWeight (Function) - Weight extractor: (d) => number

        Returns: Array<Object> - Projected points

        Example:

        const projector = new Projector(map);
        const projected = projector.project(
          myData,
          (d) => d.coordinates,
          (d) => d.value
        );

        CellQueryEngine

        Query engine for finding and accessing grid cells.

        Import

        import { CellQueryEngine } from 'screengrid';

        Static Methods

        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 result
        • bounds (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 result
        • threshold (number) - Minimum value

        Returns: Array<Object> - Array of cell information objects


        Instance Methods

        constructor(aggregationResult)

        Create a new CellQueryEngine instance.

        Parameters:

        • aggregationResult (Object, optional) - Initial aggregation result

        setAggregationResult(aggregationResult)

        Set the aggregation result for queries.

        Parameters:

        • aggregationResult (Object) - Aggregation result

        getCellAt(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 rectangle

        Returns: Array<Object> - Cells in bounds

        getCellsAboveThreshold(threshold)

        Query cells above threshold using stored result.

        Parameters:

        • threshold (number) - Threshold value

        Returns: Array<Object> - Cells above threshold


        Geometry Placement Modules (v2.1.0+)

        Modules for handling non-point geometries (Polygon, LineString, etc.) and converting them to anchor points.

        PlacementEngine

        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);

        PlacementValidator

        Validates placement configuration objects.

        Import:

        import { PlacementValidator } from 'screengrid';

        Usage:

        const isValid = PlacementValidator.validate(placementConfig);

        PlacementStrategyRegistry

        Registry for placement strategies (centroid, line-sample, grid-geo, etc.).

        Import:

        import { PlacementStrategyRegistry } from 'screengrid';

        Usage:

        const strategy = PlacementStrategyRegistry.get('centroid');

        GeometryUtils

        Utility functions for geometry operations.

        Import:

        import { GeometryUtils } from 'screengrid';

        Methods:

        • getCentroid(geometry) - Get centroid of geometry
        • sampleLine(geometry, spacing) - Sample points along line
        • gridPolygon(geometry, spacing) - Create grid within polygon

        Legend

        Main Legend class for rendering data-driven legends.

        Import

        import { Legend } from 'screengrid';

        Constructor

        new Legend(options)

        Parameters:

        • options (Object) - Configuration options:
          • layer (ScreenGridLayerGL) - ScreenGridLayerGL instance to connect to
          • type (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 element
          • renderOptions (Object, optional) - Options passed to renderers
          • categoryExtractor (Function, optional) - Function to extract category from data (for categorical)
          • valueExtractor (Function, optional) - Function to extract value from data
          • timeExtractor (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'
        });

        Methods

        update(gridData, config)

        Update legend with new data.

        Parameters:

        • gridData (Object) - Aggregation result from ScreenGridLayerGL
        • config (Object) - ScreenGridLayerGL config

        Returns: 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 title

        Returns: void


        CanvasManager

        Manages canvas creation, sizing, and cleanup. Typically used internally by ScreenGridLayerGL.

        Import

        import { CanvasManager } from 'screengrid';

        Methods

        init(map)

        Initialize the canvas overlay.

        Parameters:

        • map (Object) - MapLibre GL map instance

        Throws: 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


        Renderer

        Canvas drawing logic for grid cells. Typically used internally by ScreenGridLayerGL.

        Import

        import { Renderer } from 'screengrid';

        Static Methods

        render(aggregationResult, ctx, config)

        Render grid cells to canvas.

        Parameters:

        • aggregationResult (Object) - Result from Aggregator.aggregate()
        • ctx (CanvasRenderingContext2D) - Canvas 2D context
        • config (Object) - Configuration:
          • colorScale (Function) - Color function: (normalizedValue) => [r, g, b, a]
          • enableGlyphs (boolean) - Enable glyph rendering
          • onDrawCell (Function) - Custom glyph drawing callback
          • glyphSize (number) - Glyph size factor

        Returns: void

        renderGlyphs(aggregationResult, ctx, onDrawCell, glyphSize)

        Render with glyph mode enabled.

        Parameters:

        • aggregationResult (Object) - Aggregation result
        • ctx (CanvasRenderingContext2D) - Canvas context
        • onDrawCell (Function) - Glyph drawing callback
        • glyphSize (number, optional) - Glyph size (0-1). Default: 0.8

        Returns: void

        renderColors(aggregationResult, ctx, colorScale)

        Render with color mode enabled.

        Parameters:

        • aggregationResult (Object) - Aggregation result
        • ctx (CanvasRenderingContext2D) - Canvas context
        • colorScale (Function) - Color scale function

        Returns: void


        EventBinder

        Manages event binding and unbinding. Typically used internally by ScreenGridLayerGL.

        Import

        import { EventBinder } from 'screengrid';

        Methods

        bind(map, eventHandlers)

        Bind events to the map.

        Parameters:

        • map (Object) - MapLibre map instance
        • eventHandlers (Object) - Object with handler methods:
          • handleHover (Function) - Hover handler
          • handleClick (Function) - Click handler
          • handleZoom (Function) - Zoom handler
          • handleMove (Function) - Move handler

        Returns: 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 function

        Returns: void

        unbindEvent(eventName)

        Unbind a specific event.

        Parameters:

        • eventName (string) - Event name

        Returns: void


        EventHandlers

        Event handler implementations. Typically used internally by ScreenGridLayerGL.

        Import

        import { EventHandlers } from 'screengrid';

        Static Methods

        handleHover(event, cellQueryEngine, onHover)

        Handle hover events.

        Parameters:

        • event (Object) - MapLibre mouse event
        • cellQueryEngine (CellQueryEngine) - CellQueryEngine instance
        • onHover (Function) - Hover callback from config

        Returns: void

        handleClick(event, cellQueryEngine, onClick)

        Handle click events.

        Parameters:

        • event (Object) - MapLibre click event
        • cellQueryEngine (CellQueryEngine) - CellQueryEngine instance
        • onClick (Function) - Click callback from config

        Returns: void

        handleZoom(map, config, onZoom)

        Handle zoom events.

        Parameters:

        • map (Object) - MapLibre map instance
        • config (Object) - Layer configuration
        • onZoom (Function) - Callback after zoom handling

        Returns: void

        handleMove(onMove)

        Handle move events.

        Parameters:

        • onMove (Function) - Callback when map moves

        Returns: void


        Data Normalization and Aggregation Procedure

        Understanding how ScreenGrid processes data is crucial for effective visualization. This section explains the complete pipeline from raw data to rendered cells.

        Overview

        The library processes data through three main stages:

        1. Projection: Geographic coordinates → Screen coordinates
        2. Aggregation: Screen points → Grid cells (summing weights)
        3. Normalization: Raw cell values → Normalized values (0-1) for rendering

        Stage 1: Projection

        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:

        • Uses MapLibre's map.project() method
        • Screen coordinates update automatically when map moves/zooms
        • Each point retains its weight value (w)

        Stage 2: Aggregation

        Purpose: Assign projected points to grid cells and sum their weights.

        Algorithm:

        1. Calculate Grid Dimensions:

          const cols = Math.ceil(canvasWidth / cellSizePixels);
          const rows = Math.ceil(canvasHeight / cellSizePixels);
          // Example: 800px width, 50px cells → 16 columns
        2. 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;
        3. 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
          });

        Mathematical Example:

        Given:

        • Canvas: 800×600 pixels
        • Cell size: 50 pixels
        • Grid: 16 columns × 12 rows

        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?

        • Intuitive for counts, populations, totals
        • Preserves magnitude information
        • Works well with weighted data

        Custom Aggregation:

        If you need different aggregation (average, max, etc.), you can:

        1. 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
        2. 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
          }

        Stage 3: Normalization

        Purpose: Convert raw aggregated cell values to normalized range (0-1) for consistent rendering.

        Process:

        1. Find Maximum Value:

          const maxValue = Math.max(...grid);
          // Example: grid = [0, 5, 10, 15, 20, 0, ...]
          // maxValue = 20
        2. 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

        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:

        1. 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]
        2. Glyph Rendering:

          // onDrawCell receives normalized value
          onDrawCell: (ctx, x, y, normalizedValue, cellInfo) => {
            // Use normalizedValue for size, opacity, etc.
            const radius = glyphRadius * normalizedValue;
          }

        Complete Example

        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:

        1. 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}
          
        2. 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
          
        3. 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
          
        4. 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

        Key Behaviors

        Empty Cells

        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

        Multiple Points in Same Cell

        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

        Normalization Range

        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 grid
        • 0.5 = Half of maximum value

        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.

        Weight Function Impact

        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

        Performance Considerations

        1. Grid Size:

          • Larger cells → fewer cells → faster aggregation
          • Smaller cells → more cells → slower but more detailed
        2. Data Size:

          • More points → longer projection/aggregation time
          • Consider filtering data based on zoom level
        3. Normalization:

          • Calculated once per render
          • Requires finding max value: O(n) where n = number of cells

        Advanced: Custom Normalization

        For 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
        }

        Related Documentation


        Version

        This API reference is for ScreenGrid Library v2.2.0+