@zwishing/emap 0.1.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 (114) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/LICENSE +373 -0
  3. package/README.md +294 -0
  4. package/SECURITY.md +56 -0
  5. package/dist/adapter/mapshaper-adapter.d.ts +282 -0
  6. package/dist/core/drag-pan-handler.d.ts +28 -0
  7. package/dist/core/events.d.ts +16 -0
  8. package/dist/core/interactions.d.ts +20 -0
  9. package/dist/core/mapshaper-worker-pool.d.ts +151 -0
  10. package/dist/core/tween.d.ts +26 -0
  11. package/dist/edit/commands/composite.d.ts +16 -0
  12. package/dist/edit/commands/dataset-replace.d.ts +43 -0
  13. package/dist/edit/commands/feature-affine.d.ts +72 -0
  14. package/dist/edit/commands/feature-create.d.ts +47 -0
  15. package/dist/edit/commands/feature-delete.d.ts +72 -0
  16. package/dist/edit/commands/feature-property-change.d.ts +34 -0
  17. package/dist/edit/commands/feature-translate.d.ts +55 -0
  18. package/dist/edit/commands/field-add.d.ts +24 -0
  19. package/dist/edit/commands/field-remove.d.ts +20 -0
  20. package/dist/edit/commands/field-rename.d.ts +19 -0
  21. package/dist/edit/commands/split-shared-arcs.d.ts +71 -0
  22. package/dist/edit/commands/vertex-delete.d.ts +26 -0
  23. package/dist/edit/commands/vertex-insert.d.ts +26 -0
  24. package/dist/edit/commands/vertex-move.d.ts +45 -0
  25. package/dist/edit/edit-command.d.ts +72 -0
  26. package/dist/edit/edit-history.d.ts +130 -0
  27. package/dist/edit/transaction.d.ts +59 -0
  28. package/dist/emap-worker.js +1 -0
  29. package/dist/emap.css +157 -0
  30. package/dist/emap.js +5 -0
  31. package/dist/emap.mjs +5 -0
  32. package/dist/geo/bounds.d.ts +18 -0
  33. package/dist/geo/crs-resolver.d.ts +35 -0
  34. package/dist/geo/projection.d.ts +28 -0
  35. package/dist/geo/transform.d.ts +19 -0
  36. package/dist/geo/viewport.d.ts +52 -0
  37. package/dist/index.d.ts +86 -0
  38. package/dist/map/attribute-ops.d.ts +61 -0
  39. package/dist/map/command-args.d.ts +28 -0
  40. package/dist/map/edit-sessions.d.ts +97 -0
  41. package/dist/map/edit-state-store.d.ts +41 -0
  42. package/dist/map/emap-host.d.ts +79 -0
  43. package/dist/map/feature-accessor.d.ts +43 -0
  44. package/dist/map/feature-query.d.ts +58 -0
  45. package/dist/map/highlight-manager.d.ts +17 -0
  46. package/dist/map/layer-registry.d.ts +33 -0
  47. package/dist/map/layer.d.ts +29 -0
  48. package/dist/map/map.d.ts +386 -0
  49. package/dist/map/mapshaper-ops.d.ts +56 -0
  50. package/dist/map/op-result.d.ts +46 -0
  51. package/dist/map/ops/_context.d.ts +41 -0
  52. package/dist/map/ops/_runner.d.ts +55 -0
  53. package/dist/map/ops/affine.d.ts +4 -0
  54. package/dist/map/ops/buffer.d.ts +4 -0
  55. package/dist/map/ops/check-geometry.d.ts +4 -0
  56. package/dist/map/ops/clean.d.ts +4 -0
  57. package/dist/map/ops/clip-erase.d.ts +5 -0
  58. package/dist/map/ops/data-fill.d.ts +4 -0
  59. package/dist/map/ops/dissolve.d.ts +20 -0
  60. package/dist/map/ops/divide.d.ts +4 -0
  61. package/dist/map/ops/drop-layer.d.ts +4 -0
  62. package/dist/map/ops/each-filter.d.ts +5 -0
  63. package/dist/map/ops/explode.d.ts +4 -0
  64. package/dist/map/ops/filter-fields.d.ts +4 -0
  65. package/dist/map/ops/filter-geom.d.ts +4 -0
  66. package/dist/map/ops/filter-islands.d.ts +4 -0
  67. package/dist/map/ops/filter-slivers.d.ts +4 -0
  68. package/dist/map/ops/innerlines.d.ts +4 -0
  69. package/dist/map/ops/intersection-points.d.ts +4 -0
  70. package/dist/map/ops/join-table.d.ts +4 -0
  71. package/dist/map/ops/lines.d.ts +4 -0
  72. package/dist/map/ops/merge-layers.d.ts +4 -0
  73. package/dist/map/ops/mosaic.d.ts +4 -0
  74. package/dist/map/ops/points.d.ts +4 -0
  75. package/dist/map/ops/polygons.d.ts +4 -0
  76. package/dist/map/ops/project.d.ts +4 -0
  77. package/dist/map/ops/rebuild-topology.d.ts +4 -0
  78. package/dist/map/ops/rename-fields.d.ts +4 -0
  79. package/dist/map/ops/rename-layer.d.ts +4 -0
  80. package/dist/map/ops/simplify.d.ts +4 -0
  81. package/dist/map/ops/snap.d.ts +4 -0
  82. package/dist/map/ops/sort-features.d.ts +4 -0
  83. package/dist/map/ops/split-layer.d.ts +4 -0
  84. package/dist/map/ops/union.d.ts +4 -0
  85. package/dist/map/ops/unique-features.d.ts +4 -0
  86. package/dist/map/selection.d.ts +73 -0
  87. package/dist/map/types.d.ts +1072 -0
  88. package/dist/map/worker-routing.d.ts +40 -0
  89. package/dist/mapshaper-vendor.js +1 -0
  90. package/dist/renderer/canvas-painter.d.ts +50 -0
  91. package/dist/renderer/edit-overlay-renderer.d.ts +22 -0
  92. package/dist/renderer/painter.d.ts +52 -0
  93. package/dist/shim.d.ts +1 -0
  94. package/dist/source/display-arcs.d.ts +49 -0
  95. package/dist/source/layer-utils.d.ts +12 -0
  96. package/dist/source/mapshaper-runner.d.ts +22 -0
  97. package/dist/source/source.d.ts +80 -0
  98. package/dist/source/topology-source.d.ts +145 -0
  99. package/dist/types/mapshaper-types.d.ts +182 -0
  100. package/dist/ui/basemap-control.d.ts +35 -0
  101. package/dist/ui/box-select-control.d.ts +67 -0
  102. package/dist/ui/control.d.ts +6 -0
  103. package/dist/ui/draw-feature-control.d.ts +82 -0
  104. package/dist/ui/edit-toolbar.d.ts +27 -0
  105. package/dist/ui/history-control.d.ts +29 -0
  106. package/dist/ui/lasso-select-control.d.ts +96 -0
  107. package/dist/ui/navigation-control.d.ts +16 -0
  108. package/dist/ui/simplify-control.d.ts +40 -0
  109. package/dist/ui/status-control.d.ts +23 -0
  110. package/dist/ui/vertex-edit-control.d.ts +111 -0
  111. package/dist/validation/builtin/topology.d.ts +19 -0
  112. package/dist/validation/registry.d.ts +23 -0
  113. package/dist/validation/validator.d.ts +47 -0
  114. package/package.json +90 -0
