---
name: Geo Map
type: ATM
section: geography
why: An SVG map from first-party vector data - d3-geo projects and clips, every region is a keyboard-reachable path styled by CSS; selection and focus are attributes, so state is markup.
when: Maps of countries, continents and states - picking regions, drilling down (Europe to its countries, Germany to its states), choropleths, labelled callouts, GPS markers, geodesic lines, S2 cells and routes. For charts on a map's numbers use chart; for a schematic, diagram.
where: dist/components/geo.css + dist/components/geo.js (the extra bundle - load it after all.css / all.js; per component: dist/components/geo-map/geo-map.css + geo-map.js; the data in dist/components/geo-map/data/)
supportedStates: default, selected, focused
---

# Pattern: Geo Map

## Native basis

A `<div class="geo-map">` the component fills with one `<svg>`: every region is
a `<path role="button">` with an accessible name and `aria-pressed`, so a click
or Enter picks it and CSS styles it. The map's options, the selection and the
focus are `data-*` attributes on the element - CSS reacts to them, the State
API writes them, an outside script may write them too. Projections, clipping
(viewport, horizon, antimeridian) and the path strings are the official
d3-geo; distances are GeographicLib on WGS84; S2, the Morton index, the routing
and the data decoder are the component's own.

## Native Web APIs

- [`<svg>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg) + [`<path>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path) - one path per region, clipped to the view; only what is in view enters the DOM
- [`aria-pressed`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-pressed) - a picked region; the selection styles from the attribute
- [Pointer Events](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events) + [`setPointerCapture()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/setPointerCapture) - pan, pinch zoom
- [`wheel`](https://developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event) - zoom anchored at the cursor
- [`ResizeObserver`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver) - the map refits its box
- [`MutationObserver`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) - an attribute written from outside (`data-focus`, `data-projection`) applies at once
- [`<datalist>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist) - search suggestions under a bound input
- [`<output>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/output) - bound readouts of the selection, the focus, the zoom
- [`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) + [`DataView`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView) - DGEO chunks, decoded in the browser
- [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) - exact 64-bit S2 cell ids
- [`import()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) - the engines load with the first map
- [`@starting-style`](https://developer.mozilla.org/en-US/docs/Web/CSS/@starting-style) + [`translate`](https://developer.mozilla.org/en-US/docs/Web/CSS/translate) - a hovered region lifts off the map
- [`color-mix()`](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-mix) - palettes, the selection and dark mode from the theme
- [`prefers-reduced-motion`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion) / [`forced-colors`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/forced-colors) / [`prefers-contrast`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-contrast) - no flights or lifts, system colors, stronger borders

---

## Structure

```html
<div class="geo-map" id="atlas" aria-label="Europe" data-focus="continent:Europe" data-highlight="lift"></div>
```

- `data-src` - the data manifest (default: the release's npm package on jsDelivr,
  `cdn.jsdelivr.net/npm/defuss-shadcn@<version>/`, not its GitHub route, which
  refuses some first fetches for a repository this size; per page
  `<meta name="geo-map-data">` or `df$.shadcn.geo.configure({ data })`). A
  GeoJSON `FeatureCollection` URL works too: regions with properties
  `{ id, name, level, parent?, continent? }`, wound either way.
- `data-center="lon,lat"` and `data-zoom` - the first camera (default
  `0,12` and `1`); a `data-focus` without them opens framed on the focus.
- Keys name regions: `continent:Europe`, `country:DEU` (ADM0_A3),
  `state:DEU-1591` (Natural Earth's adm1_code), `s2:47a1` (a cell token).
- `data-selected="country:FRA country:DEU"` - picked regions;
  `data-focus="country:DEU"` - the framed region (its children are shown, the
  rest of the world dimmed and inert). `data-focus="s2:479f"` frames an S2
  cell and draws its four children in place of the layer's cells; the
  regions stay as they are.
- The map's height is `--geo-map-height` (default `28rem`).

### Layers (markers, lines, cells, styles)

```html
<div class="geo-map" id="trip" data-center="11,50" data-zoom="6">
  <script type="application/json" class="geo-map-layers">
    {
      "markers": [{ "id": "muc", "label": "Munich", "position": [11.582, 48.1351], "shape": "pin" }],
      "lines": [{ "id": "muc-ber", "from": [11.582, 48.1351], "to": [13.405, 52.52] }],
      "cells": ["47a1"],
      "styles": { "country:DEU": { "fill": "var(--chart-2)" } }
    }
  </script>
</div>
```

- A line is `coordinates`, or `from` + `to` (the WGS84 geodesic between them).
- A marker's `position` is `[lon, lat]` or `{ "s2": "<token>" }` (the cell's center).
- `styles` paint single regions (a choropleth): `fill`, `stroke`,
  `strokeWidth`, `dash`, `opacity`. `df$.shadcn.geoMap.hatch(el)` is a hatch fill.

### Outside controls

```html
<input class="input" type="search" data-geo-for="atlas" data-geo-action="search" placeholder="Search a region" aria-label="Search a region">
<button class="btn" data-variant="outline" data-geo-for="atlas" data-geo-action="focus" data-value="continent:Europe">Europe</button>
<button class="btn" data-variant="outline" data-geo-for="atlas" data-geo-action="up">Up</button>
<select class="select" data-geo-for="atlas" data-geo-param="projection" aria-label="Projection">
  <option value="equalEarth">Equal Earth</option><option value="orthographic">Globe</option>
</select>
<output data-geo-for="atlas" data-geo-output="selection"></output>
```

- `data-geo-action`: `search` (an input - suggestions in a `<datalist>`,
  Enter or a picked suggestion frames the region), `focus` (`data-value` = a
  key or a name; without one, the first selected region), `up`, `reset`,
  `zoom-in`, `zoom-out`, `select` (`data-value` = keys), `clear`.
- `data-geo-param` on a `<select>` or checkbox: `projection`, `level`,
  `palette`, `border`, `graticule`, `callouts`.
- `<output data-geo-output>`: `selection` (default), `focus`, `hover`,
  `zoom`, `level`, `center`, `regions`.

## Variants

| Attribute | Values | Behavior |
| --- | --- | --- |
| `data-projection` | `equalEarth` (default), `equalArea`, `mercator`, `equirectangular`, `orthographic` | the projection; Equal Earth and `equalArea` (Lambert azimuthal equal-area, turned to the camera) draw every region at its real size; `equalArea` and the orthographic globe rotate when panned |
| `data-level` | `country` (default), `continent`, `state`, `auto` | the boundaries; `auto` by zoom (continents below 2x, countries below 8x, states above) |
| `data-palette` | `atlas` (default), `ocean`, `forest`, `sunset`, `heat`, `mono`, `chart` | the region fills; `mono` from the theme's neutral tokens, `chart` from `--chart-1..5` |
| `data-border` | `natural` (default), `cased`, `dashed`, `none` | the border lines |
| `data-highlight` | `fill` (default), `outline`, `pulse`, `lift` | how picked regions show: filled, a marching outline, a pulse, raised with a shadow |
| `data-select` | `single` (default), `multiple`, `none` | a click picks one region (Shift / Cmd / Ctrl adds), toggles several, or nothing |
| `data-drill` | *(on)*, `none` | a double click on a region or an S2 cell focuses it |
| `data-graticule` | *(on)*, `false` | the latitude / longitude grid |
| `data-callouts` | `true` | leader lines from the regions in view to their names in gutters left and right (`--geo-map-callout-width`, default `10rem`; the names in `--geo-map-callout-size`, default `0.875rem`) |
| `data-variant` | `plain` | no border, radius or surface |

## Loading

The component ships **no engine code**. The first map (or
`df$.shadcn.geo.load()`) imports the pinned official builds once:

- `https://cdn.jsdelivr.net/npm/d3-array@3.2.4/dist/d3-array.min.js`
- `https://cdn.jsdelivr.net/npm/d3-geo@3.1.1/dist/d3-geo.min.js`
- `https://cdn.jsdelivr.net/npm/geographiclib-geodesic@2.2.0/geographiclib-geodesic.min.js`
- `https://cdn.jsdelivr.net/npm/defuss-dson@1.1.2/dist/index.mjs`

(pinned - never `@latest`; the UMD builds install `globalThis.d3` and
`globalThis.geodesic`, a page that already has d3 v7 keeps its own). Self-host
them with `df$.shadcn.geo.configure({ urls: { d3Array, d3Geo, geodesic, dson } })`
before the first map. The data is first-party: `world.dgeo` (the overview,
always resident), `country-<id>.dgeo` (50m detail from 3x),
`states-<id>.dgeo` (10m states, simplified) and `states-hi-<id>.dgeo` (as
published, from 24x), loaded when they come into view (four at a time, a
24 MB cache) - Natural Earth v5.1.2, public domain.

## ARIA

| Attribute | Where | Why |
| --- | --- | --- |
| `aria-label` | the `.geo-map` | names the map (the SVG takes it over) |
| `role="group"` + `aria-roledescription="map"` | the SVG (generated) | one tab stop; arrows pan, + / - zoom, Home resets, Escape clears the selection, then steps out of the focus |
| `role="button"` + `aria-pressed` | each region (generated) | a roving tab stop: arrows move to the nearest region in that direction, Enter / Space picks |
| `aria-busy="true"` | the `.geo-map`, while data loads | the map is not final yet |
| `role="alert"` | `.geo-map-error` (generated) | the data or the engines could not be loaded |

## Notes

- Selection and focus are attributes, so they survive a re-render and a
  write from outside: `el.dataset.focus = 'country:DEU'` frames Germany.
- A focus frames the region's main body: France without French Guiana, the
  contiguous body of an archipelago; Europe, North America and Oceania have
  built-in frames (`configure({ views })` adds or replaces them).
- Context regions around a focus are inert (`pointer-events: none`) and
  hidden from assistive technology.
- "State" is Natural Earth's first administrative level (departments,
  municipalities in some countries); the boundaries are generalized - not
  cadastral or street boundaries.
- The SVG, the tooltip and the camera are runtime-owned: render() and the
  HTML Preview Editor see only the element's attributes.

## States

| State | Meaning |
| --- | --- |
| `default` | Nothing picked, nothing framed |
| `selected` | `config.selected` regions picked, highlighted the way `data-highlight` says; entered without a selection (or an empty one), the one the markup declared |
| `focused` | `config.focus` framed with its children shown (a continent's countries, a country's states), everything else dimmed; entered without a focus (or an empty one), the one the markup declared |

```js
const map = document.querySelector('#atlas');
await map.api.settled();                                        // engines + data loaded
await map.api.setState('focused', { focus: 'continent:Europe' }); // fly to Europe, show its countries
map.api.setState('focused', { selected: ['country:FRA', 'country:DEU'] }); // pick two inside the focus
map.api.setState('default', { center: [0, 12], zoom: 1 });       // back to the world
map.api.getState(); // { name: 'default', config: { projection, level, ..., selected: [], focus: null, center, zoom } }
```

The registry global is `df$.shadcn.geoMapApi` / `df$.shadcn.geoMapStates`; the
map API is `df$.shadcn.geoMap`, the geography library `df$.shadcn.geo`.

## API

<!-- generated from the source by `bun run api-docs` - edit the JSDoc and the types in the .ts, not this section -->

### States

<code>type GeoMapState = 'default' | 'selected' | 'focused'</code> - `setState(name, config)` takes the config of the state it names (`GeoMapStateConfigs[name]`).

| State | Description |
|---|---|
| `default` | Nothing picked, nothing framed - the selection and the focus are cleared. <b>config</b> <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>projection?</code></td><td><code>GeoProjectionName</code></td><td>the projection (default equalEarth)</td></tr><tr><td><code>level?</code></td><td><code>GeoLevel \| 'auto'</code></td><td>the boundary level, or 'auto' by zoom: continents below 2x, countries below 8x, states above (default country)</td></tr><tr><td><code>palette?</code></td><td><code>GeoPalette</code></td><td>the fill palette (default atlas)</td></tr><tr><td><code>border?</code></td><td><code>GeoBorder</code></td><td>the border style (default natural)</td></tr><tr><td><code>graticule?</code></td><td><code>boolean</code></td><td>the latitude / longitude grid (default true)</td></tr><tr><td><code>callouts?</code></td><td><code>boolean</code></td><td>leader lines from the regions in view to their names outside the map (default false)</td></tr><tr><td><code>selected?</code></td><td><code>string[] \| string</code></td><td>the picked regions' keys (level:id - country:FRA); a string may list them separated by spaces or commas</td></tr><tr><td><code>focus?</code></td><td><code>string \| null</code></td><td>the framed key (a region, or an S2 cell as s2:&lt;token&gt;), or null; its children are shown, the rest dimmed</td></tr><tr><td><code>center?</code></td><td><code>LonLat</code></td><td>the view's center</td></tr><tr><td><code>zoom?</code></td><td><code>number</code></td><td>the zoom factor, 1 to 1024</td></tr></table> |
| `selected` | One or more regions picked (`config.selected`): highlighted the way data-highlight says. <b>config</b> <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>projection?</code></td><td><code>GeoProjectionName</code></td><td>the projection (default equalEarth)</td></tr><tr><td><code>level?</code></td><td><code>GeoLevel \| 'auto'</code></td><td>the boundary level, or 'auto' by zoom: continents below 2x, countries below 8x, states above (default country)</td></tr><tr><td><code>palette?</code></td><td><code>GeoPalette</code></td><td>the fill palette (default atlas)</td></tr><tr><td><code>border?</code></td><td><code>GeoBorder</code></td><td>the border style (default natural)</td></tr><tr><td><code>graticule?</code></td><td><code>boolean</code></td><td>the latitude / longitude grid (default true)</td></tr><tr><td><code>callouts?</code></td><td><code>boolean</code></td><td>leader lines from the regions in view to their names outside the map (default false)</td></tr><tr><td><code>selected?</code></td><td><code>string[] \| string</code></td><td>the picked regions' keys (level:id - country:FRA); a string may list them separated by spaces or commas</td></tr><tr><td><code>focus?</code></td><td><code>string \| null</code></td><td>the framed key (a region, or an S2 cell as s2:&lt;token&gt;), or null; its children are shown, the rest dimmed</td></tr><tr><td><code>center?</code></td><td><code>LonLat</code></td><td>the view's center</td></tr><tr><td><code>zoom?</code></td><td><code>number</code></td><td>the zoom factor, 1 to 1024</td></tr></table> |
| `focused` | A region framed in view (`config.focus`) with its children shown - a continent's countries, a country's states. <b>config</b> <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>projection?</code></td><td><code>GeoProjectionName</code></td><td>the projection (default equalEarth)</td></tr><tr><td><code>level?</code></td><td><code>GeoLevel \| 'auto'</code></td><td>the boundary level, or 'auto' by zoom: continents below 2x, countries below 8x, states above (default country)</td></tr><tr><td><code>palette?</code></td><td><code>GeoPalette</code></td><td>the fill palette (default atlas)</td></tr><tr><td><code>border?</code></td><td><code>GeoBorder</code></td><td>the border style (default natural)</td></tr><tr><td><code>graticule?</code></td><td><code>boolean</code></td><td>the latitude / longitude grid (default true)</td></tr><tr><td><code>callouts?</code></td><td><code>boolean</code></td><td>leader lines from the regions in view to their names outside the map (default false)</td></tr><tr><td><code>selected?</code></td><td><code>string[] \| string</code></td><td>the picked regions' keys (level:id - country:FRA); a string may list them separated by spaces or commas</td></tr><tr><td><code>focus?</code></td><td><code>string \| null</code></td><td>the framed key (a region, or an S2 cell as s2:&lt;token&gt;), or null; its children are shown, the rest dimmed</td></tr><tr><td><code>center?</code></td><td><code>LonLat</code></td><td>the view's center</td></tr><tr><td><code>zoom?</code></td><td><code>number</code></td><td>the zoom factor, 1 to 1024</td></tr></table> |

