@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,20 @@
1
+ import { EventDispatcher } from './events';
2
+ export declare class MouseWheel extends EventDispatcher {
3
+ private _element;
4
+ private _active;
5
+ private _timer;
6
+ private _sustainInterval;
7
+ private _fadeDelay;
8
+ private _eventTime;
9
+ private _getAverageRate;
10
+ private _getWheelDirection;
11
+ private _wheelDirection;
12
+ private _mouseX;
13
+ private _mouseY;
14
+ private _wheelHandler;
15
+ constructor(_element: HTMLElement);
16
+ destroy(): void;
17
+ private _updateSustainInterval;
18
+ private _handleWheel;
19
+ private _onTick;
20
+ }
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Worker pool that runs mapshaper commands off-thread.
3
+ *
4
+ * Wire protocol matches `src/worker/mapshaper-worker.ts`:
5
+ *
6
+ * main → worker: { id, type: 'run', cmd, packed, inputFiles? }
7
+ * worker → main: { id, type: 'ok', packed }
8
+ * | { id, type: 'error', message }
9
+ *
10
+ * **Concurrency model**: the pool maintains N workers (default 1).
11
+ * mapshaper itself is not reentrant inside ONE worker — it shares
12
+ * module-level state (parser tables, internal caches) across calls,
13
+ * which is why the worker entry serialises via an internal queue.
14
+ * Across DIFFERENT workers there is no shared state: each worker hosts
15
+ * its own mapshaper instance, so the pool can run `poolSize` jobs in
16
+ * true parallel as long as the underlying datasets are independent.
17
+ *
18
+ * Dispatch picks the worker with the fewest in-flight requests; ties
19
+ * break by round-robin index so the load distribution is stable and
20
+ * predictable.
21
+ *
22
+ * Lazy worker spawn: the underlying `Worker`s are constructed on
23
+ * demand, not at pool construction. Cheap to keep an unused pool
24
+ * around; useful for callers that toggle `useWorker` at runtime.
25
+ */
26
+ export interface MapshaperWorkerPoolOptions {
27
+ /**
28
+ * URL of the worker bundle (`emap-worker.js`). Resolved by the browser
29
+ * the same way as any `new Worker(url)` argument — pass the absolute or
30
+ * page-relative URL where the file is served.
31
+ */
32
+ workerUrl: string;
33
+ /**
34
+ * Optional override for the `Worker` constructor itself. Used by tests
35
+ * to inject a `MockWorker`. Defaults to the global `Worker`.
36
+ */
37
+ WorkerCtor?: typeof Worker;
38
+ /**
39
+ * Number of worker threads to maintain. Each adds its own mapshaper
40
+ * instance, so peak parallelism = `poolSize`. Default `1` to keep
41
+ * the historical single-worker semantics; set to e.g.
42
+ * `navigator.hardwareConcurrency - 1` to scale.
43
+ *
44
+ * Workers spawn lazily as load grows; constructing a pool with
45
+ * `poolSize: 4` does NOT immediately spawn 4 workers — only the
46
+ * first dispatch creates one, the second creates a second only if
47
+ * the first is busy, and so on.
48
+ */
49
+ poolSize?: number;
50
+ }
51
+ /**
52
+ * Wire-format ParsedCommand. Mirrors `mapshaper.internal.parseCommands(...)`
53
+ * output: `{ name: kebab-case, options: snake_case key/values }`. Plain
54
+ * data, structured-clone friendly.
55
+ */
56
+ export interface ParsedCommandWire {
57
+ name: string;
58
+ options: Record<string, unknown>;
59
+ }
60
+ export declare class MapshaperWorkerPool {
61
+ private _workerUrl;
62
+ private _WorkerCtor;
63
+ private _slots;
64
+ private _pending;
65
+ private _nextId;
66
+ /** Round-robin tie-breaker pointer for dispatch. */
67
+ private _rrCursor;
68
+ private _destroyed;
69
+ constructor(opts: MapshaperWorkerPoolOptions);
70
+ /**
71
+ * Send a command + packed dataset to the worker pool and resolve with
72
+ * the packed result. Each call gets a unique correlation id so multiple
73
+ * in-flight requests don't cross wires.
74
+ */
75
+ run(cmdOrCommands: string | ParsedCommandWire[], packed: any, inputFiles?: Record<string, Uint8Array | string>): Promise<any>;
76
+ /**
77
+ * Same as {@link run}, but also surfaces the correlation id synchronously
78
+ * so the caller can fire an event referencing the id BEFORE the promise
79
+ * resolves. Used by Emap's `workerjobstart` / `workerjobend` events.
80
+ *
81
+ * Even on an immediately-rejecting path (destroyed pool, or environments
82
+ * lacking a `Worker` constructor), the returned `id` is still drawn from
83
+ * the same monotonic counter so it never collides with live ids — UI
84
+ * code can correlate a `workerjobstart` with a synchronously-rejecting
85
+ * `workerjobend` without aliasing.
86
+ */
87
+ runWithId(cmdOrCommands: string | ParsedCommandWire[], packed: any, inputFiles?: Record<string, Uint8Array | string>): {
88
+ id: number;
89
+ promise: Promise<any>;
90
+ };
91
+ /**
92
+ * Reserve a correlation id without sending anything. Call {@link dispatchWithId}
93
+ * with the same id later to actually post the message. Useful when the
94
+ * caller wants to fire a "started" event with a stable id BEFORE doing
95
+ * expensive sync work (e.g. dataset packing) that delays the postMessage.
96
+ */
97
+ reserveId(): number;
98
+ /**
99
+ * Send a message using a previously-reserved id (see {@link reserveId}).
100
+ * Returns the result promise. Same failure modes as {@link run}: pool
101
+ * destroyed → rejects; worker spawn fails → rejects.
102
+ */
103
+ dispatchWithId(id: number, cmdOrCommands: string | ParsedCommandWire[], packed: any, inputFiles?: Record<string, Uint8Array | string>,
104
+ /**
105
+ * Optional list of `Transferable` objects (typed-array `.buffer`s,
106
+ * `MessagePort`s, …) handed to `postMessage`. When supplied,
107
+ * ownership moves to the worker — saves a structured-clone copy
108
+ * and roughly halves the main-thread memory peak around a
109
+ * pack/unpack round-trip.
110
+ *
111
+ * Callers that share the buffers with main-thread code must NOT
112
+ * pass them via this list (transfer is destructive on the source
113
+ * realm).
114
+ */
115
+ transferList?: Transferable[]): Promise<any>;
116
+ /**
117
+ * Terminate every spawned worker, reject every pending request, and
118
+ * refuse subsequent `run()` calls. Idempotent.
119
+ */
120
+ destroy(): void;
121
+ /**
122
+ * Hard-kill every spawned worker and reject every pending request as
123
+ * `'cancelled'`. Unlike {@link destroy}, the pool stays usable — the
124
+ * next {@link run} call spawns fresh workers on demand.
125
+ *
126
+ * mapshaper isn't interruptible mid-command, so this is the only sound
127
+ * way to abandon a job that's already running: terminate the whole
128
+ * worker, lose any other queued jobs as collateral, and start over. A
129
+ * future iteration could add per-request cancellation tokens; v1 keeps
130
+ * this honest by exposing only the all-or-nothing semantics.
131
+ */
132
+ cancelAll(): void;
133
+ /** True iff at least one worker has been spawned. Test/diagnostics aid. */
134
+ isWorkerSpawned(): boolean;
135
+ /** Number of worker slots configured (NOT the count of currently-spawned workers). */
136
+ get poolSize(): number;
137
+ /**
138
+ * Pick the worker slot to dispatch the next request to.
139
+ *
140
+ * Algorithm:
141
+ * 1. Among slots with the LOWEST `pendingCount`, prefer those that
142
+ * are already spawned (avoid paying spawn cost when load is low).
143
+ * 2. Within that subset, pick by round-robin so the load stays even
144
+ * across slots over time. The cursor advances on every dispatch.
145
+ */
146
+ private _pickWorker;
147
+ private _terminateAll;
148
+ private _ensureWorker;
149
+ private _onMessage;
150
+ private _onWorkerError;
151
+ }
@@ -0,0 +1,26 @@
1
+ import { EventDispatcher } from './events';
2
+ export declare class Timer extends EventDispatcher {
3
+ private _running;
4
+ private _busy;
5
+ private _tickTime;
6
+ private _startTime;
7
+ private _duration;
8
+ constructor();
9
+ start(ms?: number): void;
10
+ stop(): void;
11
+ private _startTick;
12
+ private _onTick;
13
+ }
14
+ export type EaseFunction = (n: number) => number;
15
+ export declare class Tween extends EventDispatcher {
16
+ private _timer;
17
+ private _startValue;
18
+ private _endValue;
19
+ private _ease;
20
+ constructor(ease?: EaseFunction);
21
+ start(a: number, b: number, duration?: number): void;
22
+ stop(): void;
23
+ private _onTick;
24
+ static sineInOut(n: number): number;
25
+ static quadraticOut(n: number): number;
26
+ }
@@ -0,0 +1,16 @@
1
+ import type { EditCommand } from '../edit-command';
2
+ /**
3
+ * Wraps an ordered list of child commands in a single undoable step.
4
+ *
5
+ * `do()` invokes the children in their declared order; `undo()` invokes them
6
+ * in reverse order. This is the building block for every multi-step user
7
+ * operation (e.g. delete-many, future clip / dissolve / batch attribute
8
+ * changes) — one logical action becomes one history entry.
9
+ */
10
+ export declare class CompositeCommand implements EditCommand {
11
+ private readonly children;
12
+ readonly label: string | undefined;
13
+ constructor(children: ReadonlyArray<EditCommand>, label?: string);
14
+ do(): void;
15
+ undo(): void;
16
+ }
@@ -0,0 +1,43 @@
1
+ import type { EditCommand } from '../edit-command';
2
+ import type { MapshaperDataset } from '../../types/mapshaper-types';
3
+ import type { TopologySource } from '../../source/source';
4
+ export interface DatasetReplaceCommandOptions {
5
+ /** The source whose dataset is being swapped. */
6
+ source: TopologySource;
7
+ /** Snapshot of the dataset BEFORE the operation. Restored by undo. */
8
+ before: MapshaperDataset;
9
+ /** Reference to the dataset AFTER the operation. Restored by redo. */
10
+ after: MapshaperDataset;
11
+ /** Human-readable label, surfaced via `historychange`. */
12
+ label: string;
13
+ }
14
+ /**
15
+ * Reverse a whole-dataset operation (clip / erase / dissolve / future
16
+ * polygon ops) by holding both the pre- and post-operation dataset
17
+ * references and swapping which one is active on the `TopologySource`.
18
+ *
19
+ * The `before` reference must be a deep copy (typically produced by
20
+ * `MapshaperAdapter.copyDataset`); the `after` reference is the dataset
21
+ * mapshaper mutated in place. `setDataset` rebuilds DisplayArcs and fires
22
+ * `'data'` so the map re-renders.
23
+ *
24
+ * Note: this command is a "history barrier" — earlier commands closed over
25
+ * specific layer / arc references that point at the old dataset, and must
26
+ * not be replayed across the swap. The `Emap` runner that produces this
27
+ * command clears the history stack before pushing it.
28
+ */
29
+ export declare class DatasetReplaceCommand implements EditCommand {
30
+ private readonly opts;
31
+ readonly label: string;
32
+ /**
33
+ * Pushing a DatasetReplaceCommand marks every prior entry on the undo
34
+ * stack as `stale`. Their captured dataset / arc references point at
35
+ * the object this command swapped out, so undoing them post-swap would
36
+ * write to the wrong place. See `EditCommand.stale` for the full
37
+ * rationale.
38
+ */
39
+ readonly invalidatesPriorCommands = true;
40
+ constructor(opts: DatasetReplaceCommandOptions);
41
+ do(): void;
42
+ undo(): void;
43
+ }
@@ -0,0 +1,72 @@
1
+ import type { EditCommand } from '../edit-command';
2
+ import { type ArcCollection } from '../../types/mapshaper-types';
3
+ import type { TopologySource } from '../../source/source';
4
+ import type { TranslatedPointFeature } from './feature-translate';
5
+ /**
6
+ * 2x3 affine matrix in SVG/Canvas convention.
7
+ *
8
+ * x' = a*x + c*y + tx
9
+ * y' = b*x + d*y + ty
10
+ */
11
+ export interface AffineMatrix {
12
+ a: number;
13
+ b: number;
14
+ c: number;
15
+ d: number;
16
+ tx: number;
17
+ ty: number;
18
+ }
19
+ export interface FeatureAffineCommandOptions {
20
+ source: TopologySource;
21
+ /** Shared ArcCollection for path features. Omit for point-only commands. */
22
+ arcs?: ArcCollection;
23
+ /** Forward matrix. `do()` applies it; `undo()` applies its inverse. */
24
+ matrix: AffineMatrix;
25
+ /** Unique abs-arc-ids referenced by selected path features. */
26
+ arcIds: number[];
27
+ /** Selected point features. */
28
+ pointFeatures: TranslatedPointFeature[];
29
+ /** Optional human-readable label (defaults to `Transform N features`). */
30
+ label?: string;
31
+ }
32
+ /**
33
+ * Apply an affine transform to a fixed set of arcs and point shapes,
34
+ * reversing it on undo via the analytically-computed inverse matrix.
35
+ *
36
+ * Same lightweight in-place semantics as `FeatureTranslateCommand`:
37
+ * O(touched-vertices), composes freely with other commands in one undo
38
+ * timeline, no dataset replacement, selection survives.
39
+ */
40
+ export declare class FeatureAffineCommand implements EditCommand {
41
+ private readonly opts;
42
+ readonly label: string;
43
+ constructor(opts: FeatureAffineCommandOptions);
44
+ do(): void;
45
+ undo(): void;
46
+ private _apply;
47
+ }
48
+ /**
49
+ * Rotate around `(ox, oy)` by `angleRad`.
50
+ *
51
+ * Combined transform: translate(-ox,-oy) → rotate(θ) → translate(ox,oy).
52
+ */
53
+ export declare function rotateMatrix(angleRad: number, ox?: number, oy?: number): AffineMatrix;
54
+ /**
55
+ * Scale by `(sx, sy)` around `(ox, oy)`.
56
+ *
57
+ * Combined transform: translate(-ox,-oy) → scale(sx,sy) → translate(ox,oy).
58
+ */
59
+ export declare function scaleMatrix(sx: number, sy: number, ox?: number, oy?: number): AffineMatrix;
60
+ /**
61
+ * Compose two matrices: result applies `b` first, then `a`. I.e. for vertex
62
+ * `v`, `compose(a, b)` is equivalent to `a * b * v` — the same convention
63
+ * as DOMMatrix and CSS `transform`.
64
+ */
65
+ export declare function composeMatrix(a: AffineMatrix, b: AffineMatrix): AffineMatrix;
66
+ /** Identity matrix — useful as the starting cumulative for `composeMatrix`. */
67
+ export declare const IDENTITY_MATRIX: AffineMatrix;
68
+ /**
69
+ * Analytical inverse. For a non-degenerate `m`, applying `m` then
70
+ * `invertMatrix(m)` is the identity (within floating-point epsilon).
71
+ */
72
+ export declare function invertMatrix(m: AffineMatrix): AffineMatrix;
@@ -0,0 +1,47 @@
1
+ import type { EditCommand } from '../edit-command';
2
+ import { type ArcCollection, type FeatureShape, type MapshaperLayer } from '../../types/mapshaper-types';
3
+ import type { TopologySource } from '../../source/source';
4
+ import { type MapshaperAdapter } from '../../adapter/mapshaper-adapter';
5
+ export type FeatureGeometryType = 'point' | 'polyline' | 'polygon';
6
+ export interface FeatureCreateCommandOptions {
7
+ geometryType: FeatureGeometryType;
8
+ /** Layer the feature was appended to. */
9
+ layer: MapshaperLayer;
10
+ /** Source so we can refresh DisplayArcs after the mutation. */
11
+ source: TopologySource;
12
+ /** The shape value pushed onto `layer.shapes`. */
13
+ appendedShape: FeatureShape;
14
+ /** Adapter override for tests; defaults to the process-wide singleton. */
15
+ adapter?: MapshaperAdapter;
16
+ /**
17
+ * The data record pushed onto `layer.data.getRecords()`. `null` when the
18
+ * layer has no data table.
19
+ */
20
+ appendedRecord: Record<string, unknown> | null;
21
+ /**
22
+ * Vertex coordinates of the new arc, in original order. Required for path
23
+ * geometries (polyline / polygon); omitted for points.
24
+ */
25
+ arcVertices?: [number, number][];
26
+ /** The shared ArcCollection for path geometries; omitted for points. */
27
+ arcs?: ArcCollection;
28
+ }
29
+ /**
30
+ * Reverse the creation of a drawn feature.
31
+ *
32
+ * For path features: the last appended arc is removed via mapshaper's
33
+ * `internal.deleteLastArc`, and the shape / record are popped. Redo
34
+ * re-creates the arc using mapshaper's canonical `appendEmptyArc` +
35
+ * `appendVertex` pattern, so vertex storage and z-values match the original
36
+ * append exactly.
37
+ *
38
+ * For point features: only the shape and (optional) record are popped /
39
+ * re-pushed.
40
+ */
41
+ export declare class FeatureCreateCommand implements EditCommand {
42
+ private readonly opts;
43
+ readonly label: string;
44
+ constructor(opts: FeatureCreateCommandOptions);
45
+ do(): void;
46
+ undo(): void;
47
+ }
@@ -0,0 +1,72 @@
1
+ import type { EditCommand } from '../edit-command';
2
+ import type { FeatureShape, MapshaperLayer } from '../../types/mapshaper-types';
3
+ export interface FeatureDeleteCommandOptions {
4
+ /** The layer object that owns the feature. */
5
+ layer: MapshaperLayer;
6
+ /** Index of the feature within `layer.shapes`. Captured at construction. */
7
+ featureId: number;
8
+ /** Snapshot of the shape, taken before deletion. Restored by undo. */
9
+ shape: FeatureShape | null;
10
+ /**
11
+ * Snapshot of the data record, taken before deletion. `null` when the
12
+ * layer has no data table.
13
+ */
14
+ record: Record<string, unknown> | null;
15
+ }
16
+ /**
17
+ * Removes a single feature from a layer by splicing its shape and data
18
+ * record. Mirrors mapshaper's `gui-drawing-utils.deleteFeature` /
19
+ * `insertFeature` pair so undo restores the exact prior layout.
20
+ *
21
+ * Orphan arcs referenced by deleted path features are intentionally left in
22
+ * the source's `ArcCollection` — that is mapshaper's convention. Undo
23
+ * restores the shape, which references the arcs that are still there. To
24
+ * reclaim space, run a future `clean` / `dissolve` op.
25
+ *
26
+ * No `DisplayArcs` refresh: deletion never changes the arc collection.
27
+ * `DisplayArcs.getScaledArcs` self-heals if `arcs.size()` ever changes for
28
+ * unrelated reasons (vertex add, addIntersectionCuts), so the only callers
29
+ * that need to refresh are those that mutate arcs themselves.
30
+ */
31
+ export declare class FeatureDeleteCommand implements EditCommand {
32
+ private readonly opts;
33
+ readonly label = "Delete feature";
34
+ constructor(opts: FeatureDeleteCommandOptions);
35
+ do(): void;
36
+ undo(): void;
37
+ }
38
+ export interface BulkFeatureDeleteCommandOptions {
39
+ /** The layer being mutated. */
40
+ layer: MapshaperLayer;
41
+ /**
42
+ * Snapshots of every feature being deleted. `id` is the index in the
43
+ * layer's `shapes` array at the time the command was constructed; the
44
+ * list need not be sorted but ids must be unique.
45
+ */
46
+ snapshots: Array<{
47
+ id: number;
48
+ shape: FeatureShape | null;
49
+ record: Record<string, unknown> | null;
50
+ }>;
51
+ }
52
+ /**
53
+ * Layer-scoped bulk delete. Splicing K features one at a time on a layer
54
+ * with N shapes is O(K·N) — for a 1.5M-vertex topology with K in the
55
+ * hundreds the main thread freezes for seconds. This command does it in
56
+ * one O(N) compaction pass instead.
57
+ *
58
+ * `do()` rebuilds `layer.shapes` and compacts the data table's records
59
+ * array IN PLACE so the table's reference stays valid. `undo()` walks the
60
+ * snapshots in ascending id order and re-inserts via splice — fine because
61
+ * undo is called once per delete batch, not per feature.
62
+ *
63
+ * Like {@link FeatureDeleteCommand}, no `DisplayArcs` refresh is issued;
64
+ * deletion never changes the arc collection.
65
+ */
66
+ export declare class BulkFeatureDeleteCommand implements EditCommand {
67
+ private readonly opts;
68
+ readonly label: string;
69
+ constructor(opts: BulkFeatureDeleteCommandOptions);
70
+ do(): void;
71
+ undo(): void;
72
+ }
@@ -0,0 +1,34 @@
1
+ import type { EditCommand } from '../edit-command';
2
+ import type { MapshaperLayer } from '../../types/mapshaper-types';
3
+ export interface FeaturePropertyChangeCommandOptions {
4
+ /** Layer that owns the feature. */
5
+ layer: MapshaperLayer;
6
+ /** Index of the feature within `layer.shapes`. */
7
+ featureId: number;
8
+ /**
9
+ * Sparse patch of pre-edit values, keyed by field name. The presence of a
10
+ * key means "the record had this key with this value before the edit"; an
11
+ * absent key means "the record did not have this key before the edit".
12
+ */
13
+ prev: Record<string, unknown>;
14
+ /**
15
+ * Sparse patch of post-edit values. Same key-presence semantics as `prev`:
16
+ * present = "this key should exist with this value", absent = "this key
17
+ * should not exist".
18
+ */
19
+ next: Record<string, unknown>;
20
+ /** Optional human-readable label for `historychange`. */
21
+ label?: string;
22
+ }
23
+ /**
24
+ * Reverse a single-feature attribute edit by walking a sparse `prev` / `next`
25
+ * patch. Memory cost is proportional to the number of keys that actually
26
+ * changed, not the size of the record.
27
+ */
28
+ export declare class FeaturePropertyChangeCommand implements EditCommand {
29
+ private readonly opts;
30
+ readonly label: string;
31
+ constructor(opts: FeaturePropertyChangeCommandOptions);
32
+ do(): void;
33
+ undo(): void;
34
+ }
@@ -0,0 +1,55 @@
1
+ import type { EditCommand } from '../edit-command';
2
+ import { type ArcCollection, type MapshaperLayer } from '../../types/mapshaper-types';
3
+ import type { TopologySource } from '../../source/source';
4
+ /** Point-feature reference within a single source. */
5
+ export interface TranslatedPointFeature {
6
+ layer: MapshaperLayer;
7
+ featureId: number;
8
+ }
9
+ export interface FeatureTranslateCommandOptions {
10
+ source: TopologySource;
11
+ /** Shared ArcCollection that owns the path-feature arcs. May be omitted if only point features. */
12
+ arcs?: ArcCollection;
13
+ /** Offset in source-data coordinates. */
14
+ dx: number;
15
+ dy: number;
16
+ /**
17
+ * Unique absolute arc ids (post-`absArcId`) referenced by selected path
18
+ * features in the source. Empty when no path features are selected.
19
+ */
20
+ arcIds: number[];
21
+ /**
22
+ * Selected point features whose `layer.shapes[featureId]` is offset directly.
23
+ * Empty when no point features are selected.
24
+ */
25
+ pointFeatures: TranslatedPointFeature[];
26
+ }
27
+ /**
28
+ * Translate a fixed set of arcs and point shapes by `(dx, dy)` in source-data
29
+ * coordinates. Reverses by negating the offset.
30
+ *
31
+ * Lightweight in-place mutation — no dataset replacement, no copy. Cost is
32
+ * O(vertices in the affected arcs + point coords). The same command class
33
+ * handles point-only, path-only, and mixed selections within one source.
34
+ *
35
+ * Mergeable: consecutive translates of the SAME (source, arcIds,
36
+ * pointFeatures) tuple within {@link MERGE_WINDOW_MS} accumulate their
37
+ * deltas into a single entry — useful for arrow-key nudges or any UI
38
+ * that batches `Emap.translateSelected` per keystroke.
39
+ *
40
+ * Known v1 limitation: arcs shared with unselected features are translated
41
+ * once (correctly per the topology model), which means the unselected
42
+ * neighbour's geometry follows along. The proper fix requires cutting
43
+ * shared arcs at the selection boundary first; tracked as a follow-up.
44
+ */
45
+ export declare class FeatureTranslateCommand implements EditCommand {
46
+ private readonly opts;
47
+ readonly label: string;
48
+ private _mergeAt;
49
+ constructor(opts: FeatureTranslateCommandOptions);
50
+ do(): void;
51
+ undo(): void;
52
+ mergeable(prev: EditCommand): boolean;
53
+ merge(next: EditCommand): void;
54
+ private _apply;
55
+ }
@@ -0,0 +1,24 @@
1
+ import type { EditCommand } from '../edit-command';
2
+ import type { MapshaperLayer } from '../../types/mapshaper-types';
3
+ export interface FieldAddCommandOptions {
4
+ layer: MapshaperLayer;
5
+ /** Field name to add to every record that does not already have it. */
6
+ field: string;
7
+ /** Default value to assign. Defaults to `null` when omitted. */
8
+ defaultValue?: unknown;
9
+ }
10
+ /**
11
+ * Add a new column to a layer's data table by setting `field` = `defaultValue`
12
+ * on every record that does not already have the key. Records that already
13
+ * carry the key are skipped (and not undone) so the operation is safely
14
+ * idempotent.
15
+ */
16
+ export declare class FieldAddCommand implements EditCommand {
17
+ private readonly opts;
18
+ readonly label: string;
19
+ /** Indices of records this command added the key to (used by undo). */
20
+ private _addedIndices;
21
+ constructor(opts: FieldAddCommandOptions);
22
+ do(): void;
23
+ undo(): void;
24
+ }
@@ -0,0 +1,20 @@
1
+ import type { EditCommand } from '../edit-command';
2
+ import type { MapshaperLayer } from '../../types/mapshaper-types';
3
+ export interface FieldRemoveCommandOptions {
4
+ layer: MapshaperLayer;
5
+ /** Field name to drop from every record in the layer. */
6
+ field: string;
7
+ }
8
+ /**
9
+ * Drop a column from a layer's data table. Each record's prior value is
10
+ * snapshotted on `do()` so `undo()` can restore exact contents — including
11
+ * leaving records that never had the field untouched.
12
+ */
13
+ export declare class FieldRemoveCommand implements EditCommand {
14
+ private readonly opts;
15
+ readonly label: string;
16
+ private _snapshot;
17
+ constructor(opts: FieldRemoveCommandOptions);
18
+ do(): void;
19
+ undo(): void;
20
+ }
@@ -0,0 +1,19 @@
1
+ import type { EditCommand } from '../edit-command';
2
+ import type { MapshaperLayer } from '../../types/mapshaper-types';
3
+ export interface FieldRenameCommandOptions {
4
+ layer: MapshaperLayer;
5
+ from: string;
6
+ to: string;
7
+ }
8
+ /**
9
+ * Rename a column on every record in a layer. Each record that has the
10
+ * `from` key has its value moved to `to` and the old key dropped. Records
11
+ * without the `from` key are left untouched in both directions.
12
+ */
13
+ export declare class FieldRenameCommand implements EditCommand {
14
+ private readonly opts;
15
+ readonly label: string;
16
+ constructor(opts: FieldRenameCommandOptions);
17
+ do(): void;
18
+ undo(): void;
19
+ }