mapcn-react-native
Data

Choropleths

A choropleth abstraction built on native step/interpolate expression evaluation, with scales computed once in JS.

Renderer support: MapLibre ✓  ·  Mapbox ✓

npx mapcn-rn add choropleth
import { MapChoropleth } from "@/components/ui/mapcn";

Overview

MapChoropleth colors polygons by a numeric feature property, computing the domain and breaks once in JavaScript (lib/mapcn/scale.ts) and compiling the result into a native ["step", ...] or ["interpolate", ...] expression -- all per-feature styling then happens natively, with zero JavaScript per frame.

Value accessors are deliberately not supported as a runtime callback. A JS function can't participate in native style evaluation without round-tripping every feature every frame. Instead, precompute the value once:

import { precomputeValues } from "@/lib/mapcn/geo";

const regions = precomputeValues(raw, (f) => f.properties.pop / f.properties.areaKm2, "density");

Then pass value="density" to MapChoropleth.

Props

PropTypeDefaultDescription
idstringauto-generatedSource id.
dataFeatureCollectionRequired.
valuestringRequired. The numeric feature property to color by.
scaleChoroplethScale{ type: "quantize", steps: 5 }See below.
opacitynumber0.7Fill opacity.
borderLineStyle | false{ color: "#ffffff", width: 1 }Border styling. false disables it.
missing{ color?, opacity? } | "hide"{ color: "#e5e7eb", opacity: 0.4 }How features missing value are styled. "hide" makes them fully transparent.
selectedIdstring | number | nullFeature id to highlight.
idPropertystring"id"Property compared against selectedId.
selected{ fill?: FillStyle; border?: LineStyle }Styles for the selected feature.
onFeaturePress(feature: Feature, event: MapFeaturePressEvent) => voidFires on feature press.
onLegendChange(legend: MapLegendData) => voidEmits normalized legend data whenever the computed scale changes -- feed this directly to <MapLegend data={legend} />.
beforeIdstringLayer id to insert before.
fillStyle / borderStyleRecord<string, unknown>Raw escape hatches, merged last.

ChoroplethScale

type ChoroplethScale =
  | { type: "quantize"; steps?: number; colors?: string[]; domain?: [number, number] }
  | { type: "quantile"; steps?: number; colors?: string[] }
  | { type: "threshold"; breaks: number[]; colors: string[] }
  | { type: "linear"; colors: string[]; domain?: [number, number] };

quantize splits the domain into steps equal-width buckets; quantile splits the data into steps equal-count buckets; threshold uses explicit break points; linear produces a continuous interpolate expression instead of discrete steps.

Example

import { useState } from "react";
import { Map } from "@/components/ui/mapcn";
import { MapChoropleth } from "@/components/ui/mapcn";
import { MapLegend } from "@/components/ui/mapcn";
import type { MapLegendData } from "@/lib/mapcn/types";

export function ChoroplethExample({ regions }: { regions: GeoJSON.FeatureCollection }) {
  const [legend, setLegend] = useState<MapLegendData | null>(null);

  return (
    <Map defaultViewport={{ center: [-98, 39], zoom: 4 }} className="flex-1">
      <MapChoropleth data={regions} value="density" scale={{ type: "quantile", steps: 6 }} onLegendChange={setLegend} />
      {legend && <MapLegend data={legend} title="Population density" formatValue={(v) => `${v.toFixed(0)}/km²`} />}
    </Map>
  );
}

Live example

choropleth example screenshot

Legend · GeoJSON · Heatmaps

On this page