ApexMaps 1.0.0 is the first stable release. The public API now follows semantic versioning, so breaking changes wait for a major version. The release itself adds no features and has no breaking changes since 0.4.0: it is the version number, corrected license text, and a dependency update.

The features came one release earlier. ApexMaps 0.4.0 shipped on September 1 without a post here, so this one covers it too: hex tile layouts that redraw a region set as one equal cell per region, a morph that walks each region between its outline and its cell, and a hexbin series for maps with more points than pixels.

Key takeaways

ChangeReleaseWhat it is
Stable public API1.0.0Semantic versioning from here on: breaking changes wait for a major.
Wrappers on 1.x1.0.0React, Vue and Angular wrappers peer apexmaps ^1.0.0, which spans every future minor.
Hex tile layouts (layout: 'hex')0.4.0One equal cell per region, for seven region sets. Premium.
The morph0.4.0Toggling the layout walks each region between its outline and its cell. No new gate.
Hexbin (type: 'hexbin')0.4.0Point density on a hexagonal lattice that refines as the reader zooms. Premium.
Layouts from the default CDN0.4.0apexmaps-geo@1.1.0 serves all seven layout files with no configuration.
Breaking changesbothNone. A 0.3.0 configuration runs unchanged.

What does ApexMaps 1.0 mean?

It means a minor release can no longer break your code. The 1.0.0 release commit gives the reason: ApexMaps is a product customers buy, and the 0.x signal that anything may break no longer matched that. 1.0.0 commits the public API to semver, and the README status line changed from "pre-alpha" to "stable since 1.0.0".

The change you will feel first is in the framework wrappers. A caret range on a 0.x version pins the minor, so at 0.4.0 react-apexmaps, vue-apexmaps and ngx-apexmaps all had to peer ^0.4.0, and every core minor forced all four packages to move together. At 1.0.0 each wrapper's peer widens to ^1.0.0. Under 1.x a caret spans every minor, so a later core minor no longer forces the wrappers out.

What changed in 1.0.0 itself

  • The version. The root package, all three wrappers, and the runtime VERSION constant move to 1.0.0 together.
  • The license threshold wording. The Community license now reads as it does across the rest of the family: it covers organizations whose annual revenue, operating budget, funding, or equivalent financial resources are under $2 million USD, measured across a parent company, affiliates and any entity under common control. Under the old revenue-only wording, a funded pre-revenue startup appeared to qualify. It does not.
  • The license says what each plan includes. The LICENSE now lists the features that need Premium and above, generated from the same template as every other Apex product.
  • The license renders on GitHub. LICENSE became LICENSE.md. The extensionless name made GitHub show raw Markdown and turned the pricing link into a 404.
  • A dependency update. apex-commons, the package the Apex family shares for license handling, moves to ^0.8.0.

None of this touches a map's behavior.

What is a hex tile map, and how do I make one in ApexMaps?

A hex tile map (also called a honeycomb or tilegram) gives every region one hexagon of the same size, trading a distorted map for a legible one. A choropleth paints real boundaries, and real boundaries carry an argument nobody chose: area. On a US map, most of the ink goes to large, sparsely populated states, so the same value shouts in Wyoming and is a speck in New Jersey that the reader has to hunt for.

In ApexMaps a layout is a property of the geometry, not of the series:

const map = new ApexMaps(el, {
  geo: { map: 'us', layout: 'hex' },
  series: [{ type: 'choropleth', name: 'Index', joinBy: 'abbr', data }],
})

Each layout is keyed the way its boundary pack is keyed. us/states@hex joins on abbr, the same as the US states pack, so one dataset and one joinBy serve both pictures. Switching representation is an option change, not a data migration. A layout also resolves on its own, so asking for the honeycomb never downloads boundaries it does not draw.

There are three routes to the same feature:

geo: { map: 'us', layout: 'hex' }        // toggleable, and what most callers want
geo: { map: 'us/states@hex' }            // named directly; 'us/hex' aliases to it
ApexMaps.registerLayout(id, table, meta) // your own cell table

Which layouts ship, and how good are they?

Seven ship, and each is scored by the library's own npm run check:layout against the boundary pack it claims to represent. These are the numbers from the 0.4.0 release notes:

LayoutCellsReal borders keptWest to eastNorth to south
au/admin1@hex810 of 10 (100%)0.9520.976
jp/admin1@hex4774 of 86 (86%)0.9850.977
us/states@hex5189 of 107 (83%)0.9900.951
br/admin1@hex2741 of 50 (82%)0.9550.942
eu/nuts0@hex3745 of 58 (78%)0.9220.963
ca/admin1@hex1312 of 16 (75%)0.9670.923
de/admin1@hex1621 of 29 (72%)0.8410.968

"Real borders kept" is the share of real shared boundaries whose cells touch. The last two columns are rank correlations of each cell's position against the region's true centroid, which is what stops a layout from quietly putting Florida north of Maine. Every layout has zero order errors.

