@mapvx/web-js 3.1.0 → 3.2.0-dev.2

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 (62) hide show
  1. package/dist/cjs/controllers/markerLayoutController.js +359 -0
  2. package/dist/cjs/controllers/markerLayoutController.js.map +1 -0
  3. package/dist/cjs/controllers/routeController.js +13 -0
  4. package/dist/cjs/controllers/routeController.js.map +1 -1
  5. package/dist/cjs/domain/models/mapConfig.js +14 -1
  6. package/dist/cjs/domain/models/mapConfig.js.map +1 -1
  7. package/dist/cjs/domain/models/marker.js +147 -82
  8. package/dist/cjs/domain/models/marker.js.map +1 -1
  9. package/dist/cjs/index.js +2 -1
  10. package/dist/cjs/index.js.map +1 -1
  11. package/dist/cjs/logger/sentry.js +1 -1
  12. package/dist/cjs/map/map.js +42 -4
  13. package/dist/cjs/map/map.js.map +1 -1
  14. package/dist/cjs/map/scene3DController.js +82 -10
  15. package/dist/cjs/map/scene3DController.js.map +1 -1
  16. package/dist/cjs/utils/loadGlb.js +105 -7
  17. package/dist/cjs/utils/loadGlb.js.map +1 -1
  18. package/dist/cjs/utils/mapvxHostname.js +4 -3
  19. package/dist/cjs/utils/mapvxHostname.js.map +1 -1
  20. package/dist/es/config/sdkConfig.d.ts +1 -1
  21. package/dist/es/controllers/markerLayoutController.d.ts +148 -0
  22. package/dist/es/controllers/markerLayoutController.d.ts.map +1 -0
  23. package/dist/es/controllers/markerLayoutController.js +351 -0
  24. package/dist/es/controllers/markerLayoutController.js.map +1 -0
  25. package/dist/es/controllers/routeController.d.ts +7 -0
  26. package/dist/es/controllers/routeController.d.ts.map +1 -1
  27. package/dist/es/controllers/routeController.js +13 -0
  28. package/dist/es/controllers/routeController.js.map +1 -1
  29. package/dist/es/domain/models/mapConfig.d.ts +140 -0
  30. package/dist/es/domain/models/mapConfig.d.ts.map +1 -1
  31. package/dist/es/domain/models/mapConfig.js +13 -0
  32. package/dist/es/domain/models/mapConfig.js.map +1 -1
  33. package/dist/es/domain/models/marker.d.ts +232 -1
  34. package/dist/es/domain/models/marker.d.ts.map +1 -1
  35. package/dist/es/domain/models/marker.js +146 -82
  36. package/dist/es/domain/models/marker.js.map +1 -1
  37. package/dist/es/index.d.ts +2 -2
  38. package/dist/es/index.d.ts.map +1 -1
  39. package/dist/es/index.js +1 -1
  40. package/dist/es/index.js.map +1 -1
  41. package/dist/es/logger/sentry.js +1 -1
  42. package/dist/es/map/map.d.ts +15 -1
  43. package/dist/es/map/map.d.ts.map +1 -1
  44. package/dist/es/map/map.js +43 -5
  45. package/dist/es/map/map.js.map +1 -1
  46. package/dist/es/map/scene3DController.d.ts +10 -1
  47. package/dist/es/map/scene3DController.d.ts.map +1 -1
  48. package/dist/es/map/scene3DController.js +82 -10
  49. package/dist/es/map/scene3DController.js.map +1 -1
  50. package/dist/es/utils/loadGlb.d.ts +33 -1
  51. package/dist/es/utils/loadGlb.d.ts.map +1 -1
  52. package/dist/es/utils/loadGlb.js +104 -7
  53. package/dist/es/utils/loadGlb.js.map +1 -1
  54. package/dist/es/utils/mapvxHostname.d.ts +3 -2
  55. package/dist/es/utils/mapvxHostname.d.ts.map +1 -1
  56. package/dist/es/utils/mapvxHostname.js +4 -3
  57. package/dist/es/utils/mapvxHostname.js.map +1 -1
  58. package/dist/umd/index.js +1214 -238
  59. package/dist/umd/index.js.map +1 -1
  60. package/dist/umd/styles.css +45 -19
  61. package/dist/umd/styles.css.map +1 -1
  62. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_GLB_LOAD_TIMEOUT_MS = void 0;
