--- url: 'https://d3-maps.netlify.app/api/core.md' --- # @d3-maps/core ## Modules * [annotation](annotation.md) * [feature](feature.md) * [graticule](graticule.md) * [line](line.md) * [map](map.md) * [mapObject](mapObject.md) * [marker](marker.md) * [utils](utils.md) * [zoom](zoom.md) --- --- url: 'https://d3-maps.netlify.app/api.md' description: API docs entry point for generated d3-maps core docs and local TypeDoc pages --- --- --- url: 'https://d3-maps.netlify.app/components.md' description: >- D3 SVG map components in React and Vue: MapBase, MapFeatures, MapMarker, MapZoom, and MapGraticule --- # Components Components are adapter-level building blocks for rendering map layers * [MapBase](/components/map-base) * [MapFeatures](/components/map-features) * [MapFeature](/components/map-feature) * [MapAnnotation](/components/map-annotation) * [MapLine](/components/map-line) * [MapMarker](/components/map-marker) * [MapMesh](/components/map-mesh) * [MapGraticule](/components/map-graticule) * [MapZoom](/components/map-zoom) Need helpers for custom layers and interactions? * [Helpers](/helpers/) --- --- url: 'https://d3-maps.netlify.app/guide/core-concepts.md' description: >- Core concepts for D3 SVG maps in React and Vue, including projections, features, mesh, markers, zoom, and responsive rendering --- # Core concepts Let's build the map step by step to understand how the library works ## Data [MapBase](/components/map-base) accepts either GeoJSON or TopoJSON and then transforms it into GeoJSON.\ Both used for geo data encoding, but **TopoJSON is recommended**, it's smaller. Simply pass `data` prop to render the basic map :::tabs key:framework \== Vue ```vue [vue] ``` \== React ```tsx [react] ``` ::: ## Data transformation Add `dataTransformer` to preprocess GeoJSON features before render ```ts // e.g. don't render Antarctica ๐Ÿ‡ฆ๐Ÿ‡ถ function dataTransformer(features) { return features.filter((x) => x.properties?.name !== 'Antarctica') } ``` :::tabs key:framework \== Vue ```vue{4} [vue] ``` \== React ```tsx{3} [react] ``` ::: ## Projection A map projection transforms the Earth's 3D curved surface into SVG map.\ It determines how exactly map will look. By default `geoNaturalEarth1` is used in core, but you can provide your own: :::tabs key:framework \== Vue ```vue{2,9} [vue] ``` \== React ```tsx{1,6} [react] import { geoEquirectangular } from 'd3-geo' ``` ::: ::: details * You can tweak a projection with [MapBase.projectionConfig](/components/map-base#props) (defaults are strong though) * Projections are available in [d3-geo](https://github.com/d3/d3-geo) and [d3-geo-projection](https://github.com/d3/d3-geo-projection) * Here you can see [visualized projections](https://observablehq.com/@fil/d3-projections) ::: ## Features Map feature is geographic entity, e.g. country or state.\ [MapFeatures](/components/map-features) render all features internally, [MapFeature](/components/map-feature) renders a single one.\ Switch to slot/render-function when each feature needs custom render logic. :::tabs key:framework \== Vue ```vue{7-15} [vue] ``` \== React ```tsx{6-17} [react] {({ features }) => ( <> {features.map((feature) => ( ))} )} ``` ::: ## Mesh To render borders use [MapMesh](/components/map-mesh) instead of applying `stroke`. It will render a single `` (more efficient) and ensure borders don't overlap. :::tabs key:framework \== Vue ```vue{8} [vue] ``` \== React ```tsx{7} [react] ``` ::: > Default stroke width is 0.5 ## Graticule Use [MapGraticule](/components/map-graticule) to draw latitude and longitude grid lines :::tabs key:framework \== Vue ```vue{7} [vue] ``` \== React ```tsx{6} [react] ``` ::: ## Zoom Wrap layers with [MapZoom](/components/map-zoom) to enable pan and zoom :::tabs key:framework \== Vue ```vue{7,11} [vue] ``` \== React ```tsx{6,10} [react] ``` ::: > Detailed zoom [usage example](/examples/zoom) ## Markers Add any points to the map with [MapMarker](/components/map-marker) * pass `coordinates` as `[longitude, latitude]` * and any SVG elements as a children :::tabs key:framework \== Vue ```vue{11-18} [vue] ``` \== React ```tsx{10-17} [react] Sweet home ๐Ÿงก ``` ::: ## Styling [MapFeature](/components/map-feature)\*, [MapMarker](/components/map-marker), [MapMesh](/components/map-mesh), [MapGraticule](/components/map-graticule), [MapLine](/components/map-line), and [MapAnnotation](/components/map-annotation) accept a `styles` prop ```ts const styles = { default: { fill: 'lightblue' }, // default state hover: { fill: 'skyblue' }, // on hover active: { fill: 'lightskyblue' }, // on mousedown } ``` :::tabs key:framework \== Vue ```vue{9} [vue] ``` \== React ```tsx{8} [react] Sweet home ๐Ÿงก ``` ::: > \* [MapFeatures](/components/map-features) forwards `styles` to internally rendered `MapFeature`'s ### CSS 1. Import [default stylesheet](https://github.com/souljorje/d3-maps/blob/main/packages/core/src/index.css) to simplify global map styles :::tabs key:framework-css \== Vue ```ts import '@d3-maps/vue/index.css' ``` \== React ```ts import '@d3-maps/react/index.css' ``` ::: 2. Define styles for map components with plain CSS | Component | CSS selector | | --- | --- | | [MapBase](/components/map-base) | `.d3-map` | | [MapFeature](/components/map-feature) | `[name="feature"]` | | [MapMesh](/components/map-mesh) | `[name="mesh"]` | | [MapMarker](/components/map-marker) | `[name="marker"]` | | [MapGraticule](/components/map-graticule) lines | `[name="graticule"]` | | [MapGraticule](/components/map-graticule) border | `[name="border"]` | | [MapGraticule](/components/map-graticule) background | `[name="background"]` | | [MapLine](/components/map-line) | `[name="line"]` | | [MapAnnotation](/components/map-annotation) connector | `[name="annotation-line"]` | | [MapZoom](/components/map-zoom) | `[name="zoom"]` | See example (this site) [packages/docs/.vitepress/theme/custom.css](https://github.com/souljorje/d3-maps/blob/main/packages/docs/.vitepress/theme/custom.css) ## Responsiveness Simply make it with an aspect-ratio wrapper and the `aspect-ratio` prop :::tabs key:framework \== Vue ```vue{2,7} [vue] ``` \== React ```tsx{1,6} [react]
Sweet home ๐Ÿงก
``` ::: ::: details [MapBase](/components/map-base) renders an `` with a `viewBox` and `width="100%" height="auto"`.\ Hence the **parent element must have height**, otherwise map will collapse.\ Under the hood `fitExtent([[1, 1], [width - 1, height - 1]], { type: 'Sphere' }` is used.\ Overridable with `fitExtent | fitSize | fitWidth | fitHeight` passed to `projectionConfig`. ::: ## Result ## That's it What's next? * Explore [examples](/examples/) * Check out [components](/components/) --- --- url: 'https://d3-maps.netlify.app/index.md' description: >- D3 SVG map library for React and Vue with components for choropleth maps, markers, pan and zoom, and responsive rendering --- --- --- url: 'https://d3-maps.netlify.app/examples.md' description: >- Example gallery for D3 SVG maps in React and Vue, including choropleth maps, markers, annotations, and pan and zoom --- # Examples --- --- url: 'https://d3-maps.netlify.app/helpers/get-feature-key.md' description: Helper for stable GeoJSON feature IDs in D3 SVG maps --- # getFeatureKey Resolves a feature key from a GeoJSON feature Use it when you need a stable identifier for rendering or DOM targeting ## Parameters | Parameter | Type | Default | Description | | --- | --- | --- | --- | | `feature` | [MapFeatureData](/api/core/feature#mapfeaturedata) | `โ€”` | Feature to inspect | | `idKey?` | `string` | `'id'` | Key checked on the feature and then on `feature.properties` | | `fallback?` | `string \| number` | `โ€”` | Optional fallback value returned when no key is found | ## Behavior Checks in order: 1. `feature[idKey]` 2. `feature.properties?.[idKey]` 3. `fallback` If no value is found and no fallback is provided, it returns `undefined` ## Usage ```ts const key = getFeatureKey(feature) const keyedBySlug = getFeatureKey(feature, 'slug') const keyedWithFallback = getFeatureKey(feature, 'id', index) ``` See [feature API](/api/core/feature#getfeaturekey) --- --- url: 'https://d3-maps.netlify.app/helpers/get-object-zoom-view.md' description: >- Helper for fitting D3 SVG map features and objects to a centered zoom view with React and Vue --- # getObjectZoomView `getObjectZoomView` computes a centered zoom target for a map object Use it when you want to zoom to a feature, marker geometry, or any other permissible geo object ## Parameters | Parameter | Type | Default | Description | | --- | --- | --- | --- | | `context` | `Pick` | `โ€”` | Current map path generator and dimensions | | `object` | `GeoPermissibleObjects` | `โ€”` | Geo object to fit | | `options?` | `ObjectZoomViewOptions` | `{}` | Optional `minZoom`, `maxZoom`, and `padding` | ## Return value ```ts { center: [number, number] zoom: number } ``` Returns `undefined` when the object has invalid or empty bounds ## Usage ```ts const view = getObjectZoomView(context, feature, { minZoom: 1, maxZoom: 16, }) if (view) { center = view.center zoom = view.zoom } ``` See [zoom API](/api/core/zoom#getobjectzoomview) ## Examples * [Programmatic Zoom](/examples/programmatic-zoom) --- --- url: 'https://d3-maps.netlify.app/helpers.md' description: >- Helpers for custom SVG map layers, renderers, zoom logic, and shared map state in React and Vue --- # Helpers Helpers expose reusable low-level logic for advanced use cases and custom renderers * [useCreateMapContext](/helpers/use-create-map-context) * [useMapContext](/helpers/use-map-context) * [useMapZoom](/helpers/use-map-zoom) * [useMapObject](/helpers/use-map-object) * [getFeatureKey](/helpers/get-feature-key) * [getObjectZoomView](/helpers/get-object-zoom-view) --- --- url: 'https://d3-maps.netlify.app/guide.md' description: >- Guide to building D3 SVG maps in React and Vue with GeoJSON or TopoJSON data, projections, and interactive layers --- # Introduction **d3-maps** is a set of components and helpers simplifying creating SVG maps with [D3](https://d3js.org/).\ Works with your favorite framework, batteries included. ## Architecture **Core** provides framework-agnostic complex logic *(you won't see it)* * Context creation, data transformation * Map layers types and models: features, markers, zoom, etc * Utilities for custom layers: choropleth, bubble, etc **Adapters** implement the core in a simple way *(you'll see it)* * Vue and React bindings (Solid and Svelte coming soon) * Rendering and reactivity integration * Declarative components and composables ## Installation ::::tabs key:framework \=== Vue :::tabs key:package-manager \== npm ```bash npm install @d3-maps/vue ``` \== pnpm ```bash pnpm add @d3-maps/vue ``` \== bun ```bash bun add @d3-maps/vue ``` \== CDN ```bash https://cdn.jsdelivr.net/npm/@d3-maps/vue@0.8.0/index.css https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js https://cdn.jsdelivr.net/npm/@d3-maps/vue@0.8.0 ``` ::: \=== React :::tabs key:package-manager \== npm ```bash npm install @d3-maps/react ``` \== pnpm ```bash pnpm add @d3-maps/react ``` \== bun ```bash bun add @d3-maps/react ``` \== CDN ```bash https://cdn.jsdelivr.net/npm/@d3-maps/react@0.5.0/index.css https://cdn.jsdelivr.net/npm/react@19/umd/react.production.min.js https://cdn.jsdelivr.net/npm/@d3-maps/react@0.5.0 ``` ::: :::: ## CDN support * `jsDelivr` and `UNPKG` support package-root script URLs for `@d3-maps/core`, `@d3-maps/react`, and `@d3-maps/vue` * `@d3-maps/react` and `@d3-maps/vue` browser bundles already include `@d3-maps/core`, so you only need the framework runtime plus the adapter script * browser styles are available from the adapter packages at `@d3-maps/react/index.css` and `@d3-maps/vue/index.css` * `esm.sh` and `Skypack` use the package ESM entrypoints, so prefer package-root imports there * `cdnjs` is not an npm mirror, so publishing to npm does not make `@d3-maps/*` available there automatically ## Basic usage 1. Get data ```ts import '@d3-maps/vue/index.css' import type { MapData } from '@d3-maps/vue' const data: MapData = await fetch('/some-topojson.json').then((res) => res.json()) ``` 2. Pass the data to `MapBase` :::tabs key:framework \== Vue ```vue [vue] ``` \== React ```tsx [react] import '@d3-maps/react/index.css' import { MapBase, MapFeatures, type MapData } from '@d3-maps/react' export function MapView({ data }: { data: MapData }) { return ( ) } ``` ::: 3. Your first map is ready ## Next Learn [core concepts](/guide/core-concepts/) to understand how **d3-maps** works step by step: data, projection, zoom, markers and more. --- --- url: 'https://d3-maps.netlify.app/components/map-annotation.md' description: Component for D3 SVG map coordinate-based annotations in React and Vue --- # MapAnnotation Anchors arbitrary SVG content to a map point with a connector line path.\ Use when you need a callout, label, or badge offset from the original location ## Props | Parameter | Type | Default | Description | | --- | --- | --- | --- | | `coordinates` | `[number, number]` | โ€” | Anchor coordinates `[longitude, latitude]` | | `length?` | `number` | `30` | Connector length in screen pixels | | `angle?` | `number` | `-90` | Connector angle in degrees | | `margin?` | `number` | `0` | Gap between the anchor point and the connector start | | `curve?` | `CurveFactory \| CurveFactoryLineOnly` | `curveNatural` | See [`MapLine.curve`](/components/map-line#props) | | `midpoint?` | `[lengthwise: number, crosswise: number]` | โ€” | See [`MapLine.midpoint`](/components/map-line#props) | | `styles?` | [MapObject\['styles'\]](/api/core/mapObject#property-styles) | โ€” | See [styling guide](/guide/core-concepts/#styling) | `styles` and native attributes are bound to the connector ``.\ Interaction state is tracked on the wrapper ``. ## Usage :::tabs key:framework \== Vue ```vue ``` \== React ```tsx Paris ``` ::: See [annotations example](/examples/annotations) for a few callout layouts --- --- url: 'https://d3-maps.netlify.app/components/map-base.md' description: >- Component for the root D3 SVG map container and shared map context in React and Vue --- # MapBase Renders the root `` and provides a reactive map context to children. ## Props | Parameter | Type | Default | Description | | --- | --- | --- | --- | | `data` | [MapData](/api/core/map#mapdata) | โ€” | TopoJSON or GeoJSON | | `width?` | `number` | `600` | | | `height?` | `number` | `width/aspectRatio` | | | `aspectRatio?` | `number` | `2 / 1` | Used to derive `height` when `height` is not provided. | | `projection?` | `() => GeoProjection` | `geoNaturalEarth1` | d3-geo projection factory | | `projectionConfig?` | [ProjectionConfig](/api/core/map#projectionconfig) | โ€” | See the [guide](#projectionconfig) below | | `dataTransformer?` | [DataTransformer](/api/core/map#datatransformer) | โ€” | Optional transform applied to GeoJSON features before rendering | | `context?` | [MapContext](/api/core/map#mapcontext) | โ€” | Optional externally created context. When provided, `MapBase` uses it instead of creating one from props, and `data` is not required | ### projectionConfig Use `projectionConfig` to call projection methods before rendering ```ts { [methodName: string]: Arg | Arg[] } ``` 1. Single non-array value: `Arg | [Arg]` - pass directly or wrap with an array 2. Single array value: `[Arg]` - **must be wrapped** with an array 3. Multiple values: `[Arg1, Arg2, ...]` See available methods in [d3-geo projection docs](https://d3js.org/d3-geo/projection)\ and usage example below ::: details Core defaults ```ts if (!(fitExtent || fitSize || fitWidth || fitHeight)) { mapProjection.fitExtent([[1, 1], [width - 1, height - 1]], { type: 'Sphere' }) } if (!precision) { mapProjection.precision(0.2) } ``` Source: [packes/core/src/lib/map.ts](https://github.com/souljorje/d3-maps/blob/main/packages/core/src/lib/map.ts#:~:text=makeProjection) ::: ## Usage :::tabs key:framework \== Vue ```vue ``` \== React ```tsx import { geoEquirectangular } from 'd3-geo' import { MapBase, MapFeatures, type MapData } from '@d3-maps/react' export function Example({ data }: { data: MapData }) { return ( features.map(/* some logic */)} aspectRatio={2 / 1} projection={geoEquirectangular} projectionConfig={{ rotate: [[0, 12]], // array wrapper required scale: 200, // single argument can be passed as it is precision: [0.1], // also can be array-wrapped }} > ) } ``` ::: ## Helpers * See [useCreateMapContext](/helpers/use-create-map-context) * See [useMapContext](/helpers/use-map-context) For adapter code and docs examples, prefer [useMapContext](/helpers/use-map-context) or `MapBase` slot/render-prop context over rebuilding a separate map context manually ## Advanced Composition If controls or other consumers need the same map context outside the rendered ``, create the context once in the parent, pass it to sibling UI by prop, and pass the same object into `MapBase`. :::tabs key:framework \== Vue ```vue ``` \== React ```tsx import { MapBase, MapFeatures, type MapData, useCreateMapContext, } from '@d3-maps/react' export function Example({ data }: { data: MapData }) { const context = useCreateMapContext({ data, aspectRatio: 2 / 1, }) if (!context) return null return ( <> ) } ``` ::: --- --- url: 'https://d3-maps.netlify.app/components/map-feature.md' description: >- Component for a single interactive GeoJSON feature path on D3 SVG maps in React and Vue --- # MapFeature Renders a single GeoJSON feature as an SVG ``. ## Props | Parameter | Type | Default | Description | | --- | --- | --- | --- | | `data` | GeoJSON Feature | โ€” | Rendered as an SVG path | | `styles?` | [MapObject\['styles'\]](/api/core/mapObject#property-styles) | โ€” | See [styling guide](/guide/core-concepts/#styling) | Use native SVG presentation attrs like `fill` and `stroke` directly on `MapFeature`. To use `focus` styles, make the path focusable with `tabindex="0"` / `tabIndex={0}` and add accessibility attrs like `role` and `aria-label` ## Usage :::tabs key:framework \== Vue ```vue ``` \== React ```tsx {({ features }) => ( <> {features.map((feature) => ( ))} )} ``` ::: ## Helpers * See [useMapObject](/helpers/use-map-object) --- --- url: 'https://d3-maps.netlify.app/components/map-features.md' description: Component for GeoJSON feature rendering on D3 SVG maps in React and Vue --- # MapFeatures Renders all GeoJSON features from the current map context ## Props | Parameter | Type | Default | Description | | --- | --- | --- | --- | | `idKey?` | `string` | `id` | See [`getFeatureKey`](/api/core/feature#getfeaturekey) | | `styles?` | [MapObject\['styles'\]](/api/core/mapObject#property-styles) | โ€” | Forwarded to [MapFeature](/components/map-feature#props) in default rendering mode, see [styling guide](/guide/core-concepts/#styling) | Use native SVG presentation attrs like `fill` and `stroke` directly on `MapFeatures` ## Usage :::tabs key:framework \== Vue ```vue ``` \== React ```tsx ``` ::: ## Slots :::tabs key:framework \== Vue ```vue ``` \== React ```tsx {({ features }) => ( {features.map((feature) => ( ))} )} ``` ::: --- --- url: 'https://d3-maps.netlify.app/components/map-graticule.md' description: Component for D3 SVG map graticules and outlines in React and Vue --- # MapGraticule Renders graticule lines and optional outline as SVG `` layers.\ Outline is rendered only when `background` or `border` is provided.\ The outline is drawn as two paths: fill under lines and border over lines ## Props | Parameter | Type | Default | Description | | --- | --- | --- | --- | | `background?` | `boolean \| string` | โ€” | `true` renders background outline with no inline fill, `string` sets outline fill color | | `border?` | `boolean \| string` | โ€” | `true` renders border outline with no inline stroke, `string` sets outline stroke color | | `config?` | [GraticuleConfig](/api/core/graticule#graticuleconfig) | โ€” | See [usage](#config) below | | `styles?` | [MapObject\['styles'\]](/api/core/mapObject#property-styles) | โ€” | Applies map-object interaction styles to the lines path | Use native SVG presentation attrs like `stroke` directly on `MapGraticule` lines. ### Config Use `config` to call graticule generator methods before rendering ```ts { [methodName: string]: Arg | Arg[] } ``` 1. Single non-array value: `Arg | [Arg]` - pass directly or wrap with an array 2. Single array value: `[Arg]` - **must be wrapped** with an array 3. Multiple values: `[Arg1, Arg2, ...]` See available methods in [d3-geo graticule docs](https://d3js.org/d3-geo/shape#geoGraticule) ## Usage :::tabs key:framework \== Vue ```vue ``` \== React ```tsx ``` ::: ## Examples * [Graticule](/examples/graticule) --- --- url: 'https://d3-maps.netlify.app/components/map-line.md' description: 'Component for D3 SVG map lines, arcs, and curved paths in React and Vue' --- # MapLine Renders a path between map locations ## Props | Parameter | Type | Default | Description | | --- | --- | --- | --- | | `coordinates` | `[number, number][]` | โ€” | `[longitude, latitude][]` | | `cartesian?` | `boolean` | `false` | Treat `coordinates` as local SVG points and skip map projection | | `custom?` | `boolean` | `false` | Render using [d3-shape line](https://d3js.org/d3-shape/line) instead of default | | `curve?` | `CurveFactory \| CurveFactoryLineOnly` | `curveNatural` | Any [d3-shape curve](https://d3js.org/d3-shape/curve). Works only with `custom` or `cartesian` | | `midpoint?` | `[lengthwise: number, crosswise: number]` | โ€” | Adds a point between each coordinate pair. Value sets position relative to the line center in % from its length. | | `styles?` | [MapObject\['styles'\]](/api/core/mapObject#property-styles) | โ€” | See [styling guide](/guide/core-concepts/#styling) | You can also use native SVG attrs like `stroke`, `strokeWidth` right on the MapLine ::: details `midpoint` usage Line bend depending on `midpoint[1]` value | Line direction | Positive | Negative | | --- | --- | --- | | โ†’ | Up | Down | | โ† | Down | Up | | โ†“ | Left | Right | | โ†‘ | Right | Left | ::: ## Usage ::: details Custom curves and edges **Curves** By default renders a [great arc](https://en.wikipedia.org/wiki/Great-circle_distance) using [d3-geo path](https://d3js.org/d3-geo/path#_path) with `'LineString'` (looks ok usually).\ To control line bending use `custom` + `midpoint` + `curve`. See interactive [curve examples](https://www.d3indepth.com/examples-merged/shapes/curve-explorer/) **Edges โ†โ†’** Use native attributes [marker-start](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/marker-start) and [marker-end](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/marker-end) to make an arrow or any other custom form. ๐Ÿ‘€ See both in [connections example](/examples/connections) ::: :::tabs key:framework \== Vue ```vue ``` \== React ```tsx import { curveBasis } from 'd3-shape' ``` ::: --- --- url: 'https://d3-maps.netlify.app/components/map-marker.md' description: Component for D3 SVG map markers in React and Vue --- # MapMarker Positions anything on the map based on coordinates ## Props | Parameter | Type | Default | Description | | --- | --- | --- | --- | | `coordinates?` | `[number, number]` | โ€” | Marker coordinates in `[longitude, latitude]` format. | | `styles?` | [MapObject\['styles'\]](/api/core/mapObject#property-styles) | โ€” | See [styling guide](/guide/core-concepts/#styling) | ## Usage :::tabs key:framework \== Vue ```vue ``` \== React ```tsx {cities.map((item) => ( {item.city} ))} ``` ::: ## Examples * [Markers](/examples/markers) * [Bubble Map](/examples/bubble-map) --- --- url: 'https://d3-maps.netlify.app/components/map-mesh.md' description: Component for D3 SVG map TopoJSON borders and boundary lines in React and Vue --- # MapMesh Renders a TopoJSON mesh as an SVG ``.\ Use it to draw shared borders/edges (for example country boundaries) on top of feature fills. *โ„น๏ธ Works only with **TopoJSON** data* ## Props | Parameter | Type | Default | Description | | --- | --- | --- | --- | | `styles?` | [MapObject\['styles'\]](/api/core/mapObject#property-styles) | โ€” | See [styling guide](/guide/core-concepts/#styling) | Use native SVG presentation attrs like `stroke`/`fill` directly on `MapMesh`. ## Usage :::tabs key:framework \== Vue ```vue ``` \== React ```tsx ``` ::: --- --- url: 'https://d3-maps.netlify.app/components/map-zoom.md' description: Component for D3 SVG map pan and zoom in React and Vue --- # MapZoom Enables zoom and drag behavior using `d3-zoom`. Wrap layers that should be zoomed inside [MapZoom](/components/map-zoom). Use [useMapZoom](/helpers/use-map-zoom) inside `MapZoom` when controls or overlays need zoom state Keep `center` and `zoom` controlled in the parent and update them from the zoom callbacks ## Props | Parameter | Type | Default | Description | | --- | --- | --- | --- | | `center?` | `[number, number]` | viewport center | Point to be centered in the viewport | | `zoom?` | `number` | `1` | Controlled zoom level | | `minZoom?` | `number` | `1` | Minimum zoom scale | | `maxZoom?` | `number` | `8` | Maximum zoom scale | | `transition?` | [ZoomTransition](/api/core/zoom#zoomtransition) | โ€” | Animate zoom with [d3-transition](https://d3js.org/d3-transition) and [d3-ease](https://d3js.org/d3-ease) | | `config?` | [ZoomModifiers](/api/core/zoom#zoommodifiers) | โ€” | See the [guide](#config) below | ### Config Use `config` to call zoom methods before rendering ```ts { [methodName: string]: Arg | Arg[] } ``` 1. Single non-array value: `Arg | [Arg]` - pass directly or wrap with an array 2. Single array value: `[Arg]` - **must be wrapped** with an array 3. Multiple values: `[Arg1, Arg2, ...]` See available methods in [d3-zoom docs](https://d3js.org/d3-zoom) and usage example below ## Events :::tabs key:framework \== Vue Emits: * `zoomStart` * `zoom` * `zoomEnd` * `update:center` * `update:zoom` \== React Callbacks: * `onZoomStart` * `onZoom` * `onZoomEnd` ::: ## Usage :::tabs key:framework \== Vue ```vue ``` \== React ```tsx ``` ::: ## Helpers * [useMapZoom](/helpers/use-map-zoom) * [getZoomView](/helpers/get-object-zoom-view) ## Examples * [Zoom](/examples/zoom) * [Programmatic Zoom](/examples/programmatic-zoom) --- --- url: 'https://d3-maps.netlify.app/guide/migration-from-react-simple-maps.md' description: >- Migration guide from react-simple-maps to @d3-maps/react, covering component, prop, styling, and zoom API equivalents --- # Migrate from react-simple-maps [@d3-maps/react](/components/) is fully compatible with [react-simple-maps](https://www.react-simple-maps.io/)\ But in case feel free to open an [issue](https://github.com/souljorje/d3-maps/issues) or pull request ## Migration checklist | Step | Change | | --- | --- | | Data | `Geographies.geography` -> `MapBase.data` | | Data transform | `Geographies.parseGeographies` -> `MapBase.dataTransformer` | | Style prop | `Geography.style` -> `MapFeature.styles` | | Style states | `style.pressed` -> `styles.active` | | Zoom wrapper | `ZoomableGroup` -> `MapZoom` | | Marker | `Marker` -> `MapMarker` | | Line | `Line` -> `MapLine` | | Annotation | `Annotation` -> `MapAnnotation` | | Graticule | `Graticule` -> `MapGraticule` | | Sphere | `Sphere` -> `MapGraticule` (`background`/`border`) | ## 1. Migrate data * `Geographies.geography` -> `MapBase.data`\ `MapBase.data` supports only data objects, not URLs, data fetching is non-opinionated * `Geographies.parseGeographies` -> `MapBase.dataTransformer` ```tsx import { MapBase, MapFeatures, type MapData } from '@d3-maps/react' import { useEffect, useState } from 'react' export function WorldMap() { const [data, setData] = useState(null) useEffect(() => { fetch('/world-110m.json') .then((res) => res.json()) .then((json) => setData(json as MapData)) }, []) if (!data) return null return ( features.filter((f) => f.properties?.name !== 'Antarctica')} > ) } ``` ## 2. Rename style prop * `Geography.style` -> `MapFeature.styles` * `style.pressed` -> `styles.active` This style model is supported by `MapFeature`, `MapFeatures`, `MapMarker`, `MapMesh`, and `MapGraticule` ```tsx ``` You can still use plain SVG attributes like `fill`, `stroke`, and `strokeWidth` directly on map components. ## 3. Rename zoom component `ZoomableGroup` -> `MapZoom` and rename events: * `onMoveStart` -> `onZoomStart` * `onMove` -> `onZoom` * `onMoveEnd` -> `onZoomEnd` ```tsx {}} onZoom={() => {}} onZoomEnd={() => {}} > ``` ## 4. Rename marker component `Marker` -> [MapMarker](/components/map-marker). ```tsx NYC ``` ## 5. Rename graticule component `Graticule` -> [MapGraticule](/components/map-graticule). ```tsx ``` ## 6. Migrate sphere component `Sphere` -> [MapGraticule](/components/map-graticule) with `background` and/or `border`. ```tsx ``` ## 7. Rename line component `Line` -> [MapLine](/components/map-line) `react-simple-maps` line props map directly to `MapLine.coordinates` ```tsx ``` ## 8. Migrate annotation component `Annotation` -> [MapAnnotation](/components/map-annotation) ```tsx Paris ``` ## Component mapping | react-simple-maps | d3-maps | | --- | --- | | [ComposableMap](https://www.react-simple-maps.io/docs/composable-map/) | [MapBase](/components/map-base) | | [Geographies](https://www.react-simple-maps.io/docs/geographies/) | [MapFeatures](/components/map-features) | | [Geography](https://www.react-simple-maps.io/docs/geography/) | [MapFeature](/components/map-feature) | | [Marker](https://www.react-simple-maps.io/docs/marker/) | [MapMarker](/components/map-marker) | | [Line](https://www.react-simple-maps.io/docs/line/) | [MapLine](/components/map-line) | | [ZoomableGroup](https://www.react-simple-maps.io/docs/zoomable-group/) | [MapZoom](/components/map-zoom) | | [Graticule](https://www.react-simple-maps.io/docs/graticule/) | [MapGraticule](/components/map-graticule) | | [Sphere](https://www.react-simple-maps.io/docs/sphere/) | [MapGraticule](/components/map-graticule) (`background`/`border`) or a custom SVG layer | | [Annotation](https://www.react-simple-maps.io/docs/annotation/) | [MapAnnotation](/components/map-annotation) | --- --- url: 'https://d3-maps.netlify.app/guide/troubleshooting.md' description: >- Troubleshooting guide for D3 SVG maps in React and Vue, including blank maps, misplaced markers, broken projections, and layer issues --- # Troubleshooting ## Blank map * Ensure the map container has a height (see [Responsiveness](/guide/core-concepts/#responsiveness)) * Ensure `data` is loaded before rendering [MapBase](/components/map-base) * Ensure you imported [default stylesheet](/guide/core-concepts/#css) or defined width and height for the map ## Markers appear in the wrong place Coordinates are `[longitude, latitude]` ## Layers overlap unexpectedly If something overlays incorrectly, render layers top-to-bottom in this order: * `MapGraticule` * `MapFeatures` * `MapMesh` * `MapMarker` --- --- url: 'https://d3-maps.netlify.app/helpers/use-create-map-context.md' description: >- Helpers for creating and reusing shared D3 SVG map context outside the root map component with React and Vue --- # useCreateMapContext Creates a reusable map context in the parent Use it when `MapBase` and sibling UI should share the same resolved map state ## Return value | Adapter | Type | | --- | --- | | `@d3-maps/vue` | `ComputedRef` | | `@d3-maps/react` | `MapContext \| undefined` | See [MapContext API](/api/core/map#mapcontext) ## Parameters | Parameter | Type | Default | Description | | --- | --- | --- | --- | | `config?` | `MapProps` | `โ€”` | Used to create a new context when `context` is not provided | | `context?` | `MapContext` | `โ€”` | Optional existing context to reuse instead of creating a new one | ## Usage Create the context once in the parent, pass it to sibling UI by prop, and pass the same object into `MapBase` :::tabs key:framework \== Vue ```vue ``` \== React ```tsx import { MapBase, MapFeatures, useCreateMapContext, type MapData, } from '@d3-maps/react' export function Example({ data }: { data: MapData }) { const context = useCreateMapContext({ data, width: 420, }) if (!context) return null return ( <> ) } ``` ::: If neither `config.data` nor `context` is available yet, the helper returns `undefined` ## Best Practice * Use `useCreateMapContext` in the parent when controls, toolbars, or other sibling UI need the same map context as `MapBase` * Use [useMapContext](/helpers/use-map-context) inside custom layers rendered under `MapBase` * Use `MapBase` slot or render-prop context when that already gives you what you need ## Examples * [Programmatic Zoom](/examples/programmatic-zoom) --- --- url: 'https://d3-maps.netlify.app/helpers/use-map-context.md' description: >- Helper for reading map size, features, and path state inside custom D3 SVG map layers with React and Vue --- # useMapContext Reads the current map context from [MapBase](/components/map-base)\ Use it in custom layers when you need the resolved map size, normalized features, or the shared path generator\ Throws an error if used outside `MapBase` ## Return value | Adapter | Type | | --- | --- | | `@d3-maps/vue` | `ComputedRef` | | `@d3-maps/react` | `MapContext` | See [MapContext API](/api/core/map#mapcontext) ## Usage :::tabs key:framework \== Vue ```vue ``` \== React ```tsx import { useMapContext } from '@d3-maps/react' function FeatureCountLabel() { const context = useMapContext() return ( {context.features.length} features ) } ``` ::: ## Best Practice * Use `useMapContext` in components rendered inside `MapBase` * Use `MapBase` slot/render-prop context when that already gives you what you need * Use [useCreateMapContext](/helpers/use-create-map-context) in the parent and pass the same `context` object to both `MapBase` and any sibling UI that needs it --- --- url: 'https://d3-maps.netlify.app/helpers/use-map-object.md' description: >- Helper for interaction state and resolved styles on custom D3 SVG map objects with React and Vue --- # useMapObject Provides interaction-state transitions and resolved styles for custom map SVG elements. Used internally by [MapFeature](/components/map-feature), [MapLine](/components/map-line), [MapAnnotation](/components/map-annotation), [MapMarker](/components/map-marker), and [MapMesh](/components/map-mesh) ## Usage :::tabs key:framework \== Vue ```vue ``` \== React ```tsx import type { CSSProperties } from 'react' import { useMapObject, type MapObjectProps } from '@d3-maps/react' export function CustomFeaturePath({ d }: { d: string }) { const styles: MapObjectProps['styles'] = { default: { opacity: 0.9, }, focus: { stroke: 'darkgreen', }, hover: { opacity: 0.8, }, active: { stroke: 'green', }, } const { style, ...events } = useMapObject({ styles, }) return ( ) } ``` ::: --- --- url: 'https://d3-maps.netlify.app/helpers/use-map-zoom.md' description: >- Helper for reading zoom state and zooming to map objects on D3 SVG maps with React and Vue --- # useMapZoom Reads the current zoom state from [MapZoom](/components/map-zoom)\ Use it inside `MapZoom` when you need zoom values\ Returns `undefined` if used outside `MapZoom` ## Return value | Property | Type | | --- | --- | | `center` | `[number, number] \| undefined` | | `zoom` | `number` | | `minZoom` | `number` | | `maxZoom` | `number` | | `zoomToObject(object, callback)` | `(object: ZoomObject, callback: (view: ObjectZoomView) => void) => void` | ## `zoomToObject` Computes a fitted zoom view for the given object and passes the full [`ObjectZoomView`](/api/core/zoom#objectzoomview) to the callback ::: ## Best Practice * Use [useMapContext](/helpers/use-map-context) alongside it when controls need map features or the shared path generator * Use `zoomToObject` to derive a fitted view, then hand the resulting `center` and `zoom` back to parent-controlled state