The scores are not 100% everywhere, and some of that is arithmetic rather than effort: Nagano borders eight prefectures and a hexagon has six sides. Where a layout has to flatten real geography, check:layout fails unless the layout file names the compromise with a reason. Five are recorded that way, so a decision like DC sitting level with North Carolina lives in a file instead of in a loosened threshold.

How does the morph work?

Toggling layout through updateOptions walks each region between its outline and its cell instead of swapping one picture for the other. That is what makes a cartogram readable: the reader watches Texas become a hexagon, and so knows which hexagon is Texas.

await map.updateOptions({ geo: { map: 'us', layout: 'hex' } }) // morphs
await map.updateOptions({ geo: { map: 'us', layout: null } })  // morphs back

There is no option to enable it. Three correspondence steps decide whether it reads as a morph or a glitch:

  • Each outline is resampled at equal arc length, because a hexagon has six vertices and a state's outline has hundreds.
  • Each is rotated to the cyclic offset that best matches its target, so regions do not spin.
  • Each is checked for winding, because the two pictures do not share a projection and opposite winding turns a shape inside out halfway across.

The 0.4.0 notes measure it at 8.3 ms median frame time and 9.1 ms at p90, with no measurable setup cost (74.9 ms with the morph against 76.2 ms without), because that time was always the geometry swap. It respects prefers-reduced-motion and chart.animations.enabled: false, stands down on its own when the mark count is too high for per-frame vertex work, and is skipped when the region set itself changes.

What is a hexbin map, and when should I use one?

Use a hexbin when you have more points than a marker map can show. Ten thousand markers on a country map is not a map of ten thousand things: past the first overlap the ink stops tracking the number. A hexbin lays a lattice over the projection and colors each cell by what landed in it, because a cell of fixed area can carry a number.

series: [
  {
    type: 'hexbin',
    name: 'Sightings',
    data: points,                              // { lon, lat }, { lng, lat } or { coordinates }
    radius: 12,                                // screen pixels, center to vertex
    aggregate: 'count',                        // or sum, mean, min, max
    scale: { palette: 'viridis', classes: 6 },
  },
]

Three decisions shape how it behaves:

  • count is the default and needs no value field. "Where are these things" is the usual question, and it should not require a numeric column the caller does not have.
  • The radius is in screen pixels. Cells stay the size you chose and the lattice refines as the reader zooms in rather than magnifying. Cells are rebuilt at quantized zoom levels, the same policy clustering uses, so a pan never re-bins.
  • The color domain follows the bins. Smaller cells hold fewer points, so class breaks move down as the lattice refines and the legend moves with them. Pin scale.domain when two maps must be read against each other; leave it unpinned otherwise, or every cell ends up in the palest class two zoom levels in.

Four more options tune the lattice: orientation ('pointy', the default, or 'flat'), minCount to stop drawing cells that hold fewer points than that, so a one-point cell does not shout as loudly as a hundred, gap to shrink each cell so the lattice reads as cells rather than one sheet, and valueField for the number that sum, mean, min and max aggregate.

There is no joinBy. A hexbin bins positions, so a datum with no coordinates is dropped with a counted warning. If your rows carry region keys instead of coordinates, you want a choropleth.

Hex tile layout or hexbin: which do I need?

Ask what one cell stands for. If it is a region, use a layout. If it is a patch of ground that points fell into, use a hexbin.

layout: 'hex'type: 'hexbin'
A cell isone region, placed by handone patch of the projection
It needsa region set with a layoutpoints with coordinates
Cell countfixed: one per regionwhatever the data and radius give
Boundariesreplaced by itignored by it, so it sits on a basemap
It answerswhich region, at equal weighthow much landed where

What else changed in 0.4.0?

Three smaller changes also shipped in 0.4.0, none of which needs a configuration change:

  • Theme tokens fall back to the family's. The map's chrome now falls back to the shared --apx-* root tokens, so a page can state its brand once on :root and maps follow the charts beside them. Anything set on --apexmaps-* still wins, and a page with no tokens renders as before. Dark mode stays self-contained.
  • Flow beads keep one speed at every zoom. Beads on flow: true routes used to speed up and then thin out as the reader zoomed. They now move at a constant screen speed from 0.5x to 10x zoom.
  • An empty tooltip formatter hides the tooltip. Returning '' from tooltip.formatter now hides the tooltip for that mark instead of showing an empty chip, so a mark can opt out without disabling tooltips for the whole map.

The bundle grew from 75.2 kB to 82.2 kB gzipped at 0.4.0 for layouts, the morph and hexbin, against a 150 kB budget.

Which ApexMaps features need a license?

