033 / GOOGLE CHARTS / GEOGRAPHIC

Google GeoChart Vector Map

Google Charts

Interactive SVG choropleth world and country map with dynamic color scaling, regional hover tooltips, and click callbacks.

SPEC
#033
ENGINE
Google Charts
FAMILY
Geographic
RENDERER
google-runtime
STATUS
stable

Installation

PLOTCN/REGISTRY/GOOGLE-GEOCHART/SOURCE
pnpm dlx shadcn@latest add @plotcn/google-geochart

Checking public registry…

View local registry JSON
REGISTRY direct URL·ENGINE Google Charts·FILES 1·DEPENDENCIES 2

Copied as source. No Plotcn runtime required.

× 340Container width
Measuring preview...
GOOGLE · GOOGLE-RUNTIME · 0 × 340pxMotion enabled · ResizeObserver
Component Specifications
BEST FOR
Google GeoChart Vector Map visual analytics and geo category telemetry.
DATA MODEL
Normalized geo records matching canonical dataShape.
INTERACTION
Pointer hover and focus crosshairs
RESPONSIVE
Container-aware ResizeObserver
ANIMATION
Static immediate draw
RUNTIME
Google Charts google-runtime
01 / Component Usage

Basic & Interactive Integration

Import GoogleGeoChart directly into your React client component. Provide an array of observations conforming to the data shape.

page.tsx
import { GoogleGeoChart } from "@/components/charts/google/google-geochart"

const data = [
  {
    "label": "Jan",
    "value": 186
  },
  {
    "label": "Feb",
    "value": 305
  },
  {
    "label": "Mar",
    "value": 237
  }
]

export default function ChartDemo() {
  return (
    <div className="w-full max-w-xl h-80">
      <GoogleGeoChart data={data} color="#10b981" />
    </div>
  )
}

Requires a client context ('use client') for DOM lifecycle and container measurement.

Expected ResultLive 220px
Container-aware width · 200px height
02 / Data Contract

Input Schema & Coordinates

Input data format for Google GeoChart Vector Map. Records should provide required coordinates and metrics.

Chart data contract
FieldTypeRequiredMeaning
labelstringYesCategory label or horizontal axis timestamp
valuenumberYesMetric numerical magnitude
Null / Missing Value Policy:

Missing values are gracefully handled or skipped depending on interpolation rules.

Coordinate Ordering Policy:

Records should follow monotonic sorting for sequential coordinate plots.

Example Observation Payload:
[
  {
    "label": "Jan",
    "value": 186
  },
  {
    "label": "Feb",
    "value": 305
  },
  {
    "label": "Mar",
    "value": 237
  }
]
03 / Component API & Styling

Props Reference & Interactive Prop Explorer

Inspect every component property, customize semantic color roles live with instant visual feedback, and copy production-ready code with active prop configurations.

Colors & Appearance Configuration

Customize primary, reference, or annotation series colors. Defaults derive from Plotcn theme tokens.

Generated Usage Code (Live Props):
<Chart
  data={data}
  xKey="date"
  seriesKey="value"
/>
Interactive Prop Preview Lab
colorstring

Primary theme stroke or fill color. Accepts CSS variables or color values.

Select value to preview live:#10b981
Active: color="#10b981"Default: "var(--chart-1, #10b981)"
All Properties (4)
Component properties
PropertyTypeDefaultRequiredDescription
dataReq
Record<string, any>[]Yes

Array of structured observations or datum objects to visualize.

Best for: Primary dataset

string"var(--chart-1, #10b981)"No

Primary theme stroke or fill color. Accepts CSS variables or color values.

Best for: Theming and visual branding

number | string320No

Container height in pixels or standard CSS dimension strings.

stringundefinedNo

Tailwind CSS classes or custom stylesheet class applied to container wrapper.

04 / Cookbook & States

Component Variants & Edge States

Production cookbooks showcasing configuration variants alongside verified handling of loading, empty data, and network error states.

Google GeoChart Vector Map (Default)

Standard presentation with Plotcn dark theme tokens.

