@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,50 @@
1
+ import { Painter, DrawOverlayState } from './painter';
2
+ import { AffineTransform } from '../geo/transform';
3
+ import type { ArcCollection, StrokeStyle, PointStyle, VertexDotStyle } from '../types/mapshaper-types';
4
+ export declare class CanvasPainter implements Painter {
5
+ private _canvas;
6
+ private _ctx;
7
+ private _transform;
8
+ private _pixelRatio;
9
+ constructor(_canvas: HTMLCanvasElement);
10
+ setTransform(transform: AffineTransform): void;
11
+ setPixelRatio(ratio: number): void;
12
+ drawPaths(shapes: any[], style: StrokeStyle, arcs: ArcCollection): void;
13
+ drawArcs(arcs: ArcCollection, style: StrokeStyle, filter?: (i: number) => boolean): void;
14
+ private drawPathSnapping;
15
+ drawPoints(_shapes: any[], _style: PointStyle): void;
16
+ /**
17
+ * Draw vertex dots on the main canvas context.
18
+ * Called during render() when in vertex edit mode.
19
+ */
20
+ drawVertexDots(shapes: any[], arcs: ArcCollection, style?: VertexDotStyle): void;
21
+ /**
22
+ * Draw a fill for polygon shapes in vertex edit mode.
23
+ *
24
+ * IMPORTANT: Must use getShapeIter (not getArcIter) so that reversed arcs
25
+ * (~arcId) are traversed backwards, preserving correct polygon winding order.
26
+ * This is what mapshaper does via ShapeIter and is the reason plain getArcIter
27
+ * produces incorrect fills (doesn't cover the whole polygon, or fills holes).
28
+ */
29
+ drawPolygonFill(shapes: any[], arcs: ArcCollection & {
30
+ getShapeIter?: (part: number[]) => {
31
+ x: number;
32
+ y: number;
33
+ hasNext(): boolean;
34
+ };
35
+ }, fillColor: string, filter?: (i: number) => boolean,
36
+ /**
37
+ * Multiplier on top of `fillColor`'s own alpha. `1` (default) leaves
38
+ * the colour as-is; `0.5` halves the resulting alpha. Matches MapLibre's
39
+ * `fill-opacity` semantics — independent of the colour's own alpha.
40
+ */
41
+ opacity?: number): void;
42
+ /**
43
+ * Draw the in-progress feature creation overlay.
44
+ * Renders placed vertices, connecting lines, rubber-band line to cursor,
45
+ * and snap indicator.
46
+ */
47
+ drawDrawingOverlay(state: DrawOverlayState): void;
48
+ clear(): void;
49
+ resize(width: number, height: number): void;
50
+ }
@@ -0,0 +1,22 @@
1
+ import type { EditPainter } from './painter';
2
+ import type { EditVertexState, EditDrawState } from '../map/types';
3
+ /**
4
+ * Draws edit-mode-only decorations on top of the regular layer pass:
5
+ * - polygon fill highlight while editing a polygon's vertices
6
+ * - vertex dots (with hover affordance) while in vertex mode
7
+ * - the in-progress draw overlay while creating a new feature
8
+ *
9
+ * Pulled out of `Emap.render()` so the main render loop deals with layers
10
+ * only and doesn't need to introspect edit-mode flags or downcast the
11
+ * Painter to a concrete implementation.
12
+ */
13
+ export declare class EditOverlayRenderer {
14
+ private _painter;
15
+ constructor(_painter: EditPainter);
16
+ /**
17
+ * Render the edit-mode overlay for the current frame. No-op when
18
+ * `editMode === 'none'` or the relevant state object is `null`.
19
+ */
20
+ render(editMode: 'none' | 'vertex' | 'draw', vertexState: EditVertexState | null, drawState: EditDrawState | null): void;
21
+ private _renderVertexOverlay;
22
+ }
@@ -0,0 +1,52 @@
1
+ import type { AffineTransform } from '../geo/transform';
2
+ import type { ArcCollection, StrokeStyle, PointStyle, VertexDotStyle } from '../types/mapshaper-types';
3
+ /** Geometry kind currently being authored by the draw overlay. */
4
+ export type DrawOverlayGeometryType = 'polygon' | 'polyline' | 'point';
5
+ /** Snap-target kind under the draw cursor. `null` when no target. */
6
+ export type DrawOverlaySnapKind = 'vertex' | 'edge' | null;
7
+ /**
8
+ * Render-domain state for {@link Painter.drawDrawingOverlay}.
9
+ * Owned by the renderer so painters do not back-reference `map/`.
10
+ * The map module re-exports this as `EditDrawState` for back-compat.
11
+ */
12
+ export interface DrawOverlayState {
13
+ vertices: [number, number][];
14
+ cursorCoord: [number, number] | null;
15
+ snapCoord: [number, number] | null;
16
+ snapKind: DrawOverlaySnapKind;
17
+ geometryType: DrawOverlayGeometryType;
18
+ drawColor: string;
19
+ }
20
+ /**
21
+ * Stateless drawing primitives: enough to render basemap topology, points,
22
+ * polygons, and arc highlights. Anything that paints actual map content
23
+ * should depend on `CorePainter`, not the broader `Painter`/`EditPainter`.
24
+ */
25
+ export interface CorePainter {
26
+ drawPaths(shapes: any[], style: StrokeStyle, arcs: ArcCollection): void;
27
+ drawArcs(arcs: ArcCollection, style: StrokeStyle, filter?: (i: number) => boolean): void;
28
+ drawPoints(shapes: any[], style: PointStyle): void;
29
+ drawPolygonFill(shapes: any[], arcs: ArcCollection, fillColor: string, filter?: (i: number) => boolean, opacity?: number): void;
30
+ clear(): void;
31
+ resize(width: number, height: number): void;
32
+ setTransform(transform: AffineTransform): void;
33
+ setPixelRatio(ratio: number): void;
34
+ }
35
+ /**
36
+ * Adds the edit-mode-only overlay primitives — vertex dots and the
37
+ * draw-overlay state machine — on top of `CorePainter`. Code that does
38
+ * not paint editing affordances should not depend on this interface.
39
+ */
40
+ export interface EditPainter extends CorePainter {
41
+ drawVertexDots(shapes: any[], arcs: ArcCollection, style: VertexDotStyle): void;
42
+ drawDrawingOverlay(state: DrawOverlayState): void;
43
+ }
44
+ /**
45
+ * Legacy alias preserved for callers that already import `Painter`.
46
+ * The full painter interface is the edit-aware one because every
47
+ * existing concrete painter (`CanvasPainter`) implements both halves.
48
+ */
49
+ export type Painter = EditPainter;
50
+ export interface RenderOptions {
51
+ antialias?: boolean;
52
+ }
package/dist/shim.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,49 @@
1
+ import type { ArcCollection } from '../types/mapshaper-types';
2
+ /**
3
+ * Wraps a Mapshaper ArcCollection and provides Level of Detail (LOD) switching.
4
+ * For large datasets (>500k points), generates a low-detail copy for faster
5
+ * rendering at zoomed-out scales.
6
+ *
7
+ * Based on Mapshaper's gui-display-arcs.mjs implementation.
8
+ */
9
+ export declare class DisplayArcs {
10
+ private _unfilteredArcs;
11
+ private _filteredArcs;
12
+ private _filteredSegLen;
13
+ /**
14
+ * Set by {@link markDirty} when an in-place edit (translate / vertex move /
15
+ * shared-arc split / …) mutates the underlying arcs. Cleared the next time
16
+ * {@link getScaledArcs} actually needs the filtered copy and rebuilds it.
17
+ *
18
+ * The flag lets per-frame edit sessions defer the (~O(N)) filtered-copy
19
+ * rebuild until the renderer asks for it. Most drags happen at zoom levels
20
+ * where the unfiltered arcs are used directly, so the rebuild often fires
21
+ * exactly once — at the next zoom-out.
22
+ */
23
+ private _dirty;
24
+ constructor(arcs: ArcCollection);
25
+ /**
26
+ * Mark the cached LOD copy stale. Cheap (O(1) flag flip) so callers
27
+ * inside per-frame drag loops can safely invoke this on every step;
28
+ * the actual rebuild happens lazily inside {@link getScaledArcs}.
29
+ *
30
+ * For datasets below `LARGE_DATASET_THRESHOLD` (no LOD copy ever
31
+ * created), this is effectively a no-op.
32
+ */
33
+ markDirty(): void;
34
+ private _initFilteredArcs;
35
+ /**
36
+ * Returns the appropriate arc collection based on current zoom level.
37
+ * @param unitsPerPixel - Map units per screen pixel (1 / transform.mx)
38
+ * @returns Low-detail arcs when zoomed out, full-detail arcs when zoomed in
39
+ */
40
+ getScaledArcs(unitsPerPixel: number): ArcCollection;
41
+ /**
42
+ * Returns the original (full-detail) arc collection.
43
+ */
44
+ getArcs(): ArcCollection;
45
+ /**
46
+ * Returns true if a low-detail LOD copy exists.
47
+ */
48
+ hasLOD(): boolean;
49
+ }
@@ -0,0 +1,12 @@
1
+ import type { Coord2, MapshaperLayer } from '../types/mapshaper-types';
2
+ /**
3
+ * Derive a stable layer identifier from a Mapshaper layer object.
4
+ * Falls back to a positional `layer-N` string.
5
+ */
6
+ export declare function getLayerId(layer: MapshaperLayer, index: number): string;
7
+ /**
8
+ * Coerce a mapshaper point shape to a uniform `Coord2[]` (multi-point) form.
9
+ * Tolerates the legacy bare `[x, y]` single-point shape that some older
10
+ * datasets carry by wrapping it in a one-element array.
11
+ */
12
+ export declare function normalizePointShape(shape: unknown): Coord2[];
@@ -0,0 +1,22 @@
1
+ import type { MapshaperDataset } from '../types/mapshaper-types';
2
+ import { type MapshaperAdapter } from '../adapter/mapshaper-adapter';
3
+ /** Files injected into the runner's input cache (e.g. `.shp` payloads). */
4
+ export type RunnerInputFiles = Record<string, Uint8Array | string>;
5
+ export interface MapshaperRunner {
6
+ /**
7
+ * Run a mapshaper CLI-style command string and resolve to the first
8
+ * default-target dataset. Throws on parse / runtime errors.
9
+ */
10
+ runImport(cmd: string, inputFiles: RunnerInputFiles): Promise<MapshaperDataset>;
11
+ }
12
+ /**
13
+ * Production runner that delegates to {@link MapshaperAdapter.runImport}.
14
+ * Kept as a class so callers can subclass for instrumentation (timing,
15
+ * telemetry, error remapping).
16
+ */
17
+ export declare class DefaultMapshaperRunner implements MapshaperRunner {
18
+ private readonly _adapter;
19
+ constructor(_adapter?: MapshaperAdapter);
20
+ runImport(cmd: string, inputFiles: RunnerInputFiles): Promise<MapshaperDataset>;
21
+ }
22
+ export declare function getDefaultMapshaperRunner(): MapshaperRunner;
@@ -0,0 +1,80 @@
1
+ import { EventDispatcher } from '../core/events';
2
+ import type { ArcCollection, MapshaperDataset } from '../types/mapshaper-types';
3
+ import type { DisplayArcs } from './display-arcs';
4
+ import type { Bounds } from '../geo/bounds';
5
+ export interface Source extends EventDispatcher {
6
+ id: string;
7
+ type: 'topology' | 'geojson';
8
+ getExtent(): Bounds;
9
+ }
10
+ /** File formats emap can serialize a dataset to. Mirrors the import format set. */
11
+ export type ExportFormat = 'geojson' | 'topojson' | 'shapefile' | 'msx';
12
+ /** Options for {@link TopologySource.export}. */
13
+ export interface ExportOptions {
14
+ format: ExportFormat;
15
+ }
16
+ export interface TopologySource extends Source {
17
+ type: 'topology';
18
+ getArcs(): ArcCollection | undefined;
19
+ getLayers(): any[];
20
+ /**
21
+ * Returns the live mapshaper dataset reference owned by this source.
22
+ *
23
+ * **Do not mutate the returned object directly**. Edit-history caches
24
+ * (arc-flag flags, Flatbush spatial indices, the LOD copy in DisplayArcs)
25
+ * key off `(layer, shape, arc)` identity and shape/arc counts; mutations
26
+ * applied outside the official edit-command surface will silently desync
27
+ * those caches. To change a dataset, route the change through
28
+ * `Emap.ops.*` (clip / dissolve / buffer / …), `Emap.editSession.*`
29
+ * (translate / rotate / scale), or a custom `EditCommand`. Read-only
30
+ * inspection — `getDataset()?.info?.crs_string`, `dataset.layers[0].name`,
31
+ * arc iteration via `dataset.arcs.getArcIter()` — is always safe.
32
+ *
33
+ * The TypeScript return type intentionally stays `MapshaperDataset` (not
34
+ * `Readonly<MapshaperDataset>`) because mapshaper's own internal helpers
35
+ * — and a number of in-tree edit commands — receive the dataset and
36
+ * mutate it through trusted code paths. A blanket `Readonly` would just
37
+ * force casts everywhere.
38
+ */
39
+ getDataset(): MapshaperDataset | undefined;
40
+ getDisplayArcs(): DisplayArcs | null;
41
+ /**
42
+ * Eagerly re-initialize the LOD copy in DisplayArcs from the current
43
+ * dataset arcs. Use for one-shot mutations that need the new copy ready
44
+ * immediately. Per-frame in-place edits (drag sessions) should prefer
45
+ * {@link markDisplayArcsDirty} to defer the rebuild until the renderer
46
+ * actually needs the filtered copy.
47
+ */
48
+ refreshDisplayArcs(): void;
49
+ /**
50
+ * Mark the LOD copy stale; the next `getScaledArcs` rebuilds it lazily.
51
+ * O(1); safe inside per-frame drag callbacks.
52
+ */
53
+ markDisplayArcsDirty?(): void;
54
+ /**
55
+ * Replace the active dataset (used by undo/redo of dataset-replace commands
56
+ * and by reproject). Rebuilds DisplayArcs and fires the `data` event so the
57
+ * map re-renders.
58
+ */
59
+ setDataset(dataset: MapshaperDataset): void;
60
+ /**
61
+ * Sticky simplification floor (in arc-Z units). Set by the most recent
62
+ * `-simplify` run via `setDataset`; cleared on a fresh load. The render
63
+ * loop uses this as a lower-bound for `setRetainedInterval` so the
64
+ * per-frame zoom-LOD never re-introduces detail the user filtered out.
65
+ */
66
+ getSimplifyFloor?(): number;
67
+ /**
68
+ * Serialize the current in-memory dataset to a browser `Blob`.
69
+ *
70
+ * Always emits full-detail geometry; the source's render-time LOD interval
71
+ * is restored before the promise resolves.
72
+ *
73
+ * - `geojson` / `topojson` — single-file output, returned as `application/json`
74
+ * - `shapefile` — multi-file output (.shp/.shx/.dbf/.prj), returned as a
75
+ * single `application/zip` Blob packed via fflate
76
+ */
77
+ export(options: ExportOptions): Promise<Blob>;
78
+ getCRS?(): string;
79
+ reproject?(targetCrs: string): Promise<void>;
80
+ }
@@ -0,0 +1,145 @@
1
+ import { EventDispatcher } from '../core/events';
2
+ import { TopologySource as ITopologySource } from './source';
3
+ import { Bounds } from '../geo/bounds';
4
+ import { DisplayArcs } from './display-arcs';
5
+ import type { MapshaperDataset } from '../types/mapshaper-types';
6
+ import type { ExportOptions } from './source';
7
+ import { type MapshaperRunner } from './mapshaper-runner';
8
+ export type TopologySourceData = string | {
9
+ filename: string;
10
+ content: Uint8Array;
11
+ };
12
+ /**
13
+ * Input shapes accepted by {@link TopologySource.setData}:
14
+ * - URL string,
15
+ * - single `{filename, content}` object,
16
+ * - or an array of `{filename, content}` for multi-file imports (each file
17
+ * becomes its own layer in a single dataset; matches mapshaper's
18
+ * `-i FILE1 FILE2 ...` CLI behaviour).
19
+ */
20
+ export type TopologySourceInput = TopologySourceData | Array<{
21
+ filename: string;
22
+ content: Uint8Array;
23
+ }>;
24
+ /**
25
+ * Resource ceilings applied by {@link TopologySource} when extracting a ZIP
26
+ * payload. Defaults are intentionally generous so legitimate shapefile zips
27
+ * keep working unchanged. Apps that load adversarial / public-internet zips
28
+ * should lower them.
29
+ */
30
+ export interface ZipExtractionLimits {
31
+ /** Max summed uncompressed size of all kept entries, in bytes. Default 200 MB. */
32
+ maxBytes?: number;
33
+ /** Max entry count fflate may yield. Default 5000. */
34
+ maxEntries?: number;
35
+ /** Max `uncompressedTotal / compressedInput` ratio. Default 100. */
36
+ maxRatio?: number;
37
+ }
38
+ export interface TopologySourceOptions {
39
+ data?: TopologySourceInput;
40
+ zipLimits?: ZipExtractionLimits;
41
+ /**
42
+ * Optional injection point for the mapshaper command runner used by
43
+ * the load path. Defaults to a process-wide singleton that calls
44
+ * `MapshaperAdapter.runImport / runOnDataset` directly.
45
+ * Tests and instrumentation use this to swap in a mock runner.
46
+ */
47
+ mapshaperRunner?: MapshaperRunner;
48
+ }
49
+ export declare class TopologySource extends EventDispatcher implements ITopologySource {
50
+ id: string;
51
+ type: 'topology';
52
+ private _dataset;
53
+ private _displayArcs;
54
+ private _options;
55
+ private _data;
56
+ private _loadVersion;
57
+ private _abortController;
58
+ /**
59
+ * Sticky simplification floor. mapshaper's `-simplify` writes a
60
+ * `retainedInterval` into the resulting `ArcCollection`; we cache that
61
+ * value here so the render loop's per-frame zoom-LOD doesn't stomp it.
62
+ * Re-captured on every `setDataset` / `setData`.
63
+ */
64
+ private _simplifyFloor;
65
+ private _runner;
66
+ /** Max-detail threshold the user (or last `-simplify` run) asked for. */
67
+ getSimplifyFloor(): number;
68
+ constructor(id: string, options?: TopologySourceOptions);
69
+ /**
70
+ * Convenience loader for URL-backed sources.
71
+ *
72
+ * Resolves after the first successful `data` event and rejects on the first
73
+ * load `error`, so callers can safely add the returned source to a map.
74
+ */
75
+ static fromUrl(id: string, url: string, options?: Omit<TopologySourceOptions, 'data'>): Promise<TopologySource>;
76
+ /**
77
+ * Replace the source's data and trigger a re-import.
78
+ *
79
+ * Accepts a URL, a single `{filename, content}` object, or an array of
80
+ * `{filename, content}` for multi-file imports (each file becomes its own
81
+ * layer in one dataset — same behaviour as mapshaper's
82
+ * `-i FILE1 FILE2 ...` CLI invocation).
83
+ *
84
+ * Last-write-wins: rapid back-to-back calls supersede each other. Only the
85
+ * latest call's outcome fires `data` / `error`; in-flight URL fetches from
86
+ * superseded calls are aborted.
87
+ */
88
+ setData(data: TopologySourceInput): this;
89
+ private _updateData;
90
+ private _hasSupportedExtension;
91
+ private _filenameFromContentType;
92
+ getDataset(): MapshaperDataset | undefined;
93
+ /**
94
+ * Canonical CRS identifier for the loaded dataset (`EPSG:NNNN` or a
95
+ * passthrough label). Heuristics live in {@link resolveDatasetCRS} so the
96
+ * resolution can be unit-tested independently of TopologySource.
97
+ */
98
+ getCRS(): string;
99
+ reproject(targetCrs: string): Promise<void>;
100
+ getExtent(): Bounds;
101
+ getArcs(): any;
102
+ /**
103
+ * Returns the DisplayArcs wrapper for LOD support.
104
+ * Use getScaledArcs(unitsPerPixel) to get the appropriate LOD.
105
+ */
106
+ getDisplayArcs(): DisplayArcs | null;
107
+ /**
108
+ * Mark the cached LOD copy stale; the next `getScaledArcs()` call inside
109
+ * the renderer will rebuild it lazily. Cheap (O(1)) so per-frame edit
110
+ * sessions can call this on every step without paying the rebuild cost
111
+ * until the user actually zooms out far enough to need the filtered copy.
112
+ */
113
+ markDisplayArcsDirty(): void;
114
+ /**
115
+ * Eagerly re-initialize DisplayArcs from the current dataset arcs. Use
116
+ * for one-shot mutations where the caller wants the new LOD copy ready
117
+ * immediately (project, dataset-replace). Per-frame in-place edits
118
+ * should prefer {@link markDisplayArcsDirty}.
119
+ */
120
+ refreshDisplayArcs(): void;
121
+ /**
122
+ * Swap the active dataset. Used by dataset-replace commands (clip / erase /
123
+ * dissolve / …) and by reproject. Rebuilds the LOD copy and notifies
124
+ * listeners with the `data` event.
125
+ */
126
+ setDataset(dataset: MapshaperDataset): void;
127
+ /**
128
+ * Serialize the current dataset to a browser Blob via mapshaper's exporter.
129
+ *
130
+ * Multi-file shapefile output is packed into a single zip Blob using fflate
131
+ * so callers always receive one Blob per call.
132
+ */
133
+ export(options: ExportOptions): Promise<Blob>;
134
+ /**
135
+ * Pack mapshaper's `[{filename, content}]` output into a single Blob.
136
+ * Single-file formats use the first entry directly; shapefile is zipped.
137
+ */
138
+ private _filesToBlob;
139
+ getLayers(): any[];
140
+ private _isZipFile;
141
+ private _extractZip;
142
+ private _isTextFile;
143
+ private _findPrimaryFile;
144
+ private _isAuxiliaryFile;
145
+ }
@@ -0,0 +1,182 @@
1
+ /**
2
+ * TypeScript interfaces for Mapshaper data structures.
3
+ * These replace pervasive `any` usage across the codebase.
4
+ */
5
+ /** Iterator returned by ArcCollection.getArcIter() */
6
+ export interface ArcIterator {
7
+ x: number;
8
+ y: number;
9
+ hasNext(): boolean;
10
+ }
11
+ /** Raw vertex storage exposed by ArcCollection.getVertexData() */
12
+ export interface ArcVertexData {
13
+ xx: Float64Array;
14
+ yy: Float64Array;
15
+ /** Per-vertex simplification thresholds (Visvalingam Z-values). Null if arcs are flat. */
16
+ zz: Float64Array | null;
17
+ /** Number of vertices in each arc (length === arc count) */
18
+ nn: Int32Array | Uint32Array;
19
+ /** Starting vertex index of each arc within xx/yy (length === arc count) */
20
+ ii: Int32Array | Uint32Array;
21
+ /** Per-arc bounding boxes packed as [xmin,ymin,xmax,ymax,...] */
22
+ bb?: Float64Array;
23
+ }
24
+ /** Mapshaper's ArcCollection — manages all arcs in a dataset */
25
+ export interface ArcCollection {
26
+ /** Number of arcs (NOT number of points — see getPointCount for that) */
27
+ size(): number;
28
+ getArcIter(arcId: number): ArcIterator;
29
+ getShapeIter?(part: number[]): ArcIterator;
30
+ forEachSegment?(cb: (i: number, j: number, xx: Float64Array, yy: Float64Array) => void): void;
31
+ forEachArcSegment?(arcId: number, cb: (i: number, j: number, xx: Float64Array, yy: Float64Array) => void): void;
32
+ setRetainedInterval?(interval: number): ArcCollection;
33
+ getRetainedInterval?(): number;
34
+ getThresholdByPct?(pct: number, nth?: number): number;
35
+ setThresholds?(zz: Float64Array): void;
36
+ isFlat?(): boolean;
37
+ flatten?(): void;
38
+ getFilteredCopy?(): ArcCollection;
39
+ getCopy?(): ArcCollection;
40
+ getPointCount?(): number;
41
+ getVertexData?(): ArcVertexData;
42
+ getVertex2?(vertexId: number): [number, number] | null;
43
+ transformPoints?(cb: (x: number, y: number, arcId?: number) => void | [number, number]): void;
44
+ /** Replace the arc storage. Triggers a full bounds rebuild internally. */
45
+ updateVertexData?(nn: Int32Array | Uint32Array, xx: Float64Array, yy: Float64Array, zz: Float64Array | null): void;
46
+ /** Recompute the bounding box of a single arc after in-place vertex mutation */
47
+ updateArcBounds?(arcId: number): void;
48
+ getSimpleShapeBbox?(shapeIds: number[], bbox: number[]): void;
49
+ arcIsSmaller?(i: number, minLen: number): boolean;
50
+ arcIntersectsBBox?(i: number, bbox: number[]): boolean;
51
+ }
52
+ export type GeometryType = 'point' | 'polyline' | 'polygon';
53
+ export type PathGeometryType = 'polyline' | 'polygon';
54
+ /**
55
+ * Mapshaper feature shape vocabulary.
56
+ *
57
+ * Path features (polygon / polyline):
58
+ * - {@link SignedArcId}: a signed arc id; negative values encode reversed
59
+ * direction. Use `arcId >= 0 ? arcId : ~arcId` for the absolute id.
60
+ * - {@link PathPart}: list of signed arc ids that traverse one ring or
61
+ * polyline stroke.
62
+ * - {@link PathShape}: list of parts. Polygons use multiple parts for rings
63
+ * (outer + holes); polylines use multiple parts for multipart features.
64
+ *
65
+ * Point features:
66
+ * - {@link Coord2}: a single `[x, y]` pair. Mutable so in-place edits can
67
+ * write back through the same array.
68
+ * - {@link PointShape}: list of points (multi-point features). Some legacy
69
+ * mapshaper datasets store a single bare `[x, y]` instead of `[[x, y]]`;
70
+ * prefer {@link normalizePointShape} from `source/layer-utils` to coerce.
71
+ *
72
+ * `null` is reserved for deleted-but-still-indexed features (mapshaper keeps
73
+ * positional alignment between `shapes` and `data.records`).
74
+ */
75
+ export type SignedArcId = number;
76
+ export type PathPart = SignedArcId[];
77
+ export type PathShape = PathPart[];
78
+ export type Coord2 = [number, number];
79
+ export type PointShape = Coord2[];
80
+ /** Legacy single-coord form some older datasets carry. */
81
+ export type LegacyPointShape = Coord2;
82
+ export type FeatureShape = PathShape | PointShape | LegacyPointShape;
83
+ /** Mapshaper DataTable holding feature attributes for a layer */
84
+ export interface DataTable {
85
+ getRecordAt?(id: number): Record<string, unknown>;
86
+ getRecords?(): Record<string, unknown>[];
87
+ getFields?(): string[];
88
+ size?(): number;
89
+ }
90
+ /**
91
+ * A single layer within a Mapshaper dataset.
92
+ *
93
+ * `shapes` is intentionally typed loosely (`(FeatureShape | null)[] | null`)
94
+ * because mapshaper itself does not statically tag the array. Use the
95
+ * {@link isPathLayer} / {@link isPointLayer} type guards to narrow to a
96
+ * {@link PathLayer} / {@link PointLayer} where shapes carry a precise type.
97
+ */
98
+ export interface MapshaperLayer {
99
+ name?: string;
100
+ id?: string;
101
+ geometry_type?: GeometryType;
102
+ shapes: (FeatureShape | null)[] | null;
103
+ data?: DataTable;
104
+ }
105
+ /** Layer narrowed to path geometry. `shapes[i]` is `PathShape | null`. */
106
+ export interface PathLayer extends MapshaperLayer {
107
+ geometry_type: PathGeometryType;
108
+ shapes: (PathShape | null)[] | null;
109
+ }
110
+ /**
111
+ * Layer narrowed to point geometry. `shapes[i]` is `PointShape | LegacyPointShape | null`;
112
+ * use {@link normalizePointShape} to coerce to a uniform `Coord2[]`.
113
+ */
114
+ export interface PointLayer extends MapshaperLayer {
115
+ geometry_type: 'point';
116
+ shapes: ((PointShape | LegacyPointShape) | null)[] | null;
117
+ }
118
+ /** True iff `layer.geometry_type` is `'polygon'` or `'polyline'`. */
119
+ export declare function isPathLayer(layer: MapshaperLayer): layer is PathLayer;
120
+ /** True iff `layer.geometry_type` is `'point'`. */
121
+ export declare function isPointLayer(layer: MapshaperLayer): layer is PointLayer;
122
+ /** A Mapshaper dataset containing layers and arcs */
123
+ export interface MapshaperDataset {
124
+ layers: MapshaperLayer[];
125
+ arcs?: ArcCollection;
126
+ info?: {
127
+ crs_string?: string;
128
+ prj?: string;
129
+ /** WKT1 CRS string, sometimes set by importers (e.g. FlatGeobuf, GeoPackage) */
130
+ wkt1?: string;
131
+ crs?: {
132
+ is_latlong?: boolean;
133
+ projName?: string;
134
+ a?: number;
135
+ };
136
+ };
137
+ /**
138
+ * Monotonic counter bumped by every in-place edit (vertex move / insert /
139
+ * delete, feature translate / affine, shared-arc split). Cache layers that
140
+ * key off arc geometry — the per-layer Flatbush spatial index, future
141
+ * arc-flag caches — include this in their cache key so coord-only
142
+ * mutations auto-invalidate without a manual `clear` call.
143
+ *
144
+ * Optional because mapshaper itself doesn't set it; emap initialises to
145
+ * `0` when first observed via {@link bumpEditVersion}.
146
+ */
147
+ editVersion?: number;
148
+ }
149
+ /**
150
+ * Bump (or initialise to `1`) the dataset's `editVersion` counter. Called
151
+ * by every in-place edit command at the end of `do()` / `undo()` so the
152
+ * spatial index sees a fresh cache key on the next query.
153
+ */
154
+ export declare function bumpEditVersion(dataset: MapshaperDataset | null | undefined): void;
155
+ /** Style for stroke-based rendering (lines, polygon outlines) */
156
+ export interface StrokeStyle {
157
+ color?: string;
158
+ width?: number;
159
+ }
160
+ /** Style for point rendering */
161
+ export interface PointStyle {
162
+ color?: string;
163
+ radius?: number;
164
+ fill?: boolean;
165
+ }
166
+ /** Style for vertex dot rendering in edit mode */
167
+ export interface VertexDotStyle {
168
+ dotColor?: string;
169
+ dotRadius?: number;
170
+ hoverVertex?: [number, number] | null;
171
+ /**
172
+ * Distinguishes a vertex hover (drawn as a circle) from an interpolated
173
+ * edge-midpoint hover (drawn as a square — drag-to-insert affordance).
174
+ * Defaults to `'vertex'` when omitted.
175
+ */
176
+ hoverType?: 'vertex' | 'interpolated' | null;
177
+ hoverColor?: string;
178
+ hoverRadius?: number;
179
+ /** Fill color for polygon shapes in vertex edit mode */
180
+ polygonFill?: string | null;
181
+ geometryType?: string;
182
+ }
@@ -0,0 +1,35 @@
1
+ import 'maplibre-gl/dist/maplibre-gl.css';
2
+ import { Control } from './control';
3
+ import { Emap } from '../map/map';
4
+ export interface BasemapStyle {
5
+ name: string;
6
+ url: string;
7
+ type?: 'vector' | 'raster';
8
+ }
9
+ export interface BasemapOptions {
10
+ styles?: BasemapStyle[];
11
+ defaultStyle?: string;
12
+ }
13
+ export declare class BasemapControl implements Control {
14
+ private _map;
15
+ private _container;
16
+ private _basemapContainer;
17
+ private _maplibreMap;
18
+ private _styles;
19
+ private _activeStyle;
20
+ private _isOn;
21
+ private _syncBasemapBound;
22
+ constructor(options?: BasemapOptions);
23
+ onAdd(map: Emap): HTMLElement;
24
+ private _createBasemapLayer;
25
+ private _toggleStyle;
26
+ private _showBasemap;
27
+ private _initMapLibre;
28
+ private _setStyle;
29
+ private _createMapLibreStyle;
30
+ private _syncBasemap;
31
+ private _turnOff;
32
+ private _updateButtons;
33
+ isOn(): boolean;
34
+ onRemove(): void;
35
+ }