Selection & Linked Maps

Click a feature to select it. Selection is on by default and entirely free, no license required, and it drives one visible effect: everything not selected dims.

interaction: {
  selection: { enabled: true, multiple: true, rectangle: true, modifier: 'shift' },
},
states: { muted: { opacity: 0.25 } },   // 1 turns dimming off

Click and box selection

A plain click toggles one feature in or out of the selection. interaction.selection.multiple (default true) allows more than one; set it false and a click replaces the selection instead of adding to it.

interaction.selection.rectangle (default true) turns a modified drag into a selection box: everything the box encloses gets selected. It costs nothing when unused, since a plain drag still pans.

GestureEffect
Click a featureToggles it in or out of the selection
Shift-dragDraws a box; releasing it selects everything inside
Alt-dragSame as Shift-drag, but adds to the existing selection instead of replacing it
EscapeAbandons the box mid-drag
Box over nothingClears the selection, the only obvious way for a reader to undo one
interaction: {
  selection: {
    enabled: true,
    multiple: true,
    rectangle: true,
    modifier: 'shift',   // 'shift' | 'alt' | 'meta' | 'ctrl' | 'none'
  },
},

modifier: 'none' makes every drag a selection box instead of a pan, which needs pan.enabled: false alongside it: one drag gesture cannot mean both, and ApexMaps warns in dev mode if you set 'none' without disabling pan.

Anchor-point hit testing, not bounding boxes

A box tests each feature's label anchor point, the same point the label engine computes, sitting inside the shape, rather than testing whether the feature's bounding box intersects the drawn box. Bounding-box intersection reads plausibly and behaves badly in practice: Alaska's bounding box spans the Pacific, so a box that merely touches the Aleutian tail would also select Alaska, and a box drawn over the Great Lakes would pull in half a dozen states it does not visibly cover. Testing the anchor instead matches what a reader thinks they just enclosed. Point marks (bubbles, markers) are tested at their own screen position, and the automatic basemap is excluded from box selection entirely, since a country drawn only so bubbles have a coastline to sit on carries no data and could not filter anything.

Dimming

While anything is selected, everything else dims to states.muted.opacity (default 0.25):

states: { muted: { opacity: 0.25 } }   // set to 1 to disable dimming entirely

This is what makes a selection legible on a dense map at all: an outline drawn around 3 of 3,000 counties is nearly invisible, while the other 2,997 stepping back reads instantly.

The drag-ending click is not a click

A browser fires a click event after any drag that starts and ends on the same element. Without suppressing that, panning the map and releasing over a country would select it, and dragging a selection box across a feature that has a drilldown configured would drill into whatever the pointer happened to land on. ApexMaps tracks this per gesture: a drag that moved far enough to count as a drag flags its trailing click to be swallowed, and the flag is consumed by that one click (or by the next pointerdown, whichever comes first), so it can never leak into an unrelated later click.

Reading and setting selection from code

map.setSelection(['FRA', 'DEU'])
map.clearSelection()
map.on('selectionChange', ({ ids, source }) => {
  // `source` is an instance id: the map the change originated from, useful
  // when several linked maps share one handler.
})
Premium feature

Linked maps is a Premium feature

Available on the Premium and OEM plans. Linking maps works without a key for evaluation, with a watermark on the map; call ApexMaps.setLicense(key) to remove it.

Linked maps

Two or more maps naming the same link.group brush together: making a selection on one applies it to every other map in the group, and everything unselected dims on all of them at once.

// On every map that should brush together
link: { group: 'sales-dashboard', filter: 'bidirectional' }   // or 'emit' / 'receive'

link.filter controls direction. 'bidirectional' (the default) both sends this map's selections and receives the others'. 'emit' sends without receiving, for a map that should drive the group without ever being changed by it. 'receive' follows without leading.

const sales = new ApexMaps(salesEl, {
  geo: { map: 'us' },
  series: [{ name: 'Sales', joinBy: ['abbr', 'key'], data: salesRows }],
  link: { group: 'us-dashboard' },
})
const support = new ApexMaps(supportEl, {
  geo: { map: 'us' },
  series: [{ name: 'Support load', joinBy: ['abbr', 'key'], data: supportRows }],
  link: { group: 'us-dashboard' },
})

Keys have to mean the same thing across the group, which they naturally do whenever the maps are of the same geography (both keyed on USPS state abbreviations, in the example above). When a received selection matches nothing on the receiving map, dev mode reports it rather than leaving that map mysteriously blank with no explanation. A map that receives a selection never rebroadcasts it, which is what keeps a bidirectional pair from ringing: map A's selection reaches map B once, and B applying it does not bounce a copy back to A.

link.group is licensed. It works without a key for evaluation, with a watermark on the map; a valid key removes it. Selection itself, click and box selection, setSelection, states.muted, is entirely free with or without a key.

See also

  • Drilldown for why selection does not survive a level change, and how the same click-after-drag suppression protects it.
  • Zoom, Pan & Camera for the pointer plumbing box selection shares with panning.
  • Legends, Labels & Tooltips for legend class muting, a second, independent way to dim the map.