Skip to content

alexbgh1/react-chile-map

Repository files navigation

react-chile-map

React components for data driven choropleth maps of Chile. The package includes processed BCN cartography for regions and lazy loadable provincia/comuna maps scoped to each region.

Features

  • Three ready to use components: ChileMap (16 regions), RegionComunasMap, and RegionProvinciasMap (one region subdivided into comunas/provincias), all sharing the same props.
  • Data driven choropleths: provide { officialCode: value } and the component resolves colors, interactions, and tooltips. Values join by official codes (regions "01"-"16", comuna CUT, provincia codes).
  • Bundled cartography, lazy by region: the national TopoJSON is ~151 KB; each region's comunas/provincias ship as separate 2-102 KB files imported on demand and cached.
  • Full territory with automatic insets: Rapa Nui and Juan Fernández render in side inset boxes with their own projection; oceanicIslands={false} switches to a mainland only view.
  • Three scale types plus <Legend>: linear, quantile, and threshold scales built from a shared descriptor (scaleFromData), so the legend can never diverge from the map. colorFor gives per unit control.
  • Interactions built in: hover tooltips (default, custom render prop, or disabled, with edge collision handling), click callbacks with semantic feature types, and controlled selection with stroke/fill/both highlight modes.
  • Keyboard accessible: with onClick, units become role="button" paths with a roving tab index, arrow-key navigation, Enter/Space activation, focus tooltips, and aria-pressed selection state.
  • Localizable labels: featureLabel changes presentation text (tooltips, aria-label) by stable code while canonical BCN names stay untouched in callbacks.
  • React first and SSR friendly: React owns the SVG tree (d3 only projects); regional components accept a topology override for server rendering, tests, and preloading. React 17-19.
  • Resilient partial data: units without values use fillDefault; problems surface as deduplicated development-only warnings, never crashes or production noise.
  • Typed end to end: RegionCode, ComunaCode, ProvinciaCode, opt-in regional data types, feature callbacks, scales, and every prop ship as TypeScript types.

Install

npm install react-chile-map

National region map

The national component keeps topology loading explicit so applications control when the larger national geometry is downloaded.

import { ChileMap } from "react-chile-map";
import regiones from "react-chile-map/data/regiones.json";
import type { Topology } from "topojson-specification";

<ChileMap
  topology={regiones as unknown as Topology}
  data={{ "13": 8_242_459, "05": 2_003_119 }}
  colors={["#dbeafe", "#1e40af"]}
  bins={6}
  scaleType="quantile"
  selected="13"
  highlightMode="both"
  onClick={(region) => console.log(region.code, region.name)}
  tooltip={(region) => <strong>{region.name}</strong>}
  formatValue={(value) => value.toLocaleString("es-CL")}
  width={340}
  height={720}
/>;

Comunas inside a region

RegionComunasMap loads the matching bundled topology from its region prop. Values are keyed by five digit comuna CUT codes.

import { RegionComunasMap } from "react-chile-map";

<RegionComunasMap
  region="13"
  data={{ "13101": 100, "13114": 82, "13201": 91 }}
  onClick={(comuna) => {
    console.log(comuna.code);
    console.log(comuna.region);
    console.log(comuna.province, comuna.provinceName);
  }}
  loadingFallback={<p>Loading comunas…</p>}
  errorFallback={(error) => <p>{error.message}</p>}
  onLoadError={(error) => reportError(error)}
/>;

Provincias inside a region

RegionProvinciasMap follows the same API and uses three digit provincia CUT codes.

import { RegionProvinciasMap } from "react-chile-map";

<RegionProvinciasMap
  region="13"
  data={{ "131": 100, "132": 78, "133": 52 }}
  onHover={(provincia) => console.log(provincia?.region)}
/>;

region is typed as the zero padded RegionCode union ("01" through "16"). Both regional components cache successful topology imports. Passing a new region ignores stale in flight results.

Optional regional data key types

The bundled codes for all 16 regions are available as opt-in types. Use satisfies to catch unknown codes or codes from another region while preserving the flexible Record<string, number> component prop:

import type { ComunaData, ProvinciaData } from "react-chile-map";

const comunaData = {
  "13101": 50,
  "13113": 82,
} satisfies ComunaData<"13">;

const provinciaData = {
  "131": 100,
  "132": 78,
} satisfies ProvinciaData<"13">;

<RegionComunasMap region="13" data={comunaData} />;
<RegionProvinciasMap region="13" data={provinciaData} />;

ComunaCode<R> and ProvinciaCode<R> expose the corresponding exact code unions. The opt-in types describe the bundled BCN data and do not restrict dynamic records or custom topology codes passed directly to the components.

Topology override

Use topology to bypass the built in lazy loader:

<RegionComunasMap region="13" topology={preloadedTopology} data={data} />

This supports SSR, tests, application level preloading, and custom cartography.

