home / skills / dennisadriaans / vue-chrts / maps

This skill helps you create interactive map visualizations with topojson and dotted maps, enabling choropleth coloring, pins, and regional insights.

npx playbooks add skill dennisadriaans/vue-chrts --skill maps

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
9.0 KB
---
name: maps
description: Build map visualizations with TopoJSONMap and DottedMap. Use for geographical data, choropleth maps, and location-based visualizations.
---

# Map Components

vue-chrts provides two map components:
- **TopoJSONMap**: Full-featured geographic maps using TopoJSON data
- **DottedMap**: Stylized dot-matrix world maps

## TopoJSONMap

Renders geographic regions using TopoJSON data. Supports choropleth coloring, points, and links.

### Mental Model

```
┌─────────────────────────────────────────────────────────────┐
│  TOPOJSONMAP LAYERS                                         │
│                                                             │
│  ┌───────────────────────────────────────────────────────┐ │
│  │  Areas (regions/countries from TopoJSON)              │ │
│  │  ┌─────────┐  ┌─────────┐  ┌─────────┐               │ │
│  │  │  Region │  │  Region │  │  Region │               │ │
│  │  │    A    │──│    B    │──│    C    │               │ │
│  │  └─────────┘  └─────────┘  └─────────┘               │ │
│  │                    ●  ●  ●  Points (cities, etc.)     │ │
│  │                    └──┴──┘  Links (connections)       │ │
│  └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```

### Complete Example

```vue
<script setup lang="ts">
import { TopoJSONMap, LegendPosition } from 'vue-chrts'
import usaTopoJson from './data/usa.topo.json'

interface StateData {
  id: string
  name: string
  value: number
}

const stateData: StateData[] = [
  { id: 'CA', name: 'California', value: 39500000 },
  { id: 'TX', name: 'Texas', value: 29000000 },
  { id: 'FL', name: 'Florida', value: 21500000 },
  // ... more states
]

const categories = {
  low: { name: 'Low Population', color: '#bfdbfe' },
  medium: { name: 'Medium Population', color: '#3b82f6' },
  high: { name: 'High Population', color: '#1e3a8a' }
}

const getAreaColor = (feature: any) => {
  const state = stateData.find(s => s.id === feature.properties.id)
  if (!state) return '#e5e7eb'
  if (state.value > 20000000) return categories.high.color
  if (state.value > 10000000) return categories.medium.color
  return categories.low.color
}
</script>

<template>
  <TopoJSONMap
    :data="{
      mapFeatureKey: 'id',
      data: { areas: stateData },
      topoJson: usaTopoJson
    }"
    :height="500"
    :areaColor="getAreaColor"
    :categories="categories"
    :legendPosition="LegendPosition.BottomRight"
    :fitView="true"
    :zoomExtent="[1, 8]"
  />
</template>
```

### TopoJSONMap Props

| Prop | Type | Description |
|------|------|-------------|
| `data.topoJson` | `object` | TopoJSON data object |
| `data.mapFeatureKey` | `keyof T` | Key to match features with data |
| `data.data` | `MapData` | Areas, points, links data |
| `height` | `string \| number` | Map height |
| `width` | `string \| number` | Map width |
| `projection` | `GeoProjection` | D3 geo projection |
| `areaColor` | `string \| (feature) => string` | Area fill color |
| `areaCursor` | `string \| (feature) => string` | Area cursor style |
| `pointColor` | `string \| (point) => string` | Point color |
| `pointSize` | `number \| (point) => number` | Point radius |
| `pointLabel` | `(point) => string` | Point label accessor |
| `linkColor` | `string \| (link) => string` | Link stroke color |
| `linkWidth` | `number \| (link) => number` | Link stroke width |
| `fitView` | `boolean` | Auto-fit map to container |
| `fitViewPadding` | `number` | Padding when fitting |
| `zoomFactor` | `number` | Initial zoom level |
| `zoomExtent` | `[number, number]` | Min/max zoom levels |

---

