Dotted Map
Show locations on a dotted world or regional map with custom pins and colors.
Use DottedMap to show office locations, customers, or global coverage. The world geometry is bundled. Add your pins and choose a dot density; the map inherits your application's chart theme.
Add Locations
Pins use lat and lng in degrees. Set label and color directly, or keep the v2 svgOptions API. svgOptions.radius is measured in grid cells; pinSize and a pin's radius are measured in pixels.
<script setup lang="ts">
const pins = [
{ lat: 40.7128, lng: -74.006, label: 'New York', color: '#3b82f6' },
{ lat: 51.5074, lng: -0.1278, label: 'London', color: '#22c55e' },
{ lat: 35.6762, lng: 139.6503, label: 'Tokyo', color: '#f59e0b' },
{ lat: -33.8688, lng: 151.2093, label: 'Sydney', color: '#ef4444' }
]
</script>
<template>
<DottedMap
:pins="pins"
:height="360"
:map-height="75"
:dot-size="0.3"
color="var(--ui-bg-accented)"
aria-label="Office locations"
/>
</template>
The component renders only pins you provide. Pin labels appear in tooltips; showPinLabels also renders them above the markers. Use pinColor and pinSize with a fixed value or a (pin, index) accessor.
Change the Dot Grid
mapHeight controls rows; mapWidth controls columns and takes precedence when both are set. The component calculates spacing from the map's rendered size. dotSize is a radius in grid cells: 0.3 leaves space between dots and 0.5 makes neighboring circles touch.
<template>
<DottedMap :height="360" :map-height="50" :dot-size="0.3" grid="diagonal" />
</template>
Set shape="hexagon" for six-sided dots. strokeColor, strokeWidth, and strokeOpacity style dot outlines. Country colors are keyed by the bundled map's ISO alpha-3 IDs:
<DottedMap :country-colors="{ NLD: '#3b82f6', USA: '#22c55e' }" />
Focus on a Region
Use regionName="europe", "asia", "oceania", or "usa" for a preset. The default is "world". Use countries to select ISO alpha-2 or alpha-3 country codes, or region to provide latitude/longitude bounds:
<DottedMap :countries="['NLD', 'BEL', 'DEU']" />
<DottedMap
:region="{ lat: { min: 45, max: 60 }, lng: { min: -10, max: 20 } }"
/>
A longitude range with min > max crosses the date line. avoidOuterPins hides pins outside the selected land geometry. Pins outside the visible region are hidden. Set geoJson to use a custom GeoJSON or TopoJSON dataset. mapFeatureKey selects a TopoJSON object.
Projection and Zoom
The default projection is Mercator, with the world view spanning latitude -60° to 85°. Other projection names are naturalEarth, equalEarth, equirectangular, orthographic, and albersUsa. Custom D3 projections and factories are accepted; dotted grids require an invertible projection.
Drag, pinch, or double-click to zoom. zoomOnScroll enables wheel zoom; showControls adds zoom/reset buttons. disableZoom disables gestures. Keyboard users can pan with arrow keys, zoom with +/-, and reset with 0/Home. Pin focus reveals its tooltip; Enter or Space emits pin-click.
Use a component ref to call zoomIn(), zoomOut(), zoomTo(scale), or resetView(). Configure initial scale with zoomFactor (defaultZoom remains an alias) and limits with zoomExtent.
Tooltips and Legends
Pins can contain custom fields under data. Numeric fields appear in the default tooltip. A tooltip slot receives the original pin or dot and its kind:
<DottedMap :pins="pins">
<template #tooltip="{ values }">
<div class="rounded-lg bg-elevated px-3 py-2 text-sm">
{{ values.label ?? values.data?.city }}
</div>
</template>
</DottedMap>
Use categories for the same legend API as other charts, or pass legend items with { label, color }. hideLegend and :show-legend="false" hide it. The legend slot receives items.
The pin and dot slots replace individual SVG marks and receive typed values, x, y, color, radius, scale, projection, and points. The default slot renders SVG overlays in the zoomed group and receives points, projection, width, height, and transform.
Precompute a Map
The auto-imported getMap helper produces JSON-serializable dot data. Supply it through precomputedMap to skip grid generation. getPin finds a pin's nearest grid position:
const map = getMap({ height: 75, grid: 'diagonal', countries: ['NLD', 'BEL', 'DEU'] })
const pin = getPin(map, { lat: 52.3676, lng: 4.9041 })
<DottedMap :precomputed-map="map" :pins="[pin]" />
Pass either the object or its JSON string. The component does not mutate it when rendering pins.
Props
Geography and Dots
| Prop | Type | Default | Purpose |
|---|---|---|---|
geoJson | MapGeometry | Bundled world | Custom land geometry. |
mapFeatureKey | string | Auto | Custom TopoJSON object name. |
regionName | 'world' | 'europe' | 'asia' | 'oceania' | 'usa' | 'world' | Region preset. |
region | MapRegion | World/preset bounds | Explicit latitude/longitude bounds. |
countries | string[] | All | ISO country filter. |
height / width | number | string | 400 / '100%' | Container dimensions. |
mapHeight / mapWidth | number | 60 rows | Grid density; columns take precedence. |
grid | 'vertical' | 'diagonal' | 'vertical' | Regular or staggered grid. |
shape | 'circle' | 'hexagon' | 'circle' | Dot shape. |
dotSize | number | 0.3 | Dot radius in grid cells. |
color | string | Theme | Default dot color. |
countryColors | Record<string, string> | — | Colors by ISO alpha-3 ID. |
strokeColor, strokeWidth, strokeOpacity | String / number / number | — / 0 / 1 | Dot outlines; width is in grid cells. |
precomputedMap | PrecomputedMap | string | — | Serialized dot data. |
backgroundColor | string | Transparent | Map background. |
projection | Name, D3 projection, or factory | 'mercator' | Invertible projection. |
fitView, fitViewPadding, padding | Shared map options | true / 12 / — | Projection fitting. |
Pins and Shared Chart Options
| Prop | Type | Default | Purpose |
|---|---|---|---|
pins | MapPin[] | [] | Your locations. |
pinColor | String or accessor | Pin color / primary | Marker color. |
pinSize | Number or accessor | Pin radius / 5 | Marker radius in pixels. |
showPinLabels | boolean | false | Visible marker labels. |
avoidOuterPins | boolean | false | Require pins to lie on selected land. |
maxDataPoints | number | 2000 | Maximum pins; dot density is independent. |
disableZoom, zoomOnScroll, showControls | boolean | false | Interaction options. |
zoomFactor / defaultZoom | number | 1 | Initial/reset scale. |
zoomExtent | [number, number] | [1, 8] | Scale limits. |
zoomDuration / duration | number | 250 | Zoom animation; respects reduced motion. |
showSphere, showGraticule | boolean | false | Globe outline and grid. |
sphereColor, graticuleColor | string | Theme | Outline/grid colors. |
categories, legendPosition, legendStyle, legendVariant, hideLegend | Shared chart options | Bottom center | Legend styling. |
legend / showLegend | MapLegendItem[] / boolean | — / true | Legacy legend API. |
hideTooltip, tooltipVariant, tooltipRoundness | Shared chart options | Chart defaults | Tooltip styling. |
tooltipTitleFormatter | (pinOrDot) => string | number | Label | Tooltip title. |
theme | ChartTheme | Host tokens | Shared per-map theme. |
maxHeight | number | string | — | Maximum root height. |
loading, loadingLabel, error, emptyLabel | Shared chart options | — | Loading, error, and empty states. |
ariaLabel, ariaDescription, accessibleDataTable | Shared chart options | Table enabled | Accessibility. |
Events
pin-click emits (pin, event). The v2 point-click event for a land dot keeps its (event, dot) order. mouseenter and mouseleave emit (values, event) for pointer hover and keyboard focus. zoom emits { x, y, k }.
Dotted grids use D3 geographic projections and spherical containment. For filled regions and routes, see TopoJSON Map.