@@ -0,0 +1,67 @@
1
+ import type { Control } from './control';
2
+ import type { Emap } from '../map/map';
3
+ /** Visual style for the rubber-band rectangle. */
4
+ export interface BoxSelectStyle {
5
+ /** Stroke color. Default `'#0078ff'`. */
6
+ stroke?: string;
7
+ /** Stroke width in CSS pixels. Default `1.5`. */
8
+ strokeWidth?: number;
9
+ /** Fill color. Default `'rgba(0, 120, 255, 0.1)'`. */
10
+ fill?: string;
11
+ }
12
+ export interface BoxSelectControlOptions {
13
+ /**
14
+ * Restrict the selection to a subset of layer ids. When omitted, every
15
+ * visible layer participates (matching `queryFeatures` default).
16
+ */
17
+ layers?: string[];
18
+ /** Visual style of the rubber-band rectangle. */
19
+ style?: BoxSelectStyle;
20
+ /**
21
+ * Pixel diagonal threshold below which the drag is treated as no-op.
22
+ * Default `4`.
23
+ */
24
+ dragThreshold?: number;
25
+ }
26
+ /**
27
+ * Shift+drag rubber-band feature selection. Reuses
28
+ * `Emap.queryFeatures(bbox)` for hit-testing and `Emap.select` for
29
+ * selection state management.
30
+ *
31
+ * Modifier-key conventions (layered on top of shift):
32
+ * - shift only → mode `'replace'`
33
+ * - shift + ctrl/meta → mode `'add'`
34
+ * - shift + alt → mode `'toggle'`
35
+ *
36
+ * Tiny drags (< `dragThreshold` px diagonal) cancel without selecting.
37
+ *
38
+ * Coordinates with `DragPanHandler`: the handler now skips shift-modified
39
+ * mousedowns, leaving shift+drag for this control.
40
+ */
41
+ export declare class BoxSelectControl implements Control {
42
+ private _options;
43
+ private _dragThreshold;
44
+ private _enabled;
45
+ private _map;
46
+ private _container;
47
+ private _overlay;
48
+ private _canvasContainer;
49
+ private _startPx;
50
+ private _onMouseDownBound;
51
+ private _onMouseMoveBound;
52
+ private _onMouseUpBound;
53
+ constructor(options?: BoxSelectControlOptions);
54
+ onAdd(map: Emap): HTMLElement;
55
+ onRemove(): void;
56
+ /** Disable the control — shift+drag becomes a no-op until re-enabled. */
57
+ disable(): void;
58
+ enable(): void;
59
+ isEnabled(): boolean;
60
+ private _onMouseDown;
61
+ private _onMouseMove;
62
+ private _onMouseUp;
63
+ private _cancelDrag;
64
+ private _cleanupDrag;
65
+ private _eventToContainerPx;
66
+ private _modeFromEvent;
67
+ }
@@ -0,0 +1,6 @@
1
+ import { Emap } from '../map/map';
2
+ export interface Control {
3
+ onAdd(map: Emap): HTMLElement;
4
+ onRemove(map?: Emap): void;
5
+ }
6
+ export type ControlPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
@@ -0,0 +1,82 @@
1
+ import { Control } from './control';
2
+ import { Emap } from '../map/map';
3
+ export type DrawGeometryType = 'polygon' | 'polyline' | 'point';
4
+ export interface DrawFeatureControlOptions {
5
+ /** Target source ID where new features will be added */
6
+ source: string;
7
+ /** Target layer name within the source (optional, defaults to first matching geometry layer) */
8
+ sourceLayer?: string;
9
+ /** Geometry type to draw */
10
+ type: DrawGeometryType;
11
+ /** Pixel threshold for vertex snapping (default: 10) */
12
+ snapThreshold?: number;
13
+ /**
14
+ * Sources to snap against. Defaults to `[options.source]` so the existing
15
+ * single-source behaviour is preserved when omitted. Pass `['a', 'b']` to
16
+ * also snap onto another source (e.g. drawing in source A while tracing
17
+ * along reference data in source B).
18
+ */
19
+ snapSources?: string[];
20
+ /** Enable vertex snap (default `true`). */
21
+ snapToVertex?: boolean;
22
+ /**
23
+ * Enable edge snap — perpendicular projection onto an arc segment
24
+ * (default `true`). Disable to restrict snap to existing vertices only.
25
+ */
26
+ snapToEdge?: boolean;
27
+ /** CSS color for the drawing line (default: '#0078ff') */
28
+ drawColor?: string;
29
+ /**
30
+ * Button icon. A `string` is rendered as text via `textContent` (safe;
31
+ * covers unicode glyphs like the defaults below). Pass a `Node` to render
32
+ * a pre-built DOM element such as an `<svg>` — caller is responsible for
33
+ * its own escaping.
34
+ */
35
+ icon?: string | Node;
36
+ }
37
+ export declare class DrawFeatureControl implements Control {
38
+ private _options;
39
+ private _map;
40
+ private _container;
41
+ private _btn;
42
+ private _active;
43
+ private _vertices;
44
+ private _cursorCoord;
45
+ private _snapCoord;
46
+ private _snapKind;
47
+ private _snapThreshold;
48
+ private _onMouseMoveBound;
49
+ private _onClickBound;
50
+ private _onDblClickBound;
51
+ private _onKeyDownBound;
52
+ private _onMoveHandlerBound;
53
+ constructor(options: DrawFeatureControlOptions);
54
+ onAdd(map: Emap): HTMLElement;
55
+ onRemove(): void;
56
+ private _toggle;
57
+ private _activate;
58
+ private _deactivate;
59
+ /** Deactivate UI without firing setEditMode (used when another mode takes over) */
60
+ private _deactivateQuiet;
61
+ private _clearDrawState;
62
+ private _onMapMove;
63
+ private _onMouseMove;
64
+ private _onClick;
65
+ private _onDblClick;
66
+ private _onKeyDown;
67
+ private _findSnapTarget;
68
+ private _commitFeature;
69
+ private _resolveTargetLayer;
70
+ private _appendArc;
71
+ private _updateDrawState;
72
+ }
73
+ /**
74
+ * Closest point on segment `[a, b]` to point `p`, all in 2-D pixel space.
75
+ * Parameter `t = ((p-a)·(b-a)) / |b-a|²` is clamped to `[0, 1]` so the
76
+ * returned point is always on the segment (not its infinite line). For a
77
+ * zero-length segment, returns endpoint `a` and `dist(p, a)`.
78
+ */
79
+ export declare function projectPointOnSegment(p: [number, number], a: [number, number], b: [number, number]): {
80
+ point: [number, number];
81
+ dist: number;
82
+ };
@@ -0,0 +1,27 @@
1
+ import { Control } from './control';
2
+ import { Emap } from '../map/map';
3
+ export interface EditToolbarOptions {
4
+ /** Source ID for draw tools. If not provided, draw buttons are not shown. */
5
+ drawSource?: string;
6
+ /** Source layer name for draw tools (optional, defaults to first matching layer). */
7
+ drawSourceLayer?: string;
8
+ }
9
+ /**
10
+ * EditToolbar wraps editing controls (vertex edit + draw tools) in a styled toolbar.
11
+ *
12
+ * Usage:
13
+ * // Vertex edit only (backward compatible)
14
+ * map.addControl(new EditToolbar(), 'top-left');
15
+ *
16
+ * // With draw tools
17
+ * map.addControl(new EditToolbar({ drawSource: 'my-source' }), 'top-left');
18
+ */
19
+ export declare class EditToolbar implements Control {
20
+ private _container;
21
+ private _vertexEditControl;
22
+ private _drawControls;
23
+ private _options;
24
+ constructor(options?: EditToolbarOptions);
25
+ onAdd(map: Emap): HTMLElement;
26
+ onRemove(): void;
27
+ }
@@ -0,0 +1,29 @@
1
+ import { Control } from './control';
2
+ import { Emap } from '../map/map';
3
+ export interface HistoryControlOptions {
4
+ /** Tooltip text for the undo button. Default: "Undo (Ctrl+Z)". */
5
+ undoTitle?: string;
6
+ /** Tooltip text for the redo button. Default: "Redo (Ctrl+Shift+Z)". */
7
+ redoTitle?: string;
8
+ /** Optional class to add to the control container. */
9
+ className?: string;
10
+ }
11
+ /**
12
+ * Two-button Undo / Redo control.
13
+ *
14
+ * Buttons are enabled / disabled based on the map's `historychange` event so
15
+ * they always reflect `canUndo()` / `canRedo()` without polling.
16
+ */
17
+ export declare class HistoryControl implements Control {
18
+ private _map;
19
+ private _container;
20
+ private _undoBtn;
21
+ private _redoBtn;
22
+ private _options;
23
+ private _onHistoryChange;
24
+ constructor(options?: HistoryControlOptions);
25
+ onAdd(map: Emap): HTMLElement;
26
+ onRemove(): void;
27
+ private _setEnabled;
28
+ private _createButton;
29
+ }
@@ -0,0 +1,96 @@
1
+ import type { Control } from './control';
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
+ }
14
+ export interface LassoSelectControlOptions {
15
+ /**
16
+ * Restrict the selection to a subset of layer ids. When omitted, every
17
+ * visible layer participates (matching `queryFeatures` default).
18
+ */
19
+ layers?: string[];
20
+ /** Visual style of the lasso polyline. */
21
+ style?: LassoSelectStyle;
22
+ /**
23
+ * Pixel diagonal threshold below which the drag is treated as no-op.
24
+ * Default `4`.
25
+ */
26
+ dragThreshold?: number;
27
+ /**
28
+ * Select features that intersect the lasso boundary or interior, not only
29
+ * features fully contained by it. Default `true`, matching box-select.
30
+ */
31
+ includeIntersecting?: boolean;
32
+ }
33
+ /**
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'`
46
+ *
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.
54
+ */
55
+ export declare class LassoSelectControl implements Control {
56
+ private _options;
57
+ private _dragThreshold;
58
+ private _enabled;
59
+ private _map;
60
+ 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
+ constructor(options?: LassoSelectControlOptions);
70
+ onAdd(map: Emap): HTMLElement;
71
+ onRemove(): void;
72
+ /** Disable the control — shift+drag becomes a no-op until re-enabled. */
73
+ disable(): void;
74
+ enable(): void;
75
+ isEnabled(): boolean;
76
+ private _onMouseDown;
77
+ private _onMouseMove;
78
+ private _onMouseUp;
79
+ private _cancelDrag;
80
+ private _cleanupDrag;
81
+ private _eventToContainerPx;
82
+ }
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;
@@ -0,0 +1,16 @@
1
+ import { Control } from './control';
2
+ import { Emap } from '../map/map';
3
+ export interface NavigationOptions {
4
+ showZoom?: boolean;
5
+ showHome?: boolean;
6
+ className?: string;
7
+ }
8
+ export declare class NavigationControl implements Control {
9
+ private _map;
10
+ private _container;
11
+ private _options;
12
+ constructor(options?: NavigationOptions);
13
+ onAdd(map: Emap): HTMLElement;
14
+ private _createButton;
15
+ onRemove(): void;
16
+ }
@@ -0,0 +1,40 @@
1
+ import { Control } from './control';
2
+ import type { Emap } from '../map/map';
3
+ import type { SimplifyMethod } from '../map/types';
4
+ export interface SimplifyControlOptions {
5
+ /** Source ID to simplify. Required. */
6
+ source: string;
7
+ /** Optional layer name — when omitted, the whole source dataset is simplified. */
8
+ target?: string;
9
+ /** Initial slider value, 0–100. Default 10 (= keep 10% of vertices). */
10
+ initialPercentage?: number;
11
+ /** Initial method. Default 'weighted'. */
12
+ initialMethod?: SimplifyMethod;
13
+ /** Button tooltip override. */
14
+ title?: string;
15
+ }
16
+ export declare class SimplifyControl implements Control {
17
+ private _opts;
18
+ private _map;
19
+ private _container;
20
+ private _btn;
21
+ private _popup;
22
+ private _percentageInput;
23
+ private _percentageLabel;
24
+ private _methodSel;
25
+ private _keepShapes;
26
+ private _planar;
27
+ private _applyBtn;
28
+ private _statusEl;
29
+ private _onDocClick;
30
+ private _onDocKey;
31
+ constructor(opts: SimplifyControlOptions);
32
+ onAdd(map: Emap): HTMLElement;
33
+ onRemove(): void;
34
+ private _buildPopup;
35
+ private _togglePopup;
36
+ private _setupDocListeners;
37
+ private _teardownDocListeners;
38
+ private _setStatus;
39
+ private _apply;
40
+ }
@@ -0,0 +1,23 @@
1
+ import { Control } from './control';
2
+ import { Emap } from '../map/map';
3
+ export interface StatusOptions {
4
+ showMousePos?: boolean;
5
+ showEPSG?: boolean;
6
+ alignment?: 'left' | 'right' | 'center';
7
+ className?: string;
8
+ }
9
+ export declare class StatusControl implements Control {
10
+ private _map;
11
+ private _container;
12
+ private _options;
13
+ private _mousePosEl;
14
+ private _epsgEl;
15
+ private _onMouseMoveBound;
16
+ private _onUpdateEPSGBound;
17
+ private _rafPending;
18
+ constructor(options?: StatusOptions);
19
+ onAdd(map: Emap): HTMLElement;
20
+ private _onMouseMove;
21
+ private _updateEPSG;
22
+ onRemove(): void;
23
+ }
@@ -0,0 +1,111 @@
1
+ import { Control } from './control';
2
+ import { Emap } from '../map/map';
3
+ /** Options for VertexEditControl */
4
+ 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;
11
+ }
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
+ export declare class VertexEditControl implements Control {
25
+ private _map;
26
+ private _container;
27
+ 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;
45
+ constructor(options?: VertexEditControlOptions);
46
+ onAdd(map: Emap): HTMLElement;
47
+ onRemove(): void;
48
+ 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
+ }
@@ -0,0 +1,19 @@
1
+ import type { Validator, ValidationIssue } from '../validator';
2
+ export interface TopologyValidatorOptions {
3
+ /**
4
+ * Limit the validator to these source ids. If omitted, runs over
5
+ * every registered source. Useful when a workflow has a "scratchpad"
6
+ * source where intersections are temporarily expected.
7
+ */
8
+ sources?: string[];
9
+ /** Tolerance forwarded to `findSegmentIntersections`. */
10
+ tolerance?: number;
11
+ /** Severity of reported issues. Defaults to `'error'`. */
12
+ severity?: ValidationIssue['severity'];
13
+ }
14
+ /**
15
+ * Construct a `Validator` that scans listed sources for arc
16
+ * self-intersections after every commit. Failures appear in the
17
+ * `validationfailed` event payload as one issue per offending source.
18
+ */
19
+ export declare function topologyValidator(opts?: TopologyValidatorOptions): Validator;
@@ -0,0 +1,23 @@
1
+ import type { Validator, ValidatorPhase, ValidatorResult, ValidationChange } from './validator';
2
+ import type { EmapHostInternal } from '../map/emap-host';
3
+ export declare class ValidatorRegistry {
4
+ private _all;
5
+ /** Number of currently registered validators (across all phases). */
6
+ get size(): number;
7
+ /**
8
+ * Register a validator. Returns an unregister callback — call it to
9
+ * remove this exact validator (idempotent).
10
+ */
11
+ register(v: Validator): () => void;
12
+ /** Remove every registered validator. */
13
+ unregisterAll(): void;
14
+ /**
15
+ * Run every validator whose `phase` matches `phase`, in parallel.
16
+ * Validator throws are converted to `severity: 'error'` issues so the
17
+ * caller's hook chain stays predictable.
18
+ *
19
+ * Returns the per-validator results in registration order. Callers
20
+ * typically filter `.report.ok === false` to surface failures.
21
+ */
22
+ runFor(phase: ValidatorPhase, host: EmapHostInternal, change: ValidationChange): Promise<ValidatorResult[]>;
23
+ }
@@ -0,0 +1,47 @@
1
+ import type { FeatureRef } from '../map/types';
2
+ import type { EmapHostInternal } from '../map/emap-host';
3
+ /**
4
+ * Phase at which a validator runs. Currently only `'after-commit'` is
5
+ * supported — runs after `historychange` fires. Reserved here as a
6
+ * union so future phases (`'before-commit'` for pre-flight rejection,
7
+ * `'on-load'` for source-import validation) can be added without a
8
+ * breaking signature change.
9
+ */
10
+ export type ValidatorPhase = 'after-commit';
11
+ /** One issue surfaced by a validator run. */
12
+ export interface ValidationIssue {
13
+ severity: 'error' | 'warning';
14
+ message: string;
15
+ /** Optional reference to the offending feature (UI can highlight it). */
16
+ ref?: FeatureRef;
17
+ }
18
+ /** Result of a single validator run. */
19
+ export interface ValidationReport {
20
+ /** `true` iff `issues` is empty OR contains only warnings. */
21
+ ok: boolean;
22
+ issues: ValidationIssue[];
23
+ }
24
+ /**
25
+ * Information passed to validators about the change that triggered the
26
+ * run. Lets a validator scope its work — e.g. only re-check the source
27
+ * that was just modified.
28
+ */
29
+ export interface ValidationChange {
30
+ /** Label of the command that just committed (matches history.label). */
31
+ label: string;
32
+ }
33
+ /**
34
+ * A pluggable validator. Construct via `engine.validators.register(...)`.
35
+ * The `name` is opaque to the engine but is included in the
36
+ * `validationfailed` event payload so apps can route by source.
37
+ */
38
+ export interface Validator {
39
+ name: string;
40
+ phase: ValidatorPhase;
41
+ run(host: EmapHostInternal, change: ValidationChange): Promise<ValidationReport>;
42
+ }
43
+ /** Per-validator outcome bundled into the `validationfailed` event. */
44
+ export interface ValidatorResult {
45
+ validator: string;
46
+ report: ValidationReport;
47
+ }