Eleven features are licensed on the Premium plan and above: point clustering, hexbin density, hex tile layouts, custom projections, drilldown, annotations, arc and line routes, linked-map selection, pattern fills, image fills, and story mode. Hexbin and hex tile layouts are the two that 0.4.0 added. Hexbin was licensed from its first release, so nothing that used to be unlicensed was moved behind the gate.

Every licensed feature renders in full without a key, with a watermark on the map, so you can evaluate it in your own app with your own data. ApexMaps.setLicense(key) removes the watermark.

Everything else, including the choropleth, bubble and marker series, every built-in projection and geometry pack, joins, scales, legends, tooltips, the camera and the accessibility layer, is covered by the Community license for organizations under $2M in annual revenue, budget or funding. See Licensing for the full table and pricing for current plans.

How do I upgrade to ApexMaps 1.0.0?

Install the new version. No configuration changes are needed, whether you are coming from 0.4.0 or 0.3.0.

npm install apexmaps@1.0.0

If you use a framework wrapper, upgrade it in the same step. All three are at 1.0.0 and peer apexmaps ^1.0.0:

npm install apexmaps@1.0.0 react-apexmaps@1.0.0   # or vue-apexmaps, ngx-apexmaps

Geometry needs no action on the default source. The hex layouts live in apexmaps-geo@1.1.0, and the default CDN source is pinned to apexmaps-geo@1, so it already serves them. If you self-host geometry through ApexMaps.setGeoSource(), the dataset went from 26 files to 33: copy the seven layout files across. The boundary packs are unchanged. See Geometry Registry for the layout ids and their aliases.

See it live

Hex Tile MapOpen in new tab

Open the full Hex Tile Map demoPremium feature

Press the button on the left map to watch the morph between real boundaries and hex cells, then scroll for all seven built-in layouts.

Open the full Hexbin demoPremium feature

The hexbin page bins 20,000 points onto a lattice. Its comparison panel, which draws every one of those points as a marker, waits for a click, because drawing all of them is the expensive approach the page is arguing against. Both demos are the real library rendering in your browser.

Go deeper

  • Hex Tile Layouts for the seven layouts, the morph, and registerLayout for your own table.
  • Hexbin for every option, the aggregates, and how the color domain moves with the zoom.
  • Geometry Registry for the boundary packs each layout represents.
  • React, Vue and Angular for the 1.0.0 wrappers.
  • Licensing for what is licensed and what the Community license covers.

Summary

ApexMaps 1.0.0 changes what a version number promises rather than what the library does: from here on, a minor release will not break your code, and the wrappers no longer have to move with every core minor. The features arrived a month earlier in 0.4.0: hex tile layouts that give every region equal weight, a morph that teaches the reader which cell is which place, and a hexbin series for point data too dense to draw. Upgrade with npm install apexmaps@1.0.0, read the installation guide, or browse the demos.

Frequently asked questions

Is ApexMaps stable now?

Yes. ApexMaps 1.0.0, published on October 6, 2026, commits the public API to semantic versioning: breaking changes wait for a major version. Before 1.0.0 the library was 0.x, where any minor release could change options incompatibly. The README status line now reads 'stable since 1.0.0'.

Are there breaking changes in ApexMaps 1.0.0?

No. There are no breaking changes since 0.4.0, and 0.4.0 itself renamed or removed nothing and changed no default for an existing configuration. A map written against 0.3.0 or 0.4.0 runs on 1.0.0 unchanged. The release is the version number, license text fixes, and a dependency update.

What is the difference between a hexbin and a hex tile layout in ApexMaps?

They both draw hexagons and are otherwise unrelated. A hex tile layout (geo.layout: 'hex') redraws a region set, such as the US states, as one equal cell per region, placed by hand, so every region gets the same weight. A hexbin (type: 'hexbin') lays a lattice over the projection and colors each cell by how many points landed in it, so it needs point coordinates rather than region keys and sits on top of a basemap.

Do hexbin and hex tile layouts need an ApexMaps license?

Yes. Both are licensed on the Premium plan and above. Each renders in full without a key so you can evaluate it in your own app, with a watermark on the map, and ApexMaps.setLicense(key) removes the watermark. The morph between real boundaries and hex cells adds no separate gate, because it only runs when a hex layout is toggled.

Do I need to install apexmaps-geo to use hex tile layouts?

No, not if you use the default geometry source. The seven layout files are in apexmaps-geo 1.1.0, and the library's default CDN source is pinned to apexmaps-geo@1, so it picks them up with no configuration. If you self-host the geometry with setGeoSource(), copy the seven new layout files alongside the boundary packs.

How do I upgrade to ApexMaps 1.0.0?

Run npm install apexmaps@1.0.0. If you use a framework wrapper, upgrade it at the same time: react-apexmaps, vue-apexmaps and ngx-apexmaps are also at 1.0.0 and declare a peer dependency of apexmaps ^1.0.0. Under 1.x a caret range spans every minor, so later core minors will no longer force a wrapper upgrade.