geo-morpher 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +46 -44
  2. package/data/winchester/winchester_lsoa_cartogram.geojson +3245 -0
  3. package/data/winchester/winchester_lsoa_geo.geojson +24263 -0
  4. package/data/winchester/winchester_msoa_cartogram.geojson +635 -0
  5. package/data/winchester/winchester_msoa_geo.geojson +10743 -0
  6. package/data/winchester/winchester_ward_cartogram.geojson +725 -0
  7. package/data/winchester/winchester_ward_geo.geojson +10087 -0
  8. package/examples/README.md +2 -0
  9. package/examples/leaflet/canvas-glyphs.html +44 -0
  10. package/examples/leaflet/canvas-main.js +208 -0
  11. package/examples/leaflet/index.html +13 -10
  12. package/examples/leaflet/main.js +83 -20
  13. package/examples/leaflet/zoom-scaling-glyphs.html +1 -0
  14. package/examples/maplibre/index.html +3 -3
  15. package/examples/maplibre/indonesia/index.html +164 -144
  16. package/examples/maplibre/indonesia/main.js +397 -131
  17. package/examples/maplibre/main.js +3 -21
  18. package/examples/winchester/index.html +294 -0
  19. package/examples/winchester/main.js +333 -0
  20. package/examples/winchester/winchester_example.md +145 -0
  21. package/package.json +3 -4
  22. package/src/adapters/leaflet/glyphLayer.js +23 -9
  23. package/src/adapters/leaflet/index.js +3 -1
  24. package/src/adapters/leaflet/utils/collections.js +3 -37
  25. package/src/adapters/leaflet/utils/coordinates.js +1 -5
  26. package/src/adapters/leaflet/utils/glyphNormalizer.js +19 -74
  27. package/src/adapters/maplibre/glyphLayer.js +21 -10
  28. package/src/adapters/maplibre/index.js +2 -0
  29. package/src/adapters/maplibre/morphLayers.js +6 -5
  30. package/src/adapters/maplibre/utils/coordinates.js +2 -26
  31. package/src/adapters/maplibre/utils/customGlyphLayer.js +485 -0
  32. package/src/adapters/maplibre/utils/glyphNormalizer.js +14 -117
  33. package/src/adapters/shared/collections.js +27 -0
  34. package/src/adapters/shared/dom.js +6 -0
  35. package/src/adapters/shared/geometry.js +26 -0
  36. package/src/adapters/shared/glyphNormalizer.js +103 -0
  37. package/src/adapters/shared/markerAdapter.js +64 -0
  38. package/src/core/geomorpher.js +95 -8
  39. package/src/index.js +6 -2
  40. package/src/utils/projections.js +34 -16
  41. package/morphs.js +0 -1
package/README.md CHANGED
@@ -7,10 +7,16 @@ GeoJSON morphing utilities for animating between regular geography and cartogram
7
7
 
8
8
  ![](demo.gif)
9
9
 