3
4
  exports.loadGlbRoot = loadGlbRoot;
4
5
  const draco_1 = require("../config/draco");
5
6
  const three_1 = require("./three");
@@ -24,22 +25,119 @@ function getGltfLoader() {
24
25
  }));
25
26
  return gltfLoaderPromise;
26
27
  }
28
+ /**
29
+ * Default per-asset timeout for {@link loadGlbRoot}.
30
+ *
31
+ * Guards against loaders that hang instead of throwing — a GLB whose binary chunk is truncated
32
+ * (see {@link loadGlbRoot}'s completeness check) or otherwise malformed can put Three.js's
33
+ * `DRACOLoader` into an undefined state: sometimes a decode error, sometimes no callback at all.
34
+ * Without a timeout, one such asset never settles and blocks every other load queued behind it.
35
+ *
36
+ * @group Configuration
37
+ */
38
+ exports.DEFAULT_GLB_LOAD_TIMEOUT_MS = 30000;
39
+ /**
40
+ * Magic number ("glTF" read little-endian) at byte offset 0 of every binary glTF (`.glb`)
41
+ * container. Used only to tell a binary GLB apart from a plain JSON `.gltf` payload — the latter
42
+ * has no such header and skips the completeness check in {@link assertGlbBufferComplete}.
43
+ */
44
+ const GLB_MAGIC = 0x46546c67;
45
+ /**
46
+ * Rejects a GLB download that was cut short before it reaches Three.js's `GLTFLoader`/`DRACOLoader`,
47
+ * whose behavior on truncated input ranges from a cryptic decode error (e.g. "Unexpected geometry
48
+ * type") to an outright hang, rather than a clear message pointing at the actual problem.
49
+ *
50
+ * The binary glTF container format requires the 12-byte header's declared total length to equal
51
+ * the file's real byte length (see the {@link https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#binary-header | spec}).
52
+ * A mismatch means the response body was truncated — a dropped connection, or the object stored at
53
+ * `url` is itself incomplete — so every buffer-view offset past that point reads garbage. This is
54
+ * exactly what was found in the field for one "Suelo" asset that both threw a decode error and (in
55
+ * a larger sibling file) hung: the file's own header declared a ~383 MB binary chunk while only
56
+ * ~8.7 MB had actually been received.
57
+ */
58
+ function assertGlbBufferComplete(buffer, url) {
59
+ if (buffer.byteLength < 12)
60
+ return; // too short to have a GLB header; let parse() report it
61
+ const header = new DataView(buffer, 0, 12);
62
+ if (header.getUint32(0, true) !== GLB_MAGIC)
63
+ return; // plain JSON .gltf, not a binary .glb
64
+ const declaredLength = header.getUint32(8, true);
65
+ if (declaredLength !== buffer.byteLength) {
66
+ throw new Error(`GLB download is truncated or corrupt: header declares ${declaredLength} bytes, received ${buffer.byteLength}: ${url}`);
67
+ }
68
+ }
27
69
  /**
28
70
  * Loads a GLB/GLTF from URL and returns the root scene group.
29
71
  * Central entry point so the loader implementation can be swapped later (e.g. Draco, KTX2, custom fetch).
30
72
  *
73
+ * Fetches the raw bytes itself (rather than deferring to `GLTFLoader.load`) so a truncated download
74
+ * can be caught and rejected clearly — see {@link assertGlbBufferComplete} — before it ever reaches
75
+ * the Draco/KTX2 decoders.
76
+ *
31
77
  * @param url - GLB URL
32
78
  * @returns Root `THREE.Group` from the loaded glTF scene
33
79
  * @group Utils
34
80
  */
