@zwishing/emap 0.1.3 → 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.
Files changed (39) hide show
  1. package/CHANGELOG.md +250 -1
  2. package/FEATURES.md +455 -0
  3. package/README.md +415 -205
  4. package/dist/core/event-map.d.ts +67 -0
  5. package/dist/core/feature-event-dispatcher.d.ts +70 -0
  6. package/dist/core/handler-manager.d.ts +49 -0
  7. package/dist/core/handler.d.ts +48 -0
  8. package/dist/core/handlers/box-select.d.ts +54 -0
  9. package/dist/core/handlers/click-select.d.ts +31 -0
  10. package/dist/core/handlers/drag-pan.d.ts +28 -0
  11. package/dist/core/handlers/draw-feature.d.ts +76 -0
  12. package/dist/core/handlers/lasso-select.d.ts +57 -0
  13. package/dist/core/handlers/scroll-zoom.d.ts +24 -0
  14. package/dist/core/handlers/select-geometry.d.ts +24 -0
  15. package/dist/core/handlers/select-mode.d.ts +14 -0
  16. package/dist/core/handlers/transform-feature.d.ts +41 -0
  17. package/dist/core/handlers/vertex-edit.d.ts +98 -0
  18. package/dist/core/pointer-event-dispatcher.d.ts +40 -0
  19. package/dist/core/tween.d.ts +1 -0
  20. package/dist/emap.css +42 -8
  21. package/dist/emap.js +2 -2
  22. package/dist/emap.mjs +1 -1
  23. package/dist/geo/camera.d.ts +100 -0
  24. package/dist/geo/projection.d.ts +8 -1
  25. package/dist/geo/viewport.d.ts +18 -0
  26. package/dist/index.d.ts +26 -2
  27. package/dist/map/edit-state-store.d.ts +1 -1
  28. package/dist/map/map.d.ts +89 -2
  29. package/dist/map/selection.d.ts +5 -2
  30. package/dist/renderer/edit-overlay-renderer.d.ts +2 -1
  31. package/dist/source/source.d.ts +2 -2
  32. package/dist/source/topology-source.d.ts +33 -4
  33. package/dist/ui/box-select-control.d.ts +13 -37
  34. package/dist/ui/draw-feature-control.d.ts +6 -71
  35. package/dist/ui/lasso-select-control.d.ts +14 -61
  36. package/dist/ui/status-control.d.ts +2 -2
  37. package/dist/ui/vertex-edit-control.d.ts +5 -100
  38. package/package.json +5 -1
  39. package/dist/core/drag-pan-handler.d.ts +0 -28
@@ -1,16 +1,8 @@
1
1
  import type { Control } from './control';
2
2
  import type { Emap } from '../map/map';