### Every element

| Member | Description |
|---|---|
| <code>el.api.setState&lt;S extends GeoMapState&gt;(name: S, config?: GeoMapStateConfigs[S]): unknown</code> | Enter a state: the DOM work runs (also when it is the current state), the store records it. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>name</code></td><td><code>S</code></td><td>a declared state (an unknown name throws)</td></tr><tr><td><code>config?</code></td><td><code>GeoMapStateConfigs[S]</code></td><td>that state's config (merged into the stored one when the component merges)</td></tr></table> <b>Returns</b> <code>unknown</code> - what the state's DOM work returned - a Promise for an async state (or await settled()) |
| <code>el.api.getState(): { name: GeoMapState; config: GeoMapStateConfigs[GeoMapState]; model?: ElementModel }</code> | The state the element shows now - read back from the DOM, so it includes what the user changed. <b>Returns</b> <code>{ name: GeoMapState; config: GeoMapStateConfigs[GeoMapState]; model?: ElementModel }</code> - the state's name, its config and the authored markup model render() starts from |
| <code>el.api.render(state?: { name: GeoMapState; config: GeoMapStateConfigs[GeoMapState]; model?: ElementModel }): string</code> | The element's markup in a state - the authored markup with that state applied; a pure function of the state. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>state?</code></td><td><code>{ name: GeoMapState; config: GeoMapStateConfigs[GeoMapState]; model?: ElementModel }</code></td><td>a state as getState() returns it (default: the current one)</td></tr></table> <b>Returns</b> <code>string</code> - the element's outer HTML in that state |
| <code>el.api.settled(): Promise&lt;void&gt;</code> | Wait for the last state's DOM work (async states: a diagram rendering, a chart mounting). <b>Returns</b> <code>Promise&lt;void&gt;</code> - resolves when nothing is pending |
| <code>el.store: Store&lt;{ name: GeoMapState; config: GeoMapStateConfigs[GeoMapState] }&gt;</code> | A defuss-store store of the element's state - subscribe to follow every change (also the user's), set it to drive the component. |

### Registry

| Member | Description |
|---|---|
| <code>df$.shadcn.geoMapApi.setState&lt;S extends GeoMapState&gt;(el: HTMLElement, name: S, config?: GeoMapStateConfigs[S]): unknown</code> | Enter a state: the DOM work runs (also when it is the current state), the store records it. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>el</code></td><td><code>HTMLElement</code></td><td>the component's element</td></tr><tr><td><code>name</code></td><td><code>S</code></td><td>a declared state (an unknown name throws)</td></tr><tr><td><code>config?</code></td><td><code>GeoMapStateConfigs[S]</code></td><td>that state's config (merged into the stored one when the component merges)</td></tr></table> <b>Returns</b> <code>unknown</code> - what the state's DOM work returned - a Promise for an async state (await it, or el.api.settled()) |
| <code>df$.shadcn.geoMapApi.getState(el: HTMLElement): { name: GeoMapState; config: GeoMapStateConfigs[GeoMapState]; model?: ElementModel }</code> | The state the element shows now - read back from the DOM, so it includes what the user changed. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>el</code></td><td><code>HTMLElement</code></td><td>the component's element</td></tr></table> <b>Returns</b> <code>{ name: GeoMapState; config: GeoMapStateConfigs[GeoMapState]; model?: ElementModel }</code> - the state's name, its config and the authored markup model render() starts from |
| <code>df$.shadcn.geoMapApi.render(state: { name: GeoMapState; config: GeoMapStateConfigs[GeoMapState]; model?: ElementModel }): string</code> | The element's markup in a state - the authored markup with that state applied; a pure function of the state. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>state</code></td><td><code>{ name: GeoMapState; config: GeoMapStateConfigs[GeoMapState]; model?: ElementModel }</code></td><td>a state as getState() returns it (with its model)</td></tr></table> <b>Returns</b> <code>string</code> - the element's outer HTML in that state |
| <code>df$.shadcn.geoMapApi.store(el: HTMLElement): Store&lt;{ name: GeoMapState; config: GeoMapStateConfigs[GeoMapState] }&gt;</code> | The element's store (bindComponent made it). <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>el</code></td><td><code>HTMLElement</code></td><td>the component's element</td></tr></table> <b>Returns</b> <code>Store&lt;{ name: GeoMapState; config: GeoMapStateConfigs[GeoMapState] }&gt;</code> - a defuss-store store of { name, config } - subscribe to follow every change, set it to drive the component |
| <code>df$.shadcn.geoMapApi.commit&lt;S extends GeoMapState&gt;(el: HTMLElement, name: S, config?: GeoMapStateConfigs[S]): void</code> | Record a state the element reached on its own (no DOM work) - for a component's own handlers. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>el</code></td><td><code>HTMLElement</code></td><td>the component's element</td></tr><tr><td><code>name</code></td><td><code>S</code></td><td>the state it is in</td></tr><tr><td><code>config?</code></td><td><code>GeoMapStateConfigs[S]</code></td><td>its config</td></tr></table> |
| <code>df$.shadcn.geoMapStates: GeoMapState[]</code> | The declared states, 'default' first: <code>default</code>, <code>selected</code>, <code>focused</code>. |

### `df$.shadcn.geoMap`

