Distance from here
A round map with one place at the centre and every other place at its true distance and direction. Re-centring grows the map outward.
Your data
Pass your places as places. Without it the component shows 15 demo cities, centred on London. See Your data.
Playground
Change a prop and the component re-renders. Props marked remounts set an initial value, so the component starts over.
<GeoAzimuthal defaultRings="distance" unit="km" stretch={1.5} />Installation
pnpm dlx shadcn@latest add @lumesec/geo-azimuthalFirst timeRegister the @lumesec registry once, or install by URL+
Adds @lumesec to your components.json:
pnpm dlx shadcn@latest registry add @lumesec=https://elements.lumesec.ai/r/{name}.jsonOr skip the setup and install by URL:
npx shadcn@latest add https://elements.lumesec.ai/r/geo-azimuthal.jsonUsage
import { GeoAzimuthal, type AzimuthalPlace } from "@/components/lumesec/geo-azimuthal";
const regions: AzimuthalPlace[] = [
{ id: "fra", label: "Frankfurt", lat: 50.11, lon: 8.68 },
{ id: "iad", label: "Ashburn", lat: 39.04, lon: -77.49 },
{ id: "gru", label: "São Paulo", lat: -23.55, lon: -46.63 },
{ id: "bom", label: "Mumbai", lat: 19.08, lon: 72.88 },
{ id: "nrt", label: "Tokyo", lat: 35.68, lon: 139.65 },
{ id: "syd", label: "Sydney", lat: -33.87, lon: 151.21 },
];
export function Example() {
return <GeoAzimuthal places={regions} defaultCenter="fra" defaultRings="latency" />;
}Behaviour
A round map that puts one place at the centre and every other place at its true distance and direction from it. Dotted rings mark every 2,000 km, or every 50 ms of round-trip time, and the outer edge is the point on the other side of the world.
Pick another place and the map re-centres there: every dot moves to its new position, starting with those nearest the new centre, so the map grows outward from it. The distances in the list roll to their new values.
API reference
Props
Also accepts every prop of <div> (React.ComponentProps<"div">), spread onto the root element.
centerTypestring | LatLonThe centre (controlled): a place id, or any { lat, lon } point. Use with onCenterChange.
defaultCenterTypestring | LatLonDefault"lhr"The centre when uncontrolled. An id that is not in places falls back to the first place, and to 0° N, 0° E when there are none.
onCenterChangeType(center: string | LatLon) => voidCalled when the user picks a new centre: the place id for a place, a { lat, lon } point for a click on the map away from the places.
placesTypereadonly AzimuthalPlace[]Default15 demo citiesThe places to measure: { id, label, lat, lon }. Ids must be unique; a repeated id keeps its first place. An empty array shows the land and the rings, with emptyText in the list.
ringsType"distance" | "latency"What the rings and the list measure (controlled): great-circle distance, or the round trip in fibre. Use with onRingsChange.
defaultRingsType"distance" | "latency"Default"distance"What the rings and the list measure when uncontrolled.
onRingsChangeType(rings: "distance" | "latency") => voidCalled when the user switches between Distance and Latency.
ringStepTypenumberDefault2000 km, 1000 mi or 50 msSpacing of the rings in the unit shown: km or mi for distance, ms of round trip for latency.
unitType"km" | "mi"Default"km"Distance unit of the rings and the list.
stretchTypenumberDefault1.5How much longer the fibre path is than the great circle. The round trip is 2 × distance ÷ 204 km/ms × stretch.
labelTypestringDefault"Distance from the centre"Accessible name of the map. The map's aria-label adds the centre and the ring step.
emptyTextTypestringDefault"No places"Text shown in the list when places is an empty array.
Ref
ref points at the root HTMLDivElement.
Keyboard
| Keys | Action |
|---|---|
| Tab | Moves focus to the places on the map, then to the Distance / Latency switch. The places share one tab stop: the last one focused, else the centre. |
| ArrowLeft / ArrowRight / ArrowUp / ArrowDown | On a place: move focus to the nearest place in that direction on the map. On the switch: select the other option. |
| Home / End | Move focus to the centre / the farthest place. |
| Enter / Space | Re-centre the map on the focused place. |
Accessibility
- The map has
role="group",aria-roledescription="map"and anaria-labelmade oflabel, the centre and the ring step, for example "Distance from the centre: London. Rings every 2,000 km." - Each place is a native
<button>with anaria-labelof its name and distance; the centre hasaria-pressed="true". - The Distance / Latency switch is a
radiogroupof tworadiobuttons with a roving tab stop. - The heading above the list is a polite live region, so a new centre is announced.
- The list is an ordered list of real text, sorted by distance. Its values stay text while they roll; outgoing values are hidden from assistive technology.
- The canvases, the ring labels and the place labels on the map are
aria-hidden; the buttons and the list carry the same information. - Reduced motion: the land appears at once, re-centring jumps without the staggered move, the ping, the sparks or the ring draw-on, the route of a pointed place appears without growing, list rows move to their new order at once, and values change without rolling.
Theming
Styled with Tailwind classes on your shadcn theme tokens, so light and dark follow your theme. The accent comes from --lumesec. See Theming.
This component reads --lumesec, --lumesec-soft, --lumesec-glint, --foreground, --muted-foreground, --muted, --card and --border.
Notes
- The projection is azimuthal equidistant: the distance from the centre is the true great-circle distance, the direction is the initial bearing with north up, and the rim is the antipode. Land on the far side spreads along the rim, as it does on every map of this kind.
- Latency is an estimate, not a measurement: the round trip in fibre at 204 km per ms, over a path
stretchtimes the great-circle distance. Pass real measurements to your own list if you have them. - Pointing at a place draws its great-circle route, which is a straight line on this map, and the circle of everything just as far from the centre.
- A click on the map away from the places re-centres it on that point, shown as an unlabelled crosshair, and calls
onCenterChangewith{ lat, lon }. Keyboard users re-centre on places;centertakes any point. - From 560 px wide the list sits beside the map; below that it sits underneath, in two columns from 400 px.
- Place labels place themselves around their points and stay clear of the ring labels and of each other. A label that has no room stays hidden until its place is pointed at.
- The animation runs only while something moves and pauses off screen.
Related
Was this page helpful?