3
- /** Visual style for the rubber-band lasso path. */
4
- export interface LassoSelectStyle {
5
- /** Stroke color. Default `'#0078ff'`. */
6
- stroke?: string;
7
- /** Stroke width in CSS pixels. Default `1.5`. */
8
- strokeWidth?: number;
9
- /** Fill color of the closed shape preview. Default `'rgba(0, 120, 255, 0.1)'`. */
10
- fill?: string;
11
- /** SVG `stroke-dasharray` value. Default `'4 3'` (subtly dashed). */
12
- strokeDasharray?: string;
13
- }
3
+ export { pointInPolygon, featureMatchesLasso } from '../core/handlers/select-geometry';
4
+ export type { LassoSelectStyle } from '../core/handlers/lasso-select';
5
+ import type { LassoSelectStyle } from '../core/handlers/lasso-select';
14
6
  export interface LassoSelectControlOptions {
15
7
  /**
16
8
  * Restrict the selection to a subset of layer ids. When omitted, every
@@ -31,66 +23,27 @@ export interface LassoSelectControlOptions {
31
23
  includeIntersecting?: boolean;
32
24
  }
33
25
  /**
34
- * Shift+drag free-form polygon feature selection. Sibling of
35
- * `BoxSelectControl` same activation gesture, same modifier conventions,
36
- * different shape.
37
- *
38
- * The lasso path is recorded in pixel coordinates as the user drags. On
39
- * release, the closed polygon is used to test each candidate feature's
40
- * geometry; survivors are passed to `Emap.select`.
41
- *
42
- * Modifier-key conventions (layered on top of shift):
43
- * - shift only → mode `'replace'`
44
- * - shift + ctrl/meta → mode `'add'`
45
- * - shift + alt → mode `'toggle'`
26
+ * Thin shell over the `map.lassoSelect` handler (DX P2c). The handler owns
27
+ * the shift+drag free-form gesture, the dashed `.emap-lasso-select` SVG
28
+ * polyline, polygon hit-testing, and selection; this control just forwards
29
+ * options and proxies enable/disable, returning a 0×0 anchor. Public
30
+ * class, options, anchor DOM, selection behaviour, and the dashed visual
31
+ * are unchanged from the pre-P2c control.
46
32
  *
47
- * Coexistence with `BoxSelectControl`: both consume shift+drag. Pick one,
48
- * or install both and switch between them at runtime via `enable()` /
49
- * `disable()`.
50
- *
51
- * Hit-test semantics: by default, features are selected when their geometry
52
- * intersects or is contained by the lasso, matching box-select's inclusive
53
- * feel. Set `includeIntersecting: false` for strict containment.
33
+ * Modifier conventions (on top of shift): shift→`replace`,
34
+ * shift+ctrl/meta→`add`, shift+alt→`toggle`. Mutually exclusive with
35
+ * box-select — `onAdd` propagates the handler's throw if `boxSelect` is
36
+ * already enabled.
54
37
  */
55
38
  export declare class LassoSelectControl implements Control {
56
39
  private _options;
57
- private _dragThreshold;
58
40
  private _enabled;
59
- private _map;
41
+ private _handler;
60
42
  private _container;
61
- private _svg;
62
- private _polyline;
63
- private _canvasContainer;
64
- /** Drag state — pixel-space path. null when not dragging. */
65
- private _path;
66
- private _onMouseDownBound;
67
- private _onMouseMoveBound;
68
- private _onMouseUpBound;
69
43
  constructor(options?: LassoSelectControlOptions);
70
44
  onAdd(map: Emap): HTMLElement;
71
45
  onRemove(): void;
72
- /** Disable the control — shift+drag becomes a no-op until re-enabled. */
73
46
  disable(): void;
74
47
  enable(): void;
75
48
  isEnabled(): boolean;
76
- private _onMouseDown;
77
- private _onMouseMove;
78
- private _onMouseUp;
79
- private _cancelDrag;
80
- private _cleanupDrag;
81
- private _eventToContainerPx;
82
49
  }
83
- /**
84
- * Even-odd ray-cast point-in-polygon test. The `polygon` may be open or
85
- * closed (last point == first point) — we don't require either form,
86
- * because we wrap via `j = (i - 1 + n) % n` modulo arithmetic. Self-
87
- * intersecting polygons follow standard even-odd semantics (which usually
88
- * matches the user's drawn intent).
89
- */
90
- export declare function pointInPolygon(point: [number, number], polygon: Array<[number, number]>): boolean;
91
- export declare function featureMatchesLasso(map: Emap, ref: {
92
- source: string;
93
- layer: string;
94
- id: number;
95
- geometryType?: string;
96
- }, lasso: Array<[number, number]>, includeIntersecting: boolean): boolean;
@@ -12,12 +12,12 @@ export declare class StatusControl implements Control {
12
12
  private _options;
13
13
  private _mousePosEl;
14
14
  private _epsgEl;
15
- private _onMouseMoveBound;
15
+ private _onMoveBound;
16
16
  private _onUpdateEPSGBound;
17
17
  private _rafPending;
18
18
  constructor(options?: StatusOptions);
19
19
  onAdd(map: Emap): HTMLElement;
20
- private _onMouseMove;
20
+ private _onMove;
21
21
  private _updateEPSG;
22
22
  onRemove(): void;
23
23
  }
@@ -1,111 +1,16 @@
1
- import { Control } from './control';
2
- import { Emap } from '../map/map';
3
- /** Options for VertexEditControl */
1
+ import type { Control } from './control';
2
+ import type { Emap } from '../map/map';
4
3
  export interface VertexEditControlOptions {
5
- /**
6
- * Fill color for polygon shapes in vertex edit mode.
7
- * Any CSS color string. Set to null to disable fill.
8
- * @default 'rgba(0,0,0,0.15)'
9
- */
10
- polygonFillColor?: string | null;
4
+ /** Polygon hover fill, forwarded to map.vertexEdit. Default unchanged. */
5
+ polygonFillColor?: string;
11
6
  }
12
- /**
13
- * VertexEditControl enables interactive vertex editing with topology awareness.
14
- * When a shared node is dragged, ALL coincident vertices move together.
15
- *
16
- * Uses MapshaperAdapter.findNearestVertices to discover topologically-shared
17
- * vertices, and snapVerticesToPoint to move them all simultaneously.
18
- *
19
- * @example
20
- * map.addControl(new VertexEditControl(), 'top-left');
21
- * // With custom polygon fill:
22
- * map.addControl(new VertexEditControl({ polygonFillColor: 'rgba(100,150,255,0.2)' }), 'top-left');
23
- */
24
7
  export declare class VertexEditControl implements Control {
25
8
  private _map;
26
9
  private _container;
27
10
  private _btn;
28
- private _active;
29
- private _polygonFillColor;
30
- private _hoveredFeature;
31
- private _hoverVertexCoords;
32
- private _hoverVertexIds;
33
- private _hoverType;
34
- private _hoverInsertionId;
35
- private _dragging;
36
- /** Shapes of neighboring polygons sharing the hovered arc (for shared-edge highlight) */
37
- private _neighborShapes;
38
- /** Coordinate of the dragged node before mouse-down, captured for VertexMoveCommand. */
39
- private _dragFromCoords;
40
- private _onMouseMoveBound;
41
- private _onMouseDownBound;
42
- private _onMouseUpBound;
43
- private _onMoveHandlerBound;
44
- private _onContextMenuBound;
11
+ private _opts;
45
12
  constructor(options?: VertexEditControlOptions);
46
13
  onAdd(map: Emap): HTMLElement;
47
14
  onRemove(): void;
48
15
  private _toggle;
49
- private _activate;
50
- private _deactivate;
51
- /** Redraw on map move/zoom (vertices stay fixed to geography) */
52
- private _onMapMove;
53
- /**
54
- * Right-click handler: show a context menu to delete the hovered vertex.
55
- * Guard rules (same as mapshaper):
56
- * - Must be hovering a vertex (not an interpolated edge point)
57
- * - Not currently dragging
58
- * - Vertex must NOT be an arc endpoint (deleting an endpoint breaks topology)
59
- */
60
- private _onContextMenu;
61
- /** Delete the currently hovered vertex from the arc collection */
62
- private _deleteHoveredVertex;
63
- /**
64
- * Re-initialize the source's DisplayArcs after an arc-mutating edit so that
65
- * the simplified LOD copy reflects the new vertex layout.
66
- */
67
- private _refreshSourceDisplayArcs;
68
- /**
69
- * Bump the dataset's `editVersion` after a live in-place arc mutation.
70
- * The spatial-index cache in `feature-query` keys on `editVersion`, so
71
- * this is what tells the next `queryFeatures` call that bboxes may
72
- * have changed and the index must rebuild. Cheap (a number
73
- * increment); only the next query pays the actual rebuild cost.
74
- *
75
- * The matching command's `do()/undo()` also bump, but those run on
76
- * undo / redo — not on initial commit, since `pushCommand` skips
77
- * `do()` per the memento contract.
78
- */
79
- private _bumpSourceEditVersion;
80
- /**
81
- * Show a minimal context menu at (x, y) in viewport coords.
82
- * Auto-dismissed when user clicks anywhere else.
83
- */
84
- private _showContextMenu;
85
- private _onMouseMove;
86
- /**
87
- * Use MapshaperAdapter.findNearestVertices to discover ALL vertex indices
88
- * that share the same topological node (identical coordinates across all arcs).
89
- */
90
- private _findNearestVertices;
91
- /**
92
- * Find the closest point along any segment edge (not just vertices).
93
- * Uses mapshaper's forEachSegmentInShape + findClosestPointOnSeg.
94
- * Called as fallback when no existing vertex is within hover threshold.
95
- */
96
- private _findInterpolatedPoint;
97
- /**
98
- * Find all shapes (polygons) in the source that share any arc with the hovered vertex/edge.
99
- * Handles two cases:
100
- * - Vertex hover: hoverVertexIds → arcIds via findArcIdFromVertexId
101
- * - Edge hover (interpolated): hoverInsertionId - 1 → arcId via findArcIdFromVertexId
102
- * Only runs when geometry is polygon. Populates _neighborShapes.
103
- */
104
- private _findNeighborShapes;
105
- /** Update the edit vertex state on the map so render() draws vertex dots (and polygon fill) */
106
- private _updateEditState;
107
- private _onMouseDown;
108
- private _pushVertexInsertCommand;
109
- private _handleDrag;
110
- private _onMouseUp;
111
16
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zwishing/emap",
3
- "version": "0.1.3",
3
+ "version": "0.3.0",
4
4
  "description": "A modern, decoupled rendering engine for mapshaper data",
5
5
  "main": "dist/emap.mjs",
6
6
  "module": "dist/emap.mjs",
@@ -36,6 +36,7 @@
36
36
  "style.css.d.ts",
37
37
  "dist/**/*.d.ts",
38
38
  "README.md",
39
+ "FEATURES.md",
39
40
  "SECURITY.md",
40
41
  "CHANGELOG.md",
41
42
  "LICENSE"
@@ -44,8 +45,10 @@
44
45
  "node": ">=18"
45
46
  },
46
47
  "scripts": {
48
+ "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
47
49
  "dev": "rollup -c --environment BUILD:development -w",
48
50
  "dev-build": "rollup -c --environment BUILD:development",
51
+ "prebuild": "npm run clean",
49
52
  "build": "rollup -c --environment BUILD:production && tsc -p tsconfig.build.json",
50
53
  "typecheck": "tsc --noEmit",
51
54
  "test": "vitest",
@@ -79,6 +82,7 @@
79
82
  "@rollup/plugin-node-resolve": "^15.0.0",
80
83
  "@rollup/plugin-terser": "^0.4.4",
81
84
  "@rollup/plugin-typescript": "^11.0.0",
85
+ "esbuild": "^0.21.5",
82
86
  "jsdom": "^29.1.0",
83
87
  "rollup": "^4.0.0",
84
88
  "rollup-plugin-polyfill-node": "^0.13.0",
@@ -1,28 +0,0 @@
1
- import { EventDispatcher } from './events';
2
- /**
3
- * Handles mouse drag-to-pan interaction.
4
- * Matches the MouseWheel pattern — extends EventDispatcher and emits events.
5
- *
6
- * Events:
7
- * 'pan' — { dx: number, dy: number } — pixel delta to translate
8
- * 'panstart' — drag started
9
- * 'panend' — drag ended
10
- */
11
- export declare class DragPanHandler extends EventDispatcher {
12
- private _element;
13
- private _isDragging;
14
- private _lastMousePos;
15
- private _enabled;
16
- private _onMouseDownBound;
17
- private _onMouseMoveBound;
18
- private _onMouseUpBound;
19
- constructor(element: HTMLElement);
20
- /** Temporarily disable pan (e.g. during vertex editing) */
21
- setEnabled(enabled: boolean): void;
22
- isEnabled(): boolean;
23
- isDragging(): boolean;
24
- destroy(): void;
25
- private _onMouseDown;
26
- private _onMouseMove;
27
- private _onMouseUp;
28
- }