| Member | Description |
|---|---|
| <code>select(el: HTMLElement \| string, keys: string[]): Promise&lt;void&gt;</code> | Pick regions (an empty list clears the selection); they are highlighted the way data-highlight says. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>el</code></td><td><code>HTMLElement \| string</code></td><td>the .geo-map element, or a selector for it</td></tr><tr><td><code>keys</code></td><td><code>string[]</code></td><td>region keys: country:FRA, state:DEU-1591, continent:Europe, s2:47a1</td></tr></table> <b>Returns</b> <code>Promise&lt;void&gt;</code> - resolves when the map shows them |
| <code>focus(el: HTMLElement \| string, region: string \| null): Promise&lt;void&gt;</code> | Frame a region and show its children - a continent's countries, a country's states; everything else is dimmed. An S2 cell (s2:&lt;token&gt;) frames the cell and shows its four children. A name works too (the best search hit). null clears the focus. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>el</code></td><td><code>HTMLElement \| string</code></td><td>the .geo-map element, or a selector for it</td></tr><tr><td><code>region</code></td><td><code>string \| null</code></td><td>a key (continent:Europe, country:DEU, s2:479f), a name ('Germany'), or null</td></tr></table> <b>Returns</b> <code>Promise&lt;void&gt;</code> - resolves when the camera has arrived |
| <code>up(el: HTMLElement \| string): Promise&lt;void&gt;</code> | Step out of the focus: a state to its country, a country to its continent, a continent to the world; an S2 cell to its parent, a cube face to the world. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>el</code></td><td><code>HTMLElement \| string</code></td><td>the .geo-map element, or a selector for it</td></tr></table> <b>Returns</b> <code>Promise&lt;void&gt;</code> - resolves when the camera has arrived |
| <code>reset(el: HTMLElement \| string): Promise&lt;void&gt;</code> | Back to the whole world: no focus, no selection, the authored camera. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>el</code></td><td><code>HTMLElement \| string</code></td><td>the .geo-map element, or a selector for it</td></tr></table> <b>Returns</b> <code>Promise&lt;void&gt;</code> - resolves when the camera has arrived |
| <code>search(el: HTMLElement \| string, query: string, limit: number = 10): Promise&lt;GeoSearchHit[]&gt;</code> | Find regions by name: continents and countries at once, every state once the names index has loaded. Accents and case are ignored; whole names rank before prefixes, prefixes before parts. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>el</code></td><td><code>HTMLElement \| string</code></td><td>the .geo-map element, or a selector for it</td></tr><tr><td><code>query</code></td><td><code>string</code></td><td>what was typed</td></tr><tr><td><code>limit</code></td><td><code>number</code> = <code>10</code></td><td>the most hits (default 10)</td></tr></table> <b>Returns</b> <code>Promise&lt;GeoSearchHit[]&gt;</code> - the hits, best first |
| <code>zoomBy(el: HTMLElement \| string, factor: number): void</code> | Zoom by a factor around the center (2 = twice as close). <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>el</code></td><td><code>HTMLElement \| string</code></td><td>the .geo-map element, or a selector for it</td></tr><tr><td><code>factor</code></td><td><code>number</code></td><td>greater than 0</td></tr></table> |
| <code>setView(el: HTMLElement \| string, center: LonLat, zoom?: number, animate: boolean = true): Promise&lt;void&gt;</code> | Move the camera - flying there unless `animate` is false or motion is reduced. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>el</code></td><td><code>HTMLElement \| string</code></td><td>the .geo-map element, or a selector for it</td></tr><tr><td><code>center</code></td><td><code>LonLat</code></td><td>[longitude, latitude]</td></tr><tr><td><code>zoom?</code></td><td><code>number</code></td><td>1 to 1024 (default: the current zoom)</td></tr><tr><td><code>animate</code></td><td><code>boolean</code> = <code>true</code></td><td>fly (default true)</td></tr></table> <b>Returns</b> <code>Promise&lt;void&gt;</code> - resolves when the camera has arrived |
| <code>setLayers(el: HTMLElement \| string, layers: GeoLayers): void</code> | Replace what the map draws over its boundaries - markers, lines, S2 cells, per-region looks (each one given replaces that layer; leave one out to keep it). <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>el</code></td><td><code>HTMLElement \| string</code></td><td>the .geo-map element, or a selector for it</td></tr><tr><td><code>layers</code></td><td><code>GeoLayers</code></td><td>`{ markers, lines, cells, styles }`</td></tr></table> |
| <code>visible(el: HTMLElement \| string): GeoVisibleRegion[]</code> | The regions drawn now, with their label points. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>el</code></td><td><code>HTMLElement \| string</code></td><td>the .geo-map element, or a selector for it</td></tr></table> <b>Returns</b> <code>GeoVisibleRegion[]</code> - one entry per region in view |
| <code>region(el: HTMLElement \| string, key: string): GeoRegion \| null</code> | A region by key, when the map has it (resident, or its chunk loaded). <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>el</code></td><td><code>HTMLElement \| string</code></td><td>the .geo-map element, or a selector for it</td></tr><tr><td><code>key</code></td><td><code>string</code></td><td>country:DEU, state:DEU-1591, continent:Europe</td></tr></table> <b>Returns</b> <code>GeoRegion \| null</code> - the region, or null |
| <code>project(el: HTMLElement \| string, point: LonLat): [number, number] \| null</code> | Where a position is drawn in the last rendered view (SVG pixels), or null when it is out of view or behind the globe. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>el</code></td><td><code>HTMLElement \| string</code></td><td>the .geo-map element, or a selector for it</td></tr><tr><td><code>point</code></td><td><code>LonLat</code></td><td>[longitude, latitude]</td></tr></table> <b>Returns</b> <code>[number, number] \| null</code> - [x, y] or null |
| <code>unproject(el: HTMLElement \| string, pixel: [number, number]): LonLat \| null</code> | The position drawn at an SVG pixel of the last rendered view, or null off the globe. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>el</code></td><td><code>HTMLElement \| string</code></td><td>the .geo-map element, or a selector for it</td></tr><tr><td><code>pixel</code></td><td><code>[number, number]</code></td><td>[x, y]</td></tr></table> <b>Returns</b> <code>LonLat \| null</code> - [longitude, latitude] or null |
| <code>stats(el: HTMLElement \| string): GeoRenderStats</code> | What the last render drew and loaded. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>el</code></td><td><code>HTMLElement \| string</code></td><td>the .geo-map element, or a selector for it</td></tr></table> <b>Returns</b> <code>GeoRenderStats</code> - the counts and timings |
| <code>hatch(el: HTMLElement \| string): string</code> | The fill that hatches a region (an SVG pattern of the map) - for `styles: { 'country:DEU': { fill } }`. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>el</code></td><td><code>HTMLElement \| string</code></td><td>the .geo-map element, or a selector for it</td></tr></table> <b>Returns</b> <code>string</code> - a CSS url() fill |

### `df$.shadcn.geo`

