Layers and measures
Area, point and context layers, measures per object, and the fill and size encodings.
@workspace/active-geo 0.4.0Developmentunreleased, in development in Foundationbaseline ce081dc3
Sites sized by their staffClient
Loading the map…
// apps/docs/examples/geo/points.tsx'use client';
import {useEffect, useState} from 'react';
import { englishGeoTranslator, GeoMap, type GeoAreaFeature, type GeoContextGeometry,} from '@workspace/active-geo';import { loadWorld50m, world50m,} from '@workspace/active-geo/collections/world-50m';
const BENELUX = new Set(['NLD', 'BEL', 'LUX']);
// Invented sites, sized by their staff.const SITES = [ {key: 'ams', name: 'Amsterdam', latitude: 52.37, longitude: 4.9, staff: 120}, {key: 'rtm', name: 'Rotterdam', latitude: 51.92, longitude: 4.48, staff: 64}, {key: 'utr', name: 'Utrecht', latitude: 52.09, longitude: 5.12, staff: 38}, {key: 'ein', name: 'Eindhoven', latitude: 51.44, longitude: 5.47, staff: 45}, {key: 'bru', name: 'Brussels', latitude: 50.85, longitude: 4.35, staff: 72}, {key: 'ant', name: 'Antwerp', latitude: 51.22, longitude: 4.4, staff: 51}, {key: 'lux', name: 'Luxembourg', latitude: 49.61, longitude: 6.13, staff: 19},];
/** * Point symbols over context geometry, sized by a count, with a legend, a * tooltip and selection (click, or Enter on a focused point). */export default function SitesMap() { const [outline, setOutline] = useState<GeoAreaFeature[] | null>(null); useEffect(() => { let current = true; void loadWorld50m().then((loaded) => { if (current) setOutline(loaded.filter((f) => BENELUX.has(String(f.key)))); }); return () => { current = false; }; }, []); if (!outline) { return <p className="text-muted-foreground text-sm">Loading the map…</p>; } return ( // The map takes the width of its container (a ResizeObserver); // in a centring layout the host gives it one. <div className="w-full"> <GeoMap title="Sites in the Benelux" projection="conic-equal-area" locale="en-GB" t={englishGeoTranslator} attribution={world50m.attribution} layers={[ { type: 'context', id: 'benelux', title: 'Benelux', // Context, not the frame: the Netherlands of Natural Earth // include the Caribbean islands, so the sites frame the map. fit: false, geometries: outline.flatMap((feature): GeoContextGeometry[] => feature.geometry ? [feature.geometry] : [], ), }, { type: 'point', id: 'sites', title: 'Sites', measures: [ {id: 'staff', label: 'Staff', semantics: {kind: 'count'}}, ], marker: {size: {measure: 'staff'}}, points: SITES.map(({staff, ...site}) => ({ ...site, values: {staff}, })), }, ]} /> </div> );}Layers#
type | Holds | Interactive |
|---|---|---|
area | features: {key, name?, geometry, values?, details?} | yes |
point | points: {key, latitude, longitude, name?, values?, details?} | yes |
context | geometries: areas and lines | no |
Area values can be inline (values) or joined by key from separate records (data), never both.
Measures#
A layer declares its measures: {id, label, semantics?} for a number (with the family's value
semantics: count, money, percent, …) or {id, label, kind: 'category', categories}. A value
per object is a number, a category id, missing (null or absent) or withheld
({suppressed: true}): a withheld value is never shown as a number.
Encodings#
- Fill of areas (and points):
{measure, scale}with a classed scale (threshold,quantize,categoryordiverging), or a constant colour. End classes are open. - Size of points:
{measure, domainMax?, maxRadius?}: the area of a circle is proportional to the value; zero, missing and withheld draw a hollow marker.
The legend explains every encoding that needs it, including the special states (no value, withheld).
Text#
Tooltip, labels and the accessible description read the same fields: 'name', {measure},
{encoding: 'fill'}, {detail}. Labels on areas and points are placed so they do not collide.