Choropleth
mapcn/choroplethFreeBlock
World choropleth map shading countries by a metric, with a hover tooltip and legend.
Install it
npx shadcn@latest add https://mapcn.dev/r/choropleth.jsonSource
1"use client";23import { useMemo, useState } from "react";4import { useTheme } from "next-themes";56import { Map, MapControls, MapGeoJSON, MapPopup } from "@/components/ui/map";7import { useWorldData } from "@/lib/use-world-data";8import { mapConfig, visitorsByCountry, type Theme } from "./data";910// WebGL paint can't read CSS variables, so we build a concrete value→color11// expression per theme. The hovered country is highlighted in place via the12// `hover` feature-state, restricted to countries that actually have data.13function buildFillColor(theme: Theme): unknown[] {14 const { base, ramp, hover } = mapConfig.colors[theme];15 const [s0, s1, s2, s3, s4] = mapConfig.scaleStops;16 const ramped = [17 "interpolate",18 ["linear"],19 ["coalesce", ["get", "visitors"], 0],20 s0,21 base,22 s1,23 ramp[0],24 s2,25 ramp[1],26 s3,27 ramp[2],28 s4,29 ramp[3],30 ];31 return [32 "case",33 [34 "all",35 ["boolean", ["feature-state", "hover"], false],36 [">", ["coalesce", ["get", "visitors"], 0], 0],37 ],38 hover,39 ramped,40 ];41}4243const legendGradientStyle = {44 "--choropleth-ramp-light": `linear-gradient(to right, ${mapConfig.colors.light.ramp.join(", ")})`,45 "--choropleth-ramp-dark": `linear-gradient(to right, ${mapConfig.colors.dark.ramp.join(", ")})`,46} as React.CSSProperties;4748interface HoverInfo {49 name: string;50 visitors: number;51 lng: number;52 lat: number;53}5455interface CountryProperties {56 NAME_LONG: string;57 visitors: number;58}5960type CountryFeatureCollection = GeoJSON.FeatureCollection<61 GeoJSON.Geometry,62 CountryProperties63>;6465export default function Page() {66 const { resolvedTheme } = useTheme();67 const theme: Theme = resolvedTheme === "dark" ? "dark" : "light";68 const [hover, setHover] = useState<HoverInfo | null>(null);69 const world = useWorldData();7071 const countries = useMemo<CountryFeatureCollection | null>(() => {72 if (!world) return null;73 return {74 type: "FeatureCollection",75 features: world.features.map((f) => ({76 ...f,77 properties: {78 NAME_LONG: f.properties.NAME_LONG,79 visitors: visitorsByCountry[f.properties.NAME_LONG] ?? 0,80 },81 })),82 };83 }, [world]);8485 // Recompute paint only when the theme changes; MapGeoJSON recolors in place.86 const fillPaint = useMemo(87 () => ({88 "fill-color": buildFillColor(theme) as never,89 "fill-opacity": 0.92,90 }),91 [theme],92 );9394 return (95// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from mapcn
All 9 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Analytics Cardanalytics-card | mapcn | Blocks | Free | 1 dep · 2 files | |
| Analytics Mapanalytics-map | mapcn | Blocks | Free | 2 deps · 4 files | |
| Delivery Trackerdelivery-tracker | mapcn | Blocks | Free | 1 dep · 2 files | |
| Heatmapheatmap | mapcn | Blocks | Free | no deps | |
| Logistics Networklogistics-network | mapcn | Blocks | Free | 1 dep · 4 files | |
| Store Locatorstore-locator | mapcn | Blocks | Free | 1 dep · 4 files | |
| Uptime Monitoruptime-monitor | mapcn | Blocks | Free | 1 dep · 4 files |
