Skip to main content

WorldMap

Every example on this page is live, drawn by the library's Storybook, where you can also change its props and see the result.

A monochromatic SVG map of the world, shading its countries using fill patterns and optional numeric labels. Supports three map projections: Natural Earth (default), Mercator, and Equirectangular. The map keeps its proportions, filling as much of its box as it can and centered in the rest, in any box it is laid out in. height="fill" sizes the box to the map instead.

Import​

import {
WorldMap,
COUNTRY_NAMES,
countryNameFor,
worldMapAspect,
} from "~lib/data-display/maps/world-map";

Props​

NameTypeRequiredDefaultDescription
dataPartial<Record<CountryName, WorldMapEntry>>YesN/APer-country shading and optional value
projection"natural-earth" | "mercator" | "equirectangular"No"natural-earth"Map projection to use
showValuesbooleanNofalseRender numeric labels at country centroids
markersMapMarker[]NoN/APlaces to mark, each in its shape with an optional name beside it
legendMapLegendEntry[]NoN/AWhat each marker shape stands for, in a row under the map
widthnumber | stringNo300Component width (px or CSS string); with height="fill", the column's width unless given
heightnumber | "fill" | stringNo300Component height (px or CSS string), or "fill" to be as tall as its width makes it

CountryName​

Every country the map draws. Examples: "United States", "China", "India", "Brazil", "Russia", "Japan", "Germany", "United Kingdom", "Australia", "South Africa". COUNTRY_NAMES lists them all.

countryNameFor​

countryNameFor(name: string): CountryName | undefined

The map's name for a country however it is written: a long or official form ("United States of America", "Korea, Republic of"), an ISO 3166-1 two- or three-letter code ("GB", "DEU"), the name it went by ("Burma", "Swaziland") or a common spelling ("Holland", "UK"), in any case, with or without accents. It returns nothing for a country the map does not draw, such as a city state too small for it, so a widget can tell which of its places it can shade and which it should mark with markers instead. Pass the names an installer picks or an API returns through it before keying data with them.

worldMapAspect​

worldMapAspect(projection?: Projection): number

The width over the height of the countries in a projection (Natural Earth unless given), for a widget that sizes the map's box itself. height="fill" uses it for you.

WorldMapEntry​

type WorldMapEntry = {
shading: "solid" | "diagonal" | "dots" | "crosshatch";
value?: number;
};

Projection​

ValueDescription
"natural-earth"Pseudocylindrical compromise projection (default) - good general-purpose
"mercator"Conformal cylindrical - preserves angles but distorts area at high lats
"equirectangular"Simple lat/lon grid - minimal distortion near equator

MapMarker​

type MapMarker = {
latitude: number;
longitude: number;
label?: string;
shape?: "circle" | "square" | "triangle" | "diamond"; // "circle" by default
};

MapLegendEntry​

type MapLegendEntry = {
shape: "circle" | "square" | "triangle" | "diamond";
label: string;
};

Examples​

Default (Natural Earth)​

Open Default in Storybook

With Values​

Open With Values in Storybook

Mercator​

Open Mercator in Storybook

Equirectangular​

Open Equirectangular in Storybook

All Patterns​

Open All Patterns in Storybook

Many Countries​

Open Many Countries in Storybook

With Markers​

markers puts a dot on each place you give, so a place too small to shade, such as Monaco or Singapore, still shows. A label sits beside its dot where there is room for it, and is left out where it would run off the map or cover another marker.

Open With Markers in Storybook

On a map drawn small the labels are left out and only the dots show.

Open Small With Markers in Storybook
import { WorldMap } from "~lib/data-display/maps/world-map";

const Circuit = ({
name,
latitude,
longitude,
}: {
name: string;
latitude: number;
longitude: number;
}) => (
<WorldMap
data={{}}
markers={[{ latitude, longitude, label: name }]}
width="100%"
height="100%"
/>
);

Marker Shapes​

A marker's shape tells kinds of place apart on one map, such as several species, teams or fleets. Every shape covers the same area, so none reads heavier than another. legend names what each shape stands for in a row under the map, in the order given, wrapping onto further rows when it outgrows the width. The legend is left out of a box too narrow or too short to hold it beside the map, where the map alone says more.

Open Marker Shapes in Storybook
<WorldMap
data={{}}
markers={sightings.map(({ latitude, longitude, species }) => ({
latitude,
longitude,
shape: SHAPES[species],
}))}
legend={species.map((name) => ({ shape: SHAPES[name], label: name }))}
width="100%"
height="100%"
/>

Filling a Column's Width​

height="fill" makes the box as tall as its width makes it at the countries' proportion, with the projection fitted to the countries alone, so a map across the top of a column takes no more height than it draws in and the text under it starts where the countries end. In a flex column it spans the column, or width when given, and is the first to shrink when the column runs short, the map then centered in the room that is left. A legend sits under the map, outside its proportion.

Open Fills Its Width in Storybook
Open Fills A Short Column in Storybook
<div className="flex h-full flex-col gap-2">
<WorldMap data={data} height="fill" />
<Heading level={4}>Sightings</Heading>
</div>

Countries By Any Name​

Open Countries By Any Name in Storybook
import { WorldMap, countryNameFor } from "~lib/data-display/maps/world-map";

const data = Object.fromEntries(
apiCountries.flatMap((written) => {
const country = countryNameFor(written);
return country ? [[country, { shading: "solid" }]] : [];
}),
);

See Also​

  • USMap - United States detail map
  • UKMap - United Kingdom detail map
  • EuropeMap - Europe detail map
  • Badge - Inline label for status or counts