@zwishing/emap 0.2.0 → 0.3.0
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.
- package/CHANGELOG.md +212 -1
- package/FEATURES.md +455 -0
- package/README.md +415 -210
- package/dist/core/event-map.d.ts +67 -0
- package/dist/core/feature-event-dispatcher.d.ts +70 -0
- package/dist/core/handler-manager.d.ts +49 -0
- package/dist/core/handler.d.ts +48 -0
- package/dist/core/handlers/box-select.d.ts +54 -0
- package/dist/core/handlers/click-select.d.ts +31 -0
- package/dist/core/handlers/drag-pan.d.ts +28 -0
- package/dist/core/handlers/draw-feature.d.ts +76 -0
- package/dist/core/handlers/lasso-select.d.ts +57 -0
- package/dist/core/handlers/scroll-zoom.d.ts +24 -0
- package/dist/core/handlers/select-geometry.d.ts +24 -0
- package/dist/core/handlers/select-mode.d.ts +14 -0
- package/dist/core/handlers/transform-feature.d.ts +41 -0
- package/dist/core/handlers/vertex-edit.d.ts +98 -0
- package/dist/core/pointer-event-dispatcher.d.ts +40 -0
- package/dist/core/tween.d.ts +1 -0
- package/dist/emap.css +42 -8
- package/dist/emap.js +2 -2
- package/dist/emap.mjs +1 -1
- package/dist/geo/camera.d.ts +100 -0
- package/dist/geo/projection.d.ts +8 -1
- package/dist/geo/viewport.d.ts +18 -0
- package/dist/index.d.ts +26 -2
- package/dist/map/edit-state-store.d.ts +1 -1
- package/dist/map/map.d.ts +89 -2
- package/dist/map/selection.d.ts +5 -2
- package/dist/renderer/edit-overlay-renderer.d.ts +2 -1
- package/dist/source/source.d.ts +2 -2
- package/dist/source/topology-source.d.ts +7 -2
- package/dist/ui/box-select-control.d.ts +13 -37
- package/dist/ui/draw-feature-control.d.ts +6 -71
- package/dist/ui/lasso-select-control.d.ts +14 -61
- package/dist/ui/status-control.d.ts +2 -2
- package/dist/ui/vertex-edit-control.d.ts +5 -100
- package/package.json +5 -1
- package/dist/core/drag-pan-handler.d.ts +0 -28
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,216 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.3.0] - 2026-05-21
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- DX Phase 1 (toward 0.3.0): `Handler` interface + `HandlerManager`; the pan
|
|
15
|
+
and wheel interactions are now named handlers `map.dragPan` /
|
|
16
|
+
`map.scrollZoom` with `enable()/disable()/isEnabled()/setOptions()`.
|
|
17
|
+
Enables selective interaction toggling (e.g. disable wheel, keep pan)
|
|
18
|
+
without reaching into private internals. No behavior change for the
|
|
19
|
+
default path (`interactive` unset/true): the underlying pan/wheel
|
|
20
|
+
primitives are unchanged and all existing tests pass byte-identically.
|
|
21
|
+
One intentional fix: `MapOptions.interactive: false` was previously a
|
|
22
|
+
declared-but-unwired no-op — it is now functional and disables pan+zoom
|
|
23
|
+
as the option always implied. See
|
|
24
|
+
`docs/superpowers/specs/2026-05-17-emap-maplibre-dx-design.md`.
|
|
25
|
+
- DX Phase 2a (toward 0.3.0): `HandlerManager` is now the single
|
|
26
|
+
pointer-event arbiter (`attach`/`detach`, normalized `NormalizedPointerEvent`,
|
|
27
|
+
priority-ordered dispatch with exclusive-gesture locking). `dragPan` pans
|
|
28
|
+
via `handlePointer` and owns no DOM listeners; the old internal pan
|
|
29
|
+
primitive (`src/core/drag-pan-handler.ts`) is removed. No pan behavior
|
|
30
|
+
change; this is the seam P2b's selection handlers slot into.
|
|
31
|
+
- DX Phase 2b (toward 0.3.0): three opt-in named selection handlers —
|
|
32
|
+
`map.clickSelect`, `map.boxSelect`, `map.lassoSelect` (each a `Handler`
|
|
33
|
+
with `enable/disable/isEnabled/setOptions/getOptions`). Driven by the
|
|
34
|
+
Phase-2a pointer arbiter; `box`/`lasso` sit above `dragPan` so
|
|
35
|
+
`shift`+drag selects (when enabled) instead of panning, with no
|
|
36
|
+
`addControl` needed. Shared pure `resolveMode` (configurable
|
|
37
|
+
modifier→`SelectMode` table) and a shared `select-geometry` module
|
|
38
|
+
replace the duplicated private `_modeFromEvent`. `boxSelect` and
|
|
39
|
+
`lassoSelect` are mutually exclusive (`enable()` throws if the other is
|
|
40
|
+
on). Disabled by default → `new Emap()` behavior is unchanged; the
|
|
41
|
+
legacy `BoxSelectControl`/`LassoSelectControl` keep working unchanged
|
|
42
|
+
(thin-shell rewrite is Phase 2c).
|
|
43
|
+
- DX Phase 2c (toward 0.3.0): `BoxSelectControl` / `LassoSelectControl`
|
|
44
|
+
are now button-only thin shells over the P2b `map.boxSelect` /
|
|
45
|
+
`map.lassoSelect` handlers (the ~490 lines of duplicated
|
|
46
|
+
listener/overlay/hit-test/select logic deleted) — public class,
|
|
47
|
+
constructor options, 0×0 anchor DOM, selection behaviour, and the
|
|
48
|
+
dashed-lasso visual are byte-identical (the handler now honours
|
|
49
|
+
`strokeDasharray`, default `'4 3'`). Adding both controls now surfaces
|
|
50
|
+
the handlers' mutual-exclusivity error instead of silently conflicting.
|
|
51
|
+
Duplicated types consolidated to one declaration each with re-export
|
|
52
|
+
shims (every public import path unchanged): `SelectMode` →
|
|
53
|
+
`core/handlers/select-mode`, `BoxSelectStyle` →
|
|
54
|
+
`core/handlers/box-select`, `LassoSelectStyle`/`LassoStyle` →
|
|
55
|
+
`core/handlers/lasso-select` (`LassoStyle` widened additively to include
|
|
56
|
+
the optional `strokeDasharray`). No arbiter/dispatch change.
|
|
57
|
+
- DX Phase 3 (toward 0.3.0): delegated feature events —
|
|
58
|
+
`map.on('feature:click'|'feature:hover'|'feature:enter'|'feature:leave',
|
|
59
|
+
{ source?, layers? }?, cb)`. Fed by the Phase-2a pointer arbiter, hit-test
|
|
60
|
+
reuses the existing `FeatureQuery` (no new path), decoupled from
|
|
61
|
+
selection. Zero cost when no `feature:*` listener is registered (the
|
|
62
|
+
pointer sink is installed lazily). Canonical highlight recipe:
|
|
63
|
+
`map.on('feature:enter', {}, e => map.setHighlightedFeatures([e.ref]));
|
|
64
|
+
map.on('feature:leave', {}, () => map.clearHighlightedFeatures());` —
|
|
65
|
+
replaces the manual mousemove-poll + highlight-sync boilerplate.
|
|
66
|
+
- DX Phase 4 (toward 0.3.0): opened the emap design-token namespace —
|
|
67
|
+
`controls.css` now declares 9 `--emap-*` custom properties on `:root`
|
|
68
|
+
(`accent`, `accent-soft`, `surface-bg`, `surface-border`,
|
|
69
|
+
`surface-shadow`, `radius`, `hover-bg`, `danger`, `font`) with the
|
|
70
|
+
current literal values as defaults. The vertex-edit right-click menu
|
|
71
|
+
("删除节点") migrated off inline styles + JS `mouseenter`/`mouseleave`
|
|
72
|
+
hover toggle onto class-based rules (`.emap-ctx-menu` /
|
|
73
|
+
`.emap-ctx-menu-item` with `:hover`) consuming the tokens. Default
|
|
74
|
+
rendering is byte-identical; themers override `--emap-*` on `:root` (or
|
|
75
|
+
a parent) to restyle. Existing controls' literal values are unchanged
|
|
76
|
+
— namespace opened but not retro-applied (follow-up phases may opt in).
|
|
77
|
+
- DX Phase 5 (toward 0.3.0): vertex editing is now the arbiter-driven
|
|
78
|
+
`map.vertexEdit` handler (`enable/disable/isEnabled/setOptions/
|
|
79
|
+
getOptions`), consistent with the other handlers — usable without
|
|
80
|
+
`addControl`. The arbiter gained a `contextmenu` event kind (right-click
|
|
81
|
+
vertex delete). `VertexEditControl` is now a button-only thin shell over
|
|
82
|
+
`map.vertexEdit`; its public class, constructor options, button DOM,
|
|
83
|
+
`editmodechange`/edit-mode behavior, undo commands, and the
|
|
84
|
+
`vertex_moved` event are byte-identical. Disabled by default →
|
|
85
|
+
`new Emap()` behavior unchanged. (P4 will migrate the context-menu
|
|
86
|
+
inline styles to CSS tokens.)
|
|
87
|
+
- DX Phase 6 (toward 0.3.0): feature drawing is now the arbiter-driven
|
|
88
|
+
`map.drawFeature` handler (`enable/disable/isEnabled/setOptions/
|
|
89
|
+
getOptions`) — usable without `addControl`. The arbiter gained a
|
|
90
|
+
`dblclick` event kind (finish polyline/polygon); `Escape`-to-cancel is a
|
|
91
|
+
handler-owned key listener. `enable()` throws if `source`/`type` are
|
|
92
|
+
unset. `DrawFeatureControl` is now a button-only thin shell over
|
|
93
|
+
`map.drawFeature`; its public class, constructor options (incl. `icon`),
|
|
94
|
+
button DOM, `feature_created` event, `FeatureCreateCommand`, and the
|
|
95
|
+
cross-mode auto-deactivate are byte-identical. Disabled (and
|
|
96
|
+
unconfigured) by default → `new Emap()` behavior unchanged.
|
|
97
|
+
- DX Phase 7 (toward 0.3.0): feature transform is now the arbiter-driven
|
|
98
|
+
modal `map.transformFeature` handler (`setOptions({ mode:
|
|
99
|
+
'translate'|'rotate'|'scale' })`, `enable/disable/isEnabled/getOptions`).
|
|
100
|
+
Selection is delegated to `clickSelect` (click = replace, shift+click =
|
|
101
|
+
add, click on empty space = clear); `transformFeature` owns no
|
|
102
|
+
selection logic — it press-drags an already-selected feature:
|
|
103
|
+
pointerdown over a selected feature opens the matching `editSession`,
|
|
104
|
+
drag streams the delta, pointerup commits one undo entry, `Escape`
|
|
105
|
+
cancels. `EditMode` gained `'transform'` (enters the modal pan-disable +
|
|
106
|
+
`editmodechange` like vertex/draw; cross-deactivates with
|
|
107
|
+
vertexEdit/drawFeature). The headless `map.editSession` API is unchanged
|
|
108
|
+
— this only absorbs the pointer→session boilerplate. Disabled by default
|
|
109
|
+
→ `new Emap()` behavior unchanged. The `feature-translate` /
|
|
110
|
+
`feature-rotate-scale` examples are rewritten to the one-line recipe.
|
|
111
|
+
- DX Phase 8 (toward 0.3.0): delegated `map.on('mousemove', cb)` event
|
|
112
|
+
(payload `{ point, mapCoord, originalEvent }`), fed by the Phase-2a
|
|
113
|
+
pointer arbiter via the same sink mechanism as the Phase-3 `feature:*`
|
|
114
|
+
events — exported `PointerMoveEvent` type. `StatusControl` no longer
|
|
115
|
+
hand-wires a raw canvas `mousemove`; it subscribes the delegated event
|
|
116
|
+
(public class/options/DOM/coordinate-string unchanged). Zero cost when
|
|
117
|
+
no `mousemove`/`feature:*` listener is registered (the pointer sink is
|
|
118
|
+
installed lazily and shared). One intentional, documented behavior
|
|
119
|
+
change: the coordinate readout pauses during an exclusive pan/drag
|
|
120
|
+
gesture (consistent with `feature:hover`) and resumes on release.
|
|
121
|
+
Disabled-by-default cost model unchanged → `new Emap()` behavior
|
|
122
|
+
identical.
|
|
123
|
+
- DX Phase 9 (toward 0.3.0): MapLibre-parity camera API — `map.jumpTo`,
|
|
124
|
+
`setCenter`, `setZoom`, `easeTo`, `panTo`, `panBy`, `zoomTo`, `flyTo`
|
|
125
|
+
(van-Wijk parabolic), `fitBounds`, `stop` (all chainable, return
|
|
126
|
+
`this`), built on the existing `Tween`/`Viewport`. Fires a
|
|
127
|
+
`movestart`/`move`/`moveend` + `zoomstart`/`zoom`/`zoomend` lifecycle.
|
|
128
|
+
Camera state is `{ center (projected/data coords, = the Phase-8
|
|
129
|
+
`mapCoord` space), scale }`; `zoom` is an optional Web-Mercator
|
|
130
|
+
convenience (`Projection.getScale` inverse) — non-Web-Mercator CRSs
|
|
131
|
+
pass `{ scale }`. 2D only (no bearing/pitch). A new camera call (or a
|
|
132
|
+
user pan/wheel) interrupts a running animation; the interrupted move
|
|
133
|
+
still fires its `moveend`. `getCenter`/`getZoom`/`setExtent`/`reset`/
|
|
134
|
+
`zoomIn`/`zoomOut` are byte-identical; default `new Emap()` behaviour
|
|
135
|
+
unchanged (no animation runs until a camera method is called).
|
|
136
|
+
- DX Phase 10 (toward 0.3.0): typed `EmapEventMap` — `map.on` / `off` /
|
|
137
|
+
`once` now give
|
|
138
|
+
event-name autocomplete and payload inference for the camera lifecycle
|
|
139
|
+
(`movestart`/`move`/`moveend`/`zoomstart`/`zoom`/`zoomend`) and the
|
|
140
|
+
`data`/`error`/`selectionchange`/`historychange`/`editmodechange`/
|
|
141
|
+
`crschange`/`resize`/`validationfailed` events. `EmapEventMap` is an
|
|
142
|
+
augmentable `interface` (`declare module` to register custom events);
|
|
143
|
+
unknown event names still compile (escape hatch preserved). Compile-time
|
|
144
|
+
only — zero runtime change. Exported: `EmapEventMap`, `CameraEvent`.
|
|
145
|
+
- DX Phase 11 (toward 0.3.0): per-handler cursor — each `Handler` may
|
|
146
|
+
implement `getCursor(): string | null`; `HandlerManager` arbitrates one
|
|
147
|
+
effective cursor (active gesture > priority order > default) and writes
|
|
148
|
+
it to the map element via `refreshCursor()` / on every dispatch. Adds
|
|
149
|
+
the previously-absent `grab`/`grabbing` pan cursors and the draw
|
|
150
|
+
crosshair (the old `.emap-draw-active` CSS rule was dead); the ad-hoc
|
|
151
|
+
`.emap-edit-active`/`.emap-draw-active` CSS-class mechanism is removed
|
|
152
|
+
(single source of truth). No dispatch/priority behaviour change.
|
|
153
|
+
|
|
154
|
+
### Changed
|
|
155
|
+
|
|
156
|
+
- **`LassoStyle` widened (additive, back-compat):** the public
|
|
157
|
+
`LassoStyle` type (`@zwishing/emap` index, from
|
|
158
|
+
`core/handlers/lasso-select`) gained an optional `strokeDasharray?:
|
|
159
|
+
string` field (default `'4 3'`). Every existing 3-field value remains
|
|
160
|
+
assignable; consumers passing an extra `strokeDasharray` to a lasso
|
|
161
|
+
handler/control now see the dashed visual previously only possible via
|
|
162
|
+
the `LassoSelectControl` surface.
|
|
163
|
+
- **Adding `BoxSelectControl` + `LassoSelectControl` together now
|
|
164
|
+
throws:** the P2b handlers are mutually exclusive (one of `enable()`
|
|
165
|
+
throws `cannot enable boxSelect: lassoSelect is enabled`). The legacy
|
|
166
|
+
controls silently coexisted with undefined behavior; the P2c thin
|
|
167
|
+
shells surface the conflict honestly. Install one, OR call
|
|
168
|
+
`map.boxSelect.disable()` before enabling the other (see the updated
|
|
169
|
+
`test/examples/lasso-select.html` for the canonical toggle recipe).
|
|
170
|
+
- Release metadata now targets `0.3.0`, matching the handler-centric public API
|
|
171
|
+
documented in README/FEATURES.
|
|
172
|
+
|
|
173
|
+
### Fixed
|
|
174
|
+
|
|
175
|
+
- Made the bundle self-contained smoke test portable on Windows by resolving
|
|
176
|
+
local CLI shims through `cmd /c`, adding explicit `esbuild` dev dependency
|
|
177
|
+
coverage, and relaxing the GeoJSON bundle-load timeout for slower full-suite
|
|
178
|
+
runs.
|
|
179
|
+
- Completed the typed event surface: `EmapEventMap` now includes the delegated
|
|
180
|
+
`mousemove` and `feature:*` events, so facade authors can index the event map
|
|
181
|
+
for those 0.3.0 APIs instead of relying only on `map.on(...)` overloads.
|
|
182
|
+
|
|
183
|
+
### Documentation
|
|
184
|
+
|
|
185
|
+
- Added third-party release guidance: static asset deployment, full custom
|
|
186
|
+
box-selection wiring without bundled controls, known limitations, API
|
|
187
|
+
stability boundaries, and a release checklist. The build now cleans `dist`
|
|
188
|
+
before production output so stale declaration files are not packed.
|
|
189
|
+
- Refreshed the project documentation for the current handler-centric public
|
|
190
|
+
API: rewrote `README.md` around third-party integration, headless handler
|
|
191
|
+
usage, custom UI patterns, feature events, editing, worker setup, theming,
|
|
192
|
+
and built-in controls; moved `docs/FEATURES.md` to the package root as
|
|
193
|
+
`FEATURES.md` and updated it as the canonical capability matrix. Removed
|
|
194
|
+
the mandatory OpenSpec workflow instructions from `AGENTS.md` and
|
|
195
|
+
`CLAUDE.md`, keeping them focused on current project architecture and
|
|
196
|
+
contribution rules.
|
|
197
|
+
- Documented the explicit 0.2.0 loading contract: `setData()` resolves only
|
|
198
|
+
after the dataset is populated and `data{reason:'load'}` has fired, and
|
|
199
|
+
`map.addSource()` is order-independent (back-fills an already-loaded
|
|
200
|
+
source). Added a troubleshooting note — a blank map with no error after
|
|
201
|
+
"upgrading to 0.2.0" is the *pre-0.2.0* fire-and-forget symptom and
|
|
202
|
+
indicates a stale install, not an emap defect (a reopened Friction #9
|
|
203
|
+
report was root-caused to this; the published 0.2.0 runtime was verified
|
|
204
|
+
to settle the promise after the data event).
|
|
205
|
+
- Modernized all 41 `test/examples/*.html` to the canonical awaitable
|
|
206
|
+
recipe (`await source.setData(...)` → `map.addSource(...)` →
|
|
207
|
+
`map.setExtent(...)` in a `try/catch`), replacing the older event-driven
|
|
208
|
+
`source.on('data'/'error')` load pattern. Examples now match the README
|
|
209
|
+
"Loading contract" verbatim, removing the example/doc divergence that
|
|
210
|
+
contributed to the reopened #9 misdiagnosis. Per-file status text,
|
|
211
|
+
post-load logic, and multi-file/Promise-wrapper variants preserved.
|
|
212
|
+
|
|
213
|
+
### Tested
|
|
214
|
+
|
|
215
|
+
- Added `src/map/setdata-addsource-ordering.test.ts`: end-to-end regression
|
|
216
|
+
proving both `addSource`→`await setData` and `await setData`→`addSource`
|
|
217
|
+
populate the dataset before the promise resolves and schedule a render
|
|
218
|
+
(guards the loading contract against regression).
|
|
219
|
+
|
|
10
220
|
## [0.2.0] - 2026-05-17
|
|
11
221
|
|
|
12
222
|
### Changed
|
|
@@ -112,7 +322,8 @@ Initial public release.
|
|
|
112
322
|
- Distributed control stylesheet as `dist/emap.css` (importable via
|
|
113
323
|
`@zwishing/emap/style.css`).
|
|
114
324
|
|
|
115
|
-
[Unreleased]: https://github.com/zwishing/emap/compare/v0.
|
|
325
|
+
[Unreleased]: https://github.com/zwishing/emap/compare/v0.3.0...HEAD
|
|
326
|
+
[0.3.0]: https://github.com/zwishing/emap/compare/v0.2.0...v0.3.0
|
|
116
327
|
[0.2.0]: https://github.com/zwishing/emap/compare/v0.1.3...v0.2.0
|
|
117
328
|
[0.1.3]: https://github.com/zwishing/emap/compare/v0.1.2...v0.1.3
|
|
118
329
|
[0.1.2]: https://github.com/zwishing/emap/compare/v0.1.1...v0.1.2
|
package/FEATURES.md
ADDED
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
# emap Feature Overview
|
|
2
|
+
|
|
3
|
+
This document lists the current public capabilities of `emap`. It complements
|
|
4
|
+
the quick-start focused [README.md](README.md).
|
|
5
|
+
|
|
6
|
+
## 1. Runtime and Packaging
|
|
7
|
+
|
|
8
|
+
- Browser-only TypeScript library.
|
|
9
|
+
- Framework-agnostic: usable from vanilla HTML, React, Vue, Svelte, Angular, or
|
|
10
|
+
any other browser app.
|
|
11
|
+
- IIFE and ESM builds.
|
|
12
|
+
- Self-contained browser bundler path with Mapshaper supplied as package
|
|
13
|
+
sibling bundles.
|
|
14
|
+
- Optional worker bundle for off-thread dataset operations.
|
|
15
|
+
- Public CSS entry: `@zwishing/emap/style.css`.
|
|
16
|
+
|
|
17
|
+
## 2. Public API Stability
|
|
18
|
+
|
|
19
|
+
Recommended stable integration surface:
|
|
20
|
+
|
|
21
|
+
- `Emap`
|
|
22
|
+
- `TopologySource`
|
|
23
|
+
- map source/layer/camera APIs
|
|
24
|
+
- named handlers exposed on `map.*`
|
|
25
|
+
- feature events and typed map events
|
|
26
|
+
- `map.ops.*`
|
|
27
|
+
- `map.features`, `map.validators`, `map.editSession`
|
|
28
|
+
- built-in controls
|
|
29
|
+
- documented types exported from the package root
|
|
30
|
+
|
|
31
|
+
Advanced but less stable surfaces:
|
|
32
|
+
|
|
33
|
+
- `HandlerManager`
|
|
34
|
+
- concrete handler classes
|
|
35
|
+
- `CanvasPainter` and `EditOverlayRenderer`
|
|
36
|
+
- `MapshaperAdapter` replacement hooks
|
|
37
|
+
- edit command classes
|
|
38
|
+
- raw Mapshaper topology types
|
|
39
|
+
|
|
40
|
+
These advanced exports are useful for custom integrations and tests, but they
|
|
41
|
+
may change faster than the main `Emap` and `TopologySource` API while the
|
|
42
|
+
project is still pre-production.
|
|
43
|
+
|
|
44
|
+
## 3. Data Sources
|
|
45
|
+
|
|
46
|
+
Supported inputs:
|
|
47
|
+
|
|
48
|
+
| Input | Entry |
|
|
49
|
+
|---|---|
|
|
50
|
+
| GeoJSON | `TopologySource.fromUrl()`, `fromBytes()`, `setData()` |
|
|
51
|
+
| TopoJSON | `TopologySource.fromUrl()`, `fromBytes()`, `setData()` |
|
|
52
|
+
| ZIP Shapefile | `TopologySource.fromUrl()`, `fromBytes()`, `setData()` |
|
|
53
|
+
| Mapshaper snapshot | `map.loadSnapshot()` |
|
|
54
|
+
|
|
55
|
+
Source capabilities:
|
|
56
|
+
|
|
57
|
+
- Awaitable loading contract: `setData()` resolves after data is ready.
|
|
58
|
+
- Order-independent `map.addSource()`.
|
|
59
|
+
- CRS inference from GeoJSON defaults and Shapefile `.prj`.
|
|
60
|
+
- ZIP extraction limits for archive count, decompressed size, and ratio checks.
|
|
61
|
+
- `getLayers()`, `getDataset()`, `getExtent()`, `getArcs()`, and export helpers.
|
|
62
|
+
- `DisplayArcs` LOD wrapper for large datasets.
|
|
63
|
+
|
|
64
|
+
## 4. Layers and Rendering
|
|
65
|
+
|
|
66
|
+
Layer types:
|
|
67
|
+
|
|
68
|
+
- `line`
|
|
69
|
+
- `fill`
|
|
70
|
+
- `circle`
|
|
71
|
+
|
|
72
|
+
Layer APIs:
|
|
73
|
+
|
|
74
|
+
- `map.addLayer(layer, before?)`
|
|
75
|
+
- `map.removeLayer(id)`
|
|
76
|
+
- `map.getLayer(id)`
|
|
77
|
+
- `map.getLayers()`
|
|
78
|
+
- `map.moveLayer(id, beforeId?)`
|
|
79
|
+
- `map.setLayerVisibility(id, visibility)`
|
|
80
|
+
- `map.setPaintProperty(id, name, value)`
|
|
81
|
+
|
|
82
|
+
Rendering capabilities:
|
|
83
|
+
|
|
84
|
+
- HTML5 Canvas 2D renderer.
|
|
85
|
+
- Batched stroke drawing for topology arcs.
|
|
86
|
+
- Shared-arc line rendering so polygon boundaries can be drawn once.
|
|
87
|
+
- Polygon fill rendering with even-odd fill handling.
|
|
88
|
+
- Point rendering.
|
|
89
|
+
- Highlight overlay rendering.
|
|
90
|
+
- Edit and draw overlay rendering.
|
|
91
|
+
|
|
92
|
+
## 5. Camera and View
|
|
93
|
+
|
|
94
|
+
Camera methods:
|
|
95
|
+
|
|
96
|
+
- `jumpTo()`
|
|
97
|
+
- `setCenter()`
|
|
98
|
+
- `setZoom()`
|
|
99
|
+
- `easeTo()`
|
|
100
|
+
- `flyTo()`
|
|
101
|
+
- `panTo()`
|
|
102
|
+
- `panBy()`
|
|
103
|
+
- `zoomTo()`
|
|
104
|
+
- `fitBounds()`
|
|
105
|
+
- `stop()`
|
|
106
|
+
|
|
107
|
+
View and coordinate methods:
|
|
108
|
+
|
|
109
|
+
- `getCenter()`
|
|
110
|
+
- `getZoom()`
|
|
111
|
+
- `getExtent()`
|
|
112
|
+
- `setExtent()`
|
|
113
|
+
- `reset()`
|
|
114
|
+
- `project()`
|
|
115
|
+
- `unproject()`
|
|
116
|
+
- `resize()`
|
|
117
|
+
|
|
118
|
+
Camera events:
|
|
119
|
+
|
|
120
|
+
- `movestart`
|
|
121
|
+
- `move`
|
|
122
|
+
- `moveend`
|
|
123
|
+
- `zoomstart`
|
|
124
|
+
- `zoom`
|
|
125
|
+
- `zoomend`
|
|
126
|
+
|
|
127
|
+
## 6. Named Interaction Handlers
|
|
128
|
+
|
|
129
|
+
`emap` exposes built-in interactions as named handlers. Third-party apps can use
|
|
130
|
+
these directly without using bundled UI controls.
|
|
131
|
+
|
|
132
|
+
| Handler | Purpose |
|
|
133
|
+
|---|---|
|
|
134
|
+
| `map.dragPan` | Pointer drag map panning |
|
|
135
|
+
| `map.scrollZoom` | Wheel zoom |
|
|
136
|
+
| `map.clickSelect` | Click selection |
|
|
137
|
+
| `map.boxSelect` | Shift-drag rectangular selection |
|
|
138
|
+
| `map.lassoSelect` | Free-form lasso selection |
|
|
139
|
+
| `map.vertexEdit` | Topology-aware vertex editing |
|
|
140
|
+
| `map.drawFeature` | Point, polyline, and polygon drawing |
|
|
141
|
+
| `map.transformFeature` | Translate, rotate, or scale selected features |
|
|
142
|
+
|
|
143
|
+
Uniform handler surface:
|
|
144
|
+
|
|
145
|
+
- `enable()`
|
|
146
|
+
- `disable()`
|
|
147
|
+
- `isEnabled()`
|
|
148
|
+
- `setOptions()`
|
|
149
|
+
- `getOptions()`
|
|
150
|
+
- `handlePointer()`
|
|
151
|
+
- optional `getCursor()`
|
|
152
|
+
|
|
153
|
+
`HandlerManager` arbitrates pointer events with priority ordering, exclusive
|
|
154
|
+
gesture locking, and cursor resolution.
|
|
155
|
+
|
|
156
|
+
## 7. Selection, Hit Testing, and Feature Events
|
|
157
|
+
|
|
158
|
+
Selection APIs:
|
|
159
|
+
|
|
160
|
+
- `map.select(features, { mode })`
|
|
161
|
+
- `map.deselect(features)`
|
|
162
|
+
- `map.clearSelection()`
|
|
163
|
+
- `map.getSelection()`
|
|
164
|
+
- `map.isSelected(feature)`
|
|
165
|
+
- `map.deleteSelected()`
|
|
166
|
+
|
|
167
|
+
Selection modes:
|
|
168
|
+
|
|
169
|
+
- `replace`
|
|
170
|
+
- `add`
|
|
171
|
+
- `toggle`
|
|
172
|
+
|
|
173
|
+
Feature querying:
|
|
174
|
+
|
|
175
|
+
- Point query: `map.queryFeatures([x, y], options?)`
|
|
176
|
+
- BBox query: `map.queryFeatures([[x1, y1], [x2, y2]], options?)`
|
|
177
|
+
- Layer filtering through `{ layers: [...] }`
|
|
178
|
+
- Lazy Flatbush spatial indexes.
|
|
179
|
+
- `map.prebuildSpatialIndex(sourceId?)`
|
|
180
|
+
- `map.clearSpatialIndex(sourceId?)`
|
|
181
|
+
|
|
182
|
+
Delegated events:
|
|
183
|
+
|
|
184
|
+
- `feature:click`
|
|
185
|
+
- `feature:hover`
|
|
186
|
+
- `feature:enter`
|
|
187
|
+
- `feature:leave`
|
|
188
|
+
- `mousemove`
|
|
189
|
+
|
|
190
|
+
Feature accessor:
|
|
191
|
+
|
|
192
|
+
- `map.features.get(ref)`
|
|
193
|
+
- `map.features.iter(sourceId, layerId)`
|
|
194
|
+
- `map.features.count(sourceId, layerId)`
|
|
195
|
+
|
|
196
|
+
Highlighting:
|
|
197
|
+
|
|
198
|
+
- `map.setHighlightedFeatures(features, style?)`
|
|
199
|
+
- `map.clearHighlightedFeatures()`
|
|
200
|
+
- `map.setHighlightStyle(style)`
|
|
201
|
+
|
|
202
|
+
## 8. Editing Model
|
|
203
|
+
|
|
204
|
+
Undoable command families:
|
|
205
|
+
|
|
206
|
+
- Vertex commands: `VertexMoveCommand`, `VertexInsertCommand`,
|
|
207
|
+
`VertexDeleteCommand`.
|
|
208
|
+
- Feature commands: `FeatureCreateCommand`, `FeatureDeleteCommand`,
|
|
209
|
+
`BulkFeatureDeleteCommand`, `FeatureTranslateCommand`, `FeatureAffineCommand`.
|
|
210
|
+
- Topology commands: `SplitSharedArcsCommand`.
|
|
211
|
+
- Dataset replace: `DatasetReplaceCommand`.
|
|
212
|
+
- Attribute and schema commands: `FeaturePropertyChangeCommand`,
|
|
213
|
+
`FieldAddCommand`, `FieldRemoveCommand`, `FieldRenameCommand`.
|
|
214
|
+
- Multi-command envelope: `CompositeCommand`.
|
|
215
|
+
|
|
216
|
+
Session editing:
|
|
217
|
+
|
|
218
|
+
- `map.editSession.translateSelected(dx, dy)`
|
|
219
|
+
- `map.editSession.rotateSelected(angle, origin?)`
|
|
220
|
+
- `map.editSession.scaleSelected(sx, sy?, origin?)`
|
|
221
|
+
- `map.editSession.beginTranslateSession(options?)`
|
|
222
|
+
- `map.editSession.beginAffineSession(matrix?, origin?)`
|
|
223
|
+
|
|
224
|
+
Transactions:
|
|
225
|
+
|
|
226
|
+
- `map.beginTransaction()`
|
|
227
|
+
- `tx.commit(label?)`
|
|
228
|
+
- `tx.rollback()`
|
|
229
|
+
|
|
230
|
+
Undo/redo:
|
|
231
|
+
|
|
232
|
+
- `map.undo()`
|
|
233
|
+
- `map.redo()`
|
|
234
|
+
- `map.canUndo()`
|
|
235
|
+
- `map.canRedo()`
|
|
236
|
+
- `map.clearHistory()`
|
|
237
|
+
- `map.bindHistoryShortcuts()`
|
|
238
|
+
|
|
239
|
+
## 9. Mapshaper Operations
|
|
240
|
+
|
|
241
|
+
All operations live under `map.ops` and return `Promise<OpResult>`.
|
|
242
|
+
|
|
243
|
+
Geometry and topology:
|
|
244
|
+
|
|
245
|
+
- `clipLayer`
|
|
246
|
+
- `eraseLayer`
|
|
247
|
+
- `dissolveLayer`
|
|
248
|
+
- `bufferLayer`
|
|
249
|
+
- `simplifyLayer`
|
|
250
|
+
- `projectLayer`
|
|
251
|
+
- `affineLayer`
|
|
252
|
+
- `cleanLayer`
|
|
253
|
+
- `snapLayer`
|
|
254
|
+
- `rebuildTopology`
|
|
255
|
+
- `checkGeometry`
|
|
256
|
+
|
|
257
|
+
Set and overlay operations:
|
|
258
|
+
|
|
259
|
+
- `mosaicLayer`
|
|
260
|
+
- `unionLayers`
|
|
261
|
+
- `divideLayer`
|
|
262
|
+
- `intersectionPointsLayer`
|
|
263
|
+
|
|
264
|
+
Geometry conversion:
|
|
265
|
+
|
|
266
|
+
- `pointsLayer`
|
|
267
|
+
- `linesLayer`
|
|
268
|
+
- `polygonsLayer`
|
|
269
|
+
- `innerlinesLayer`
|
|
270
|
+
- `explodeLayer`
|
|
271
|
+
|
|
272
|
+
Layer management:
|
|
273
|
+
|
|
274
|
+
- `renameLayer`
|
|
275
|
+
- `mergeLayers`
|
|
276
|
+
- `splitLayer`
|
|
277
|
+
- `dropLayer`
|
|
278
|
+
|
|
279
|
+
Filtering and attributes:
|
|
280
|
+
|
|
281
|
+
- `applyExpression`
|
|
282
|
+
- `filterFeatures`
|
|
283
|
+
- `filterIslands`
|
|
284
|
+
- `filterSlivers`
|
|
285
|
+
- `filterGeom`
|
|
286
|
+
- `sortFeatures`
|
|
287
|
+
- `uniqueFeatures`
|
|
288
|
+
- `filterFields`
|
|
289
|
+
- `renameFields`
|
|
290
|
+
- `joinTable`
|
|
291
|
+
- `dataFill`
|
|
292
|
+
|
|
293
|
+
Selection-driven:
|
|
294
|
+
|
|
295
|
+
- `mergeSelected`
|
|
296
|
+
|
|
297
|
+
Operation runtime features:
|
|
298
|
+
|
|
299
|
+
- Parsed command objects instead of shell strings.
|
|
300
|
+
- Effect-aware selection preservation.
|
|
301
|
+
- Dataset-replace undo barriers.
|
|
302
|
+
- Optional worker routing.
|
|
303
|
+
- Structured `OpResult` and `OpError` responses.
|
|
304
|
+
|
|
305
|
+
## 10. Validation
|
|
306
|
+
|
|
307
|
+
Validator registry:
|
|
308
|
+
|
|
309
|
+
- `map.validators.register(validator)`
|
|
310
|
+
- returned unregister function
|
|
311
|
+
- `validationfailed` event
|
|
312
|
+
|
|
313
|
+
Built-in validator:
|
|
314
|
+
|
|
315
|
+
- `topologyValidator(options)`
|
|
316
|
+
|
|
317
|
+
Validation runs after committed history changes. The engine reports failures and
|
|
318
|
+
leaves application policy decisions to the host app.
|
|
319
|
+
|
|
320
|
+
## 11. Worker Offloading
|
|
321
|
+
|
|
322
|
+
Worker options:
|
|
323
|
+
|
|
324
|
+
- `useWorker: false | true | 'auto'`
|
|
325
|
+
- `workerMode` compatibility alias
|
|
326
|
+
- `workerThreshold`
|
|
327
|
+
- `workerUrl`
|
|
328
|
+
- `workerPoolSize`
|
|
329
|
+
- `workerPool`
|
|
330
|
+
- `workerRouting(info)`
|
|
331
|
+
|
|
332
|
+
Worker features:
|
|
333
|
+
|
|
334
|
+
- Lazy worker creation.
|
|
335
|
+
- Multiple worker instances through `MapshaperWorkerPool`.
|
|
336
|
+
- Command-family-aware routing.
|
|
337
|
+
- Cancellation through `map.cancelWorkerJobs()`.
|
|
338
|
+
- Transferable arc buffers where supported by the Mapshaper pack/unpack path.
|
|
339
|
+
|
|
340
|
+
## 12. Snapshots and Export
|
|
341
|
+
|
|
342
|
+
Map snapshot APIs:
|
|
343
|
+
|
|
344
|
+
- `map.exportSnapshot(options?)`
|
|
345
|
+
- `map.loadSnapshot(input, options?)`
|
|
346
|
+
|
|
347
|
+
Source export formats:
|
|
348
|
+
|
|
349
|
+
- GeoJSON
|
|
350
|
+
- TopoJSON
|
|
351
|
+
- Shapefile ZIP
|
|
352
|
+
|
|
353
|
+
Snapshots use Mapshaper pack data with `emap` source metadata for multi-source
|
|
354
|
+
restore.
|
|
355
|
+
|
|
356
|
+
## 13. Built-In Controls
|
|
357
|
+
|
|
358
|
+
| Control | Purpose |
|
|
359
|
+
|---|---|
|
|
360
|
+
| `NavigationControl` | Zoom in, zoom out, reset |
|
|
361
|
+
| `StatusControl` | Pointer coordinates and CRS |
|
|
362
|
+
| `BasemapControl` | MapLibre raster basemap toggle |
|
|
363
|
+
| `HistoryControl` | Undo/redo |
|
|
364
|
+
| `EditToolbar` | Combined edit toolbar |
|
|
365
|
+
| `VertexEditControl` | Button shell over `map.vertexEdit` |
|
|
366
|
+
| `DrawFeatureControl` | Button shell over `map.drawFeature` |
|
|
367
|
+
| `BoxSelectControl` | Thin shell over `map.boxSelect` |
|
|
368
|
+
| `LassoSelectControl` | Thin shell over `map.lassoSelect` |
|
|
369
|
+
| `SimplifyControl` | Simplification UI |
|
|
370
|
+
|
|
371
|
+
Custom controls implement:
|
|
372
|
+
|
|
373
|
+
- `onAdd(map): HTMLElement`
|
|
374
|
+
- `onRemove(map?)`
|
|
375
|
+
|
|
376
|
+
Control positions:
|
|
377
|
+
|
|
378
|
+
- `top-left`
|
|
379
|
+
- `top-right`
|
|
380
|
+
- `bottom-left`
|
|
381
|
+
- `bottom-right`
|
|
382
|
+
|
|
383
|
+
## 14. Events
|
|
384
|
+
|
|
385
|
+
Typed map events include:
|
|
386
|
+
|
|
387
|
+
- `data`
|
|
388
|
+
- `error`
|
|
389
|
+
- `selectionchange`
|
|
390
|
+
- `historychange`
|
|
391
|
+
- `editmodechange`
|
|
392
|
+
- `validationfailed`
|
|
393
|
+
- `crschange`
|
|
394
|
+
- `resize`
|
|
395
|
+
- camera lifecycle events
|
|
396
|
+
|
|
397
|
+
`EmapEventMap` is augmentable through TypeScript module augmentation for
|
|
398
|
+
application-specific events.
|
|
399
|
+
|
|
400
|
+
## 15. CRS and Geometry Utilities
|
|
401
|
+
|
|
402
|
+
Exports:
|
|
403
|
+
|
|
404
|
+
- `Bounds`
|
|
405
|
+
- `AffineTransform`
|
|
406
|
+
- `Viewport`
|
|
407
|
+
- `Projection`
|
|
408
|
+
- `DEFAULT_CRS`
|
|
409
|
+
- `inferFromPrj`
|
|
410
|
+
- `normalizeCrsString`
|
|
411
|
+
- `resolveDatasetCRS`
|
|
412
|
+
|
|
413
|
+
Mapshaper topology types are also exported for consumers that need to build
|
|
414
|
+
custom commands or inspect raw datasets.
|
|
415
|
+
|
|
416
|
+
## 16. Public Advanced Surfaces
|
|
417
|
+
|
|
418
|
+
Advanced exports include:
|
|
419
|
+
|
|
420
|
+
- `DefaultMapshaperAdapter`
|
|
421
|
+
- `getDefaultMapshaperAdapter`
|
|
422
|
+
- `setDefaultMapshaperAdapter`
|
|
423
|
+
- `MapshaperWorkerPool`
|
|
424
|
+
- `HandlerManager`
|
|
425
|
+
- built-in handler classes
|
|
426
|
+
- `CanvasPainter`
|
|
427
|
+
- `EditOverlayRenderer`
|
|
428
|
+
- edit command classes
|
|
429
|
+
- `ValidatorRegistry`
|
|
430
|
+
- `Err`, `OK`, and `okValue`
|
|
431
|
+
- layer paint resolvers
|
|
432
|
+
- CLI safety helpers: `quoteCliArg`, `isValidLayerName`, `isValidFieldName`
|
|
433
|
+
|
|
434
|
+
## 17. Security and Constraints
|
|
435
|
+
|
|
436
|
+
- Browser runtime only.
|
|
437
|
+
- No server dependency.
|
|
438
|
+
- Mapshaper internals are isolated behind `MapshaperAdapter`.
|
|
439
|
+
- Expression-bearing APIs default to `expressionPolicy: 'disabled'`.
|
|
440
|
+
- Apps must opt in to `expressionPolicy: 'trusted'` before executing trusted
|
|
441
|
+
expression strings.
|
|
442
|
+
- Worker assets must be served by the host app when worker offloading is used.
|
|
443
|
+
|
|
444
|
+
## 18. Examples and Tests
|
|
445
|
+
|
|
446
|
+
- Manual examples: `test/examples/*.html`.
|
|
447
|
+
- Unit tests: `src/**/*.test.ts`.
|
|
448
|
+
- Type tests: `*.test-d.ts`.
|
|
449
|
+
- Build and verification:
|
|
450
|
+
|
|
451
|
+
```bash
|
|
452
|
+
cmd /c npm run typecheck
|
|
453
|
+
cmd /c npm run test:run
|
|
454
|
+
cmd /c npm run build
|
|
455
|
+
```
|