@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.
- package/dist/cjs/controllers/markerLayoutController.js +359 -0
- package/dist/cjs/controllers/markerLayoutController.js.map +1 -0
- package/dist/cjs/controllers/routeController.js +13 -0
- package/dist/cjs/controllers/routeController.js.map +1 -1
- package/dist/cjs/domain/models/mapConfig.js +14 -1
- package/dist/cjs/domain/models/mapConfig.js.map +1 -1
- package/dist/cjs/domain/models/marker.js +147 -82
- package/dist/cjs/domain/models/marker.js.map +1 -1
- package/dist/cjs/index.js +2 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/logger/sentry.js +1 -1
- package/dist/cjs/map/map.js +42 -4
- package/dist/cjs/map/map.js.map +1 -1
- package/dist/cjs/map/scene3DController.js +82 -10
- package/dist/cjs/map/scene3DController.js.map +1 -1
- package/dist/cjs/utils/loadGlb.js +105 -7
- package/dist/cjs/utils/loadGlb.js.map +1 -1
- package/dist/cjs/utils/mapvxHostname.js +4 -3
- package/dist/cjs/utils/mapvxHostname.js.map +1 -1
- package/dist/es/config/sdkConfig.d.ts +1 -1
- package/dist/es/controllers/markerLayoutController.d.ts +148 -0
- package/dist/es/controllers/markerLayoutController.d.ts.map +1 -0
- package/dist/es/controllers/markerLayoutController.js +351 -0
- package/dist/es/controllers/markerLayoutController.js.map +1 -0
- package/dist/es/controllers/routeController.d.ts +7 -0
- package/dist/es/controllers/routeController.d.ts.map +1 -1
- package/dist/es/controllers/routeController.js +13 -0
- package/dist/es/controllers/routeController.js.map +1 -1
- package/dist/es/domain/models/mapConfig.d.ts +140 -0
- package/dist/es/domain/models/mapConfig.d.ts.map +1 -1
- package/dist/es/domain/models/mapConfig.js +13 -0
- package/dist/es/domain/models/mapConfig.js.map +1 -1
- package/dist/es/domain/models/marker.d.ts +232 -1
- package/dist/es/domain/models/marker.d.ts.map +1 -1
- package/dist/es/domain/models/marker.js +146 -82
- package/dist/es/domain/models/marker.js.map +1 -1
- package/dist/es/index.d.ts +2 -2
- package/dist/es/index.d.ts.map +1 -1
- package/dist/es/index.js +1 -1
- package/dist/es/index.js.map +1 -1
- package/dist/es/logger/sentry.js +1 -1
- package/dist/es/map/map.d.ts +15 -1
- package/dist/es/map/map.d.ts.map +1 -1
- package/dist/es/map/map.js +43 -5
- package/dist/es/map/map.js.map +1 -1
- package/dist/es/map/scene3DController.d.ts +10 -1
- package/dist/es/map/scene3DController.d.ts.map +1 -1
- package/dist/es/map/scene3DController.js +82 -10
- package/dist/es/map/scene3DController.js.map +1 -1
- package/dist/es/utils/loadGlb.d.ts +33 -1
- package/dist/es/utils/loadGlb.d.ts.map +1 -1
- package/dist/es/utils/loadGlb.js +104 -7
- package/dist/es/utils/loadGlb.js.map +1 -1
- package/dist/es/utils/mapvxHostname.d.ts +3 -2
- package/dist/es/utils/mapvxHostname.d.ts.map +1 -1
- package/dist/es/utils/mapvxHostname.js +4 -3
- package/dist/es/utils/mapvxHostname.js.map +1 -1
- package/dist/umd/index.js +1214 -238
- package/dist/umd/index.js.map +1 -1
- package/dist/umd/styles.css +45 -19
- package/dist/umd/styles.css.map +1 -1
- 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
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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":"
|
|
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`,
|
|
7
|
-
* `
|
|
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":";;
|
|
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://
|
|
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":"AAAA,OAAO,EAA2B,KAAK,cAAc,EAAE,MAAM,aAAa,CAAA;AAC1E,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AACpE,OAAO,EAAE,KAAK,eAAe,EAAe,YAAY,EAAE,MAAM,yBAAyB,CAAA;AACzF,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,oDAAoD;AACpD,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAOD;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,cAAc,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAU/E,CAAA;AAED,2EAA2E;AAC3E,eAAO,MAAM,cAAc,EAAE,YAAY,EAKxC,CAAA;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAC7B,MAAM,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,QAAQ,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAC3C,MAAM,EAAE,cAAc,GACrB,IAAI,CAQN;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,IAAI,EACd,SAAS,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAC5C,QAAQ,EAAE,YAAY,EACtB,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,GACpB,IAAI,CAgCN;AAED,iDAAiD;AACjD,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAO5D;AAED,uCAAuC;AACvC,wBAAgB,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,GAAG,OAAO,CAOxD;AAED;;;;;;;;;GASG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkB;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA8B;IACrD,OAAO,CAAC,cAAc,CAAoE;IAC1F,OAAO,CAAC,aAAa,CAAoE;IACzF,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAgD;IACjF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAY;IACxC,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,QAAQ,CAAQ;gBAEZ,GAAG,EAAE,gBAAgB,EAAE,MAAM,EAAE,QAAQ,CAAC,kBAAkB,CAAC;IAMvE,OAAO,KAAK,GAAG,GAEd;IAED;;;;OAIG;IACH,MAAM,IAAI,IAAI;IAQd;;;;;;;;;;OAUG;IACH,oBAAoB,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI;IAMlD;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IAgB9B,2DAA2D;IAC3D,OAAO,IAAI,IAAI;IAWf;;;;;;;;;OASG;IACH,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI;IAM/C,8EAA8E;IAC9E,gBAAgB,IAAI,IAAI;IAQxB,OAAO,CAAC,aAAa;IA0BrB,0FAA0F;IAC1F,OAAO,CAAC,WAAW;IAyBnB,OAAO,CAAC,gBAAgB;IAMxB;;;;;OAKG;IACH,OAAO,CAAC,eAAe;IAKvB;;;;;;OAMG;IACH,OAAO,CAAC,aAAa;IAcrB;;;;;;;OAOG;IACH,OAAO,CAAC,gBAAgB;IAkDxB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,QAAQ;IAahB,qFAAqF;IACrF,OAAO,CAAC,cAAc;CAWvB"}
|