| Member | Description |
|---|---|
| <code>load(): Promise&lt;void&gt;</code> | Load the engines once: d3-geo with d3-array, GeographicLib and defuss-dson (the pinned builds, or the configured URLs). Every map calls it; call it yourself before using the geodesic functions. A failed load can be retried. <b>Returns</b> <code>Promise&lt;void&gt;</code> - resolves when every engine is ready |
| <code>configure(options: GeoConfigureOptions): void</code> | Set the data URL, the engine URLs or the focus views for every map on the page (maps already showing keep their data). Engine URLs only take effect before the engines first load. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>options</code></td><td><code>GeoConfigureOptions</code></td><td>`{ data, urls, views }`</td></tr></table> |
| <code>urls: GeoVendorUrls</code> | The pinned official builds the component loads (never @latest). |
| <code>WGS84: GeoEllipsoid</code> | WGS84: the GPS reference ellipsoid. |
| <code>inverse(a: LonLat, b: LonLat, ellipsoid?: GeoEllipsoid): GeoInverse</code> | The distance and bearings between two positions along the ellipsoid's surface (Karney's algorithm - nearly antipodal points included). Excludes altitude, terrain and road detours. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>a</code></td><td><code>LonLat</code></td><td>[longitude, latitude] of the start</td></tr><tr><td><code>b</code></td><td><code>LonLat</code></td><td>[longitude, latitude] of the end</td></tr><tr><td><code>ellipsoid?</code></td><td><code>GeoEllipsoid</code></td><td>the reference ellipsoid (default WGS84)</td></tr></table> <b>Returns</b> <code>GeoInverse</code> - metres and the bearings at both ends |
| <code>direct(origin: LonLat, bearing: number, meters: number, ellipsoid?: GeoEllipsoid): LonLat</code> | Where a geodesic leads: the position a given distance away from a start in a given bearing. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>origin</code></td><td><code>LonLat</code></td><td>[longitude, latitude] of the start</td></tr><tr><td><code>bearing</code></td><td><code>number</code></td><td>degrees clockwise from north</td></tr><tr><td><code>meters</code></td><td><code>number</code></td><td>the distance along the surface</td></tr><tr><td><code>ellipsoid?</code></td><td><code>GeoEllipsoid</code></td><td>the reference ellipsoid (default WGS84)</td></tr></table> <b>Returns</b> <code>LonLat</code> - the end position |
| <code>path(a: LonLat, b: LonLat, maxStepMeters: number = 20_000, ellipsoid?: GeoEllipsoid): LonLat[]</code> | The geodesic between two positions as positions at most `maxStepMeters` apart - a line the map draws as the shortest surface path. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>a</code></td><td><code>LonLat</code></td><td>the start</td></tr><tr><td><code>b</code></td><td><code>LonLat</code></td><td>the end</td></tr><tr><td><code>maxStepMeters</code></td><td><code>number</code> = <code>20_000</code></td><td>the largest spacing between samples (default 20000)</td></tr><tr><td><code>ellipsoid?</code></td><td><code>GeoEllipsoid</code></td><td>the reference ellipsoid (default WGS84)</td></tr></table> <b>Returns</b> <code>LonLat[]</code> - the positions, a first and b last |
| <code>length(points: LonLat[], ellipsoid?: GeoEllipsoid): number</code> | The length of a polyline along the ellipsoid: the sum of its segments' geodesic distances. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>points</code></td><td><code>LonLat[]</code></td><td>two or more positions</td></tr><tr><td><code>ellipsoid?</code></td><td><code>GeoEllipsoid</code></td><td>the reference ellipsoid (default WGS84)</td></tr></table> <b>Returns</b> <code>number</code> - metres |
| <code>s2Cell(point: LonLat, level: number = 12): S2Cell</code> | The S2 cell holding a position at a level. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>point</code></td><td><code>LonLat</code></td><td>[longitude, latitude]</td></tr><tr><td><code>level</code></td><td><code>number</code> = <code>12</code></td><td>0 to 30 (default 12, about 2 km across)</td></tr></table> <b>Returns</b> <code>S2Cell</code> - its id, token and level |
| <code>s2Id(cell: string \| bigint): bigint</code> | An S2 cell id from a hexadecimal token or a bigint, validated. A string is ALWAYS a hex token - pass a decimal id as BigInt(decimalString). <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>cell</code></td><td><code>string \| bigint</code></td><td>a token ('47a1') or an id</td></tr></table> <b>Returns</b> <code>bigint</code> - the 64-bit id |
| <code>s2Token(cell: string \| bigint): string</code> | A cell's canonical token. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>cell</code></td><td><code>string \| bigint</code></td><td>a token or an id</td></tr></table> <b>Returns</b> <code>string</code> - the lowercase hex token |
| <code>s2Level(cell: string \| bigint): number</code> | A cell's level. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>cell</code></td><td><code>string \| bigint</code></td><td>a token or an id</td></tr></table> <b>Returns</b> <code>number</code> - 0 to 30 |
| <code>s2Center(cell: string \| bigint): LonLat</code> | The center of a cell (in its face's (s, t) square - not the original GPS fix a cell was made from). <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>cell</code></td><td><code>string \| bigint</code></td><td>a token or an id</td></tr></table> <b>Returns</b> <code>LonLat</code> - [longitude, latitude] |
| <code>s2Vertices(cell: string \| bigint): LonLat[]</code> | A cell's four corners (counterclockwise, as S2 orders them). <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>cell</code></td><td><code>string \| bigint</code></td><td>a token or an id</td></tr></table> <b>Returns</b> <code>LonLat[]</code> - four [longitude, latitude] positions |
| <code>s2Polygon(cell: string \| bigint): GeoRegion</code> | A cell as a region the map can draw (great-circle edges; its ring wound for D3). <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>cell</code></td><td><code>string \| bigint</code></td><td>a token or an id</td></tr></table> <b>Returns</b> <code>GeoRegion</code> - a GeoJSON polygon feature (properties.id = the token) |
| <code>s2Neighbors(cell: string \| bigint): string[]</code> | The four cells sharing an edge with a cell, at its level (below, right, above, left in its face's frame). <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>cell</code></td><td><code>string \| bigint</code></td><td>a token or an id</td></tr></table> <b>Returns</b> <code>string[]</code> - four tokens |
| <code>s2Children(cell: string \| bigint): string[]</code> | A cell's four children, one level finer (none at level 30). <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>cell</code></td><td><code>string \| bigint</code></td><td>a token or an id</td></tr></table> <b>Returns</b> <code>string[]</code> - their tokens in Hilbert order |
| <code>s2Parent(cell: string \| bigint, level?: number): string</code> | The cell containing a cell at a coarser level. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>cell</code></td><td><code>string \| bigint</code></td><td>a token or an id</td></tr><tr><td><code>level?</code></td><td><code>number</code></td><td>0 to the cell's own level (default one coarser)</td></tr></table> <b>Returns</b> <code>string</code> - the parent's token |
| <code>resolvePosition(value: LonLat \| { s2: string \| bigint }): LonLat</code> | A position from either form a marker takes: [longitude, latitude] as given, or an S2 cell's center. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>value</code></td><td><code>LonLat \| { s2: string \| bigint }</code></td><td>a position or `{ s2: token }`</td></tr></table> <b>Returns</b> <code>LonLat</code> - [longitude, latitude] |
| <code>inBounds(point: LonLat, bounds: GeoBounds): boolean</code> | Whether a position lies inside a rectangle (one whose west exceeds its east crosses the antimeridian). <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>point</code></td><td><code>LonLat</code></td><td>[longitude, latitude]</td></tr><tr><td><code>bounds</code></td><td><code>GeoBounds</code></td><td>[west, south, east, north]</td></tr></table> <b>Returns</b> <code>boolean</code> - true inside or on the edge |
| <code>mortonEncode(x: number, y: number, bits: number = 16): bigint</code> | Interleave two grid coordinates into a Morton key (x on the even bits, y on the odd). <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>x</code></td><td><code>number</code></td><td>0 to 2^bits - 1</td></tr><tr><td><code>y</code></td><td><code>number</code></td><td>0 to 2^bits - 1</td></tr><tr><td><code>bits</code></td><td><code>number</code> = <code>16</code></td><td>bits per coordinate, 1 to 26 (default 16)</td></tr></table> <b>Returns</b> <code>bigint</code> - the key |
| <code>mortonDecode(key: bigint, bits: number = 16): [number, number]</code> | Split a Morton key back into its grid coordinates. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>key</code></td><td><code>bigint</code></td><td>the key</td></tr><tr><td><code>bits</code></td><td><code>number</code> = <code>16</code></td><td>bits per coordinate (default 16)</td></tr></table> <b>Returns</b> <code>[number, number]</code> - [x, y] |
| <code>mortonKey(point: LonLat, bits: number = 16): bigint</code> | A position's Morton key on a 2^bits x 2^bits longitude / latitude grid. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>point</code></td><td><code>LonLat</code></td><td>[longitude, latitude]</td></tr><tr><td><code>bits</code></td><td><code>number</code> = <code>16</code></td><td>bits per coordinate (default 16)</td></tr></table> <b>Returns</b> <code>bigint</code> - the key |
| <code>mortonIndex(items: readonly T[], position: (item: T) =&gt; LonLat, bits: number = 16): GeoMortonIndex</code> | A Morton index over items with positions: sorted keys, rectangle queries by recursive prefix ranges, then the exact position test (no grid false positives). <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>items</code></td><td><code>readonly T[]</code></td><td>the items</td></tr><tr><td><code>position</code></td><td><code>(item: T) =&gt; LonLat</code></td><td>an item's [longitude, latitude]</td></tr><tr><td><code>bits</code></td><td><code>number</code> = <code>16</code></td><td>bits per coordinate (default 16)</td></tr></table> <b>Returns</b> <code>GeoMortonIndex</code> - the index |
| <code>routeGraph(nodes: GeoRouteNode[], segments: GeoRouteSegment[]): GeoRouteGraph</code> | A route graph over nodes and the segments between them. Dijkstra minimizes the SUPPLIED lengths (no A*: an application's lengths may undercut the surface distance, so a geodesic heuristic would not be admissible); a Morton index finds nodes by position. Needs the engines (df$.shadcn.geo.load()) for nearestNode and routeAt. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>nodes</code></td><td><code>GeoRouteNode[]</code></td><td>the nodes (unique ids)</td></tr><tr><td><code>segments</code></td><td><code>GeoRouteSegment[]</code></td><td>the segments (unique ids; lengths finite and &gt;= 0)</td></tr></table> <b>Returns</b> <code>GeoRouteGraph</code> - the graph |
| <code>positionAlongRoute(route: GeoRoute, meters: number): LonLat</code> | The position a given distance along a route, measured in its own (supplied) metres; within a step its geometry is parametrized by its ellipsoidal arc length. Needs the engines. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>route</code></td><td><code>GeoRoute</code></td><td>a route from a graph</td></tr><tr><td><code>meters</code></td><td><code>number</code></td><td>0 to route.lengthMeters</td></tr></table> <b>Returns</b> <code>LonLat</code> - [longitude, latitude] |
| <code>decode(bytes: Uint8Array): GeoTopology</code> | Decode a topology: DGEO bytes (DSON metadata + varint arcs) or quantized TopoJSON as UTF-8 JSON - for first-party data (DSON is no sandbox for hostile metadata). Needs the engines. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>bytes</code></td><td><code>Uint8Array</code></td><td>the file's bytes</td></tr></table> <b>Returns</b> <code>GeoTopology</code> - the topology, arcs delta-encoded as in TopoJSON |
| <code>features(topology: GeoTopology, object: string): GeoRegion[]</code> | A topology object's geometries as GeoJSON features (TopoJSON's feature(): arcs stitched, shared points dropped, reversed arcs turned). <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>topology</code></td><td><code>GeoTopology</code></td><td>a decoded topology</td></tr><tr><td><code>object</code></td><td><code>string</code></td><td>the object's name (world.dgeo: 'countries', 'continents'; a chunk: 'regions')</td></tr></table> <b>Returns</b> <code>GeoRegion[]</code> - the features |
| <code>rewind(region: GeoRegion): GeoRegion</code> | A region from any GeoJSON polygon feature, its rings turned to D3's winding where needed (each ring by its spherical area: an outer ring encloses the smaller side) - so RFC 7946 and D3-wound input both draw. The input is not changed. Needs the engines. <table><tr><th>Argument</th><th>Type</th><th>Description</th></tr><tr><td><code>region</code></td><td><code>GeoRegion</code></td><td>a Polygon / MultiPolygon feature with properties `{ id, name, level, parent? }`</td></tr></table> <b>Returns</b> <code>GeoRegion</code> - the region, ready for a map |

### Events

| Event | Description |
|---|---|
| `geo-map-error` | a chunk or the data could not be loaded - the map keeps what it has <code>detail</code>: <code>GeoMapErrorDetail</code> <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>message</code></td><td><code>string</code></td><td>the message</td></tr><tr><td><code>url</code></td><td><code>string</code></td><td>the URL that failed, or ''</td></tr></table> |
| `geo-map-focus` | the focus changed: a region framed (its children shown), or the focus cleared <code>detail</code>: <code>GeoMapFocusDetail</code> <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>key</code></td><td><code>string \| null</code></td><td>its key, or null when the focus was cleared</td></tr><tr><td><code>name</code></td><td><code>string \| null</code></td><td>its name, or null</td></tr></table> |
| `geo-map-render` | a render finished: what it drew and what is still loading No <code>detail</code>. |
| `geo-map-select` | the selection changed - by a click, a key or setState <code>detail</code>: <code>GeoMapSelectDetail</code> <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>keys</code></td><td><code>string[]</code></td><td>their keys</td></tr><tr><td><code>names</code></td><td><code>string[]</code></td><td>their names (a key whose region is not loaded names itself)</td></tr></table> |
| `geo-map-view` | the camera came to rest (a pan, a zoom, a flight) <code>detail</code>: <code>GeoMapViewDetail</code> <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>center</code></td><td><code>LonLat</code></td><td>the center</td></tr><tr><td><code>zoom</code></td><td><code>number</code></td><td>the zoom factor</td></tr><tr><td><code>level</code></td><td><code>GeoLevel</code></td><td>the level drawn</td></tr></table> |

### Types

| Type | Description |
|---|---|
| `GeoBorder` | How region borders are drawn. = <code>'natural' \| 'cased' \| 'dashed' \| 'none'</code> |
| `GeoBounds` | A rectangle in degrees: [west, south, east, north]; west &gt; east crosses the antimeridian. = <code>[number, number, number, number]</code> |
| `GeoConfigureOptions` | What configure() sets for every map and the library. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>data?</code></td><td><code>string</code></td><td>the default data manifest URL (a map's data-src wins)</td></tr><tr><td><code>urls?</code></td><td><code>Partial&lt;GeoVendorUrls&gt;</code></td><td>engine URLs to load instead of the pinned jsDelivr builds (the same versions, self-hosted)</td></tr><tr><td><code>views?</code></td><td><code>Record&lt;string, GeoBounds&gt;</code></td><td>the bounds a focus frames, by region key, over the built-in ones (Europe, North America, Oceania)</td></tr></table> |
| `GeoEllipsoid` | A reference ellipsoid: equatorial radius and flattening. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>a</code></td><td><code>number</code></td><td>the equatorial radius in metres</td></tr><tr><td><code>f</code></td><td><code>number</code></td><td>the flattening (0 = a sphere)</td></tr></table> |
| `GeoGeometry` | A region's outline: a polygon or several, rings in D3 winding (the smaller spherical area is the inside). <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>type</code></td><td><code>'Polygon' \| 'MultiPolygon'</code></td><td>'Polygon' or 'MultiPolygon'</td></tr><tr><td><code>coordinates</code></td><td><code>LonLat[][] \| LonLat[][][]</code></td><td>rings of [longitude, latitude] positions (a MultiPolygon: one list of rings per polygon)</td></tr></table> |
| `GeoInverse` | The inverse geodesic problem solved: how far apart two positions are and in which direction. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>meters</code></td><td><code>number</code></td><td>the surface distance along the geodesic, in metres</td></tr><tr><td><code>initialBearing</code></td><td><code>number</code></td><td>the bearing leaving the first position, degrees clockwise from north</td></tr><tr><td><code>finalBearing</code></td><td><code>number</code></td><td>the bearing arriving at the second position</td></tr></table> |
| `GeoLayers` | What a map draws over its boundaries (the script.geo-map-layers JSON has the same shape). <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>markers?</code></td><td><code>GeoMarker[]</code></td><td>markers</td></tr><tr><td><code>lines?</code></td><td><code>GeoLine[]</code></td><td>lines</td></tr><tr><td><code>cells?</code></td><td><code>string[]</code></td><td>S2 cells, by token</td></tr><tr><td><code>styles?</code></td><td><code>Record&lt;string, GeoTileStyle&gt;</code></td><td>per-region looks, by key (country:DEU, state:DEU-1591, continent:Europe, s2:47a1)</td></tr></table> |
| `GeoLevel` | A boundary level: continents, countries (and territories), first-order administrative regions. = <code>'continent' \| 'country' \| 'state'</code> |
| `GeoLine` | A line on the map: given positions, or the geodesic between two. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>id</code></td><td><code>string</code></td><td>a unique id</td></tr><tr><td><code>coordinates?</code></td><td><code>LonLat[]</code></td><td>the positions it passes</td></tr><tr><td><code>from?</code></td><td><code>LonLat</code></td><td>with `to` instead of coordinates: the WGS84 geodesic from here</td></tr><tr><td><code>to?</code></td><td><code>LonLat</code></td><td>the geodesic's end</td></tr><tr><td><code>color?</code></td><td><code>string</code></td><td>a CSS color</td></tr><tr><td><code>width?</code></td><td><code>number</code></td><td>the stroke width in px</td></tr><tr><td><code>dash?</code></td><td><code>string</code></td><td>an SVG dash array ("4 3")</td></tr></table> |
| `GeoMapConfig` | A map's state: every field optional in setState() (merged into the current one); getState() reports all. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>projection?</code></td><td><code>GeoProjectionName</code></td><td>the projection (default equalEarth)</td></tr><tr><td><code>level?</code></td><td><code>GeoLevel \| 'auto'</code></td><td>the boundary level, or 'auto' by zoom: continents below 2x, countries below 8x, states above (default country)</td></tr><tr><td><code>palette?</code></td><td><code>GeoPalette</code></td><td>the fill palette (default atlas)</td></tr><tr><td><code>border?</code></td><td><code>GeoBorder</code></td><td>the border style (default natural)</td></tr><tr><td><code>graticule?</code></td><td><code>boolean</code></td><td>the latitude / longitude grid (default true)</td></tr><tr><td><code>callouts?</code></td><td><code>boolean</code></td><td>leader lines from the regions in view to their names outside the map (default false)</td></tr><tr><td><code>selected?</code></td><td><code>string[] \| string</code></td><td>the picked regions' keys (level:id - country:FRA); a string may list them separated by spaces or commas</td></tr><tr><td><code>focus?</code></td><td><code>string \| null</code></td><td>the framed key (a region, or an S2 cell as s2:&lt;token&gt;), or null; its children are shown, the rest dimmed</td></tr><tr><td><code>center?</code></td><td><code>LonLat</code></td><td>the view's center</td></tr><tr><td><code>zoom?</code></td><td><code>number</code></td><td>the zoom factor, 1 to 1024</td></tr></table> |
| `GeoMapErrorDetail` | The `geo-map-error` event's detail: what could not be loaded. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>message</code></td><td><code>string</code></td><td>the message</td></tr><tr><td><code>url</code></td><td><code>string</code></td><td>the URL that failed, or ''</td></tr></table> |
| `GeoMapFocusDetail` | The `geo-map-focus` event's detail: the framed region. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>key</code></td><td><code>string \| null</code></td><td>its key, or null when the focus was cleared</td></tr><tr><td><code>name</code></td><td><code>string \| null</code></td><td>its name, or null</td></tr></table> |
| `GeoMapSelectDetail` | The `geo-map-select` event's detail: the picked regions. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>keys</code></td><td><code>string[]</code></td><td>their keys</td></tr><tr><td><code>names</code></td><td><code>string[]</code></td><td>their names (a key whose region is not loaded names itself)</td></tr></table> |
| `GeoMapViewDetail` | The `geo-map-view` event's detail: where the camera came to rest. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>center</code></td><td><code>LonLat</code></td><td>the center</td></tr><tr><td><code>zoom</code></td><td><code>number</code></td><td>the zoom factor</td></tr><tr><td><code>level</code></td><td><code>GeoLevel</code></td><td>the level drawn</td></tr></table> |
| `GeoMarker` | A marker on the map. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>id</code></td><td><code>string</code></td><td>a unique id</td></tr><tr><td><code>label?</code></td><td><code>string</code></td><td>a label beside it (and its accessible name)</td></tr><tr><td><code>position</code></td><td><code>LonLat \| { s2: string }</code></td><td>where: [longitude, latitude], or an S2 cell's center</td></tr><tr><td><code>color?</code></td><td><code>string</code></td><td>a CSS color (default: the route color)</td></tr><tr><td><code>shape?</code></td><td><code>'circle' \| 'diamond' \| 'square' \| 'pin'</code></td><td>circle (default), diamond, square or pin</td></tr></table> |
| `GeoMortonIndex` | A Morton (Z-order) index over positions. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>size</code></td><td><code>number</code></td><td>how many items it holds</td></tr><tr><td><code>ordered</code></td><td><code>() =&gt; unknown[]</code></td><td>the items in Morton order</td></tr><tr><td><code>query</code></td><td><code>(bounds: GeoBounds) =&gt; unknown[]</code></td><td>the items inside a rectangle</td></tr></table> |
| `GeoNearestNode` | The nearest node to a position. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>node</code></td><td><code>GeoRouteNode</code></td><td>the node</td></tr><tr><td><code>meters</code></td><td><code>number</code></td><td>its WGS84 distance from the position, in metres</td></tr></table> |
| `GeoPalette` | A fill palette for the regions. = <code>'atlas' \| 'ocean' \| 'forest' \| 'sunset' \| 'heat' \| 'mono' \| 'chart'</code> |
| `GeoProjectionName` | A map projection. = <code>'equalEarth' \| 'equalArea' \| 'mercator' \| 'equirectangular' \| 'orthographic'</code> |
| `GeoRegion` | A region as a GeoJSON feature. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>type</code></td><td><code>'Feature'</code></td><td>always 'Feature'</td></tr><tr><td><code>properties</code></td><td><code>GeoRegionProperties</code></td><td>identity, name, level and parent</td></tr><tr><td><code>geometry</code></td><td><code>GeoGeometry</code></td><td>the outline</td></tr></table> |
| `GeoRegionProperties` | What a region is: its identity and place in the hierarchy. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>id</code></td><td><code>string</code></td><td>the id within its level: a continent's name, a country's ADM0_A3 code, a state's adm1_code</td></tr><tr><td><code>name</code></td><td><code>string</code></td><td>the display name (English)</td></tr><tr><td><code>level</code></td><td><code>GeoLevel</code></td><td>its level</td></tr><tr><td><code>parent?</code></td><td><code>string</code></td><td>a state's country (ADM0_A3)</td></tr><tr><td><code>continent?</code></td><td><code>string</code></td><td>a country's continent</td></tr></table> |
| `GeoRenderStats` | What the last render drew and loaded. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>visibleRegions</code></td><td><code>number</code></td><td>regions drawn</td></tr><tr><td><code>contextRegions</code></td><td><code>number</code></td><td>context regions drawn dimmed around a focus</td></tr><tr><td><code>visibleCells</code></td><td><code>number</code></td><td>S2 cells drawn</td></tr><tr><td><code>visibleMarkers</code></td><td><code>number</code></td><td>markers drawn</td></tr><tr><td><code>callouts</code></td><td><code>number</code></td><td>callouts drawn</td></tr><tr><td><code>renderMs</code></td><td><code>number</code></td><td>milliseconds the render took</td></tr><tr><td><code>cachedChunks</code></td><td><code>number</code></td><td>detail chunks in the cache</td></tr><tr><td><code>loadedBytes</code></td><td><code>number</code></td><td>encoded bytes of those chunks</td></tr><tr><td><code>loading</code></td><td><code>number</code></td><td>chunks still loading</td></tr></table> |
| `GeoRoute` | A shortest route. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>lengthMeters</code></td><td><code>number</code></td><td>the summed segment lengths in metres</td></tr><tr><td><code>nodeIds</code></td><td><code>string[]</code></td><td>the nodes passed, in order</td></tr><tr><td><code>steps</code></td><td><code>GeoRouteStep[]</code></td><td>the segments travelled</td></tr><tr><td><code>coordinates</code></td><td><code>LonLat[]</code></td><td>the whole path</td></tr></table> |
| `GeoRouteGraph` | A weighted directed graph: Dijkstra over the supplied lengths, a Morton index over the node positions. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>route</code></td><td><code>(from: string, to: string) =&gt; GeoRoute \| null</code></td><td>the shortest route between two nodes, or null when none connects them</td></tr><tr><td><code>routeAt</code></td><td><code>(from: GeoSegmentPosition, to: GeoSegmentPosition) =&gt; GeoRoute \| null</code></td><td>the shortest route between two positions inside segments (each cut proportionally)</td></tr><tr><td><code>nearestNode</code></td><td><code>(position: LonLat, bounds?: GeoBounds) =&gt; GeoNearestNode \| null</code></td><td>the node closest to a position (WGS84), optionally among the nodes in a rectangle</td></tr><tr><td><code>nodesInBounds</code></td><td><code>(bounds: GeoBounds) =&gt; GeoRouteNode[]</code></td><td>the nodes inside a rectangle (Morton prefix ranges, then the exact test)</td></tr><tr><td><code>mortonOrder</code></td><td><code>() =&gt; string[]</code></td><td>the node ids in Morton (Z) order</td></tr></table> |
| `GeoRouteNode` | A node of a route graph. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>id</code></td><td><code>string</code></td><td>a unique id</td></tr><tr><td><code>position</code></td><td><code>LonLat</code></td><td>where it is</td></tr><tr><td><code>name?</code></td><td><code>string</code></td><td>a display name</td></tr></table> |
| `GeoRouteSegment` | A segment between two nodes, with the length the application measured. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>id</code></td><td><code>string</code></td><td>a unique id</td></tr><tr><td><code>from</code></td><td><code>string</code></td><td>the start node's id</td></tr><tr><td><code>to</code></td><td><code>string</code></td><td>the end node's id</td></tr><tr><td><code>lengthMeters</code></td><td><code>number</code></td><td>the network length in metres - authoritative, independent of the drawn geometry</td></tr><tr><td><code>bidirectional?</code></td><td><code>boolean</code></td><td>usable in both directions (default: only from the from node to the to node)</td></tr><tr><td><code>coordinates?</code></td><td><code>LonLat[]</code></td><td>the drawn path; its first and last positions equal the nodes' (default: the straight pair)</td></tr></table> |
| `GeoRouteStep` | One segment a route travels. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>segment</code></td><td><code>string</code></td><td>the segment's id</td></tr><tr><td><code>from</code></td><td><code>string</code></td><td>the node it leaves</td></tr><tr><td><code>to</code></td><td><code>string</code></td><td>the node it reaches</td></tr><tr><td><code>reversed</code></td><td><code>boolean</code></td><td>travelled against its direction</td></tr><tr><td><code>lengthMeters</code></td><td><code>number</code></td><td>the metres it contributes</td></tr><tr><td><code>coordinates</code></td><td><code>LonLat[]</code></td><td>its path, in travel order</td></tr></table> |
| `GeoSearchHit` | One search result. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>key</code></td><td><code>string</code></td><td>the region's key (country:DEU)</td></tr><tr><td><code>name</code></td><td><code>string</code></td><td>its name</td></tr><tr><td><code>level</code></td><td><code>GeoLevel</code></td><td>its level</td></tr><tr><td><code>label</code></td><td><code>string</code></td><td>what a list shows: the name, a state's country after a comma</td></tr></table> |
| `GeoSegmentPosition` | A position inside a segment, as a fraction of its length. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>segment</code></td><td><code>string</code></td><td>the segment's id</td></tr><tr><td><code>fraction</code></td><td><code>number</code></td><td>0 (its from node) to 1 (its to node)</td></tr></table> |
| `GeoTileStyle` | A region's or cell's own look, over its palette fill. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>fill?</code></td><td><code>string</code></td><td>a CSS fill (a color, a token, the hatch url)</td></tr><tr><td><code>stroke?</code></td><td><code>string</code></td><td>a CSS stroke</td></tr><tr><td><code>strokeWidth?</code></td><td><code>number</code></td><td>the stroke width in px</td></tr><tr><td><code>dash?</code></td><td><code>string</code></td><td>an SVG dash array</td></tr><tr><td><code>opacity?</code></td><td><code>number</code></td><td>0 to 1</td></tr></table> |
| `GeoTopology` | A quantized TopoJSON topology (what a DGEO chunk decodes to). <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>type</code></td><td><code>'Topology'</code></td><td>always 'Topology'</td></tr><tr><td><code>objects</code></td><td><code>Record&lt;string, unknown&gt;</code></td><td>the named geometry collections</td></tr><tr><td><code>arcs</code></td><td><code>number[][][]</code></td><td>the delta-encoded arcs</td></tr><tr><td><code>transform?</code></td><td><code>{ scale: [number, number]; translate: [number, number] }</code></td><td>the quantization transform</td></tr></table> |
| `GeoVendorUrls` | The engines' URLs (the pinned official builds). <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>d3Array</code></td><td><code>string</code></td><td>d3-array (UMD; d3-geo's helpers)</td></tr><tr><td><code>d3Geo</code></td><td><code>string</code></td><td>d3-geo (UMD)</td></tr><tr><td><code>geodesic</code></td><td><code>string</code></td><td>GeographicLib geodesic (UMD)</td></tr><tr><td><code>dson</code></td><td><code>string</code></td><td>defuss-dson (ESM)</td></tr></table> |
| `GeoVisibleRegion` | A region drawn in the current view. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>key</code></td><td><code>string</code></td><td>its key</td></tr><tr><td><code>name</code></td><td><code>string</code></td><td>its name</td></tr><tr><td><code>level</code></td><td><code>GeoLevel</code></td><td>its level</td></tr><tr><td><code>anchor</code></td><td><code>[number, number] \| null</code></td><td>its label point in SVG pixels</td></tr></table> |
| `LonLat` | A position in WGS84 degrees, longitude first (GeoJSON order): [longitude, latitude]. = <code>[number, number]</code> |
| `S2Cell` | An S2 cell: its 64-bit id, its hexadecimal token and its level. <table><tr><th>Field</th><th>Type</th><th>Description</th></tr><tr><td><code>id</code></td><td><code>bigint</code></td><td>the exact cell id (never a Number - 64 bits do not fit)</td></tr><tr><td><code>token</code></td><td><code>string</code></td><td>the canonical lowercase hex token (trailing zeros dropped)</td></tr><tr><td><code>level</code></td><td><code>number</code></td><td>0 (a cube face) to 30 (about 1 cm²)</td></tr></table> |