10
+ To quickly create a grid cartogram, checkout my other library: ![gridmapper](https://danylaksono.is-a.dev/gridmapper/demo/).
10
11
 
11
- ## Status
12
12
 
13
- This library is currently in early-stage development (v0.1.0) and has recently completed a migration to a MapLibre-first adapter. The core morphing engine is stable, but the MapLibre adapter is new and under active development. Leaflet compatibility is maintained. Community feedback and contributions are welcome.
13
+ ## Features
14
+
15
+ - **MapLibre & Leaflet Adapters**: High-performance MapLibre-first implementation with Leaflet compatibility helpers.
16
+ - **Generic Morphing Engine**: Smoothly interpolates between any two aligned GeoJSON geometries using `flubber`.
17
+ - **Multivariate Glyphs**: Highly customizable DOM/SVG/Canvas overlays (charts, icons, sparklines) that stay synced with morphing geometry.
18
+ - **Basemap Effects**: Synchronized fading, blurring, or grayscale effects for basemap layers during transitions.
19
+ - **Projection Agnostic**: Auto-detects WGS84 (lat/lng) data; defaults to OSGB (British National Grid) for UK data but supports any CRS via `proj4`.
14
20
 
15
21
 
16
22
  ## Installation
@@ -19,30 +25,16 @@ This library is currently in early-stage development (v0.1.0) and has recently c
19
25
  npm install geo-morpher
20
26
  ```
21
27
 
22
- Bring your own MapLibre or Leaflet instance (both listed as peer dependencies). MapLibre is the default adapter; Leaflet remains supported for backward compatibility.
28
+ Leaflet is provided as a peer dependency—bring your own Leaflet instance when using the compatibility helpers. MapLibre remains the default adapter and is bundled as a dependency for out-of-the-box usage; if your build already supplies `maplibre-gl`, mark it as external to avoid duplicating the library.
23
29
 
24
30
  ## Usage
25
31
 
26
- Project structure highlights:
27
-
28
- ```text
29
- src/
30
- core/ # GeoMorpher core engine
31
- adapters/ # Integration helpers (Leaflet, etc.)
32
- lib/ # Shared runtime utilities (OSGB projection)
33
- utils/ # Data enrichment and projection helpers
34
- data/ # Sample Oxford LSOA datasets
35
- examples/ # Runnable browser demos (MapLibre & Leaflet)
36
- test/ # node:test coverage for core behaviours
37
- ```
38
-
39
32
  ### MapLibre adapter (default)
40
33
 
41
34
  - `createMapLibreMorphLayers` provisions GeoJSON sources and fill layers for regular, cartogram, and interpolated geometries, exposing an `updateMorphFactor` helper to drive tweening from UI controls.
42
35
  - `createMapLibreGlyphLayer` renders glyphs with `maplibregl.Marker` instances; enable `scaleWithZoom` to regenerate glyph markup as users zoom.
43
36
  - Pass your MapLibre namespace explicitly (`maplibreNamespace: maplibregl`) when calling glyph helpers in module-bundled builds where `maplibregl` is not attached to `globalThis`.
44
37
  - For heavy glyph scenes, consider upgrading to a [CustomLayerInterface](https://www.maplibre.org/maplibre-gl-js/docs/API/interfaces/CustomLayerInterface/) implementation that batches drawing on the GPU. The marker pipeline keeps the API simple while offering a documented migration path.
45
- - Track ongoing enhancements and open items in `docs/maplibre-migration-plan.md` before relying on the adapter in production.
46
38
 
47
39
  #### MapLibre basemap effects
48
40
 
@@ -103,39 +95,27 @@ const cartogram = morpher.getCartogramFeatureCollection();
103
95
  const tween = morpher.getInterpolatedFeatureCollection(0.5);
104
96
  ```
105
97
 
106
- #### Using custom projections
98
+ #### Projections & Coordinate Systems
107
99
 
108
- By default, `GeoMorpher` assumes input data is in **OSGB** (British National Grid) and converts to WGS84 for Leaflet. If your data is in a different coordinate system, pass a custom projection:
100
+ While `geo-morpher` was born out of UK-centric cartography, it is fully generic. It internally projects all data to WGS84 (latitude/longitude) for mapping compatibility.
101
+
102
+ - **Auto-detection**: If no projection is provided, `GeoMorpher` inspects your coordinates. If they look like WGS84, it uses them as-is.
103
+ - **OSGB Default**: If coordinates fall outside the geographic range, it assumes OSGB (EPSG:27700) and transforms them to WGS84.
104
+ - **Manual Override**: Pass a helper like `WebMercatorProjection` or a custom `proj4` wrapper for other systems.
109
105
 
110
106
  ```js
111
- import { GeoMorpher, WGS84Projection, isLikelyWGS84 } from "geo-morpher";
107
+ import { GeoMorpher, WGS84Projection, createProj4Projection } from "geo-morpher";
108
+ import proj4 from "proj4";
112
109
 
113
- // Auto-detect coordinate system
114
- const detectedProjection = isLikelyWGS84(regularGeoJSON);
115
- console.log("Detected:", detectedProjection); // 'WGS84', 'OSGB', or 'UNKNOWN'
110
+ // 1. Auto-detected (usually works for WGS84 or OSGB)
111
+ const morpher = new GeoMorpher({ regularGeoJSON, cartogramGeoJSON });
116
112
 
117
- // For data already in WGS84 (lat/lng)
118
- const morpher = new GeoMorpher({
119
- regularGeoJSON,
120
- cartogramGeoJSON,
121
- projection: WGS84Projection, // No transformation needed
122
- });
113
+ // 2. Explicit WGS84 (Identity)
114
+ const morpher = new GeoMorpher({ ..., projection: WGS84Projection });
123
115
 
124
- // For Web Mercator data
125
- import { WebMercatorProjection } from "geo-morpher";
126
- const morpher = new GeoMorpher({
127
- regularGeoJSON,
128
- cartogramGeoJSON,
129
- projection: WebMercatorProjection,
130
- });
131
-
132
- // Custom projection (e.g., using proj4)
133
- const customProjection = {
134
- toGeo: ([x, y]) => {
135
- // Transform [x, y] to [lng, lat]
136
- return [lng, lat];
137
- }
138
- };
116
+ // 3. Custom Projection (e.g., UTM Zone 33N)
117
+ const projection = createProj4Projection("+proj=utm +zone=33 +datum=WGS84", proj4);
118
+ const morpher = new GeoMorpher({ ..., projection });
139
119
  ```
140
120
 
141
121
  See `examples/maplibre/projections/index.html` for a browser-based custom projection demo.
@@ -241,6 +221,24 @@ slider.addEventListener("input", (event) => {
241
221
  updateMorphFactor(value);
242
222
  glyphLayer.updateGlyphs({ morphFactor: value });
243
223
  });
224
+
225
+ // You can also decouple glyphs from the GeoMorpher by providing a
226
+ // `featureCollection` or a live `featureProvider({ geometry, morphFactor })`:
227
+ //
228
+ // const glyph = await createLeafletGlyphLayer({
229
+ // drawGlyph,
230
+ // L,
231
+ // featureCollection: morpher.getRegularFeatureCollection(), // static set
232
+ // });
233
+ //
234
+ // const glyphProvider = await createLeafletGlyphLayer({
235
+ // drawGlyph,
236
+ // L,
237
+ // featureProvider: ({ geometry, morphFactor }) => morpher.getInterpolatedFeatureCollection(morphFactor),
238
+ // });
239
+ //
240
+ // The adapters also export small helper functions to convert normalized glyph values
241
+ // into platform-specific objects: `createLeafletIcon` and `createMapLibreMarkerData`.
244
242
  ```
245
243
 
246
244
  `drawGlyph` receives `{ feature, featureId, data, morpher, geometry, morphFactor }` and can return:
@@ -487,6 +485,10 @@ Run the bundled smoke tests with:
487
485
  npm test
488
486
  ```
489
487
 
488
+ ## Author
489
+
490
+ Dany Laksono
491
+
490
492
  ## License
491
493
 
492
494
  MIT