<GoogleGeoChart data={data} region="world" displayMode="regions" />
Lifecycle & Exception States
01. Loading State

Skeletons indicate runtime fetch or pending data queries.

02. Empty Data State

Handles empty collections ([]) gracefully without crashing.

03. Error State

Graceful failure banner when data source or script fails.

05 / Responsive Lab

Container-Driven Breakpoints

Scales gracefully according to container width, recalculating layout bounds.

Desktop
1100px+

Full horizontal scale and complete axis tick labeling.

Tablet
768px

Tighter margins with optimized coordinate grid spacing.

Mobile
390px

Compact labels and touch-friendly interaction.

Tablet Preview (768px Container Constraint)
Mobile Preview (390px Container Constraint)
06 / Assistive Technology

Accessibility & Navigation Standards

Accessible visualization presenting Google GeoChart Vector Map data with semantic contrast.

Semantic Role & Landmark

Container mounts as figure[role="region"] with explicit assistive label.

Color-Independent Legibility

Coordinate baselines and labels preserve data legibility regardless of color perception.

Screen Reader Summary

Embeds visually hidden summary (.sr-only) declaring: “Google GeoChart Vector Map data visualization

Reduced Motion Support

Suppresses transitions when user prefers reduced motion.

Keyboard Interaction Model
Keyboard interaction model
KeyAction
TabFocus chart container and navigate through interactive regions.
07 / Source Anatomy

Internal Architecture & File Dependencies

Source-first ownership model. Inspect the exact component call tree, dependencies, and full implementation below.

Component Architecture Call Tree
GoogleGeoChart(Component Entry)
└──Google Charts Engine Layer[google-runtime]

Visualization calculations and rendering via Google Charts.

Involved Source Files & Registry Assets
registry/google/google-geochart.tsx
Primary component source implementation.
registry/google/google-geochart.tsx
"use client"import * as React from "react"import {  loadGoogleChartsPackages,  resolveGoogleColor,  escapeGoogleTooltipText,  type GoogleChartsLoaderState,  type GoogleVisualizationChart,} from "./google-chart-loader"import { GoogleChartContainer } from "./google-chart-container"export interface GeoChartDatum {  region: string  value: number  [key: string]: unknown}export interface GoogleGeoChartProps {  data: GeoChartDatum[]  regionKey?: string  valueKey?: string  region?: string  displayMode?: "regions" | "markers"  color?: string  colorMin?: string  colorMax?: string  height?: number | string  className?: string  onRegionSelect?: (regionCode: string) => void}/** * Google GeoChart Component * Renders statistical geographic choropleths with automatic data transformation and ResizeObserver redraw. */export function GoogleGeoChart({  data,  regionKey = "region",  valueKey = "value",  region = "world",  displayMode = "regions",  color,  colorMin = "var(--chart-grid-emphasis)",  colorMax = "var(--chart-1)",  height = 360,  className,  onRegionSelect,}: GoogleGeoChartProps) {  const chartRef = React.useRef<HTMLDivElement>(null)  const chartInstanceRef = React.useRef<GoogleVisualizationChart | null>(null)  const [status, setStatus] = React.useState<GoogleChartsLoaderState>("loading")  const [errorMsg, setErrorMsg] = React.useState<string>()  // Initialize and load geochart package  React.useEffect(() => {    let active = true    loadGoogleChartsPackages(["geochart"])      .then(() => {        if (active) setStatus("ready")      })      .catch((err) => {        if (active) {          setStatus("error")          setErrorMsg(err.message)        }      })    return () => {      active = false    }  }, [])  // Draw chart when ready or data changes  const drawChart = React.useCallback(() => {    if (status !== "ready" || !chartRef.current || !window.google?.visualization) return    // Transform application data to DataTable    const dataTable = new window.google.visualization.DataTable()    dataTable.addColumn("string", "Region")    dataTable.addColumn("number", "Value")    dataTable.addColumn({ type: "string", role: "tooltip", p: { html: true } })    const css = getComputedStyle(chartRef.current)    const gridColor = css.getPropertyValue("--chart-grid").trim() || "#27272a"    const surfaceColor = css.getPropertyValue("--muted").trim() || "#18181b"    const targetMax = color || colorMax    const resolvedMin = resolveGoogleColor(colorMin, chartRef.current, "#3f3f46")    const resolvedMax = resolveGoogleColor(targetMax, chartRef.current, "#f4f4f5")    data.forEach((item) => {      const regionName = String(item[regionKey])      const safeRegionName = escapeGoogleTooltipText(regionName)      const val = Number(item[valueKey])      const displayVal = Number.isFinite(val) ? val.toLocaleString() : String(item[valueKey])      const tooltipHtml = `        <div class="plotcn-tooltip-card">          <div class="plotcn-tooltip-header">            <span class="plotcn-tooltip-indicator" style="background-color: ${resolvedMax};"></span>            <span class="plotcn-tooltip-title">${safeRegionName}</span>          </div>          <div class="plotcn-tooltip-metric">            <span class="plotcn-tooltip-label">${valueKey}</span>            <span class="plotcn-tooltip-value">${displayVal}</span>          </div>        </div>      `.trim()      dataTable.addRow([regionName, val, tooltipHtml])    })    const options = {      region,      displayMode,      backgroundColor: "transparent",      datalessRegionColor: surfaceColor,      defaultColor: gridColor,      colorAxis: {        colors: [resolvedMin, resolvedMax],      },      legend: "none",      keepAspectRatio: true,      tooltip: {        isHtml: true,      },    }    if (!chartInstanceRef.current) {      chartInstanceRef.current = new window.google.visualization.GeoChart(chartRef.current)      if (onRegionSelect) {        window.google.visualization.events.addListener(chartInstanceRef.current, "select", () => {          const selection = chartInstanceRef.current?.getSelection?.()          if (selection && selection.length > 0) {            const row = selection[0].row            if (row !== null && row !== undefined && dataTable.getValue) {              const regionCode = dataTable.getValue(row, 0)              onRegionSelect(String(regionCode))            }          }        })      }    }    chartInstanceRef.current?.draw(dataTable, options)  }, [status, data, regionKey, valueKey, region, displayMode, color, colorMin, colorMax, onRegionSelect])  React.useEffect(() => {    drawChart()  }, [drawChart])  // Handle ResizeObserver debounced redraw  React.useEffect(() => {    if (!chartRef.current) return    let timeoutId: NodeJS.Timeout    const observer = new ResizeObserver(() => {      clearTimeout(timeoutId)      timeoutId = setTimeout(() => {        drawChart()      }, 150)    })    observer.observe(chartRef.current)    return () => {      clearTimeout(timeoutId)      observer.disconnect()    }  }, [drawChart])  // Cleanup chart instance ONLY on component unmount  React.useEffect(() => {    return () => {      if (chartInstanceRef.current) {        chartInstanceRef.current.clearChart?.()        chartInstanceRef.current = null      }    }  }, [])  React.useEffect(() => {    const surface = chartRef.current?.closest("[data-theme]")    const observer = new MutationObserver(drawChart)    if (surface) observer.observe(surface, { attributes: true, attributeFilter: ["data-theme"] })    if (typeof document !== "undefined") {      observer.observe(document.documentElement, { attributes: true, attributeFilter: ["class", "data-theme"] })    }    const media = window.matchMedia("(prefers-color-scheme: dark)")    media.addEventListener("change", drawChart)    return () => { observer.disconnect(); media.removeEventListener("change", drawChart) }  }, [drawChart])  return (    <GoogleChartContainer      status={status}      errorMessage={errorMsg}      height={height}      className={className}      chartRef={chartRef}      title={`GeoChart of ${region}`}      onRetry={() => {        setStatus("loading")        loadGoogleChartsPackages(["geochart"])          .then(() => setStatus("ready"))          .catch((err) => {            setStatus("error")            setErrorMsg(err.message)          })      }}    >      <span className="sr-only">Interactive choropleth visualization displaying statistical regional values.</span>    </GoogleChartContainer>  )}