Engines
d3gl gives you two engines:
geoMap()— geographic. Layers are GeoJSON features drawn through a d3GeoProjection, with rotation, re-projection, and a GPU globe.plot()— 2D Cartesian. Layers are drawn with adraw(ctx, datum)callback orx/ypoint accessors in plot coordinates (trees, charts, link diagrams, scatter plots).
They are siblings over a shared base (BaseEngine, internal). They differ only in how a
layer’s geometry is defined. Everything else — interaction, per-drawable styling, backends, view
transform, and export — lives in the base, so it behaves identically on both. Pick the engine
that matches your data; the rest of the API is the same.
import { geoMap } from "@mapequation/d3gl/map"; // geographicimport { plot } from "@mapequation/d3gl/map"; // 2D CartesianShared API (both engines)
Section titled “Shared API (both engines)”Once you have an engine instance, these work the same regardless of which one you created:
| Concern | API |
|---|---|
| Events | on("hover", …), on("click", …) — hit: { layer, id, datum } | null |
| Hit-testing | pick(x, y) (clip-aware; retained layers are pickable by default) |
| Highlight | highlight(layer, idOrIds, styleOrDraw) |
| Selection | select(layer, ids) |
| Style overrides | setStyle(layer, ids, …), clearStyle(layer, ids) |
| View | enableZoom(extent), setTransform(t), render() |
| Sizing | width / height / aspectRatio options, setSize(w, h) — see Sizing |
| Backend | setBackend(type), whenReady() — see Rendering backends |
| Export | toPNG(), toSVG() |
| Teardown | destroy() |
Retained layers on both engines also accept the same declarative interaction options
(InteractiveLayerOptions), forwarded into the layer the same way:
engine.layer("things", data, { hover: true, // or a style, or a (datum, HighlightBuilder) draw fn tooltip: (d, id) => `${d.name}`, // string | HTMLElement | null selection: { others: { opacity: 0.3 } }, pickable: true, // default; false skips the hit index});See the Interaction guide for what each one does and what it costs — every
example there reads identically whether engine is a geoMap or a plot.
Sizing
Section titled “Sizing”Both engines are responsive by default and resize in place — when their container changes
size they reconcile the rendering surface and re-render without tearing down, so the view
transform, layers, hover, and selection are all preserved. Three modes, picked by which options
you pass (to the plot() / geoMap() constructors or the React <Plot> / <GeoMap> props):
| You pass | Mode | Behavior |
|---|---|---|
aspectRatio | width-driven | Fills the parent’s width and keeps width ÷ height = aspectRatio. |
| nothing | fill-parent | Tracks the parent box. The parent must give it a height (from your CSS). |
both width & height | fixed | A static pixel size — the opt-out (the pre-responsive behavior). |
<Plot aspectRatio={16 / 9} /> {/* fills width, keeps the ratio */}<GeoMap /> {/* fills the parent box */}<Plot width={800} height={400} /> {/* fixed size */}// Bare engines take the same options; the engine observes its host element.const chart = plot(host, { aspectRatio: 2 });// Resize imperatively at any time (no recreate):chart.setSize(1024, 512);A resized geoMap also refits its projection to the new box, so the map keeps filling it.
A uniform resize (always the case in aspectRatio mode) preserves your original framing exactly;
an aspect-ratio change (possible in fill-parent mode) re-letterboxes the map to the new shape.
Engine-specific API
Section titled “Engine-specific API”What’s unique to each engine is the layer definition (its geometry) plus a few domain methods:
geoMap() | plot() | |
|---|---|---|
| Constructor option | projection (required) | — |
| Layer geometry | layer(name, features, opts) — GeoJSON + projection | layer(name, data, { draw }) and points(name, data, { x, y }) |
| Domain methods | setProjection(), enableRotation() | — |
| Coordinates | geographic [lon, lat], projected each frame | plot coordinates, drawn directly |
// geoMap: GeoJSON features through a projectionconst map = geoMap(host, { width, height, projection });map.layer("land", [world.land], { fill: "#e3e6ea", hover: true });
// plot: a draw callback in plot coordinatesconst chart = plot(host, { width, height });chart.layer("boxes", rects, { draw: (ctx, d) => ctx.rect(d.x, d.y, 40, 40), fill: "#4477aa", hover: { fill: "#ee6677" },});Choosing an engine
Section titled “Choosing an engine”- Mapping anything geographic (GeoJSON, projections, a globe) →
geoMap(). - Everything else in a 2D plane (trees, scatter, links, custom marks) →
plot().
Because the shared base is the same object, you can move between them without relearning interaction, styling, or backends — only the layer-definition call changes.