Shared behavior

All components support:

  • linear or quantile color scales;
  • custom colorFor logic;
  • localized presentation labels through featureLabel, without changing canonical BCN names;
  • controlled selection;
  • hover and click callbacks with level specific feature types;
  • default or custom tooltips;
  • stroke, fill, or both highlight modes;
  • configurable missing data, border, highlight, and size props;
  • automatic side insets for oceanic islands, or oceanicIslands={false} for a mainland-only view.

Missing values are normal and render with fillDefault (#e2e8f0 by default). In development, the package emits one aggregated console.warn for data codes absent from the current topology and another for non finite values. Every finite value in data, including values for codes outside the current topology, participates in the scale domain.

Localized feature labels

Keep official names in the topology and resolve presentation text from stable codes:

const englishLabels: Record<string, string> = {
  "13": "Santiago Metropolitan Region",
};

<ChileMap topology={regiones} featureLabel={(feature) => englishLabels[feature.code] ?? feature.name} />;

featureLabel controls the default tooltip heading and each SVG path's aria-label. Callbacks still receive the unmodified official feature.name, so applications can change locale without replacing geometry.

Feature types

interface MapFeature {
  code: string;
  name: string;
  value?: number;
}

interface ProvinciaFeature extends MapFeature {
  region: RegionCode;
}

interface ComunaFeature extends MapFeature {
  region: RegionCode;
  province: string;
  provinceName: string;
}

The rendering engine uses normalized parent metadata internally while callbacks expose level-specific semantic fields.

Scales and legend

The map fills come from a shared scale descriptor. Build the same descriptor with scaleFromData and pass it to <Legend> so boundaries always match the map:

import { ChileMap, Legend, scaleFromData } from "react-chile-map";

const scale = scaleFromData(data, { colors, bins: 6, type: "quantile" });

<ChileMap topology={regiones} data={data} colors={colors} bins={6} scaleType="quantile" />
<Legend scale={scale} formatValue={(v) => v.toLocaleString("es-CL")} showMissing />

scaleType accepts "linear", "quantile", or "threshold" (with an explicit thresholds array). The domain covers every finite value in data. Low-level helpers createScale, makePalette, quantize, and quantile are also exported. See API.md for the full prop-by-prop reference.

Accessibility

When onClick is provided, every unit is a role="button" path with a roving tab index: one Tab stop per map, arrow keys move between units, Enter/Space activate, focus shows the tooltip, and aria-pressed reflects the controlled selection.

Development

npm install
npm run dev
npm run test               # vitest suite (rendering, interactions, loaders)
npm run test:coverage      # unit suite plus V8 coverage thresholds
npm run test:browser       # Chromium keyboard and axe checks
npm run test:visual        # deterministic cartography screenshots
npm run build-data         # regenerate TopoJSON from the BCN shapefiles
npm run generate-data-types # regenerate opt-in regional code types
npm run validate-data      # assert artifact counts, bounds, and size budgets
npm run validate-data-types # assert generated types match all regional data
npm run verify-package     # pack + consumer fixtures (React 17/18/19)
npm run typecheck --workspace=react-chile-map
npm run build --workspace=react-chile-map
npm run build:demo
npm run build:docs         # build the English and Spanish Docusaurus site
npm run dev:docs           # preview both locales with a working language selector
npm run dev:docs:en        # English-only hot reload
npm run dev:docs:es        # Spanish-only hot reload

Cartography, insets, and known exclusions

Source: Biblioteca del Congreso Nacional de Chile (BCN), mapas vectoriales.

The published TopoJSON covers the full national territory present in the BCN sources, including the Pacific islands (Rapa Nui, Juan Fernández). Because those islands lie thousands of kilometers west of the mainland, every component automatically renders polygons west of longitude -76.5 inside side inset boxes with their own projection - one box for Rapa Nui and one for the remaining Pacific islands. Insets appear only when the rendered topology contains oceanic geometry (the national map and Región de Valparaíso today); hover, click, selection, and choropleth colors work identically inside them.

Pass oceanicIslands={false} to render a mainland-only view: oceanic polygons are dropped, no inset column is reserved, and fully oceanic units (such as the Isla de Pascua comuna) keep their data but draw no shape.

Known exclusions:

  • The BCN sources contain no Antarctic geometry, so the "Antártica" comuna and the "Antártica Chilena" provincia have no published polygons. The artifacts therefore contain 345 comunas and 56 provincias.
  • Islets smaller than each layer's minIslandArea pipeline threshold (for example Salas y Gómez, Santa Clara, and the Desventuradas) are removed to control package size. Their parent comunas remain present.

The source material is referential and should not be used where geodetic precision is required. Maps depicting Chilean limits and borders do not bind the State of Chile.

About

React choropleth maps of Chilean regions, provincias, and comunas with ready to use BCN TopoJSON data

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors