/

3D Map Chart

Top-down 3D map with extruded height regions. Choropleth-style visualization where data values control both color and extrusion height.

Quick Start

import { Map3D } from "@chartts/gl"
 
const chart = Map3D("#chart", {
  data: {
    series: [
      {
        name: "Population",
        values: [39.5, 29.1, 21.5, 13.0, 12.8, 11.8, 10.6, 8.3],
        x: [0, 1.2, 2.4, 3.6, 4.8, 6.0, 7.2, 8.4],
        z: [0, 0, 0, 0, 0, 0, 0, 0],
      },
    ],
    categories: [
      "California", "Texas", "Florida", "New York",
      "Pennsylvania", "Illinois", "Ohio", "Georgia",
    ],
  },
})

That renders a grid of extruded 3D blocks where each block's height and color correspond to the data value. The camera auto-positions itself above and slightly angled to give a clear top-down perspective. Labels float above each region, and the choropleth coloring transitions from cool blues (low values) through purples to warm tones (high values).

When to Use 3D Map Charts

3D map charts combine the spatial layout of a choropleth with the magnitude encoding of bar height. They work best when you want to show both geographic arrangement and value magnitude simultaneously.

Use a 3D map chart when:

  • Comparing regional values where spatial position matters
  • You want height and color to double-encode the same value for emphasis
  • The data has a natural grid or geographic layout
  • Interactive orbit controls can help users inspect the tallest and shortest regions

Don't use a 3D map chart when:

  • You need actual geographic boundaries (use a GeoJSON-based choropleth)
  • Precise value comparison between regions is critical (height perspective distorts)
  • You have hundreds of regions (the scene becomes too dense)
  • The visualization is for print without interactivity

Props Reference

PropTypeDefaultDescription
dataGLChartDatarequiredChart data with series of GLSeries3D. Use categories for region labels
cameraCameraOptionsauto-fitCamera auto-positions based on data extent. Override for custom angles
orbitboolean | OrbitConfigtrueEnable orbit controls with optional auto-rotation
lightPartial<LightConfig>defaultPhong lighting for extruded blocks
theme'dark' | 'light' | GLTheme'dark'Color theme for background, text, and grid
animatebooleantrueEnable extrusion growth animation on mount
tooltipbooleantrueShow tooltip on hover with region name and value

Extruded Heights

Each data value is normalized against the maximum value in the dataset and then scaled to an extrusion height. This means the tallest block always represents the maximum value, and all other blocks are proportional.

Map3D("#chart", {
  data: {
    series: [
      {
        name: "GDP",
        values: [21400, 14700, 5100, 3800, 2800, 2100],
        x: [0, 1.2, 2.4, 0, 1.2, 2.4],
        z: [0, 0, 0, 1.2, 1.2, 1.2],
      },
    ],
    categories: ["US", "China", "Japan", "Germany", "UK", "India"],
  },
})

The entry animation scales blocks from zero height upward, creating a satisfying growth effect that draws attention to the tallest regions first.


Auto Camera Positioning

When no explicit camera is provided, Map3D computes the spatial extent of all data points and positions the camera at an elevated angle that encompasses the entire layout. This ensures all regions are visible without manual camera adjustment.

// Camera auto-fits to data extent
Map3D("#chart", { data: mapData })
 
// Override with a custom angle
Map3D("#chart", {
  data: mapData,
  camera: {
    position: [15, 12, 15],
    target: [5, 0, 3],
  },
})

The auto-fit algorithm uses the x and z extent of the data to compute a comfortable viewing distance, then places the camera at a 30-degree elevation angle.


Region Coloring

Colors are derived from a value-to-color function that maps the data range to a gradient. Low values appear as cool blue tones, mid values as blue-purple, and high values as warm purple-coral tones. Side faces of each block use a darker shade of the top face color to add depth.

Map3D("#chart", {
  data: {
    series: [
      {
        name: "Density",
        values: [1, 5, 15, 30, 50, 80, 100],
        x: [0, 1.2, 2.4, 3.6, 4.8, 6.0, 7.2],
        z: [0, 0, 0, 0, 0, 0, 0],
      },
    ],
    categories: [
      "Low", "Low-Med", "Medium",
      "Med-High", "High", "Very High", "Peak",
    ],
  },
})

Accessibility

  • Each region displays a floating text label with its name above the extruded block
  • Tooltip shows the exact value and region name on hover
  • Height and color provide dual encoding of the same value for redundancy
  • Dark side faces create natural depth cues that do not rely on color alone

Real-World Examples

State population comparison

Map3D("#population", {
  data: {
    series: [
      {
        name: "Population (millions)",
        values: [39.5, 29.1, 21.5, 19.3, 13.0, 12.8, 11.8, 10.6],
        x: [0, 1.2, 2.4, 3.6, 0, 1.2, 2.4, 3.6],
        z: [0, 0, 0, 0, 1.2, 1.2, 1.2, 1.2],
      },
    ],
    categories: [
      "California", "Texas", "Florida", "New York",
      "Pennsylvania", "Illinois", "Ohio", "Georgia",
    ],
  },
  theme: "dark",
  orbit: { autoRotate: true, autoRotateSpeed: 0.2 },
})

Data center capacity

Map3D("#datacenters", {
  data: {
    series: [
      {
        name: "Servers",
        values: [12000, 8500, 6200, 4800, 3500, 2800],
        x: [0, 1.2, 2.4, 0, 1.2, 2.4],
        z: [0, 0, 0, 1.2, 1.2, 1.2],
      },
    ],
    categories: [
      "Virginia", "Oregon", "Dublin",
      "Singapore", "Tokyo", "Sydney",
    ],
  },
  theme: "light",
})

Sales territory performance

Map3D("#sales", {
  data: {
    series: [
      {
        name: "Revenue ($K)",
        values: [450, 380, 320, 280, 220, 180, 150, 120, 90],
        x: [0, 1.2, 2.4, 0, 1.2, 2.4, 0, 1.2, 2.4],
        z: [0, 0, 0, 1.2, 1.2, 1.2, 2.4, 2.4, 2.4],
      },
    ],
    categories: [
      "North", "Northeast", "East",
      "Central", "Metro", "Southeast",
      "West", "Southwest", "South",
    ],
  },
  orbit: { autoRotate: true, autoRotateSpeed: 0.3 },
})

Other Charts