Markers & ClusteringOpen in new tab
View source
// CDN build: `ApexMaps` is a global (see index.html). With a bundler:
//   import ApexMaps from 'apexmaps'

// Premium feature: runs with a watermark until licensed. ApexMaps.setLicense(key) clears it.

// Markers with clustering. A marker means "something is here", so its size is
// fixed; what varies is whether nearby pins merge. `cluster` groups pins that
// collide on screen, and one zoom step dissolves the groups.
const capitals = [
  { name: 'Vienna', lon: 16.3738, lat: 48.2082, bloc: 'European Union' },
  { name: 'Bratislava', lon: 17.1077, lat: 48.1486, bloc: 'European Union' },
  { name: 'Budapest', lon: 19.0402, lat: 47.4979, bloc: 'European Union' },
  { name: 'Brussels', lon: 4.3517, lat: 50.8503, bloc: 'European Union' },
  { name: 'Amsterdam', lon: 4.9041, lat: 52.3676, bloc: 'European Union' },
  { name: 'Luxembourg', lon: 6.1319, lat: 49.6116, bloc: 'European Union' },
  { name: 'Paris', lon: 2.3522, lat: 48.8566, bloc: 'European Union' },
  { name: 'Berlin', lon: 13.405, lat: 52.52, bloc: 'European Union' },
  { name: 'Rome', lon: 12.4964, lat: 41.9028, bloc: 'European Union' },
  { name: 'Madrid', lon: -3.7038, lat: 40.4168, bloc: 'European Union' },
  { name: 'Warsaw', lon: 21.0122, lat: 52.2297, bloc: 'European Union' },
  { name: 'Stockholm', lon: 18.0686, lat: 59.3293, bloc: 'European Union' },
  { name: 'London', lon: -0.1276, lat: 51.5072, bloc: 'Outside the EU' },
  { name: 'Oslo', lon: 10.7522, lat: 59.9139, bloc: 'Outside the EU' },
  { name: 'Bern', lon: 7.4474, lat: 46.948, bloc: 'Outside the EU' },
  { name: 'Belgrade', lon: 20.4489, lat: 44.7866, bloc: 'Outside the EU' },
  { name: 'Reykjavík', lon: -21.9426, lat: 64.1466, bloc: 'Outside the EU' },
]

// A categorical palette registered once, so the two blocs get exactly these two
// colours instead of the first two of a general ramp.
ApexMaps.registerPalette('capitals', {
  kind: 'categorical',
  stops: ['#2f6fd0', '#dd4d6a'],
})

const map = new ApexMaps(document.getElementById('map'), {
  chart: { height: 580 },
  geo: {
    map: 'world/countries@50m',
    // Lambert azimuthal equal-area centred on 10°E 52°N (EPSG:3035), the
    // projection the EU's own statistical maps use.
    projection: { name: 'azimuthalEqualArea', rotate: [-10, -52] },
    view: { fit: [-25, 33, 45, 71], padding: 12 },
    fill: '#e9edf4',
  },
  series: [
    {
      type: 'marker',
      name: 'Capitals',
      data: capitals,
      shape: 'pin', // anchored at its point, not its centre
      size: 15,
      colorBy: 'bloc', // categorical colour, straight from the palette
      palette: 'capitals',
      stroke: { color: '#141a22', width: 1.3 },
      labels: { show: false },
      cluster: {
        radius: 34, // merge distance in screen pixels
        minPoints: 3, // a pair stays two pins
        size: [15, 26], // cluster radius scales by member count
        color: '#4a5568',
      },
    },
  ],
  legend: { show: false },
  tooltip: {
    // A cluster's `datum` is the ARRAY of its members, so one formatter serves
    // both a single pin and a merged group.
    formatter: ({ name, value, datum }) =>
      Array.isArray(datum)
        ? `<div style="font-weight:640">${value} capitals</div>` +
          `<div style="opacity:.62">${datum
            .slice(0, 3)
            .map((m) => m?.name)
            .filter(Boolean)
            .join(', ')}${value > 3 ? ` and ${value - 3} more` : ''}</div>`
        : `<div style="font-weight:640">${name}</div>` +
          `<div style="opacity:.62">${datum?.bloc ?? ''}</div>`,
  },
})

map.render()
Markers & Clustering - ApexMaps Demo | ApexCharts.js