35
- async function loadGlbRoot(url) {
36
- const gltfLoader = await getGltfLoader();
37
- return new Promise((resolve, reject) => {
38
- gltfLoader.load(url, (gltf) => {
39
- resolve(gltf.scene);
40
- }, undefined, (error) => {
81
+ async function loadGlbRoot(url, options = {}) {
82
+ const { timeoutMs = exports.DEFAULT_GLB_LOAD_TIMEOUT_MS, onProgress } = options;
83
+ const [gltfLoader, { THREE: three }] = await Promise.all([getGltfLoader(), (0, three_1.loadThree)()]);
84
+ // Set once the caller has stopped waiting (success, failure, or timeout) so any callback three
85
+ // fires afterwards — e.g. a timed-out fetch/decode that keeps running in the background — is a
86
+ // no-op instead of resolving/rejecting an already-settled promise or emitting a stray progress
87
+ // event after the batch this asset belongs to already reported `done: true`.
88
+ let settled = false;
89
+ const fileLoader = new three.FileLoader();
90
+ fileLoader.setResponseType("arraybuffer");
91
+ const load = new Promise((resolve, reject) => {
92
+ const onError = (error) => {
93
+ if (settled)
94
+ return;
41
95
  reject(error instanceof Error ? error : new Error(String(error)));
42
- });
96
+ };
97
+ fileLoader.load(url, (data) => {
98
+ if (settled)
99
+ return;
100
+ const buffer = data;
101
+ try {
102
+ assertGlbBufferComplete(buffer, url);
103
+ }
104
+ catch (err) {
105
+ onError(err);
106
+ return;
107
+ }
108
+ gltfLoader.parse(buffer, three.LoaderUtils.extractUrlBase(url), (gltf) => {
109
+ if (settled)
110
+ return;
111
+ resolve(gltf.scene);
112
+ }, onError);
113
+ }, (event) => {
114
+ if (!settled)
115
+ onProgress === null || onProgress === void 0 ? void 0 : onProgress(event);
116
+ }, onError);
117
+ });
118
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
119
+ try {
120
+ return await load;
121
+ }
122
+ finally {
123
+ settled = true;
124
+ }
125
+ }
126
+ let timer;
127
+ const timeout = new Promise((_resolve, reject) => {
128
+ timer = setTimeout(() => reject(new Error(`Timed out loading GLB after ${timeoutMs}ms: ${url}`)), timeoutMs);
43
129
  });
130
+ try {
131
+ return await Promise.race([load, timeout]);
132
+ }
133
+ finally {
134
+ settled = true;
135
+ clearTimeout(timer);
136
+ // Cancels the underlying fetch (and, by never delivering its buffer, the Draco/KTX2 decode)
137
+ // so a timed-out asset actually frees its network/CPU usage instead of running to completion
138
+ // unattended — otherwise GLB_LOAD_CONCURRENCY only bounds how many loads the caller awaits,
139
+ // not how many are truly in flight. A no-op if `load` already won the race.
140
+ fileLoader.abort();
141
+ }
44
142
  }
45
143
  //# sourceMappingURL=loadGlb.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"loadGlb.js","sourceRoot":"","sources":["../../../src/utils/loadGlb.ts"],"names":[],"mappings":";;AAyCA,kCAcC;AArDD,2CAA0F;AAC1F,mCAAmC;AAEnC;;;;;GAKG;AACH,IAAI,iBAES,CAAA;AAEb,SAAS,aAAa;IACpB,iBAAiB,aAAjB,iBAAiB,cAAjB,iBAAiB,IAAjB,iBAAiB,GAAK,IAAA,iBAAS,GAAE,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;QAC7C,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,WAAW,EAAE,CAAA;QACzC,WAAW,CAAC,cAAc,CAAC,kCAA0B,CAAC,CAAA;QAEtD,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,UAAU,EAAE,CAAA;QACvC,UAAU,CAAC,cAAc,CAAC,WAAW,CAAC,CAAA;QAEtC,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,UAAU,EAAE,CAAA;QACvC,UAAU,CAAC,iBAAiB,CAAC,oCAA4B,CAAC,CAAA;QAC1D,UAAU,CAAC,aAAa,CAAC,UAAU,CAAC,CAAA;QACpC,UAAU,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;QAE1E,OAAO,UAAU,CAAA;IACnB,CAAC,CAAC,EAAA;IACF,OAAO,iBAAiB,CAAA;AAC1B,CAAC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,WAAW,CAAC,GAAW;IAC3C,MAAM,UAAU,GAAG,MAAM,aAAa,EAAE,CAAA;IACxC,OAAO,IAAI,OAAO,CAAc,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAClD,UAAU,CAAC,IAAI,CACb,GAAG,EACH,CAAC,IAAU,EAAE,EAAE;YACb,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACrB,CAAC,EACD,SAAS,EACT,CAAC,KAAc,EAAE,EAAE;YACjB,MAAM,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QACnE,CAAC,CACF,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC"}
1
+ {"version":3,"file":"loadGlb.js","sourceRoot":"","sources":["../../../src/utils/loadGlb.ts"],"names":[],"mappings":"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"}
@@ -3,8 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isMapVxRequestHostname = isMapVxRequestHostname;
4
4
  /**
5
5
  * Returns whether a URL hostname is part of the MapVX API domain tree.
6
- * Matches `mapvx.com` and any subdomain (`api.mapvx.com`, `public-api.mapvx.com`,
7
- * `integration.mapvx.com`, etc.). Does not match lookalike domains (e.g. `notmapvx.com`).
6
+ * Matches `mapvx.com` and `mapvx.dev` plus any subdomain (`api.mapvx.com`,
7
+ * `public-api.mapvx.com`, `api.mapvx.dev`, `portal.mapvx.dev`, etc.).
8
+ * Does not match lookalike domains (e.g. `notmapvx.com`).
8
9
  *
9
10
  * @param hostname - Value from `URL.hostname` (no port)
10
11
  * @returns True if context headers should be attached for this host
@@ -15,6 +16,6 @@ function isMapVxRequestHostname(hostname) {
15
16
  if (!h) {
16
17
  return false;
17
18
  }
18
- return /^(?:[a-z0-9-]+\.)*mapvx\.com$/.test(h);
19
+ return /^(?:[a-z0-9-]+\.)*mapvx\.(?:com|dev)$/.test(h);
19
20
  }
20
21
  //# sourceMappingURL=mapvxHostname.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mapvxHostname.js","sourceRoot":"","sources":["../../../src/utils/mapvxHostname.ts"],"names":[],"mappings":";;AASA,wDAMC;AAfD;;;;;;;;GAQG;AACH,SAAgB,sBAAsB,CAAC,QAAgB;IACrD,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IACvC,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;IACD,OAAO,+BAA+B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AAChD,CAAC"}
1
+ {"version":3,"file":"mapvxHostname.js","sourceRoot":"","sources":["../../../src/utils/mapvxHostname.ts"],"names":[],"mappings":";;AAUA,wDAMC;AAhBD;;;;;;;;;GASG;AACH,SAAgB,sBAAsB,CAAC,QAAgB;IACrD,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IACvC,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;IACD,OAAO,uCAAuC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACxD,CAAC"}
@@ -94,7 +94,7 @@ export interface SDKConfig {
94
94
  /**
95
95
  * The base API URL for the SDK requests.
96
96
  * Can be used to point to different environments or custom servers.
97
- * For example: 'https://public-api.mapvx.com' for production, 'https://integration.mapvx.com' for staging.
97
+ * For example: 'https://public-api.mapvx.com' for production, 'https://api.mapvx.dev' for staging.
98
98
  * @defaultValue `https://public-api.mapvx.com`
99
99
  */
100
100
  apiUrl?: string;
@@ -0,0 +1,148 @@
1
+ import { type PositionAnchor } from "maplibre-gl";
2
+ import { type MarkerLayoutConfig } from "../domain/models/mapConfig";
3
+ import { type MarkerAttribute, TextPosition } from "../domain/models/marker";
4
+ import { type InternalMapVXMap } from "../map/map";
5
+ /** Axis-aligned box in screen (CSS pixel) space. */
6
+ export interface Rect {
7
+ left: number;
8
+ top: number;
9
+ width: number;
10
+ height: number;
11
+ }
12
+ /**
13
+ * Fraction of the icon's own box, along each axis, that MapLibre's Marker
14
+ * anchor math (`translate(-x%, -y%)`) aligns to the geodetic point. Mirrors
15
+ * MapLibre's own `anchorTranslate` table so the collision math agrees with
16
+ * what's actually on screen.
17
+ */
18
+ export declare const ANCHOR_FRACTIONS: Record<PositionAnchor, {
19
+ fx: number;
20
+ fy: number;
21
+ }>;
22
+ /** Candidate order tried when a marker's preferred side is unavailable. */
23
+ export declare const FALLBACK_ORDER: TextPosition[];
24
+ /** Builds the icon's on-screen rect from its projected point, size and anchor. */
25
+ export declare function computeIconRect(screen: {
26
+ x: number;
27
+ y: number;
28
+ }, iconSize: {
29
+ width: number;
30
+ height: number;
31
+ }, anchor: PositionAnchor): Rect;
32
+ /**
33
+ * Builds a candidate label rect for one side of an icon. Mirrors the CSS in
34
+ * `styles.css` (`.text-container.right/left/top/bottom`) exactly, so a
35
+ * position the algorithm picks as collision-free renders collision-free.
36
+ */
37
+ export declare function computeCandidateRect(iconRect: Rect, labelSize: {
38
+ width: number;
39
+ height: number;
40
+ }, position: TextPosition, gapPx: number, verticalGapPx: number): Rect;
41
+ /** Expands a rect by `padding` on every side. */
42
+ export declare function expandRect(rect: Rect, padding: number): Rect;
43
+ /** Standard AABB intersection test. */
44
+ export declare function rectsIntersect(a: Rect, b: Rect): boolean;
45
+ /**
46
+ * Automatic collision avoidance for marker text labels: keeps a marker's
47
+ * icon fixed while moving (or hiding) its label to avoid overlapping
48
+ * neighboring markers' icons/labels, similar to Google Maps' label
49
+ * placement. Below `minZoomForLabels` it withholds every label instead, so
50
+ * a zoomed-out map shows pins only. See {@link MarkerLayoutConfig}.
51
+ *
52
+ * Not part of the public SDK surface — owned and driven entirely by
53
+ * {@link InternalMapVXMap}, mirroring `RouteController`.
54
+ */
55
+ export declare class MarkerLayoutController {
56
+ private readonly mapvxMap;
57
+ private readonly config;
58
+ private labelSizeCache;
59
+ private iconSizeCache;
60
+ private readonly lastAppliedState;
61
+ private readonly boundOnMove;
62
+ private rafHandle;
63
+ private attached;
64
+ constructor(map: InternalMapVXMap, config: Required<MarkerLayoutConfig>);
65
+ private get map();
66
+ /**
67
+ * Starts listening for camera movement. Safe to call once the underlying
68
+ * MapLibre `Map` instance exists; a single `"move"` listener covers pan,
69
+ * zoom, rotate, pitch and `resize()`.
70
+ */
71
+ attach(): void;
72
+ /**
73
+ * Publishes the configured gaps and label width cap as CSS custom
74
+ * properties, which `styles.css` reads to offset labels from their icon.
75
+ * Without this the stylesheet would keep its hardcoded defaults while the
76
+ * collision math used the configured values, so any custom `gapPx` /
77
+ * `verticalGapPx` would produce placements this controller believes are
78
+ * collision-free but that visibly overlap on screen.
79
+ *
80
+ * Called with the map's own container, so every marker MapLibre mounts
81
+ * inside it inherits the values.
82
+ */
83
+ applyLayoutVariables(container: HTMLElement): void;
84
+ /**
85
+ * A label measured before its web font finishes loading is measured in the
86
+ * fallback font, and that wrong footprint would otherwise be cached for
87
+ * the marker's lifetime. Drop every measurement once fonts settle.
88
+ */
89
+ private remeasureWhenFontsLoad;
90
+ /** Stops listening and cancels any pending layout pass. */
91
+ destroy(): void;
92
+ /**
93
+ * Drops everything cached for a marker, e.g. after its text/content
94
+ * changed.
95
+ *
96
+ * The last applied decision has to go too: rebuilding a marker's DOM
97
+ * replaces its `.text-container` with a fresh one carrying the preferred
98
+ * side and no `visibility`, so a decision remembered from the old element
99
+ * would make {@link applyDecisions} short-circuit and leave the new label
100
+ * on the wrong side — or visible when it should be hidden.
101
+ */
102
+ invalidateMarker(marker: MarkerAttribute): void;
103
+ /** Coalesces repeated calls into a single layout pass per animation frame. */
104
+ scheduleRelayout(): void;
105
+ private performLayout;
106
+ /** Read phase: project + measure, no writes. Culls markers fully outside the viewport. */
107
+ private readMarkers;
108
+ private resolveLabelSize;
109
+ /**
110
+ * The icon's box. Markers built from a caller-supplied `element` with no
111
+ * declared `iconProperties` are measured from the DOM, since their real
112
+ * size is whatever that element renders at; everyone else's box is exactly
113
+ * what `MarkerUtils.createMarkerElement` pinned it to.
114
+ */
115
+ private resolveIconSize;
116
+ /**
117
+ * Measures an element once and remembers it. A zero measurement is
118
+ * returned but never cached: it means the element isn't laid out yet (a
119
+ * `display: none` ancestor, a first pass before the web font loads), and
120
+ * caching it would freeze that marker's footprint at nothing for the rest
121
+ * of its life.
122
+ */
123
+ private measureCached;
124
+ /**
125
+ * Compute phase: pure, no DOM access. Icons always block; labels negotiate
126
+ * a side or hide.
127
+ *
128
+ * Below `minZoomForLabels` every label is hidden and none is placed, so no
129
+ * label ever becomes an obstacle for a neighbor at that zoom — a label the
130
+ * threshold withheld must not displace anything on its way out.
131
+ */
132
+ private decidePlacements;
133
+ /**
134
+ * Whether a candidate label rect clashes with any other marker's icon or
135
+ * with a label already placed this pass.
136
+ *
137
+ * A label's own icon is deliberately excluded: `gapPx`/`verticalGapPx`
138
+ * already define the spacing to it, and `paddingPx` is breathing room
139
+ * against *neighbors*. Counting the own icon here would make top/bottom
140
+ * impossible for every marker as soon as `paddingPx` exceeded
141
+ * `verticalGapPx` (4 vs 4 by default) — and at `paddingPx: 10` would hide
142
+ * every label on the map.
143
+ */
144
+ private collides;
145
+ /** Write phase: only touches the DOM for markers whose decision actually changed. */
146
+ private applyDecisions;
147
+ }
148
+ //# sourceMappingURL=markerLayoutController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markerLayoutController.d.ts","sourceRoot":"","sources":["../../../src/controllers/markerLayoutController.ts"],"names":[],"mappings":"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"}