## DottedMap

Creates stylized dot-matrix world maps. Great for showing global presence, locations, or minimalist geographic visualizations.

### Mental Model

```
┌─────────────────────────────────────────────────────────────┐
│  DOTTED MAP                                                 │
│                                                             │
│    ·  · ·  ·  · ·  ·  · ·  ·  · ·  ·  · ·  ·             │
│   · ·  ·  · ·  ·  · ·  ·  · ·  ·  · ·  ·  · ·            │
│    ·  · ●  ·  · ·  ·  ● ·  ·  · ·  ·  · ·  ·  ← Pins     │
│   · ·  ·  · ·  ·  · ·  ·  · ·  ●  · ·  ·  · ·            │
│    ·  · ·  ·  · ·  ·  · ·  ·  · ·  ·  · ·  ·             │
│                                                             │
│  Base dots = landmass                                       │
│  Pins = custom locations with lat/lng                       │
└─────────────────────────────────────────────────────────────┘
```

### Complete Example

```vue
<script setup lang="ts">
import { DottedMap, getMap, getPin } from 'vue-chrts'

const pins = [
  getPin({ lat: 40.7128, lng: -74.0060, color: '#ef4444', radius: 3 }), // New York
  getPin({ lat: 51.5074, lng: -0.1278, color: '#3b82f6', radius: 3 }),  // London
  getPin({ lat: 35.6762, lng: 139.6503, color: '#10b981', radius: 3 }), // Tokyo
  getPin({ lat: -33.8688, lng: 151.2093, color: '#f59e0b', radius: 3 }) // Sydney
]
</script>

<template>
  <DottedMap
    :mapHeight="50"
    :pins="pins"
    color="#4b5563"
    :dotSize="0.4"
    backgroundColor="#1f2937"
    shape="circle"
  />
</template>
```

### DottedMap Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `mapHeight` | `number` | - | Height in dots (auto-calculates width) |
| `mapWidth` | `number` | - | Width in dots (auto-calculates height) |
| `countries` | `string[]` | all | ISO 3166-1 alpha-3 country codes to include |
| `region` | `MapRegion` | - | Specific lat/lng bounds to display |
| `grid` | `'vertical' \| 'diagonal'` | `'vertical'` | Dot alignment pattern |
| `pins` | `MapPin[]` | - | Location markers |
| `precomputedMap` | `string \| object` | - | Pre-generated map data |
| `color` | `string` | `'#ffffff'` | Default dot color |
| `dotSize` | `number` | `0.5` | Dot radius |
| `strokeColor` | `string` | - | Dot stroke color |
| `strokeWidth` | `number` | - | Dot stroke width |
| `shape` | `'circle' \| 'hexagon'` | `'circle'` | Dot shape |
| `countryColors` | `Record<string, string>` | - | Per-country colors |
| `backgroundColor` | `string` | - | Container background |
| `avoidOuterPins` | `boolean` | `false` | Hide pins outside region |

### Pin Helper Function

```typescript
import { getPin } from 'vue-chrts'

const pin = getPin({
  lat: 40.7128,
  lng: -74.0060,
  color: '#ef4444',
  radius: 5,
  strokeColor: '#ffffff',
  strokeWidth: 1
})
```

### MapPin Structure

```typescript
interface MapPin {
  lat: number
  lng: number
  svgOptions?: {
    color?: string
    radius?: number
    strokeColor?: string
    strokeWidth?: number
    strokeOpacity?: number
  }
  data?: Record<string, unknown>
}
```

## Common Patterns

### Highlight Specific Countries

```vue
<DottedMap
  :mapHeight="40"
  :countries="['USA', 'GBR', 'DEU', 'JPN', 'AUS']"
  :countryColors="{
    'USA': '#3b82f6',
    'GBR': '#ef4444',
    'DEU': '#f59e0b',
    'JPN': '#10b981',
    'AUS': '#8b5cf6'
  }"
  color="#374151"
/>
```

### Regional Focus

```vue
<DottedMap
  :mapHeight="60"
  :region="{
    lat: { min: 35, max: 72 },
    lng: { min: -25, max: 45 }
  }"
  color="#6b7280"
  :dotSize="0.6"
/>
```

### Office Locations

```vue
<script setup>
import { getPin } from 'vue-chrts'

const offices = [
  { city: 'HQ', lat: 37.7749, lng: -122.4194 },
  { city: 'NYC', lat: 40.7128, lng: -74.0060 },
  { city: 'London', lat: 51.5074, lng: -0.1278 },
]

const pins = offices.map(office => getPin({
  lat: office.lat,
  lng: office.lng,
  color: '#10b981',
  radius: 4
}))
</script>

<template>
  <DottedMap
    :mapHeight="50"
    :pins="pins"
    color="#4b5563"
    backgroundColor="transparent"
  />
</template>
```

## Gotchas

1. **TopoJSON required for TopoJSONMap**: You need valid TopoJSON data for regions
2. **Country codes are ISO 3166-1 alpha-3**: Use 'USA' not 'US', 'GBR' not 'UK'
3. **Lat/Lng order matters**: Latitude first, then longitude
4. **DottedMap dimensions**: Specify either mapHeight OR mapWidth, not both
5. **Large maps are slow**: DottedMap with many dots can be performance-heavy

Overview

This skill provides two Vue 3 map components for building geographic visualizations: TopoJSONMap for full-featured region maps and DottedMap for stylized dot-matrix world maps. It is optimized for choropleths, point markers, links, and minimalist global views. Use it to turn geographic data into interactive, production-ready visuals in Vue applications.

How this skill works

TopoJSONMap renders geographic areas from a TopoJSON object and overlays data-driven fills, points, and links. You provide topoJson, a mapFeatureKey to match data entries to features, and optional accessors for colors, sizes, and labels. DottedMap renders a dot-grid representation of landmasses and places pins using latitude/longitude; it accepts options for grid shape, per-country colors, region cropping, and precomputed maps for performance.

When to use it

  • Create choropleth maps by coloring regions based on metrics (population, sales, risk).
  • Show city or office locations with labeled pins and size-scaled points.
  • Visualize network links between geographic points (routes, flows).
  • Design minimalist global overviews or product presence maps using dot matrices.
  • Focus on a specific region or subset of countries with region or country filters.

Best practices

  • Always supply valid TopoJSON for TopoJSONMap; match features using a stable mapFeatureKey.
  • Use accessor functions for areaColor, pointColor, and linkColor to keep styling logic separate from data.
  • Limit the DottedMap mapHeight (or mapWidth) to balance fidelity and performance; precompute maps for large or static displays.
  • Use ISO 3166-1 alpha-3 country codes when targeting specific countries in DottedMap.
  • Provide fitView, zoomExtent, and sensible padding for interactive TopoJSONMap views to ensure good initial framing.

Example use cases

  • US state-level choropleth showing population or revenue using TopoJSONMap with custom areaColor accessor.
  • Global office footprint using DottedMap pins for HQ and regional offices with distinct colors and radii.
  • Flight or trade lanes drawn with TopoJSONMap links connecting city points to highlight flows.
  • Regional sales heatmap: crop DottedMap or TopoJSONMap to a lat/lng region and render per-country color scale.
  • Minimal product availability map: DottedMap with selected countryColors and a dark background for dashboards.

FAQ

Do I need TopoJSON or GeoJSON?

TopoJSONMap requires a valid TopoJSON object. Convert GeoJSON to TopoJSON if needed for smaller payloads and topology-aware rendering.

Which country codes should I use with DottedMap?

Use ISO 3166-1 alpha-3 codes (e.g., 'USA', 'GBR', 'DEU'). Alpha-2 codes like 'US' or 'UK' are not supported.

Can I show pins outside the displayed region?

DottedMap has an avoidOuterPins option to hide pins outside the specified region; otherwise pins may be clipped or positioned off-grid.