GeoMap
GeoMap draws a geographic source as vector paths. It belongs to
@gum-jsx/maps; the CLI and editor include its bindings by default.
Start with Making maps for a source-to-annotation walkthrough.
| Property | Default | Meaning |
|---|---|---|
source | — | A source returned by geojson, topojson, world_countries, or us_states |
source-resource | — | Name of a GeoSource or PreparedSource resource on the layout pass; supply exactly one of this and source |
width / height | Natural view fits within 720px × 400px | Allocated map size; omit an axis to derive it from the projected fit target and padding |
aspect | Inferred from the projected fit target | Override the preferred outer width divided by height |
projection | "naturalEarth1" | Projection preset; see the table below |
fit-to | "sphere"; "data" for Albers USA | "sphere", "data", or an array of feature IDs such as ['276', '040'] |
bounds | — | [west, south, east, north] in degrees; fits and clips to this box, overriding fit-to |
padding | 0 | Inset around the fitted geography |
center | Fit target centered automatically | [longitude, latitude] in degrees to pan to the viewport midpoint after fitting |
rotate | Projection preset | [lambda, phi, gamma?] spherical rotation in degrees; omitted gamma is zero |
clip-angle | Projection preset | Spherical clipping angle in degrees, greater than zero and at most 180; null uses antimeridian cutting |
precision | Projection preset | Nonnegative adaptive sampling tolerance in pixels |
fill | "#dce5e8" | Default feature fill |
background | none | Fill the projected sphere behind the features; the exterior stays transparent |
styles | — | (id) => style callback or dictionary mapping feature IDs to style objects |
border-mode | "all" | "all", "interior", or "none"; interior borders require TopoJSON |
border-color | "#ffffff" | Paint for borders and line features |
border-width | px(0.7) | Nonnegative border width |
point-radius | px(3) | Nonnegative radius for geographic point features |
Sources and feature IDs
One map owns one source. Load or prepare external data before rendering; GeoMap does not fetch URLs or read files. The bundled accessors run offline:
| Helper | Source |
|---|---|
world_countries(options?) | World-atlas 2.0.2 countries at 1:110m; three-digit country IDs such as "840" and "076", plus stable local IDs for three features |
us_states(options?) | US-atlas 3.0.1 states and territories at 1:10m; two-digit FIPS IDs such as "06" |
geojson(data, options?) | GeoJSON geometry, feature, or feature collection in longitude/latitude coordinates |
topojson(data, objectName, options?) | A named Topology object, retaining shared arcs for borders |
Each bundled accessor returns a fresh copy with its version, source URL, and
boundary viewpoint in provenance. Preserve leading zeros in the atlas IDs.
The world atlas's local IDs are local:northern-cyprus, local:somaliland, and
local:kosovo.
All four helpers accept an ids option to filter what the map draws:
world_countries({ ids: ['276', '040'] }) selects Germany and Austria, and
us_states({ ids: ['06', '32'] }) selects California and Nevada. Your own sources
use geojson(data, { ids: [...] }) or topojson(data, objectName, { ids: [...] }).
Filtering happens before borders are built, preserving shared TopoJSON arcs.
Inputs are not mutated. The source retains its original feature order, repeated
requested IDs select a feature once, and unknown IDs are errors.
IDs are strings matched exactly, including leading zeros, and honor id_property
when specified. Filtering requires explicit matching IDs; autogenerated positional
IDs cannot be selected. Omit ids for all features; ids: [] selects none.
An empty source can use sphere or bounds fitting, but cannot fit to data.
Styles apply only to retained features; dictionaries still reject absent IDs.
Both source constructors accept id_property and provenance options.
Feature IDs normally come from feature.id; for a property-based ID, use
geojson(data, { id_property: 'ADM0_A3' }). IDs become strings and must be unique.
Feature styles require explicit IDs on every feature. Dictionaries reject
unknown keys. Styles match IDs, not names or feature order.
geojson expects RFC 7946 polygon winding by default. It stitches antimeridian
and polar cuts and reverses rings for the spherical projection pipeline without
mutating the input. Use { winding: 'd3' } only for data already using D3's
winding convention. See GeoJSON edge cases
for runnable sources with holes and antimeridian cuts.
Feature styles
Use a callback to derive a style from each geographic ID:
styles={id => ({ fill: highlights[id] })}. Or supply an ID-to-style dictionary:
styles={{ '840': { fill: blue }, '076': { fill: green, opacity: 0.6 } }}.
Missing dictionary entries, undefined callback results, and omitted style
fields inherit the map's style. Callback IDs are strings, including leading zeros.
Style objects accept ordinary Gum style props such as fill, opacity,
stroke, stroke_width, stroke_dasharray, stroke_linecap, and
stroke_linejoin, plus point_radius for geographic points. Use underscore
keys inside JavaScript objects. Colors can use theme paints; lengths accept
px/em/fractions as on the map. A feature's font_size controls its em lengths.
Callbacks run once per source feature at element construction, and their results
are copied into immutable props. They are not rerun when the map is resized.
Callbacks require an inline source; maps using source-resource accept the
dictionary form, which is checked against the resource at layout time.
Feature strokes draw after the shared borders, so a selected feature can have
its own highlighted outline. Shared borders keep the map's border-color,
border-width, and opacity. Use border-mode="none" for feature strokes alone;
adjacent feature strokes can overlap. See the
world countries callback and
US states dictionary.
Projection and fitting
| Preset | Typical use |
|---|---|
naturalEarth1 | General world illustrations; the default |
equalEarth | Equal-area world maps |
equirectangular | Rectangular longitude/latitude views |
mercator | Mercator views |
orthographic | Globe views, with the far side clipped by default |
albersUsa | Lower 48 states with Alaska and Hawaii insets |
The projection fits its target into the allocated rectangle minus padding.
Use fit-to="data" for a regional source, or fit-to={['276', '040']}
to fit selected features from a larger source. Selected IDs set the extent;
they do not filter the drawn features. Fitting is independent of styles.
Unknown selected IDs and fit targets without geometry are errors.
For a coordinate box, use bounds={[-10, 35, 30, 60]}. When supplied, bounds
takes precedence over fit-to for both fitting and natural sizing; the unused
fit target is not looked up. Bounds are
[west, south, east, north] in degrees. Longitudes must be in [-180, 180], and
latitudes must satisfy -90 <= south < north <= 90. Longitude span must be
positive; [-180, south, 180, north] spans all longitudes. A west value greater
than east crosses the antimeridian, such as [170, -20, -170, 20]. Rotation is
unchanged: use rotate={[-180, 0, 0]} for a continuous Pacific-facing view.
Bounds fit a sampled geographic rectangle and clip all map content to its projected outline, including curved edges. Water, features, borders, and children share this clip. The projection keeps its proportions, so a narrow longitude range in a wide allocation leaves transparent space on either side instead of showing extra geography. Source features themselves remain intact. Bounds fit the visible portion under the chosen projection; a fully hidden or degenerate target is an error.
Source selection and bounds fitting combine independently:
Only Germany and Austria draw, inside the requested frame. Omit bounds and
use fit-to="data" to fit tightly around the filtered geography. See
Filtering and bounds.
center={[30, 20]} places 30° east, 20° north at the viewport midpoint.
Fitting sets the scale first, then the map pans to this location. This can move
parts of the fitted geometry outside the viewport; omit center to keep the
fit target centered automatically. An explicit center={[0, 0]} also overrides
the automatic center of a regional fit.
center pans the projected map; rotate turns the globe before projection.
For an orthographic globe facing 30° east, 20° north, use rotate={[-30, -20, 0]}.
Panning alone does not reveal points hidden on the far side. If both props are
set, center refers to the original longitude/latitude, before rotation.
albersUsa fits data by default and cannot fit the whole sphere. It has fixed
center, rotation, and spherical clipping, so it rejects center, rotate, and
clip-angle. The projection excludes territories outside the lower 48 states,
Alaska, and Hawaii. Compare the projection gallery,
US states, and
selected-region fit.
Map dimensions use ordinary Gum sizing.
The projected fit target supplies the map's natural proportions, including
rotation and spherical clipping. Specify only height for a narrow region and
the map derives its width; specify only width to derive its height. This also
works for sphere, data, and selected-ID fits. Map padding adds space around that
projected extent. Box, Frame, and stacks can hug the
result without a manually supplied aspect:
With neither dimension nor an offer, the view fits within 720px × 400px.
An explicit aspect overrides these natural proportions for the outer map box.
Two exact dimensions, including parent stretch allocations, take precedence;
the map then fits inside that rectangle with any extra space transparent.
See Natural map sizes.
padding, border-width, and point-radius accept px/em lengths or fractions
of the shorter allocated axis. Padding must be nonnegative and leave a positive
drawing area. Projection precision controls curve sampling, not source-data
simplification. Geometry is always clipped to the map rectangle.
Fills, borders, and annotations
Fills are drawn before borders. TopoJSON draws the selected shared-arc mesh once;
GeoJSON draws each feature's edges, so adjacent edges can repeat.
border-mode="interior" selects only shared TopoJSON boundaries.
border-mode="none", a zero border-width, or border-color={none} hides borders.
Use the border props to style the shared borders and line features. Ordinary
stroke props add feature outlines after those borders; styles can override
them by ID. Points render as circular paths using point-radius.
Set background={interp(white, blue, 0.15)} to color the water. The background
is the projected sphere, drawn before feature fills and borders. It follows
the same projection, rotation, clipping, and fitted extent as the geography,
leaving the area outside the projection transparent. An orthographic globe gets
a circular background; bounds fitting crops it to the projected geographic box.
Albers USA uses the composite projection's clip regions. Background colors can
also use theme paints such as "theme:accent"; the default is none.
This is a backdrop for the supplied geometry: gaps and polygon holes show the background, but lakes need to be represented as holes or omitted areas in the source. A surrounding Box can supply a separate rectangular background outside the projection.
Nest marks and annotations directly inside GeoMap. Use {lon, lat} records
in degrees for mark coordinates and direct-child pos values. Tuples
[longitude, latitude] and records {x: longitude, y: latitude} are aliases.
Both components are required, and records cannot mix lon/lat with x/y.
Children draw above the geography and share its fitted size, padding,
center, rotation, and clipping. For example:
Text and marker shapes keep their ordinary layout sizes and orientations.
Points hidden by the projection are omitted, and sampled paths break at hidden
points. Supply an Arrow's intermediate longitude/latitude samples when the route
should curve; ordinary marks do not automatically resample or split at the
antimeridian. space="local" opts marks out, and Cartesian lengths such as
pos={[px(12), px(24)]} position annotations in local pixels. Geographic
components must be numeric. GeoJSON, TopoJSON, center, and the geographic
helpers retain their array formats. Children inherit the map's ordinary styles, so set
stroke explicitly on route arrows. See Map routes
and Projections.
Line, HLine, VLine,
Polyline, and Polygon use the map projection
by default, just like Points. Use space="local" for local decorations.
For annotations outside the map subtree, the helper
project_geo_point(source, view, width, height, [longitude, latitude]) accepts a
raw or prepared source and returns local pixel coordinates, or null if hidden
by the projection's spherical clipping. The map's bounds and viewport clips
apply to its subtree; external annotations need their own clipping.
Use the same source, view, and allocated dimensions as the map. Helper
padding is in pixels; element padding accepts Gum lengths. See
projected city markers for this lower-level
sibling-overlay pattern.
For lower-level work, create_geo_projection(prepared, view, width, height)
returns the fitted D3 projection. Prepare its source with prepare_geo_source.
Directly calling that projection does not test spherical visibility; use
project_geo_point to check that visibility.
Host integration and shared sources
Embedded evaluators can import * as maps from @gum-jsx/maps and pass
scope: maps to Evaluator. Host element props use underscores, such as
fit_to and border_color; evaluated JSX also accepts dashed names.
See Rendering for the host rendering workflow.
For a large source shared by several maps, install it once on a LayoutPass instead of copying it into every element's immutable props: