Symbology¶
Symbology is how a layer is drawn. Every layer carries a symbology field (Esri layers can omit it). There are three kinds you write inline, plus a ref that points at a reusable named entry in app/symbology.ts.
// inline simple symbology
symbology: { kind: 'simple', color: '#2c8a3e', strokeColor: '#fff', strokeWidth: 1 }
// reference a named entry from app/symbology.ts
symbology: { kind: 'ref', name: 'airports-by-passengers' }
simple¶
One color (plus a few paint knobs). The field meanings depend on the layer's geometry.
| Field | Type | Default | Applies to |
|---|---|---|---|
color |
string |
— (required) | point: dot fill · line: line color · polygon: fill color |
width |
number |
2 |
line width / polygon outline width |
radius |
number |
5 |
point dot radius |
strokeColor |
string |
#ffffff (point), #ffffff (polygon outline) |
point: ring color · polygon: border color |
strokeWidth |
number |
1 (point), 0 (polygon) |
point: ring width · polygon: border width (0 = no border) |
// a point layer
symbology: { kind: 'simple', color: '#0891b2', radius: 6, strokeColor: '#fff', strokeWidth: 3 }
// a polygon layer with a visible outline
symbology: { kind: 'simple', color: '#838291', strokeColor: '#fff', strokeWidth: 1 }
raw¶
A raw MapLibre paint object — full control, including data-driven expressions for categorized and graduated styling. Use this when simple isn't expressive enough.
| Field | Type | Description |
|---|---|---|
paint |
Record<string, unknown> |
A MapLibre paint object (e.g. circle-color, fill-color, line-width) |
layout |
Record<string, unknown> |
Optional extra layout properties |
legend |
LegendOverride |
Optional explicit legend (below) |
description |
string |
A muted one-line note shown under the layer name in the legend (e.g. 'Annual passengers') — friendlier than a raw column name |
Categorized (a match expression)¶
{
kind: 'raw',
description: 'Energy source',
paint: {
'circle-color': [
'match', ['get', 'primsource'],
'solar', '#f59e0b',
'wind', '#22c55e',
'natural gas', '#60a5fa',
'coal', '#78716c',
/* other */ '#94a3b8',
],
'circle-radius': 4,
'circle-stroke-color': '#ffffff',
'circle-stroke-width': 0.5,
},
}
Graduated (an interpolate expression)¶
{
kind: 'raw',
description: 'Annual passengers',
paint: {
'circle-color': [
'interpolate', ['linear'], ['get', 'passengers'],
0, '#bfdbfe', 2000000, '#60a5fa', 8000000, '#2563eb', 20000000, '#1e3a8a',
],
'circle-radius': [
'interpolate', ['linear'], ['get', 'passengers'],
0, 4, 2000000, 7, 8000000, 11, 20000000, 16,
],
},
}
The legend automatically introspects common match and interpolate expressions on color paint props, rendering category swatches or a gradient bar. For anything it can't read, supply an explicit legend (below).
ref¶
Point at a named entry in app/symbology.ts so multiple layers share one definition (and you edit it in one place).
app/symbology.ts exports a symbologies registry — a map of name → a simple or raw symbology:
import type { SymbologyRegistry } from '@/core/types'
export const symbologies: SymbologyRegistry = {
'airports-by-passengers': {
kind: 'raw',
description: 'Annual passengers',
paint: { /* … */ },
},
}
If a layer references a name that doesn't exist, the app throws a clear error at boot listing the available names.
Legend overrides (raw symbology only)¶
When the legend can't auto-introspect your raw paint — or you want to control exactly what's shown — add a legend field. Three shapes:
// discrete swatches
legend: {
kind: 'categories',
entries: [
{ label: 'Solar', color: '#f59e0b' },
{ label: 'Wind', color: '#22c55e' },
],
}
// a continuous gradient bar
legend: {
kind: 'gradient',
stops: [
{ value: 0, label: 'Low', color: '#bfdbfe' },
{ value: 20000000, label: 'High', color: '#1e3a8a' },
],
}
// hide this raw layer from the legend
legend: { kind: 'hidden' }
Hiding any layer from the legend
legend: { kind: 'hidden' } only applies to raw symbology. To hide a layer of any symbology kind, use the top-level hideFromLegend: true on the layer instead.
Defaults¶
The simple paint defaults (width: 2, radius: 5, white point stroke at width 1, no polygon border) can be set app-wide — but currently only per layer. App-wide label defaults exist (see UI & Layout); global symbology paint defaults are a planned addition.