geo-morpher
v0.1.5
Published
GeoJSON morphing utilities with MapLibre-first adapter and Leaflet compatibility
Downloads
871
Maintainers
Readme
geo-morpher
GeoJSON morphing utilities for animating between regular geography and cartograms, with first-class MapLibre GL JS support. Smoothly interpolate between any two aligned GeoJSON geometries and overlay multivariate glyphs that stay in sync.

[!TIP] To quickly create a grid cartogram, check out gridmapper (https://danylaksono.is-a.dev/gridmapper/).
Features
- MapLibre-first: High-performance adapter for modern vector maps.
- Smooth Morphing: Seamlessly interpolate between any two aligned GeoJSON geometries (using
flubber). - Multivariate Glyphs: Position-synced DOM overlays for charts, icons, and sparklines.
- Basemap Effects: Synchronized fading and styling of basemaps during transitions.
- Projection Agnostic: Automatic support for WGS84, OSGB, and custom projections.
Installation
npm install geo-morpherQuick Start (MapLibre)
import maplibregl from "maplibre-gl";
import { GeoMorpher, createMapLibreMorphLayers } from "geo-morpher";
// 1. Prepare data (regular vs cartogram geography)
const morpher = new GeoMorpher({
regularGeoJSON: await (await fetch('regular_lsoa.json')).json(),
cartogramGeoJSON: await (await fetch('cartogram_lsoa.json')).json(),
});
await morpher.prepare();
// 2. Initialize MapLibre
const map = new maplibregl.Map({ ... });
map.on('load', async () => {
// 3. Create morphing layers
const morph = await createMapLibreMorphLayers({
morpher,
map,
interpolatedStyle: {
paint: { "fill-color": "#22c55e", "fill-opacity": 0.4 }
}
});
// 4. Drive the morph (0 = regular, 1 = cartogram)
morph.updateMorphFactor(0.5);
});Multivariate Glyphs
Overlay custom visualizations (SVG, Canvas, or HTML) that stay synced with the morphing polygons.
import { createMapLibreGlyphLayer } from "geo-morpher";
const glyphLayer = await createMapLibreGlyphLayer({
morpher,
map,
drawGlyph: ({ data, feature }) => ({
html: `<div class="glyph">${feature.properties.value}</div>`,
iconSize: [40, 40],
iconAnchor: [20, 20]
}),
maplibreNamespace: maplibregl
});
// Update glyphs during morphing
glyphLayer.updateGlyphs({ morphFactor: 0.5 });Basemap Effects
Automatically adjust basemap styles as you morph to focus attention on the data.
const morph = await createMapLibreMorphLayers({
morpher,
map,
basemapEffect: {
layers: ["osm-tiles"],
properties: {
"raster-opacity": [1, 0.25],
"raster-saturation": [0, -1]
}
}
});Core API
GeoMorpher
The core engine for geometry interpolation.
new GeoMorpher({ regularGeoJSON, cartogramGeoJSON, data, aggregations })prepare(): Run initialization (projection, enrichment).getInterpolatedFeatureCollection(factor): Get the geometry at a specific state.
Projections
Auto-detects WGS84 or OSGB. For UTM or others:
import { createProj4Projection } from "geo-morpher";
import proj4 from "proj4";
const projection = createProj4Projection("+proj=utm +zone=33 +datum=WGS84", proj4);
const morpher = new GeoMorpher({ ..., projection });Examples
Run the local server to see demos:
npm run examples:browser- MapLibre Demo: Basic morphing and glyphs.
- Indonesia: Large-scale, multipolygon geometry morphing.
- Projections: Custom coordinate systems.
Legacy Support
Leaflet is still supported via createLeafletMorphLayers and createLeafletGlyphLayer. See API Reference for details.
Documentation
License
MIT © Dany Laksono
