screengrid

Placement Configuration: Validation Shape and Rules

This document defines the configuration shape for geometry placement (Option B) and the validation rules the layer should enforce.

The goal is to keep defaults sensible, ensure errors are actionable, and make it clear when view-dependent recomputation will occur.


Types

type PlacementStrategy =
  | 'point'          // Pass-through points
  | 'centroid'       // One anchor per feature (polygon/line centroid)
  | 'polylabel'      // Better polygon label placement (optional dependency; falls back to centroid)
  | 'line-sample'    // Sample points along line/multiline
  | 'grid-geo'       // Sample polygon interior at geodesic spacing (meters; respects holes)
  | 'grid-screen';   // Sample polygon interior at screen-grid centers (pixels; view-dependent)

type PlacementPartition = 'union' | 'per-part'; // Multipolygons

type Spacing =
  | { meters: number }
  | { pixels: number };

interface PlacementConfig {
  strategy: PlacementStrategy;
  spacing?: Spacing;
  partition?: PlacementPartition;
  maxPerFeature?: number;
  minArea?: number;        // m²; polygons smaller than this may fallback
  minLength?: number;      // meters; lines shorter than this may fallback
  jitterPixels?: number;
  zoomAdaptive?: boolean;  // Convert pixels<->meters using current zoom/lat
}

type RenderMode = 'screen-grid' | 'feature-anchors';

interface LayerOptionsExtension {
  // Mutually exclusive with existing `data` + `getPosition`
  source?: GeoJSON.FeatureCollection | GeoJSON.Feature[];
  placement?: PlacementConfig;
  renderMode?: RenderMode;         // default: 'screen-grid'
  anchorSizePixels?: number;       // only in 'feature-anchors' mode
}

Validation Rules

1) Mutual exclusivity

2) Required fields for geometry input

3) Strategy-specific requirements

4) Spacing constraints

5) Numeric bounds

6) Partition

7) Double aggregation safeguard

8) View-dependent recomputation

9) Fallbacks

10) Source validation


Error and Warning Messages (Proposed)


Defaulting Strategy


Sample Valid Configs

// 1) Admin boundaries, one glyph per polygon (centroid)
{
  source: adminGeoJSON,
  placement: { strategy: 'centroid', partition: 'union' },
  renderMode: 'feature-anchors',
  anchorSizePixels: 18,
  glyph: 'circle',
  enableGlyphs: true
}

// 2) Roads sampled every 200 meters, still aggregated into screen grid
{
  source: roadsGeoJSON,
  placement: { strategy: 'line-sample', spacing: { meters: 200 }, zoomAdaptive: true },
  renderMode: 'screen-grid',
  cellSizePixels: 60
}

// 3) Admin areas filled with anchors from screen grid centers; drawn per anchor
{
  source: adminGeoJSON,
  placement: { strategy: 'grid-screen', spacing: { pixels: 60 } },
  renderMode: 'feature-anchors',
  anchorSizePixels: 14,
  glyph: 'heatmap',
  enableGlyphs: true
}

Notes for Implementers

See Also