@arenarium/maps 1.2.7 → 1.2.9

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 (3) hide show
  1. package/dist/main.css +1 -97
  2. package/dist/main.js +1 -1899
  3. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -1,1899 +1 @@
1
- // src/lib/core/http.ts
2
- async function delay(ms) {
3
- return new Promise((resolve) => setTimeout(resolve, ms));
4
- }
5
- async function retry(fn, options) {
6
- let tries = 0;
7
- let retries = Math.max(1, options?.retry ?? 1);
8
- while (tries < retries) {
9
- try {
10
- return await fn();
11
- } catch (error) {
12
- console.log(`[HTTP RETRY] ${tries} of ${retries}`);
13
- console.log(error);
14
- tries++;
15
- if (tries == retries)
16
- throw error;
17
- if (options?.delay)
18
- await delay(options.delay[tries - 1] ?? 0);
19
- }
20
- }
21
- throw new Error("Unreachable code");
22
- }
23
- async function get(url, options) {
24
- const response = await retry(async () => await fetch(url, options));
25
- if (!response.ok)
26
- throw new Error(response.statusText);
27
- return await response.json();
28
- }
29
- async function post(url, body, options) {
30
- const response = await fetch(url, {
31
- method: "POST",
32
- body: JSON.stringify(body),
33
- headers: {
34
- "Content-Type": "application/json",
35
- ...options?.headers
36
- },
37
- ...options
38
- });
39
- if (!response.ok)
40
- throw new Error(response.statusText);
41
- return await response.json();
42
- }
43
- async function put(url, body, options) {
44
- const response = await fetch(url, {
45
- method: "PUT",
46
- body: JSON.stringify(body),
47
- headers: {
48
- "Content-Type": "application/json",
49
- ...options?.headers
50
- },
51
- ...options
52
- });
53
- if (!response.ok)
54
- throw new Error(response.statusText);
55
- }
56
- var http_default = {
57
- delay,
58
- retry,
59
- get,
60
- post,
61
- put
62
- };
63
-
64
- // src/lib/core/processor.ts
65
- class Processor {
66
- endtime = 0;
67
- lifespan;
68
- paused = false;
69
- enqueued = false;
70
- interval;
71
- timeout;
72
- callback;
73
- constructor(callback, lifespan, interval) {
74
- if ((lifespan ?? 0) < 0)
75
- throw new Error("Lifespan must be greater than 0");
76
- if ((interval ?? 0) < 0)
77
- throw new Error("Interval must be greater than 0");
78
- this.interval = interval ?? (navigator?.hardwareConcurrency ? 100 : 200 / navigator.hardwareConcurrency);
79
- this.lifespan = lifespan ?? this.interval;
80
- this.callback = callback;
81
- }
82
- async run() {
83
- const now = performance.now();
84
- if (this.enqueued) {
85
- this.endtime = now + this.lifespan;
86
- this.enqueued = false;
87
- }
88
- if (this.endtime < now) {
89
- this.stop();
90
- return;
91
- }
92
- if (this.paused == false) {
93
- const stop = await this.callback();
94
- if (stop && !this.enqueued) {
95
- this.stop();
96
- return;
97
- }
98
- }
99
- this.timeout = window.setTimeout(this.run.bind(this), this.interval);
100
- }
101
- start() {
102
- this.enqueued = true;
103
- if (!this.timeout)
104
- this.run();
105
- }
106
- stop() {
107
- if (this.timeout)
108
- window.clearTimeout(this.timeout);
109
- this.timeout = undefined;
110
- }
111
- pause() {
112
- this.paused = true;
113
- }
114
- resume() {
115
- this.paused = false;
116
- }
117
- }
118
-
119
- // src/lib/map/marker.ts
120
- class MapMarker {
121
- data;
122
- state;
123
- constructor(data) {
124
- this.data = data;
125
- this.state = undefined;
126
- }
127
- get input() {
128
- return {
129
- id: this.data.id,
130
- rank: this.data.rank,
131
- lat: this.data.lat,
132
- lng: this.data.lng,
133
- width: this.data.tooltip.style.dimensions.width,
134
- height: this.data.tooltip.style.dimensions.height,
135
- margin: this.data.tooltip.style.dimensions.margin
136
- };
137
- }
138
- }
139
-
140
- // src/lib/core/interval.ts
141
- class Interval {
142
- callback;
143
- timeout;
144
- id;
145
- constructor(callback, timeout) {
146
- if (timeout <= 0)
147
- throw new Error("Timeout must be greater than 0");
148
- this.callback = callback;
149
- this.timeout = timeout;
150
- }
151
- start() {
152
- if (this.id != null)
153
- return;
154
- this.id = window.setInterval(this.callback, this.timeout);
155
- }
156
- stop() {
157
- if (this.id == undefined)
158
- return;
159
- window.clearInterval(this.id);
160
- this.id = undefined;
161
- }
162
- }
163
-
164
- // src/lib/map/state.ts
165
- class MapStateManager {
166
- viewport = undefined;
167
- state = "idle";
168
- provider;
169
- interval;
170
- onCancel;
171
- onError;
172
- onMove;
173
- onIdle;
174
- constructor(provider, timeout, onCancel, onError, onMove, onIdle) {
175
- this.provider = provider;
176
- this.interval = new Interval(this.onInterval.bind(this), timeout);
177
- this.onCancel = onCancel;
178
- this.onError = onError;
179
- this.onMove = onMove;
180
- this.onIdle = onIdle;
181
- }
182
- start() {
183
- this.interval.start();
184
- }
185
- stop() {
186
- this.interval.stop();
187
- }
188
- onInterval() {
189
- try {
190
- if (this.onCancel()) {
191
- this.interval.stop();
192
- return;
193
- }
194
- const viewport = this.provider.getViewport();
195
- const oldState = this.state;
196
- const newState = JSON.stringify(viewport) !== JSON.stringify(this.viewport) ? "move" : "idle";
197
- if (newState == "move")
198
- this.onMove();
199
- if (newState == "idle" && oldState == "move")
200
- this.onIdle();
201
- this.state = newState;
202
- this.viewport = viewport;
203
- } catch (error) {
204
- this.onError("Failed to process map state interval", error);
205
- }
206
- }
207
- }
208
-
209
- // src/lib/core/constants.ts
210
- var ANIMATION_PIN_SCALE_DURATION = 75;
211
- var ANIMATION_TOOLTIP_SCALE_DURATION = 150;
212
- var ANIMATION_TOOLTIP_ANGLE_STIFFNESS = 0.00025;
213
- var ELEMENT_PIN_Z_INDEX_OFFSET = 1e6;
214
- var ELEMENT_TOOLTIP_Z_INDEX_OFFSET = 2000000;
215
- var ELEMENT_POPUP_Z_INDEX_OFFSET = 3000000;
216
- var ELEMENT_Z_INDEX_SCALE = 10;
217
- var ELEMENT_PIN_DEFAULT_SIZE = 16;
218
- var ELEMENT_PIN_DEFAULT_PADDING = 2;
219
- var ELEMENT_PIN_UNDEFINED_SCALE = 0.5;
220
- var COLOR_DEFAULT_BACKGROUND = "white";
221
- var COLOR_DEFAULT_PRIMARY = "darkgreen";
222
- var COLOR_DEFAULT_SHADOW = "0px 2px 2px rgba(0, 0, 0, 0.5)";
223
-
224
- // src/lib/map/region.ts
225
- import Mercator from "@arenarium/maps-core/mercator";
226
-
227
- class MapRegionBlock {
228
- sw;
229
- ne;
230
- constructor(swLat, swLng, neLat, neLng) {
231
- if (neLat < swLat)
232
- throw new Error(`Invalid bounds: ${swLat}, ${swLng}, ${neLat}, ${neLng}`);
233
- if (neLng < swLng)
234
- throw new Error(`Invalid bounds: ${swLat}, ${swLng}, ${neLat}, ${neLng}`);
235
- this.sw = { lat: swLat, lng: swLng };
236
- this.ne = { lat: neLat, lng: neLng };
237
- }
238
- contains(lat, lng) {
239
- if (lat < this.sw.lat || this.ne.lat < lat)
240
- return false;
241
- if (lng < this.sw.lng || this.ne.lng < lng)
242
- return false;
243
- return true;
244
- }
245
- intersects(bounds) {
246
- if (bounds.ne.lat < this.sw.lat || this.ne.lat < bounds.sw.lat)
247
- return false;
248
- if (bounds.ne.lng < this.sw.lng || this.ne.lng < bounds.sw.lng)
249
- return false;
250
- return true;
251
- }
252
- }
253
-
254
- class MapRegion {
255
- blockL;
256
- blockR;
257
- sw;
258
- ne;
259
- constructor(swLat, swLng, neLat, neLng) {
260
- if (neLat < swLat)
261
- throw new Error(`Invalid bounds: ${swLat}, ${swLng}, ${neLat}, ${neLng}`);
262
- this.sw = { lat: swLat, lng: swLng };
263
- this.ne = { lat: neLat, lng: neLng };
264
- if (swLng < neLng) {
265
- this.blockL = new MapRegionBlock(swLat, swLng, neLat, neLng);
266
- this.blockR = new MapRegionBlock(0, 0, 0, 0);
267
- } else {
268
- this.blockL = new MapRegionBlock(swLat, -180, neLat, neLng);
269
- this.blockR = new MapRegionBlock(swLat, swLng, neLat, 180);
270
- }
271
- }
272
- static normalize(viewport) {
273
- const bounds = viewport.bounds;
274
- const center = viewport.center;
275
- if (Math.abs(bounds.ne.lng - center.lng) + Math.abs(bounds.sw.lng - center.lng) > 360) {
276
- bounds.sw.lng = -180;
277
- bounds.ne.lng = 180;
278
- }
279
- if (bounds.ne.lng - bounds.sw.lng > 360) {
280
- bounds.sw.lng = -180;
281
- bounds.ne.lng = 180;
282
- return;
283
- }
284
- if (bounds.sw.lng < -180)
285
- bounds.sw.lng += 360;
286
- if (bounds.sw.lng > 180)
287
- bounds.sw.lng -= 360;
288
- if (bounds.ne.lng < -180)
289
- bounds.ne.lng += 360;
290
- if (bounds.ne.lng > 180)
291
- bounds.ne.lng -= 360;
292
- }
293
- static bounds(viewport) {
294
- this.normalize(viewport);
295
- const bounds = viewport.bounds;
296
- const sw = bounds.sw;
297
- const ne = bounds.ne;
298
- return new MapRegion(sw.lat, sw.lng, ne.lat, ne.lng);
299
- }
300
- static offset(viewport, size, offsets) {
301
- this.normalize(viewport);
302
- const bounds = viewport.bounds;
303
- const zoom = viewport.zoom;
304
- const zoomMapSize = size * Math.pow(2, zoom);
305
- const blPoint = Mercator.project(bounds.sw.lat, bounds.sw.lng, zoomMapSize);
306
- const trPoint = Mercator.project(bounds.ne.lat, bounds.ne.lng, zoomMapSize);
307
- let swX = Math.max(blPoint.x - offsets.left, 0);
308
- let swY = Math.min(blPoint.y + offsets.bottom, zoomMapSize);
309
- let neX = Math.min(trPoint.x + offsets.right, zoomMapSize);
310
- let neY = Math.max(trPoint.y - offsets.top, 0);
311
- const sw = Mercator.unproject(swX, swY, zoomMapSize);
312
- const ne = Mercator.unproject(neX, neY, zoomMapSize);
313
- return new MapRegion(sw.lat, sw.lng, ne.lat, ne.lng);
314
- }
315
- contains(lat, lng) {
316
- return this.blockL.contains(lat, lng) || this.blockR.contains(lat, lng);
317
- }
318
- intersects(bounds) {
319
- return this.blockL.intersects(bounds) || this.blockR.intersects(bounds);
320
- }
321
- }
322
-
323
- // src/lib/map/visibility/tree/cell.ts
324
- class MapMarkerCell {
325
- id;
326
- bounds;
327
- markers;
328
- constructor(id, bounds) {
329
- this.id = id;
330
- this.bounds = bounds;
331
- this.markers = [];
332
- }
333
- belongs(data) {
334
- const sw = this.bounds.sw;
335
- if (data.lat < sw.lat)
336
- return false;
337
- if (data.lng < sw.lng)
338
- return false;
339
- const ne = this.bounds.ne;
340
- if (ne.lat < data.lat)
341
- return false;
342
- if (ne.lng < data.lng)
343
- return false;
344
- return true;
345
- }
346
- neighbours(cell, limit) {
347
- const diff = Math.abs(cell.id.length - this.id.length);
348
- if (diff > limit)
349
- return false;
350
- const count = Math.min(this.id.length, cell.id.length) - limit + diff;
351
- for (let i = 0;i < count; i++) {
352
- if (this.id[i] != cell.id[i]) {
353
- return false;
354
- }
355
- }
356
- return true;
357
- }
358
- }
359
-
360
- // src/lib/map/visibility/tree/branch.ts
361
- class MapMarkerBranch {
362
- tree;
363
- zoom;
364
- cell;
365
- branches;
366
- constructor(tree, id, zoom, bounds) {
367
- this.tree = tree;
368
- this.zoom = zoom;
369
- this.cell = new MapMarkerCell(id, bounds);
370
- this.branches = new Array;
371
- }
372
- split() {
373
- const bounds = this.cell.bounds;
374
- const chunks = Math.pow(2, this.tree.depth);
375
- const branchLatChunk = (bounds.ne.lat - bounds.sw.lat) / chunks;
376
- const branchLngChunk = (bounds.ne.lng - bounds.sw.lng) / chunks;
377
- for (let i = 0;i < chunks; i++) {
378
- for (let j = 0;j < chunks; j++) {
379
- const branchSwLat = bounds.sw.lat + i * branchLatChunk;
380
- const branchSwLng = bounds.sw.lng + j * branchLngChunk;
381
- const branchNeLat = branchSwLat + branchLatChunk;
382
- const branchNeLng = branchSwLng + branchLngChunk;
383
- this.branches.push(new MapMarkerBranch(this.tree, `${this.cell.id}${i * 2 + j}`, this.zoom + this.tree.depth, {
384
- sw: { lat: branchSwLat, lng: branchSwLng },
385
- ne: { lat: branchNeLat, lng: branchNeLng }
386
- }));
387
- }
388
- }
389
- }
390
- add(marker) {
391
- if (this.cell.belongs(marker.data) == false)
392
- return false;
393
- if (this.cell.markers.length < this.tree.capacity) {
394
- this.cell.markers.push(marker);
395
- return true;
396
- }
397
- if (this.branches.length == 0)
398
- this.split();
399
- for (let i = 0;i < this.branches.length; i++) {
400
- const branch = this.branches[i];
401
- if (branch.add(marker))
402
- return true;
403
- }
404
- throw new Error("Failed to add marker to branch");
405
- }
406
- compact() {
407
- if (this.branches.length == 0)
408
- return;
409
- for (let i = 0;i < this.branches.length; i++) {
410
- const branch2 = this.branches[i];
411
- branch2.compact();
412
- }
413
- const branches = new Array;
414
- const markers = new Array;
415
- for (let i = 0;i < this.branches.length; i++) {
416
- const branch2 = this.branches[i];
417
- branches.push(...branch2.branches);
418
- markers.push(...branch2.cell.markers);
419
- }
420
- const branch = new MapMarkerBranch(this.tree, this.cell.id, this.zoom + this.tree.depth, this.cell.bounds);
421
- branch.branches = branches;
422
- branch.cell.markers = markers;
423
- this.branches = [branch];
424
- }
425
- cells(zoom, region, cells) {
426
- if (zoom < this.zoom)
427
- return cells;
428
- if (region.intersects(this.cell.bounds) == false)
429
- return cells;
430
- cells.push(this.cell);
431
- for (let i = 0;i < this.branches.length; i++) {
432
- this.branches[i].cells(zoom, region, cells);
433
- }
434
- return cells;
435
- }
436
- print(level) {
437
- console.log(`${"---".repeat(level)}|${this.cell.id} zoom=[${this.zoom}] markers=[${this.cell.markers.length}]`);
438
- for (let i = 0;i < this.branches.length; i++) {
439
- this.branches[i].print(level + 1);
440
- }
441
- }
442
- count() {
443
- return this.cell.markers.length + this.branches.reduce((acc, cur) => acc + cur.count(), 0);
444
- }
445
- }
446
-
447
- class MapMarkerTree {
448
- capacity;
449
- depth;
450
- root;
451
- constructor(zoom, delta, capacity) {
452
- this.capacity = capacity;
453
- this.depth = delta;
454
- this.root = new MapMarkerBranch(this, "R", zoom, {
455
- sw: { lat: -90, lng: -180 },
456
- ne: { lat: 90, lng: 180 }
457
- });
458
- }
459
- add(marker) {
460
- return this.root.add(marker);
461
- }
462
- compact() {
463
- this.root.compact();
464
- }
465
- cells(zoom, region) {
466
- const cells = new Array;
467
- this.root.cells(zoom, region, cells);
468
- return cells;
469
- }
470
- print() {
471
- this.root.print(0);
472
- }
473
- }
474
-
475
- // src/lib/map/visibility/manager.ts
476
- var TREE_CELL_CAPACITY = 2;
477
- var TREE_CELL_DEPTH = 1;
478
- var TREE_CELL_SIZE = ELEMENT_PIN_DEFAULT_SIZE * 4;
479
- var TREE_VISIBLE_LIMIT = 1024;
480
-
481
- class MapMarkerVisibilityManager {
482
- mapProvider;
483
- mapMarkersVisibilityTree;
484
- mapMarkersVisible;
485
- mapMarkerTreeCellCapacity = TREE_CELL_CAPACITY;
486
- mapMarkerTreeCellZoomDelta = TREE_CELL_DEPTH;
487
- mapMarkerTreeCellSize = TREE_CELL_SIZE;
488
- mapMarkerTreeLimit = TREE_VISIBLE_LIMIT;
489
- constructor(mapProvider) {
490
- this.mapProvider = mapProvider;
491
- }
492
- set configuration(configuration) {
493
- this.mapMarkerTreeCellCapacity = configuration?.process?.visibility?.cell?.capacity ?? TREE_CELL_CAPACITY;
494
- this.mapMarkerTreeCellZoomDelta = configuration?.process?.visibility?.cell?.depth ?? TREE_CELL_DEPTH;
495
- this.mapMarkerTreeCellSize = configuration?.process?.visibility?.cell?.size ?? TREE_CELL_SIZE;
496
- this.mapMarkerTreeLimit = configuration?.process?.visibility?.limit ?? TREE_VISIBLE_LIMIT;
497
- }
498
- get markers() {
499
- return Array.from(this.mapMarkersVisible ?? []);
500
- }
501
- insertMarkers(markers) {
502
- this.mapMarkersVisibilityTree = this.createVisibilityTree(markers);
503
- }
504
- clearMarkers() {
505
- this.mapMarkersVisibilityTree = undefined;
506
- this.mapMarkersVisible = undefined;
507
- }
508
- updateVisibleMarkers(mapViewport, mapParameters) {
509
- if (this.mapMarkersVisibilityTree == undefined)
510
- return;
511
- const mapRegion = MapRegion.bounds(mapViewport);
512
- let mapMarkersArray = [];
513
- let mapMarkersZoom = mapViewport.zoom;
514
- while (mapMarkersZoom < mapParameters.zoomMax && mapMarkersArray.length < this.mapMarkerTreeLimit) {
515
- mapMarkersArray = this.mapMarkersVisibilityTree.cells(mapMarkersZoom, mapRegion).flatMap((cell) => cell.markers);
516
- mapMarkersZoom++;
517
- }
518
- this.mapMarkersVisible = mapMarkersArray;
519
- }
520
- createVisibilityTree(markers) {
521
- if (markers.length < this.mapMarkerTreeLimit) {
522
- const tree = new MapMarkerTree(0, 0, markers.length);
523
- for (let i = 0;i < markers.length; i++) {
524
- const marker = markers[i];
525
- const added = tree.add(marker);
526
- if (!added)
527
- throw new Error("Failed to add marker to fill tree");
528
- }
529
- return tree;
530
- } else {
531
- const treeRootZoom = -Math.floor(Math.log2(this.mapProvider.getParameters().mapSize / this.mapMarkerTreeCellSize));
532
- const tree = new MapMarkerTree(treeRootZoom, this.mapMarkerTreeCellZoomDelta, this.mapMarkerTreeCellCapacity);
533
- for (let i = 0;i < markers.length; i++) {
534
- const marker = markers[i];
535
- const added = tree.add(marker);
536
- if (!added)
537
- throw new Error("Failed to add marker to fill tree");
538
- }
539
- const compactCount = -treeRootZoom;
540
- for (let i = 0;i < compactCount; i++) {
541
- tree.compact();
542
- }
543
- return tree;
544
- }
545
- }
546
- }
547
-
548
- // src/lib/map/elements/managers/pin/element.ts
549
- import { mount } from "svelte";
550
-
551
- // src/lib/map/elements/components/pin/Pin.svelte
552
- import"svelte/internal/disclose-version";
553
- import * as $ from "svelte/internal/client";
554
- import { sineInOut } from "svelte/easing";
555
-
556
- // src/lib/map/elements/components/animations/easing.ts
557
- class EasingAnimation {
558
- animationEasing;
559
- animationRun;
560
- animating;
561
- value;
562
- time;
563
- constructor(options) {
564
- if (options.max <= options.min)
565
- throw new Error("Min must be less than max");
566
- if (options.value < options.min || options.max < options.value)
567
- throw new Error("Value must be between min and max");
568
- this.animationEasing = options.easing;
569
- this.animationRun = options.callback;
570
- this.animating = false;
571
- this.value = { current: options.value, start: options.value, end: options.value, min: options.min, max: options.max };
572
- this.time = { start: 0, end: 0, span: options.timespan };
573
- }
574
- animationFrame() {
575
- const now = performance.now();
576
- if (now > this.time.end) {
577
- this.value.current = this.value.end;
578
- } else {
579
- const time = (now - this.time.start) / (this.time.end - this.time.start);
580
- const eased = this.animationEasing(time);
581
- this.value.current = this.value.start + (this.value.end - this.value.start) * eased;
582
- }
583
- this.animationRun(this.value.current);
584
- if (this.value.current === this.value.end) {
585
- this.animating = false;
586
- return;
587
- }
588
- window.requestAnimationFrame(this.animationFrame.bind(this));
589
- }
590
- target(target) {
591
- if (target === this.value.end)
592
- return;
593
- this.value.start = this.value.current;
594
- this.value.end = target;
595
- const now = performance.now();
596
- const valueDistance = Math.abs(this.value.start - this.value.end);
597
- const valueVariance = this.value.max - this.value.min;
598
- this.time.start = now;
599
- this.time.end = now + this.time.span * Math.sqrt(valueDistance / valueVariance);
600
- if (this.animating)
601
- return;
602
- this.animating = true;
603
- window.requestAnimationFrame(this.animationFrame.bind(this));
604
- }
605
- set(target) {
606
- if (target === this.value.end)
607
- return;
608
- this.value.current = target;
609
- this.value.start = target;
610
- this.value.end = target;
611
- const now = performance.now();
612
- this.time.start = now;
613
- this.time.end = now;
614
- window.requestAnimationFrame(this.animationRun.bind(this, target));
615
- }
616
- end() {
617
- this.set(this.value.end);
618
- }
619
- expired() {
620
- return performance.now() > this.time.end;
621
- }
622
- }
623
-
624
- // src/lib/map/elements/components/pin/Pin.svelte
625
- Pin[$.FILENAME] = "src/lib/map/elements/components/pin/Pin.svelte";
626
- var root = $.add_locations($.from_html(`
627
-
628
- <div></div>
629
-
630
- `, 1), Pin[$.FILENAME], [[156, 0]]);
631
- function Pin($$anchor, $$props) {
632
- $.check_target(new.target);
633
- $.push($$props, true, Pin);
634
- let props = $.rest_props($$props, ["$$slots", "$$events", "$$legacy"], "props");
635
- let id = $$props.id;
636
- let style = $$props.style;
637
- let content = $$props.content;
638
- let functions = {
639
- setDisplayed,
640
- getDisplayed,
641
- setSuppressed,
642
- setCollapsed,
643
- getCollapsed,
644
- setScale
645
- };
646
- function invoke() {
647
- return functions;
648
- }
649
- let pin;
650
- let pinWidth = style.dimensions.width;
651
- let pinHeight = style.dimensions.height;
652
- let pinRadius = style.dimensions.radius;
653
- let pinPadding = style.dimensions.padding ?? ELEMENT_PIN_DEFAULT_PADDING;
654
- let pinBorder = style.colors?.border ?? COLOR_DEFAULT_BACKGROUND;
655
- let pinBackground = style.colors?.background ?? COLOR_DEFAULT_PRIMARY;
656
- let pinShadow = style.colors?.shadow ?? COLOR_DEFAULT_SHADOW;
657
- let displayed = $.tag($.state(false), "displayed");
658
- let contentLoading = false;
659
- let contentLoaded = false;
660
- function setDisplayed(value) {
661
- if ($.equals(value, $.get(displayed)))
662
- return;
663
- $.set(displayed, value, true);
664
- if ($.equals(value, true)) {
665
- if ($.equals(content, undefined))
666
- return;
667
- if (contentLoaded)
668
- return;
669
- if (contentLoading)
670
- return;
671
- contentLoading = true;
672
- content(id).then((element) => {
673
- if (element instanceof HTMLElement) {
674
- pin.appendChild(element);
675
- } else {
676
- console.error("Failed to load pin content");
677
- }
678
- }).catch((error) => console.error(...$.log_if_contains_state("error", error))).finally(() => {
679
- contentLoaded = true;
680
- contentLoading = false;
681
- });
682
- }
683
- if ($.equals(value, false)) {
684
- scaleAnimation.end();
685
- }
686
- }
687
- function getDisplayed() {
688
- return $.get(displayed);
689
- }
690
- let suppressed = $.tag($.state(true), "suppressed");
691
- function setSuppressed(value) {
692
- if ($.equals(value, $.get(suppressed)))
693
- return;
694
- $.set(suppressed, value, true);
695
- if (value) {
696
- scaleTarget = ELEMENT_PIN_UNDEFINED_SCALE;
697
- scaleAnimation.set(ELEMENT_PIN_UNDEFINED_SCALE);
698
- }
699
- }
700
- let collapsed = $.tag($.state(true), "collapsed");
701
- function setCollapsed(value) {
702
- if ($.equals(value, $.get(collapsed)))
703
- return;
704
- $.set(collapsed, value, true);
705
- scaleAnimation.target($.get(collapsed) ? 0 : scaleTarget);
706
- }
707
- function getCollapsed() {
708
- if (!$.get(displayed))
709
- return true;
710
- return scaleAnimation.expired();
711
- }
712
- let scaleTarget = ELEMENT_PIN_UNDEFINED_SCALE;
713
- let scaleAnimation = new EasingAnimation({
714
- value: ELEMENT_PIN_UNDEFINED_SCALE,
715
- min: 0,
716
- max: 1,
717
- timespan: ANIMATION_PIN_SCALE_DURATION,
718
- easing: sineInOut,
719
- callback: animationCallback
720
- });
721
- function setScale(value) {
722
- scaleTarget = value;
723
- scaleAnimation.target(value);
724
- }
725
- function animationCallback(scale) {
726
- pin.style.scale = scale.toString();
727
- pin.style.filter = `brightness(${animationScaleBrightness(scale)})`;
728
- }
729
- function animationScaleBrightness(scale) {
730
- return 0.25 + 0.75 * scale;
731
- }
732
- var $$exports = {
733
- get invoke() {
734
- return invoke;
735
- },
736
- ...$.legacy_api()
737
- };
738
- $.next();
739
- var fragment = root();
740
- var div = $.sibling($.first_child(fragment));
741
- let styles;
742
- $.bind_this(div, ($$value) => pin = $$value, () => pin);
743
- $.next();
744
- $.template_effect(($0) => {
745
- $.set_class(div, 1, $.clsx([
746
- "pin",
747
- $.get(displayed) && "displayed",
748
- $.get(suppressed) && "suppressed"
749
- ]), "svelte-e30vfn4rttu1");
750
- styles = $.set_style(div, "", styles, $0);
751
- }, [
752
- () => ({
753
- width: `${pinWidth}px`,
754
- height: `${pinHeight}px`,
755
- "border-radius": `${pinRadius}px`,
756
- "border-color": pinBorder,
757
- "background-color": pinBackground,
758
- "border-width": `${pinPadding}px`,
759
- "box-shadow": pinShadow,
760
- scale: ELEMENT_PIN_UNDEFINED_SCALE,
761
- filter: `brightness(${animationScaleBrightness(ELEMENT_PIN_UNDEFINED_SCALE)})`
762
- })
763
- ]);
764
- $.append($$anchor, fragment);
765
- return $.pop($$exports);
766
- }
767
- if (undefined) {}
768
- var Pin_default = Pin;
769
-
770
- // src/lib/map/elements/abstract.ts
771
- class MapAbstractElementMarker {
772
- div;
773
- marker;
774
- constructor(provider, lat, lng, zIndex) {
775
- this.div = document.createElement("div");
776
- this.marker = provider.createMarker(this.div, lat, lng, zIndex);
777
- }
778
- insert() {
779
- if (this.marker.inserted() == true)
780
- return;
781
- this.marker.insert();
782
- }
783
- remove() {
784
- if (this.marker.inserted() == false)
785
- return;
786
- this.marker.remove();
787
- }
788
- update(zIndex) {
789
- this.marker.update(zIndex);
790
- }
791
- }
792
-
793
- class MapAbstractElement {
794
- shown;
795
- id;
796
- lat;
797
- lng;
798
- rank;
799
- marker;
800
- constructor(data, marker) {
801
- if (new.target === MapAbstractElement)
802
- throw new Error("Cannot instantiate an abstract class directly.");
803
- this.shown = true;
804
- this.id = data.id;
805
- this.lat = data.lat;
806
- this.lng = data.lng;
807
- this.rank = data.rank;
808
- this.marker = marker;
809
- }
810
- }
811
-
812
- // src/lib/map/elements/managers/pin/element.ts
813
- class MapPinElement extends MapAbstractElement {
814
- width;
815
- height;
816
- zoom;
817
- component;
818
- constructor(data, provider) {
819
- super(data, new MapAbstractElementMarker(provider, data.lat, data.lng, data.rank));
820
- const width = data.pin?.style.dimensions.width ?? ELEMENT_PIN_DEFAULT_SIZE;
821
- const height = data.pin?.style.dimensions.height ?? ELEMENT_PIN_DEFAULT_SIZE;
822
- const padding = data.pin?.style.dimensions.padding ?? ELEMENT_PIN_DEFAULT_PADDING;
823
- const radius = data.pin?.style.dimensions.radius ?? ELEMENT_PIN_DEFAULT_SIZE / 2;
824
- this.width = width;
825
- this.height = height;
826
- this.zoom = NaN;
827
- this.component = mount(Pin_default, {
828
- target: this.marker.div,
829
- props: {
830
- id: this.id,
831
- style: {
832
- dimensions: {
833
- width,
834
- height,
835
- padding,
836
- radius
837
- },
838
- colors: data.pin?.style.colors
839
- },
840
- content: data.pin?.body
841
- }
842
- });
843
- }
844
- get zIndex() {
845
- if (Number.isNaN(this.zoom))
846
- return this.rank;
847
- const zIndex = Math.round(-this.zoom * ELEMENT_Z_INDEX_SCALE);
848
- return zIndex + ELEMENT_PIN_Z_INDEX_OFFSET;
849
- }
850
- }
851
-
852
- // src/lib/map/elements/managers/tooltip/element.ts
853
- import { mount as mount2 } from "svelte";
854
-
855
- // src/lib/map/elements/components/tooltip/Tooltip.svelte
856
- import"svelte/internal/disclose-version";
857
- import * as $2 from "svelte/internal/client";
858
- import { sineInOut as sineInOut2 } from "svelte/easing";
859
-
860
- // src/lib/map/elements/components/animations/spring.ts
861
- class SpringAnimation {
862
- animating;
863
- animationTimestamp;
864
- animationEnd;
865
- animationCallback;
866
- speed;
867
- value;
868
- constructor(options) {
869
- this.animating = false;
870
- this.animationTimestamp = 0;
871
- this.animationEnd = 0;
872
- this.animationCallback = options.callback;
873
- this.speed = { current: 0, spring: { stiffness: options.stiffness, damping: 2 * Math.sqrt(options.stiffness) } };
874
- this.value = { current: options.value, target: options.value, precision: options.precision, min: options.min, max: options.max };
875
- }
876
- animationFrame() {
877
- try {
878
- const now = performance.now();
879
- const time = now - this.animationTimestamp;
880
- this.animationTimestamp = now;
881
- if (now >= this.animationEnd) {
882
- this.speed.current = 0;
883
- this.value.current = this.value.target;
884
- return;
885
- }
886
- const distance = this.value.target - this.value.current;
887
- if (Math.abs(distance) < this.value.precision) {
888
- this.speed.current = 0;
889
- this.value.current = this.value.target;
890
- return;
891
- }
892
- const acceleration = distance * this.speed.spring.stiffness - this.speed.spring.damping * this.speed.current;
893
- this.speed.current += acceleration * time;
894
- this.value.current += this.speed.current * time;
895
- if (this.value.current < this.value.min) {
896
- this.value.current = this.value.target;
897
- this.speed.current = 0;
898
- return;
899
- }
900
- if (this.value.current > this.value.max) {
901
- this.value.current = this.value.target;
902
- this.speed.current = 0;
903
- return;
904
- }
905
- } finally {
906
- this.animationCallback(this.value.current);
907
- if (this.value.current === this.value.target) {
908
- this.animating = false;
909
- return;
910
- }
911
- window.requestAnimationFrame(this.animationFrame.bind(this));
912
- }
913
- }
914
- target(target) {
915
- if (target === this.value.target)
916
- return;
917
- const duration = Math.sqrt(2 * Math.abs(target - this.value.current) / this.speed.spring.stiffness);
918
- this.animationEnd = performance.now() + duration;
919
- this.value.target = target;
920
- if (this.animating)
921
- return;
922
- this.animating = true;
923
- this.animationTimestamp = performance.now();
924
- window.requestAnimationFrame(this.animationFrame.bind(this));
925
- }
926
- set(target) {
927
- if (target === this.value.target)
928
- return;
929
- this.animationEnd = performance.now();
930
- this.value.current = target;
931
- this.value.target = target;
932
- this.speed.current = 0;
933
- window.requestAnimationFrame(this.animationCallback.bind(this, target));
934
- }
935
- end() {
936
- this.set(this.value.target);
937
- }
938
- expired() {
939
- return performance.now() > this.animationEnd;
940
- }
941
- }
942
-
943
- // src/lib/map/elements/components/tooltip/Tooltip.svelte
944
- import Rectangle from "@arenarium/maps-core/rectangle";
945
- Tooltip[$2.FILENAME] = "src/lib/map/elements/components/tooltip/Tooltip.svelte";
946
- var root2 = $2.add_locations($2.from_html(`
947
-
948
- <div>
949
- <div class="element pointer svelte-vkqe2rkto2oe"></div>
950
- <div class="element tooltip svelte-vkqe2rkto2oe">
951
- <div class="element body svelte-vkqe2rkto2oe"></div>
952
- </div>
953
- </div>
954
-
955
- `, 1), Tooltip[$2.FILENAME], [[244, 0, [[245, 1], [252, 1, [[259, 2]]]]]]);
956
- function Tooltip($$anchor, $$props) {
957
- $2.check_target(new.target);
958
- $2.push($$props, true, Tooltip);
959
- let props = $2.rest_props($$props, ["$$slots", "$$events", "$$legacy"], "props");
960
- let id = $$props.id;
961
- let style = $$props.style;
962
- let content = $$props.content;
963
- let functions = {
964
- setDisplayed,
965
- getDisplayed,
966
- setCollapsed,
967
- getCollapsed,
968
- getExpanded,
969
- setAngle
970
- };
971
- function invoke() {
972
- return functions;
973
- }
974
- let anchor;
975
- let anchorShadow = style.colors?.shadow ?? COLOR_DEFAULT_SHADOW;
976
- let pointer;
977
- let pointerWidth = Math.min(style.dimensions.width, style.dimensions.height) / Math.SQRT2;
978
- let pointerHeight = Math.min(style.dimensions.width, style.dimensions.height) / Math.SQRT2;
979
- let pointerBackground = style.colors?.background ?? COLOR_DEFAULT_BACKGROUND;
980
- let tooltip;
981
- let tooltipWidth = style.dimensions.width + 2 * style.dimensions.margin;
982
- let tooltipHeight = style.dimensions.height + 2 * style.dimensions.margin;
983
- let tooltipPadding = style.dimensions.margin;
984
- let body;
985
- let bodyWidth = style.dimensions.width;
986
- let bodyHeight = style.dimensions.height;
987
- let bodyRadius = style.dimensions.radius;
988
- let bodyBackground = style.colors?.background ?? COLOR_DEFAULT_BACKGROUND;
989
- let displayed = $2.tag($2.state(false), "displayed");
990
- let contentLoading = false;
991
- let contentLoaded = false;
992
- function setDisplayed(value) {
993
- if ($2.equals(value, $2.get(displayed)))
994
- return;
995
- $2.set(displayed, value, true);
996
- if (value) {
997
- if ($2.equals(content, undefined))
998
- return;
999
- if (contentLoaded)
1000
- return;
1001
- if (contentLoading)
1002
- return;
1003
- contentLoading = true;
1004
- content(id).then((element) => {
1005
- if (element instanceof HTMLElement) {
1006
- body.appendChild(element);
1007
- } else {
1008
- console.error("Failed to load tooltip content");
1009
- }
1010
- }).catch((error) => console.error(...$2.log_if_contains_state("error", error))).finally(() => {
1011
- contentLoaded = true;
1012
- contentLoading = false;
1013
- });
1014
- }
1015
- if ($2.equals(value, false)) {
1016
- scaleAnimation.end();
1017
- offsetXAnimation.end();
1018
- offsetYAnimation.end();
1019
- }
1020
- }
1021
- function getDisplayed() {
1022
- return $2.get(displayed);
1023
- }
1024
- let collapsed = $2.tag($2.state(true), "collapsed");
1025
- function setCollapsed(value) {
1026
- if ($2.equals(value, $2.get(collapsed)))
1027
- return;
1028
- $2.set(collapsed, value, true);
1029
- scaleAnimation.target($2.get(collapsed) ? 0 : 1);
1030
- }
1031
- function getCollapsed() {
1032
- if (!$2.get(displayed))
1033
- return true;
1034
- return scaleAnimation.expired();
1035
- }
1036
- function getExpanded() {
1037
- if (!$2.get(displayed))
1038
- return false;
1039
- return scaleAnimation.expired();
1040
- }
1041
- let scaleAnimation = new EasingAnimation({
1042
- value: 0,
1043
- min: 0,
1044
- max: 1,
1045
- timespan: ANIMATION_TOOLTIP_SCALE_DURATION,
1046
- easing: sineInOut2,
1047
- callback: scaleAnimationCallback
1048
- });
1049
- function scaleAnimationCallback(scale) {
1050
- anchor.style.opacity = `${scale}`;
1051
- tooltip.style.scale = `${scale}`;
1052
- pointer.style.scale = `${scale}`;
1053
- }
1054
- let angle = NaN;
1055
- let angleDefined = $2.tag($2.state(false), "angleDefined");
1056
- let offsetX = -tooltipWidth / 2;
1057
- let offsetXAnimation = new SpringAnimation({
1058
- value: -tooltipWidth / 2,
1059
- min: -tooltipWidth,
1060
- max: 0,
1061
- precision: 1,
1062
- stiffness: ANIMATION_TOOLTIP_ANGLE_STIFFNESS,
1063
- callback: offsetXAnimationCallback
1064
- });
1065
- let offsetY = -tooltipHeight / 2;
1066
- let offsetYAnimation = new SpringAnimation({
1067
- value: -tooltipHeight / 2,
1068
- min: -tooltipHeight,
1069
- max: 0,
1070
- precision: 1,
1071
- stiffness: ANIMATION_TOOLTIP_ANGLE_STIFFNESS,
1072
- callback: offsetYAnimationCallback
1073
- });
1074
- function setAngle(value, force) {
1075
- if (Number.isNaN(value)) {
1076
- angle = NaN;
1077
- $2.set(angleDefined, false);
1078
- return;
1079
- }
1080
- if ($2.equals($2.get(angleDefined), false) || $2.equals(force, true)) {
1081
- $2.set(angleDefined, true);
1082
- angle = value;
1083
- const angleOffsets = Rectangle.getOffsets(tooltipWidth, tooltipHeight, value);
1084
- offsetXAnimation.set(Math.round(angleOffsets.x));
1085
- offsetYAnimation.set(Math.round(angleOffsets.y));
1086
- return;
1087
- }
1088
- if ($2.equals(angle, value, false)) {
1089
- angle = value;
1090
- const angleOffsets = Rectangle.getOffsets(tooltipWidth, tooltipHeight, value);
1091
- offsetXAnimation.target(Math.round(angleOffsets.x));
1092
- offsetYAnimation.target(Math.round(angleOffsets.y));
1093
- return;
1094
- }
1095
- }
1096
- function offsetXAnimationCallback(value) {
1097
- offsetX = value;
1098
- offsetAnimationCallback();
1099
- }
1100
- function offsetYAnimationCallback(value) {
1101
- offsetY = value;
1102
- offsetAnimationCallback();
1103
- }
1104
- function offsetAnimationCallback() {
1105
- const tooltipOffsetX = offsetX;
1106
- const tooltipOffsetY = offsetY;
1107
- const tooltipCenterX = tooltipOffsetX + tooltipWidth / 2;
1108
- const tooltipCenterY = tooltipOffsetY + tooltipHeight / 2;
1109
- const pointerCenterX = tooltipHeight < tooltipWidth ? tooltipCenterX * tooltipHeight / tooltipWidth : tooltipCenterX;
1110
- const pointerCenterY = tooltipHeight > tooltipWidth ? tooltipCenterY * tooltipWidth / tooltipHeight : tooltipCenterY;
1111
- const pointerAngleRad = Math.atan2(pointerCenterY, pointerCenterX);
1112
- const pointerMinSkew = 0;
1113
- const pointerMaxSkew = 30;
1114
- const pointerCenterDistance = Math.sqrt(pointerCenterX * pointerCenterX + pointerCenterY * pointerCenterY);
1115
- const pointerCenterMinDistance = Math.min(tooltipWidth, tooltipHeight) / 2;
1116
- const pointerCenterMaxDistance = pointerCenterMinDistance * Math.SQRT2;
1117
- const pointerSkewRatio = (pointerCenterDistance - pointerCenterMinDistance) / (pointerCenterMaxDistance - pointerCenterMinDistance);
1118
- const pointerAngleDeg = pointerAngleRad / Math.PI * 180 - 45;
1119
- const pointerSkewDeg = pointerMinSkew + pointerSkewRatio * (pointerMaxSkew - pointerMinSkew);
1120
- const pointerScale = pointerCenterDistance < pointerCenterMinDistance ? pointerCenterDistance / pointerCenterMinDistance : 1;
1121
- tooltip.style.transform = `translate(${Math.round(tooltipOffsetX)}px, ${Math.round(tooltipOffsetY)}px)`;
1122
- pointer.style.transform = `scale(${pointerScale}) rotate(${pointerAngleDeg}deg) skew(${pointerSkewDeg}deg, ${pointerSkewDeg}deg)`;
1123
- }
1124
- var $$exports = {
1125
- get invoke() {
1126
- return invoke;
1127
- },
1128
- ...$2.legacy_api()
1129
- };
1130
- $2.next();
1131
- var fragment = root2();
1132
- var div = $2.sibling($2.first_child(fragment));
1133
- let styles;
1134
- var div_1 = $2.sibling($2.child(div));
1135
- let styles_1;
1136
- $2.bind_this(div_1, ($$value) => pointer = $$value, () => pointer);
1137
- var div_2 = $2.sibling(div_1, 2);
1138
- let styles_2;
1139
- var div_3 = $2.sibling($2.child(div_2));
1140
- let styles_3;
1141
- $2.bind_this(div_3, ($$value) => body = $$value, () => body);
1142
- $2.next();
1143
- $2.reset(div_2);
1144
- $2.bind_this(div_2, ($$value) => tooltip = $$value, () => tooltip);
1145
- $2.next();
1146
- $2.reset(div);
1147
- $2.bind_this(div, ($$value) => anchor = $$value, () => anchor);
1148
- $2.next();
1149
- $2.template_effect(() => {
1150
- $2.set_class(div, 1, $2.clsx(["element anchor", $2.get(displayed) && "displayed"]), "svelte-vkqe2rkto2oe");
1151
- styles = $2.set_style(div, "", styles, { filter: `drop-shadow(${anchorShadow})` });
1152
- styles_1 = $2.set_style(div_1, "", styles_1, {
1153
- width: `${pointerWidth}px`,
1154
- height: `${pointerHeight}px`,
1155
- "background-color": pointerBackground
1156
- });
1157
- styles_2 = $2.set_style(div_2, "", styles_2, {
1158
- width: `${tooltipWidth}px`,
1159
- height: `${tooltipHeight}px`,
1160
- padding: `${tooltipPadding}px;`
1161
- });
1162
- styles_3 = $2.set_style(div_3, "", styles_3, {
1163
- width: `${bodyWidth}px`,
1164
- height: `${bodyHeight}px`,
1165
- "border-radius": `${bodyRadius}px;`,
1166
- "background-color": bodyBackground
1167
- });
1168
- });
1169
- $2.append($$anchor, fragment);
1170
- return $2.pop($$exports);
1171
- }
1172
- if (undefined) {}
1173
- var Tooltip_default = Tooltip;
1174
-
1175
- // src/lib/map/elements/managers/tooltip/element.ts
1176
- class MapTooltipElement extends MapAbstractElement {
1177
- width;
1178
- height;
1179
- zoom;
1180
- angle;
1181
- states;
1182
- component;
1183
- constructor(data, provider) {
1184
- super(data, new MapAbstractElementMarker(provider, data.lat, data.lng, data.rank));
1185
- this.width = data.tooltip.style.dimensions.width + data.tooltip.style.dimensions.margin * 2;
1186
- this.height = data.tooltip.style.dimensions.height + data.tooltip.style.dimensions.margin * 2;
1187
- this.zoom = NaN;
1188
- this.angle = NaN;
1189
- this.states = [];
1190
- this.component = mount2(Tooltip_default, {
1191
- target: this.marker.div,
1192
- props: {
1193
- id: this.id,
1194
- style: data.tooltip.style,
1195
- content: data.tooltip.body
1196
- }
1197
- });
1198
- }
1199
- get zIndex() {
1200
- if (Number.isNaN(this.zoom))
1201
- return this.rank;
1202
- const zIndex = Math.round(-this.zoom * ELEMENT_Z_INDEX_SCALE);
1203
- return zIndex + ELEMENT_TOOLTIP_Z_INDEX_OFFSET;
1204
- }
1205
- }
1206
-
1207
- // src/lib/map/elements/managers/popup/element.ts
1208
- import { mount as mount3 } from "svelte";
1209
- class MapPopupElement extends MapAbstractElement {
1210
- width;
1211
- height;
1212
- margin;
1213
- angle;
1214
- component;
1215
- constructor(data, provider) {
1216
- if (data.popup == undefined)
1217
- throw new Error("Failed to create popup");
1218
- super(data, new MapAbstractElementMarker(provider, data.lat, data.lng, ELEMENT_POPUP_Z_INDEX_OFFSET));
1219
- this.width = data.popup.style.dimensions.width;
1220
- this.height = data.popup.style.dimensions.height;
1221
- this.margin = data.popup.style.dimensions.margin;
1222
- this.angle = NaN;
1223
- this.shown = false;
1224
- this.component = mount3(Tooltip_default, {
1225
- target: this.marker.div,
1226
- props: {
1227
- id: this.id,
1228
- style: data.popup.style,
1229
- content: data.popup.body
1230
- }
1231
- });
1232
- }
1233
- get zIndex() {
1234
- return ELEMENT_POPUP_Z_INDEX_OFFSET;
1235
- }
1236
- }
1237
-
1238
- // src/lib/map/elements/element.ts
1239
- class MapMarkerElement {
1240
- id;
1241
- state = undefined;
1242
- pin;
1243
- tooltip;
1244
- popup;
1245
- constructor(data, provider) {
1246
- this.id = data.id;
1247
- this.pin = new MapPinElement(data, provider);
1248
- this.tooltip = new MapTooltipElement(data, provider);
1249
- if (data.popup != null)
1250
- this.popup = new MapPopupElement(data, provider);
1251
- }
1252
- }
1253
-
1254
- // src/lib/map/elements/managers/pin/manager.ts
1255
- var MAP_PINS_MAX_ZOOM = 4;
1256
-
1257
- class MapPinManager {
1258
- pins = new Set;
1259
- pinMaxWidth = 0;
1260
- pinMaxHeight = 0;
1261
- pinFade = false;
1262
- pinZoomMax = MAP_PINS_MAX_ZOOM;
1263
- pinZoomDelta = MAP_PINS_MAX_ZOOM;
1264
- set configuration(configuration) {
1265
- this.pinFade = configuration?.pin?.fade ?? true;
1266
- this.pinZoomMax = configuration?.pin?.maxZoom ?? MAP_PINS_MAX_ZOOM;
1267
- this.pinZoomDelta = this.pinZoomMax;
1268
- }
1269
- insert(pin, state3) {
1270
- this.update(pin, state3);
1271
- this.pins.add(pin);
1272
- }
1273
- update(pin, state3) {
1274
- pin.zoom = state3 ? state3[0] : NaN;
1275
- pin.marker.update(pin.zIndex);
1276
- }
1277
- remove(pin) {
1278
- pin.shown = true;
1279
- pin.zoom = NaN;
1280
- pin.component.invoke().setCollapsed(false);
1281
- pin.component.invoke().setSuppressed(true);
1282
- pin.component.invoke().setDisplayed(false);
1283
- pin.marker.update(pin.zIndex);
1284
- pin.marker.remove();
1285
- this.pins.delete(pin);
1286
- }
1287
- clear() {
1288
- this.pins.forEach((element) => element.marker.remove());
1289
- this.pins.clear();
1290
- }
1291
- refresh() {
1292
- const pins = Array.from(this.pins);
1293
- this.pinMaxWidth = pins.reduce((a, b) => Math.max(a, b.width), 0);
1294
- this.pinMaxHeight = pins.reduce((a, b) => Math.max(a, b.height), 0);
1295
- this.pinZoomDelta = Math.max(1, this.pinZoomMax - Math.log10(pins.length));
1296
- }
1297
- render(mapViewport, mapParameters) {
1298
- const mapZoom = mapViewport.zoom;
1299
- const mapSize = mapParameters.mapSize;
1300
- const mapRegion = MapRegion.offset(mapViewport, mapSize, {
1301
- top: this.pinMaxHeight,
1302
- bottom: this.pinMaxHeight,
1303
- right: this.pinMaxWidth,
1304
- left: this.pinMaxWidth
1305
- });
1306
- for (const pin of this.pins) {
1307
- if (mapRegion.contains(pin.lat, pin.lng)) {
1308
- if (Number.isNaN(pin.zoom)) {
1309
- pin.component.invoke().setDisplayed(true);
1310
- pin.component.invoke().setSuppressed(true);
1311
- pin.component.invoke().setCollapsed(false);
1312
- pin.marker.insert();
1313
- } else {
1314
- pin.component.invoke().setSuppressed(false);
1315
- if (pin.shown && mapZoom < pin.zoom && pin.zoom < mapZoom + this.pinZoomDelta) {
1316
- pin.component.invoke().setDisplayed(true);
1317
- pin.component.invoke().setCollapsed(false);
1318
- pin.component.invoke().setScale(this.pinFade ? Math.max(0, 1 - (pin.zoom - mapZoom) * 0.2) : 1);
1319
- pin.marker.insert();
1320
- } else {
1321
- pin.component.invoke().setCollapsed(true);
1322
- if (pin.component.invoke().getCollapsed()) {
1323
- pin.component.invoke().setDisplayed(false);
1324
- pin.marker.remove();
1325
- }
1326
- }
1327
- }
1328
- } else {
1329
- pin.component.invoke().setDisplayed(false);
1330
- pin.marker.remove();
1331
- }
1332
- }
1333
- }
1334
- }
1335
-
1336
- // src/lib/map/elements/managers/tooltip/manager.ts
1337
- import Angles from "@arenarium/maps-core/angles";
1338
-
1339
- class MapTooltipManager {
1340
- tooltips = new Set;
1341
- tooltipMaxWidth = 0;
1342
- tooltipMaxHeight = 0;
1343
- insert(tooltip, state3) {
1344
- this.update(tooltip, state3);
1345
- this.tooltips.add(tooltip);
1346
- }
1347
- update(tooltip, state3) {
1348
- if (state3) {
1349
- tooltip.zoom = state3[0];
1350
- tooltip.states = state3[1].map((s) => [s[0], Angles.DEGREES[s[1]]]);
1351
- } else {
1352
- tooltip.zoom = NaN;
1353
- tooltip.states = [];
1354
- }
1355
- tooltip.marker.update(tooltip.zIndex);
1356
- }
1357
- remove(tooltip) {
1358
- tooltip.shown = true;
1359
- tooltip.zoom = NaN;
1360
- tooltip.angle = NaN;
1361
- tooltip.states = [];
1362
- tooltip.component.invoke().setAngle(NaN);
1363
- tooltip.component.invoke().setCollapsed(true);
1364
- tooltip.component.invoke().setDisplayed(false);
1365
- tooltip.marker.update(tooltip.zIndex);
1366
- tooltip.marker.remove();
1367
- this.tooltips.delete(tooltip);
1368
- }
1369
- clear() {
1370
- this.tooltips.forEach((tooltip) => tooltip.marker.remove());
1371
- this.tooltips.clear();
1372
- }
1373
- refresh() {
1374
- const tooltips = Array.from(this.tooltips);
1375
- this.tooltipMaxWidth = tooltips.reduce((a, b) => Math.max(a, b.width), 0);
1376
- this.tooltipMaxHeight = tooltips.reduce((a, b) => Math.max(a, b.height), 0);
1377
- }
1378
- render(mapViewport, mapParameters) {
1379
- const mapZoom = mapViewport.zoom;
1380
- const mapSize = mapParameters.mapSize;
1381
- const mapRegion = MapRegion.offset(mapViewport, mapSize, {
1382
- top: this.tooltipMaxHeight,
1383
- bottom: this.tooltipMaxHeight,
1384
- right: this.tooltipMaxWidth,
1385
- left: this.tooltipMaxWidth
1386
- });
1387
- for (const tooltip of this.tooltips) {
1388
- if (mapRegion.contains(tooltip.lat, tooltip.lng)) {
1389
- if (Number.isNaN(tooltip.zoom) == false && tooltip.shown && tooltip.zoom <= mapZoom) {
1390
- const angle = tooltip.states.findLast((s) => s[0] <= mapZoom)?.[1];
1391
- if (angle == undefined)
1392
- throw new Error("Angle not found");
1393
- tooltip.angle = angle;
1394
- tooltip.component.invoke().setDisplayed(true);
1395
- tooltip.component.invoke().setCollapsed(false);
1396
- tooltip.component.invoke().setAngle(angle);
1397
- tooltip.marker.insert();
1398
- } else {
1399
- tooltip.component.invoke().setCollapsed(true);
1400
- if (tooltip.component.invoke().getCollapsed()) {
1401
- tooltip.component.invoke().setDisplayed(false);
1402
- tooltip.marker.remove();
1403
- }
1404
- }
1405
- } else {
1406
- tooltip.component.invoke().setDisplayed(false);
1407
- tooltip.marker.remove();
1408
- }
1409
- }
1410
- }
1411
- }
1412
-
1413
- // src/lib/map/elements/managers/popup/manager.ts
1414
- import Mercator2 from "@arenarium/maps-core/mercator";
1415
- import Rectangle2 from "@arenarium/maps-core/rectangle";
1416
-
1417
- class MapPopupManager {
1418
- popups = new Set;
1419
- pan = true;
1420
- set configuration(configuration) {
1421
- this.pan = configuration?.popup?.pan ?? true;
1422
- }
1423
- insert(popup) {
1424
- this.popups.add(popup);
1425
- }
1426
- remove(popup) {
1427
- popup.angle = NaN;
1428
- popup.shown = false;
1429
- popup.marker.remove();
1430
- popup.component.invoke().setAngle(NaN);
1431
- popup.component.invoke().setCollapsed(true);
1432
- popup.component.invoke().setDisplayed(false);
1433
- this.popups.delete(popup);
1434
- }
1435
- clear() {
1436
- this.popups.forEach((popup) => popup.marker.remove());
1437
- this.popups.clear();
1438
- }
1439
- show(element, provider) {
1440
- if (!element.popup || !element.tooltip || !element.pin)
1441
- return;
1442
- element.pin.shown = false;
1443
- element.tooltip.shown = false;
1444
- element.popup.angle = element.tooltip.angle;
1445
- element.popup.shown = true;
1446
- if (this.pan == false)
1447
- return;
1448
- const mapPopup = element.popup;
1449
- const mapViewport = provider.getViewport();
1450
- const mapBounds = mapViewport.bounds;
1451
- const mapZoom = mapViewport.zoom;
1452
- const mapSize = provider.getParameters().mapSize;
1453
- const mapZoomSize = mapSize * Math.pow(2, mapZoom);
1454
- const mapTopLeftPoint = Mercator2.project(mapBounds.ne.lat, mapBounds.sw.lng, mapZoomSize);
1455
- const mapBottomRightPoint = Mercator2.project(mapBounds.sw.lat, mapBounds.ne.lng, mapZoomSize);
1456
- const mapWidth = mapBottomRightPoint.x - mapTopLeftPoint.x;
1457
- const mapHeight = mapBottomRightPoint.y - mapTopLeftPoint.y;
1458
- const mapPopupWidth = mapPopup.width + mapPopup.margin * 8;
1459
- const mapPopupHeight = mapPopup.height + mapPopup.margin * 8;
1460
- const mapPopupPoint = Mercator2.project(mapPopup.lat, mapPopup.lng, mapZoomSize);
1461
- const mapPopupAngleOffsets = Rectangle2.getOffsets(mapPopupWidth, mapPopupHeight, element.tooltip.angle);
1462
- const mapPopupLeftEdge = mapPopupPoint.x + mapPopupAngleOffsets.x;
1463
- const mapPopupRightEdge = mapPopupLeftEdge + mapPopupWidth;
1464
- const mapPopupTopEdge = mapPopupPoint.y + mapPopupAngleOffsets.y;
1465
- const mapPopupBottomEdge = mapPopupTopEdge + mapPopupHeight;
1466
- const mapPopupLeftDistance = mapPopupLeftEdge - mapTopLeftPoint.x;
1467
- const mapPopupRightDistance = mapBottomRightPoint.x - mapPopupRightEdge;
1468
- const mapPopupTopDistance = mapPopupTopEdge - mapTopLeftPoint.y;
1469
- const mapPopupBottomDistance = mapBottomRightPoint.y - mapPopupBottomEdge;
1470
- let panX = 0;
1471
- if (mapWidth < mapPopupWidth) {
1472
- panX = (mapPopupLeftDistance - mapPopupRightDistance) / 2;
1473
- } else {
1474
- if (mapPopupLeftDistance < 0)
1475
- panX = mapPopupLeftDistance;
1476
- if (mapPopupRightDistance < 0)
1477
- panX = -mapPopupRightDistance;
1478
- }
1479
- let panY = 0;
1480
- if (mapHeight < mapPopupHeight) {
1481
- panY = (mapPopupTopDistance - mapPopupBottomDistance) / 2;
1482
- } else {
1483
- if (mapPopupTopDistance < 0)
1484
- panY = mapPopupTopDistance;
1485
- if (mapPopupBottomDistance < 0)
1486
- panY = -mapPopupBottomDistance;
1487
- }
1488
- if (panX != 0 || panY != 0)
1489
- provider.panBy(panX, panY);
1490
- }
1491
- hide(element) {
1492
- if (!element.popup || !element.tooltip || !element.pin)
1493
- return;
1494
- element.pin.shown = true;
1495
- element.tooltip.shown = true;
1496
- element.popup.shown = false;
1497
- }
1498
- render() {
1499
- for (const popup of this.popups) {
1500
- if (popup.shown) {
1501
- popup.component.invoke().setDisplayed(true);
1502
- popup.component.invoke().setCollapsed(false);
1503
- popup.component.invoke().setAngle(popup.angle, true);
1504
- popup.marker.insert();
1505
- } else {
1506
- popup.component.invoke().setCollapsed(true);
1507
- if (popup.component.invoke().getCollapsed()) {
1508
- popup.component.invoke().setDisplayed(false);
1509
- popup.marker.remove();
1510
- }
1511
- }
1512
- }
1513
- }
1514
- }
1515
-
1516
- // src/lib/map/elements/manager.ts
1517
- class MapMarkerElementManager {
1518
- mapProvider;
1519
- mapPinManager;
1520
- mapTooltipManager;
1521
- mapPopupManager;
1522
- mapElements;
1523
- constructor(mapProvider) {
1524
- this.mapProvider = mapProvider;
1525
- this.mapPinManager = new MapPinManager;
1526
- this.mapTooltipManager = new MapTooltipManager;
1527
- this.mapPopupManager = new MapPopupManager;
1528
- this.mapElements = new Map;
1529
- }
1530
- set configuration(configuration) {
1531
- this.mapPinManager.configuration = configuration;
1532
- this.mapPopupManager.configuration = configuration;
1533
- }
1534
- clearElements() {
1535
- this.mapElements.clear();
1536
- this.mapPinManager.clear();
1537
- this.mapTooltipManager.clear();
1538
- this.mapPopupManager.clear();
1539
- }
1540
- removeElements(markers) {
1541
- for (const marker of markers) {
1542
- let element = this.mapElements.get(marker.data.id);
1543
- if (element == undefined)
1544
- continue;
1545
- this.mapPinManager.remove(element.pin);
1546
- this.mapTooltipManager.remove(element.tooltip);
1547
- if (element.popup != null)
1548
- this.mapPopupManager.remove(element.popup);
1549
- }
1550
- this.mapPinManager.refresh();
1551
- this.mapTooltipManager.refresh();
1552
- }
1553
- updateElements(markers) {
1554
- for (const marker of markers) {
1555
- let element = this.mapElements.get(marker.data.id);
1556
- if (element == undefined)
1557
- continue;
1558
- this.mapPinManager.update(element.pin, marker.state);
1559
- this.mapTooltipManager.update(element.tooltip, marker.state);
1560
- }
1561
- }
1562
- insertElements(markers, onClick) {
1563
- for (const marker of markers) {
1564
- let element = this.mapElements.get(marker.data.id);
1565
- if (element == undefined) {
1566
- element = new MapMarkerElement(marker.data, this.mapProvider);
1567
- element.tooltip.marker.div.addEventListener("click", (e) => onClick(e, marker.data.id));
1568
- this.mapElements.set(marker.data.id, element);
1569
- }
1570
- this.mapPinManager.insert(element.pin, marker.state);
1571
- this.mapTooltipManager.insert(element.tooltip, marker.state);
1572
- if (element.popup != null)
1573
- this.mapPopupManager.insert(element.popup);
1574
- }
1575
- this.mapPinManager.refresh();
1576
- this.mapTooltipManager.refresh();
1577
- }
1578
- renderElements(viewport, parameters) {
1579
- this.mapPopupManager.render();
1580
- this.mapTooltipManager.render(viewport, parameters);
1581
- this.mapPinManager.render(viewport, parameters);
1582
- }
1583
- showPopup(id) {
1584
- const elements = this.mapElements.values();
1585
- for (const element of elements) {
1586
- if (element.id == id) {
1587
- this.mapPopupManager.show(element, this.mapProvider);
1588
- } else {
1589
- this.mapPopupManager.hide(element);
1590
- }
1591
- }
1592
- }
1593
- hidePopup(id) {
1594
- const element = this.mapElements.get(id);
1595
- if (element == undefined)
1596
- return;
1597
- this.mapPopupManager.hide(element);
1598
- }
1599
- hidePopups() {
1600
- const elements = this.mapElements.values();
1601
- for (const element of elements) {
1602
- this.mapPopupManager.hide(element);
1603
- }
1604
- }
1605
- }
1606
-
1607
- // src/lib/map/states/manager.ts
1608
- import Hash from "@arenarium/maps-core/hash";
1609
- import Angles2 from "@arenarium/maps-core/angles";
1610
- var API_STATES_URL = `${"http://127.0.0.1:8787"}/states`;
1611
- var DEFAULT_RETRIES = 3;
1612
- var DEFAULT_DELAY = [500, 1000, 2000];
1613
-
1614
- class MapMarkerStateManager {
1615
- apiKey;
1616
- apiToken;
1617
- apiDevEnvironment;
1618
- mapMarkerStatesStore;
1619
- constructor(apiKey, apiToken) {
1620
- this.apiKey = apiKey;
1621
- this.apiToken = apiToken;
1622
- this.apiDevEnvironment = window?.location.host.startsWith("localhost") || window?.location.host.startsWith("127.0.0.1");
1623
- this.mapMarkerStatesStore = new Map;
1624
- }
1625
- clearStates() {
1626
- this.mapMarkerStatesStore.clear();
1627
- }
1628
- resetStates(markers) {
1629
- for (let i = 0;i < markers.length; i++) {
1630
- const marker = markers[i];
1631
- marker.state = undefined;
1632
- }
1633
- }
1634
- async updateStates(markers, parameters) {
1635
- if (markers.length == 0)
1636
- return;
1637
- markers.sort((a, b) => a.data.id.localeCompare(b.data.id));
1638
- const markerStatesInputs = markers.map((marker) => marker.input);
1639
- const markerStatesInputsHash = await Hash.object(markerStatesInputs);
1640
- let states = this.mapMarkerStatesStore.get(markerStatesInputsHash);
1641
- if (states == undefined) {
1642
- states = await this.fetchStates(markerStatesInputs, parameters);
1643
- this.mapMarkerStatesStore.set(markerStatesInputsHash, states);
1644
- }
1645
- for (let i = 0;i < markers.length; i++) {
1646
- const marker = markers[i];
1647
- marker.state = states[i];
1648
- }
1649
- }
1650
- async fetchStates(inputs, parameters) {
1651
- if (inputs.length == 0)
1652
- return [];
1653
- if (inputs.length == 1)
1654
- return [[0, [[0, Angles2.DEGREES.indexOf(Angles2.DEGREES_DEFAULT)]]]];
1655
- const markerStatesRequest = {
1656
- key: this.apiKey,
1657
- token: this.apiToken,
1658
- input: inputs,
1659
- parameters
1660
- };
1661
- const markerStatesResponse = await http_default.retry(async () => await http_default.post(API_STATES_URL, markerStatesRequest, {
1662
- headers: { "Cache-Control": this.apiDevEnvironment ? "no-cache" : "" },
1663
- retry: DEFAULT_RETRIES,
1664
- delay: DEFAULT_DELAY
1665
- }));
1666
- if (markerStatesResponse.token)
1667
- this.apiToken = markerStatesResponse.token;
1668
- return markerStatesResponse.states;
1669
- }
1670
- }
1671
-
1672
- // src/lib/map/manager.ts
1673
- import {
1674
- apiKeySchema,
1675
- apiTokenSchema,
1676
- mapMarkerDataSchema,
1677
- mapProviderSchema
1678
- } from "@arenarium/maps-core/schemas";
1679
- import * as v from "valibot";
1680
- var VERSION = "1.2.6";
1681
- var API_AUTH_URL = `${"http://127.0.0.1:8787"}/auth`;
1682
- var API_LOG_URL = `${"http://127.0.0.1:8787"}/log`;
1683
- var MAP_STATE_BASE_INTERVAL = 100;
1684
- var MAP_MARKER_PROCESS_LIFESPAN = 500;
1685
- var MAP_MARKER_PROCESS_STATE_DELAY = 500;
1686
-
1687
- class MapManager {
1688
- apiKey;
1689
- mapProvider;
1690
- mapMarkers;
1691
- mapMarkersVisibilityManager;
1692
- mapMarkerElementsManager;
1693
- mapMarkerStatesManager;
1694
- mapMarkerRenderProcessor;
1695
- mapMarkerVisibilityProcessor;
1696
- mapMarkerStateProcessor;
1697
- mapMarkerStatesProcessDelay = 500;
1698
- mapMarkerStatesProcessTimeout = undefined;
1699
- mapStateManager;
1700
- constructor(apiKey, apiToken, mapProvider, mapConfiguration) {
1701
- v.parse(apiKeySchema, apiKey);
1702
- v.parse(apiTokenSchema, apiToken);
1703
- v.parse(mapProviderSchema, mapProvider);
1704
- this.apiKey = apiKey;
1705
- this.mapProvider = mapProvider;
1706
- this.mapProvider.getContainer().addEventListener("click", this.onMapClick.bind(this));
1707
- this.mapMarkers = new Map;
1708
- this.mapMarkersVisibilityManager = new MapMarkerVisibilityManager(this.mapProvider);
1709
- this.mapMarkerElementsManager = new MapMarkerElementManager(this.mapProvider);
1710
- this.mapMarkerStatesManager = new MapMarkerStateManager(apiKey, apiToken);
1711
- this.mapMarkerRenderProcessor = new Processor(this.onMapMarkerRenderProcess.bind(this), MAP_MARKER_PROCESS_LIFESPAN);
1712
- this.mapMarkerVisibilityProcessor = new Processor(this.onMapMarkerVisiblityProcess.bind(this), MAP_MARKER_PROCESS_LIFESPAN);
1713
- this.mapMarkerStateProcessor = new Processor(this.onMapMarkerStateProcess.bind(this));
1714
- this.mapStateManager = new MapStateManager(this.mapProvider, MAP_STATE_BASE_INTERVAL / (navigator?.hardwareConcurrency ?? 1), this.dettached.bind(this), this.error.bind(this), this.onMapMove.bind(this), this.onMapIdle.bind(this));
1715
- this.configuration = mapConfiguration;
1716
- }
1717
- static async create(apiKey, mapProvider, mapConfiguration) {
1718
- const apiAuthRequest = { key: apiKey, version: VERSION };
1719
- const apiAuthResponse = await http_default.post(API_AUTH_URL, apiAuthRequest);
1720
- let apiToken = apiAuthResponse.token;
1721
- if (!apiToken)
1722
- throw new Error("Failed to get api token");
1723
- return new MapManager(apiKey, apiToken, mapProvider, mapConfiguration);
1724
- }
1725
- set configuration(configuration) {
1726
- this.mapMarkerStatesProcessDelay = configuration?.process?.states?.delay ?? MAP_MARKER_PROCESS_STATE_DELAY;
1727
- this.mapMarkersVisibilityManager.configuration = configuration;
1728
- this.mapMarkerElementsManager.configuration = configuration;
1729
- }
1730
- clear() {
1731
- this.mapMarkers.clear();
1732
- this.mapMarkersVisibilityManager.clearMarkers();
1733
- this.mapMarkerStatesManager.clearStates();
1734
- this.mapMarkerElementsManager.clearElements();
1735
- this.mapStateManager.stop();
1736
- this.mapMarkerVisibilityProcessor.stop();
1737
- this.mapMarkerStateProcessor.stop();
1738
- this.mapMarkerRenderProcessor.stop();
1739
- }
1740
- dettached() {
1741
- return this.mapProvider.getContainer().parentElement == null;
1742
- }
1743
- error(message, error) {
1744
- this.log("error", message, error);
1745
- this.configuration?.events?.error?.(message, error);
1746
- }
1747
- async log(level, title, content) {
1748
- switch (level) {
1749
- case "info":
1750
- console.info(content);
1751
- break;
1752
- case "warning":
1753
- console.warn(content);
1754
- break;
1755
- case "error":
1756
- console.error(content);
1757
- break;
1758
- }
1759
- if (content instanceof Error == false)
1760
- return;
1761
- try {
1762
- const log = {
1763
- key: this.apiKey,
1764
- title,
1765
- level,
1766
- content: {
1767
- version: VERSION,
1768
- ...content
1769
- }
1770
- };
1771
- await http_default.put(API_LOG_URL, log);
1772
- } catch (error) {
1773
- console.error(error);
1774
- }
1775
- }
1776
- onMapClick() {
1777
- this.hidePopup();
1778
- }
1779
- onMapMarkerClick(e, id) {
1780
- e.stopPropagation();
1781
- this.showPopup(id);
1782
- }
1783
- onMapMove() {
1784
- this.mapMarkerVisibilityProcessor.start();
1785
- }
1786
- onMapIdle() {
1787
- if (this.mapMarkerStatesProcessTimeout) {
1788
- window.clearTimeout(this.mapMarkerStatesProcessTimeout);
1789
- }
1790
- this.mapMarkerStatesProcessTimeout = window.setTimeout(() => {
1791
- this.mapMarkerStateProcessor.start();
1792
- }, this.mapMarkerStatesProcessDelay);
1793
- }
1794
- async onMapMarkerVisiblityProcess() {
1795
- try {
1796
- if (this.dettached())
1797
- return true;
1798
- const mapViewport = this.mapProvider.getViewport();
1799
- const mapParameters = this.mapProvider.getParameters();
1800
- const oldVisibleMarkers = new Set(this.mapMarkersVisibilityManager.markers);
1801
- this.mapMarkersVisibilityManager.updateVisibleMarkers(mapViewport, mapParameters);
1802
- const newVisibleMarkers = new Set(this.mapMarkersVisibilityManager.markers);
1803
- const removeMarkers = Array.from(oldVisibleMarkers.difference(newVisibleMarkers));
1804
- const insertMarkers = Array.from(newVisibleMarkers.difference(oldVisibleMarkers));
1805
- this.mapMarkerStatesManager.resetStates(removeMarkers);
1806
- this.mapMarkerElementsManager.removeElements(removeMarkers);
1807
- this.mapMarkerElementsManager.insertElements(insertMarkers, this.onMapMarkerClick.bind(this));
1808
- this.mapMarkerRenderProcessor.start();
1809
- return false;
1810
- } catch (error) {
1811
- this.clear();
1812
- this.error("Failed to process map move", error);
1813
- return true;
1814
- }
1815
- }
1816
- async onMapMarkerStateProcess() {
1817
- try {
1818
- if (this.dettached())
1819
- return true;
1820
- const mapMarkers = this.mapMarkersVisibilityManager.markers;
1821
- const mapParameters = this.mapProvider.getParameters();
1822
- await this.mapMarkerStatesManager.updateStates(mapMarkers, mapParameters);
1823
- this.mapMarkerElementsManager.updateElements(mapMarkers);
1824
- this.mapMarkerRenderProcessor.start();
1825
- return false;
1826
- } catch (error) {
1827
- this.clear();
1828
- this.error("Failed to process map idle", error);
1829
- return true;
1830
- }
1831
- }
1832
- async onMapMarkerRenderProcess() {
1833
- try {
1834
- if (this.dettached())
1835
- return true;
1836
- const mapViewport = this.mapProvider.getViewport();
1837
- const mapParameters = this.mapProvider.getParameters();
1838
- this.mapMarkerElementsManager.renderElements(mapViewport, mapParameters);
1839
- return false;
1840
- } catch (error) {
1841
- this.clear();
1842
- this.error("Failed to process map render", error);
1843
- return true;
1844
- }
1845
- }
1846
- updateMarkers(markerData) {
1847
- v.parse(v.array(mapMarkerDataSchema), markerData);
1848
- try {
1849
- for (const data of markerData) {
1850
- if (this.mapMarkers.has(data.id) == false) {
1851
- this.mapMarkers.set(data.id, new MapMarker(data));
1852
- }
1853
- }
1854
- const markers = Array.from(this.mapMarkers.values());
1855
- markers.sort((a, b) => b.data.rank - a.data.rank);
1856
- this.mapMarkersVisibilityManager.insertMarkers(markers);
1857
- this.mapStateManager.start();
1858
- this.mapMarkerVisibilityProcessor.start();
1859
- this.mapMarkerStateProcessor.start();
1860
- this.mapMarkerRenderProcessor.start();
1861
- } catch (error) {
1862
- this.clear();
1863
- this.error("Failed to update markers", error);
1864
- throw error;
1865
- }
1866
- }
1867
- removeMarkers() {
1868
- try {
1869
- this.clear();
1870
- } catch (error) {
1871
- this.error("Failed to remove markers", error);
1872
- throw error;
1873
- }
1874
- }
1875
- showPopup(id) {
1876
- try {
1877
- this.mapMarkerElementsManager.showPopup(id);
1878
- } catch (error) {
1879
- this.mapMarkerElementsManager.hidePopups();
1880
- this.error("Failed to show popup", error);
1881
- throw error;
1882
- } finally {
1883
- this.mapMarkerRenderProcessor.start();
1884
- }
1885
- }
1886
- hidePopup() {
1887
- try {
1888
- this.mapMarkerElementsManager.hidePopups();
1889
- } catch (error) {
1890
- this.error("Failed to hide popup", error);
1891
- throw error;
1892
- } finally {
1893
- this.mapMarkerRenderProcessor.start();
1894
- }
1895
- }
1896
- }
1897
- export {
1898
- MapManager
1899
- };
1
+ async function s0(x){return new Promise((q)=>setTimeout(q,x))}async function r0(x,q){let J=0,Q=Math.max(1,q?.retry??1);while(J<Q)try{return await x()}catch(F){if(console.log(`[HTTP RETRY] ${J} of ${Q}`),console.log(F),J++,J==Q)throw F;if(q?.delay)await s0(q.delay[J-1]??0)}throw Error("Unreachable code")}async function H2(x,q){let J=await r0(async()=>await fetch(x,q));if(!J.ok)throw Error(J.statusText);return await J.json()}async function O2(x,q,J){let Q=await fetch(x,{method:"POST",body:JSON.stringify(q),headers:{"Content-Type":"application/json",...J?.headers},...J});if(!Q.ok)throw Error(Q.statusText);return await Q.json()}async function z2(x,q,J){let Q=await fetch(x,{method:"PUT",body:JSON.stringify(q),headers:{"Content-Type":"application/json",...J?.headers},...J});if(!Q.ok)throw Error(Q.statusText)}var L={delay:s0,retry:r0,get:H2,post:O2,put:z2};class d{endtime=0;lifespan;paused=!1;enqueued=!1;interval;timeout;callback;constructor(x,q,J){if((q??0)<0)throw Error("Lifespan must be greater than 0");if((J??0)<0)throw Error("Interval must be greater than 0");this.interval=J??(navigator?.hardwareConcurrency?100:200/navigator.hardwareConcurrency),this.lifespan=q??this.interval,this.callback=x}async run(){let x=performance.now();if(this.enqueued)this.endtime=x+this.lifespan,this.enqueued=!1;if(this.endtime<x){this.stop();return}if(this.paused==!1){if(await this.callback()&&!this.enqueued){this.stop();return}}this.timeout=window.setTimeout(this.run.bind(this),this.interval)}start(){if(this.enqueued=!0,!this.timeout)this.run()}stop(){if(this.timeout)window.clearTimeout(this.timeout);this.timeout=void 0}pause(){this.paused=!0}resume(){this.paused=!1}}class J0{data;state;constructor(x){this.data=x,this.state=void 0}get input(){return{id:this.data.id,rank:this.data.rank,lat:this.data.lat,lng:this.data.lng,width:this.data.tooltip.style.dimensions.width,height:this.data.tooltip.style.dimensions.height,margin:this.data.tooltip.style.dimensions.margin}}}class Q0{callback;timeout;id;constructor(x,q){if(q<=0)throw Error("Timeout must be greater than 0");this.callback=x,this.timeout=q}start(){if(this.id!=null)return;this.id=window.setInterval(this.callback,this.timeout)}stop(){if(this.id==null)return;window.clearInterval(this.id),this.id=void 0}}class G0{viewport=void 0;state="idle";provider;interval;onCancel;onError;onMove;onIdle;constructor(x,q,J,Q,F,G){this.provider=x,this.interval=new Q0(this.onInterval.bind(this),q),this.onCancel=J,this.onError=Q,this.onMove=F,this.onIdle=G}start(){this.interval.start()}stop(){this.interval.stop()}onInterval(){try{if(this.onCancel()){this.interval.stop();return}let x=this.provider.getViewport(),q=this.state,J=JSON.stringify(x)!==JSON.stringify(this.viewport)?"move":"idle";if(J=="move")this.onMove();if(J=="idle"&&q=="move")this.onIdle();this.state=J,this.viewport=x}catch(x){this.onError("Failed to process map state interval",x)}}}var i0=75,n0=150,R0=0.00025,p0=1e6,o0=2000000,k0=3000000,F0=10,g=16,h0=2,$=0.5,n="white",t0="darkgreen",K0="0px 2px 2px rgba(0, 0, 0, 0.5)";import W0 from"@arenarium/maps-core/mercator";class p{sw;ne;constructor(x,q,J,Q){if(J<x)throw Error(`Invalid bounds: ${x}, ${q}, ${J}, ${Q}`);if(Q<q)throw Error(`Invalid bounds: ${x}, ${q}, ${J}, ${Q}`);this.sw={lat:x,lng:q},this.ne={lat:J,lng:Q}}contains(x,q){if(x<this.sw.lat||this.ne.lat<x)return!1;if(q<this.sw.lng||this.ne.lng<q)return!1;return!0}intersects(x){if(x.ne.lat<this.sw.lat||this.ne.lat<x.sw.lat)return!1;if(x.ne.lng<this.sw.lng||this.ne.lng<x.sw.lng)return!1;return!0}}class b{blockL;blockR;sw;ne;constructor(x,q,J,Q){if(J<x)throw Error(`Invalid bounds: ${x}, ${q}, ${J}, ${Q}`);if(this.sw={lat:x,lng:q},this.ne={lat:J,lng:Q},q<Q)this.blockL=new p(x,q,J,Q),this.blockR=new p(0,0,0,0);else this.blockL=new p(x,-180,J,Q),this.blockR=new p(x,q,J,180)}static normalize(x){let{bounds:q,center:J}=x;if(Math.abs(q.ne.lng-J.lng)+Math.abs(q.sw.lng-J.lng)>360)q.sw.lng=-180,q.ne.lng=180;if(q.ne.lng-q.sw.lng>360){q.sw.lng=-180,q.ne.lng=180;return}if(q.sw.lng<-180)q.sw.lng+=360;if(q.sw.lng>180)q.sw.lng-=360;if(q.ne.lng<-180)q.ne.lng+=360;if(q.ne.lng>180)q.ne.lng-=360}static bounds(x){this.normalize(x);let q=x.bounds,J=q.sw,Q=q.ne;return new b(J.lat,J.lng,Q.lat,Q.lng)}static offset(x,q,J){this.normalize(x);let{bounds:Q,zoom:F}=x,G=q*Math.pow(2,F),j=W0.project(Q.sw.lat,Q.sw.lng,G),U=W0.project(Q.ne.lat,Q.ne.lng,G),V=Math.max(j.x-J.left,0),O=Math.min(j.y+J.bottom,G),B=Math.min(U.x+J.right,G),S=Math.max(U.y-J.top,0),N=W0.unproject(V,O,G),I=W0.unproject(B,S,G);return new b(N.lat,N.lng,I.lat,I.lng)}contains(x,q){return this.blockL.contains(x,q)||this.blockR.contains(x,q)}intersects(x){return this.blockL.intersects(x)||this.blockR.intersects(x)}}class Y0{id;bounds;markers;constructor(x,q){this.id=x,this.bounds=q,this.markers=[]}belongs(x){let q=this.bounds.sw;if(x.lat<q.lat)return!1;if(x.lng<q.lng)return!1;let J=this.bounds.ne;if(J.lat<x.lat)return!1;if(J.lng<x.lng)return!1;return!0}neighbours(x,q){let J=Math.abs(x.id.length-this.id.length);if(J>q)return!1;let Q=Math.min(this.id.length,x.id.length)-q+J;for(let F=0;F<Q;F++)if(this.id[F]!=x.id[F])return!1;return!0}}class Z0{tree;zoom;cell;branches;constructor(x,q,J,Q){this.tree=x,this.zoom=J,this.cell=new Y0(q,Q),this.branches=[]}split(){let x=this.cell.bounds,q=Math.pow(2,this.tree.depth),J=(x.ne.lat-x.sw.lat)/q,Q=(x.ne.lng-x.sw.lng)/q;for(let F=0;F<q;F++)for(let G=0;G<q;G++){let j=x.sw.lat+F*J,U=x.sw.lng+G*Q,V=j+J,O=U+Q;this.branches.push(new Z0(this.tree,`${this.cell.id}${F*2+G}`,this.zoom+this.tree.depth,{sw:{lat:j,lng:U},ne:{lat:V,lng:O}}))}}add(x){if(this.cell.belongs(x.data)==!1)return!1;if(this.cell.markers.length<this.tree.capacity)return this.cell.markers.push(x),!0;if(this.branches.length==0)this.split();for(let q=0;q<this.branches.length;q++)if(this.branches[q].add(x))return!0;throw Error("Failed to add marker to branch")}compact(){if(this.branches.length==0)return;for(let Q=0;Q<this.branches.length;Q++)this.branches[Q].compact();let x=[],q=[];for(let Q=0;Q<this.branches.length;Q++){let F=this.branches[Q];x.push(...F.branches),q.push(...F.cell.markers)}let J=new Z0(this.tree,this.cell.id,this.zoom+this.tree.depth,this.cell.bounds);J.branches=x,J.cell.markers=q,this.branches=[J]}cells(x,q,J){if(x<this.zoom)return J;if(q.intersects(this.cell.bounds)==!1)return J;J.push(this.cell);for(let Q=0;Q<this.branches.length;Q++)this.branches[Q].cells(x,q,J);return J}print(x){console.log(`${"---".repeat(x)}|${this.cell.id} zoom=[${this.zoom}] markers=[${this.cell.markers.length}]`);for(let q=0;q<this.branches.length;q++)this.branches[q].print(x+1)}count(){return this.cell.markers.length+this.branches.reduce((x,q)=>x+q.count(),0)}}class o{capacity;depth;root;constructor(x,q,J){this.capacity=J,this.depth=q,this.root=new Z0(this,"R",x,{sw:{lat:-90,lng:-180},ne:{lat:90,lng:180}})}add(x){return this.root.add(x)}compact(){this.root.compact()}cells(x,q){let J=[];return this.root.cells(x,q,J),J}print(){this.root.print(0)}}var a0=2,e0=1,x2=g*4,q2=1024;class j0{mapProvider;mapMarkersVisibilityTree;mapMarkersVisible;mapMarkerTreeCellCapacity=a0;mapMarkerTreeCellZoomDelta=e0;mapMarkerTreeCellSize=x2;mapMarkerTreeLimit=q2;constructor(x){this.mapProvider=x}set configuration(x){this.mapMarkerTreeCellCapacity=x?.process?.visibility?.cell?.capacity??a0,this.mapMarkerTreeCellZoomDelta=x?.process?.visibility?.cell?.depth??e0,this.mapMarkerTreeCellSize=x?.process?.visibility?.cell?.size??x2,this.mapMarkerTreeLimit=x?.process?.visibility?.limit??q2}get markers(){return Array.from(this.mapMarkersVisible??[])}insertMarkers(x){this.mapMarkersVisibilityTree=this.createVisibilityTree(x)}clearMarkers(){this.mapMarkersVisibilityTree=void 0,this.mapMarkersVisible=void 0}updateVisibleMarkers(x,q){if(this.mapMarkersVisibilityTree==null)return;let J=b.bounds(x),Q=[],F=x.zoom;while(F<q.zoomMax&&Q.length<this.mapMarkerTreeLimit)Q=this.mapMarkersVisibilityTree.cells(F,J).flatMap((G)=>G.markers),F++;this.mapMarkersVisible=Q}createVisibilityTree(x){if(x.length<this.mapMarkerTreeLimit){let q=new o(0,0,x.length);for(let J=0;J<x.length;J++){let Q=x[J];if(!q.add(Q))throw Error("Failed to add marker to fill tree")}return q}else{let q=-Math.floor(Math.log2(this.mapProvider.getParameters().mapSize/this.mapMarkerTreeCellSize)),J=new o(q,this.mapMarkerTreeCellZoomDelta,this.mapMarkerTreeCellCapacity);for(let F=0;F<x.length;F++){let G=x[F];if(!J.add(G))throw Error("Failed to add marker to fill tree")}let Q=-q;for(let F=0;F<Q;F++)J.compact();return J}}}import{mount as I2}from"svelte";import"svelte/internal/disclose-version";import*as K from"svelte/internal/client";import{sineInOut as B2}from"svelte/easing";class m{animationEasing;animationRun;animating;value;time;constructor(x){if(x.max<=x.min)throw Error("Min must be less than max");if(x.value<x.min||x.max<x.value)throw Error("Value must be between min and max");this.animationEasing=x.easing,this.animationRun=x.callback,this.animating=!1,this.value={current:x.value,start:x.value,end:x.value,min:x.min,max:x.max},this.time={start:0,end:0,span:x.timespan}}animationFrame(){let x=performance.now();if(x>this.time.end)this.value.current=this.value.end;else{let q=(x-this.time.start)/(this.time.end-this.time.start),J=this.animationEasing(q);this.value.current=this.value.start+(this.value.end-this.value.start)*J}if(this.animationRun(this.value.current),this.value.current===this.value.end){this.animating=!1;return}window.requestAnimationFrame(this.animationFrame.bind(this))}target(x){if(x===this.value.end)return;this.value.start=this.value.current,this.value.end=x;let q=performance.now(),J=Math.abs(this.value.start-this.value.end),Q=this.value.max-this.value.min;if(this.time.start=q,this.time.end=q+this.time.span*Math.sqrt(J/Q),this.animating)return;this.animating=!0,window.requestAnimationFrame(this.animationFrame.bind(this))}set(x){if(x===this.value.end)return;this.value.current=x,this.value.start=x,this.value.end=x;let q=performance.now();this.time.start=q,this.time.end=q,window.requestAnimationFrame(this.animationRun.bind(this,x))}end(){this.set(this.value.end)}expired(){return performance.now()>this.time.end}}var N2=K.from_html("<div></div>");function S0(x,q){K.push(q,!0);let J=K.rest_props(q,["$$slots","$$events","$$legacy"]),Q=q.id,F=q.style,G=q.content,j={setDisplayed:l,getDisplayed:A,setSuppressed:P,setCollapsed:z,getCollapsed:y,setScale:r};function U(){return j}let V,O=F.dimensions.width,B=F.dimensions.height,S=F.dimensions.radius,N=F.dimensions.padding??h0,I=F.colors?.border??n,D=F.colors?.background??t0,X=F.colors?.shadow??K0,Z=K.state(!1),M=!1,v=!1;function l(Y){if(Y==K.get(Z))return;if(K.set(Z,Y,!0),Y==!0){if(G==null)return;if(v)return;if(M)return;M=!0,G(Q).then((w)=>{if(w instanceof HTMLElement)V.appendChild(w);else console.error("Failed to load pin content")}).catch((w)=>console.error(w)).finally(()=>{v=!0,M=!1})}if(Y==!1)_.end()}function A(){return K.get(Z)}let C=K.state(!0);function P(Y){if(Y==K.get(C))return;if(K.set(C,Y,!0),Y)s=$,_.set($)}let H=K.state(!0);function z(Y){if(Y==K.get(H))return;K.set(H,Y,!0),_.target(K.get(H)?0:s)}function y(){if(!K.get(Z))return!0;return _.expired()}let s=$,_=new m({value:$,min:0,max:1,timespan:i0,easing:B2,callback:y0});function r(Y){s=Y,_.target(Y)}function y0(Y){V.style.scale=Y.toString(),V.style.filter=`brightness(${e(Y)})`}function e(Y){return 0.25+0.75*Y}var b0={invoke:U},T=N2();let x0;return K.bind_this(T,(Y)=>V=Y,()=>V),K.template_effect((Y)=>{K.set_class(T,1,K.clsx(["pin",K.get(Z)&&"displayed",K.get(C)&&"suppressed"]),"svelte-e30vfn4rttu1"),x0=K.set_style(T,"",x0,Y)},[()=>({width:`${O}px`,height:`${B}px`,"border-radius":`${S}px`,"border-color":I,"background-color":D,"border-width":`${N}px`,"box-shadow":X,scale:$,filter:`brightness(${e($)})`})]),K.append(x,T),K.pop(b0)}class E{div;marker;constructor(x,q,J,Q){this.div=document.createElement("div"),this.marker=x.createMarker(this.div,q,J,Q)}insert(){if(this.marker.inserted()==!0)return;this.marker.insert()}remove(){if(this.marker.inserted()==!1)return;this.marker.remove()}update(x){this.marker.update(x)}}class k{shown;id;lat;lng;rank;marker;constructor(x,q){if(new.target===k)throw Error("Cannot instantiate an abstract class directly.");this.shown=!0,this.id=x.id,this.lat=x.lat,this.lng=x.lng,this.rank=x.rank,this.marker=q}}class V0 extends k{width;height;zoom;component;constructor(x,q){super(x,new E(q,x.lat,x.lng,x.rank));let J=x.pin?.style.dimensions.width??g,Q=x.pin?.style.dimensions.height??g,F=x.pin?.style.dimensions.padding??h0,G=x.pin?.style.dimensions.radius??g/2;this.width=J,this.height=Q,this.zoom=NaN,this.component=I2(S0,{target:this.marker.div,props:{id:this.id,style:{dimensions:{width:J,height:Q,padding:F,radius:G},colors:x.pin?.style.colors},content:x.pin?.body}})}get zIndex(){if(Number.isNaN(this.zoom))return this.rank;return Math.round(-this.zoom*F0)+p0}}import{mount as D2}from"svelte";import"svelte/internal/disclose-version";import*as h from"svelte/internal/client";import{sineInOut as y2}from"svelte/easing";class t{animating;animationTimestamp;animationEnd;animationCallback;speed;value;constructor(x){this.animating=!1,this.animationTimestamp=0,this.animationEnd=0,this.animationCallback=x.callback,this.speed={current:0,spring:{stiffness:x.stiffness,damping:2*Math.sqrt(x.stiffness)}},this.value={current:x.value,target:x.value,precision:x.precision,min:x.min,max:x.max}}animationFrame(){try{let x=performance.now(),q=x-this.animationTimestamp;if(this.animationTimestamp=x,x>=this.animationEnd){this.speed.current=0,this.value.current=this.value.target;return}let J=this.value.target-this.value.current;if(Math.abs(J)<this.value.precision){this.speed.current=0,this.value.current=this.value.target;return}let Q=J*this.speed.spring.stiffness-this.speed.spring.damping*this.speed.current;if(this.speed.current+=Q*q,this.value.current+=this.speed.current*q,this.value.current<this.value.min){this.value.current=this.value.target,this.speed.current=0;return}if(this.value.current>this.value.max){this.value.current=this.value.target,this.speed.current=0;return}}finally{if(this.animationCallback(this.value.current),this.value.current===this.value.target){this.animating=!1;return}window.requestAnimationFrame(this.animationFrame.bind(this))}}target(x){if(x===this.value.target)return;let q=Math.sqrt(2*Math.abs(x-this.value.current)/this.speed.spring.stiffness);if(this.animationEnd=performance.now()+q,this.value.target=x,this.animating)return;this.animating=!0,this.animationTimestamp=performance.now(),window.requestAnimationFrame(this.animationFrame.bind(this))}set(x){if(x===this.value.target)return;this.animationEnd=performance.now(),this.value.current=x,this.value.target=x,this.speed.current=0,window.requestAnimationFrame(this.animationCallback.bind(this,x))}end(){this.set(this.value.target)}expired(){return performance.now()>this.animationEnd}}import J2 from"@arenarium/maps-core/rectangle";var b2=h.from_html('<div><div class="element pointer svelte-vkqe2rkto2oe"></div> <div class="element tooltip svelte-vkqe2rkto2oe"><div class="element body svelte-vkqe2rkto2oe"></div></div></div>');function a(x,q){h.push(q,!0);let J=h.rest_props(q,["$$slots","$$events","$$legacy"]),Q=q.id,F=q.style,G=q.content,j={setDisplayed:s,getDisplayed:_,setCollapsed:y0,getCollapsed:e,getExpanded:b0,setAngle:h2};function U(){return j}let V,O=F.colors?.shadow??K0,B,S=Math.min(F.dimensions.width,F.dimensions.height)/Math.SQRT2,N=Math.min(F.dimensions.width,F.dimensions.height)/Math.SQRT2,I=F.colors?.background??n,D,X=F.dimensions.width+2*F.dimensions.margin,Z=F.dimensions.height+2*F.dimensions.margin,M=F.dimensions.margin,v,l=F.dimensions.width,A=F.dimensions.height,C=F.dimensions.radius,P=F.colors?.background??n,H=h.state(!1),z=!1,y=!1;function s(W){if(W==h.get(H))return;if(h.set(H,W,!0),W){if(G==null)return;if(y)return;if(z)return;z=!0,G(Q).then((f)=>{if(f instanceof HTMLElement)v.appendChild(f);else console.error("Failed to load tooltip content")}).catch((f)=>console.error(f)).finally(()=>{y=!0,z=!1})}if(W==!1)T.end(),D0.end(),v0.end()}function _(){return h.get(H)}let r=h.state(!0);function y0(W){if(W==h.get(r))return;h.set(r,W,!0),T.target(h.get(r)?0:1)}function e(){if(!h.get(H))return!0;return T.expired()}function b0(){if(!h.get(H))return!1;return T.expired()}let T=new m({value:0,min:0,max:1,timespan:n0,easing:y2,callback:x0});function x0(W){V.style.opacity=`${W}`,D.style.scale=`${W}`,B.style.scale=`${W}`}let Y=NaN,w=h.state(!1),_0=-X/2,D0=new t({value:-X/2,min:-X,max:0,precision:1,stiffness:R0,callback:K2}),$0=-Z/2,v0=new t({value:-Z/2,min:-Z,max:0,precision:1,stiffness:R0,callback:W2});function h2(W,f){if(Number.isNaN(W)){Y=NaN,h.set(w,!1);return}if(h.get(w)==!1||f==!0){h.set(w,!0),Y=W;let R=J2.getOffsets(X,Z,W);D0.set(Math.round(R.x)),v0.set(Math.round(R.y));return}if(Y!=W){Y=W;let R=J2.getOffsets(X,Z,W);D0.target(Math.round(R.x)),v0.target(Math.round(R.y));return}}function K2(W){_0=W,E0()}function W2(W){$0=W,E0()}function E0(){let W=_0,f=$0,R=W+X/2,m0=f+Z/2,T0=Z<X?R*Z/X:R,f0=Z>X?m0*X/Z:m0,Z2=Math.atan2(f0,T0),u2=0,L2=30,w0=Math.sqrt(T0*T0+f0*f0),i=Math.min(X,Z)/2,j2=i*Math.SQRT2,V2=(w0-i)/(j2-i),X2=Z2/Math.PI*180-45,l0=0+V2*30,U2=w0<i?w0/i:1;D.style.transform=`translate(${Math.round(W)}px, ${Math.round(f)}px)`,B.style.transform=`scale(${U2}) rotate(${X2}deg) skew(${l0}deg, ${l0}deg)`}var Y2={invoke:U},u=b2();let c0;var C0=h.child(u);let u0;h.bind_this(C0,(W)=>B=W,()=>B);var q0=h.sibling(C0,2);let L0;var d0=h.child(q0);let g0;return h.bind_this(d0,(W)=>v=W,()=>v),h.reset(q0),h.bind_this(q0,(W)=>D=W,()=>D),h.reset(u),h.bind_this(u,(W)=>V=W,()=>V),h.template_effect(()=>{h.set_class(u,1,h.clsx(["element anchor",h.get(H)&&"displayed"]),"svelte-vkqe2rkto2oe"),c0=h.set_style(u,"",c0,{filter:`drop-shadow(${O})`}),u0=h.set_style(C0,"",u0,{width:`${S}px`,height:`${N}px`,"background-color":I}),L0=h.set_style(q0,"",L0,{width:`${X}px`,height:`${Z}px`,padding:`${M}px;`}),g0=h.set_style(d0,"",g0,{width:`${l}px`,height:`${A}px`,"border-radius":`${C}px;`,"background-color":P})}),h.append(x,u),h.pop(Y2)}class X0 extends k{width;height;zoom;angle;states;component;constructor(x,q){super(x,new E(q,x.lat,x.lng,x.rank));this.width=x.tooltip.style.dimensions.width+x.tooltip.style.dimensions.margin*2,this.height=x.tooltip.style.dimensions.height+x.tooltip.style.dimensions.margin*2,this.zoom=NaN,this.angle=NaN,this.states=[],this.component=D2(a,{target:this.marker.div,props:{id:this.id,style:x.tooltip.style,content:x.tooltip.body}})}get zIndex(){if(Number.isNaN(this.zoom))return this.rank;return Math.round(-this.zoom*F0)+o0}}import{mount as v2}from"svelte";class U0 extends k{width;height;margin;angle;component;constructor(x,q){if(x.popup==null)throw Error("Failed to create popup");super(x,new E(q,x.lat,x.lng,k0));this.width=x.popup.style.dimensions.width,this.height=x.popup.style.dimensions.height,this.margin=x.popup.style.dimensions.margin,this.angle=NaN,this.shown=!1,this.component=v2(a,{target:this.marker.div,props:{id:this.id,style:x.popup.style,content:x.popup.body}})}get zIndex(){return k0}}class H0{id;state=void 0;pin;tooltip;popup;constructor(x,q){if(this.id=x.id,this.pin=new V0(x,q),this.tooltip=new X0(x,q),x.popup!=null)this.popup=new U0(x,q)}}var M0=4;class O0{pins=new Set;pinMaxWidth=0;pinMaxHeight=0;pinFade=!1;pinZoomMax=M0;pinZoomDelta=M0;set configuration(x){this.pinFade=x?.pin?.fade??!0,this.pinZoomMax=x?.pin?.maxZoom??M0,this.pinZoomDelta=this.pinZoomMax}insert(x,q){this.update(x,q),this.pins.add(x)}update(x,q){x.zoom=q?q[0]:NaN,x.marker.update(x.zIndex)}remove(x){x.shown=!0,x.zoom=NaN,x.component.invoke().setCollapsed(!1),x.component.invoke().setSuppressed(!0),x.component.invoke().setDisplayed(!1),x.marker.update(x.zIndex),x.marker.remove(),this.pins.delete(x)}clear(){this.pins.forEach((x)=>x.marker.remove()),this.pins.clear()}refresh(){let x=Array.from(this.pins);this.pinMaxWidth=x.reduce((q,J)=>Math.max(q,J.width),0),this.pinMaxHeight=x.reduce((q,J)=>Math.max(q,J.height),0),this.pinZoomDelta=Math.max(1,this.pinZoomMax-Math.log10(x.length))}render(x,q){let J=x.zoom,Q=q.mapSize,F=b.offset(x,Q,{top:this.pinMaxHeight,bottom:this.pinMaxHeight,right:this.pinMaxWidth,left:this.pinMaxWidth});for(let G of this.pins)if(F.contains(G.lat,G.lng)){if(Number.isNaN(G.zoom))G.component.invoke().setDisplayed(!0),G.component.invoke().setSuppressed(!0),G.component.invoke().setCollapsed(!1),G.marker.insert();else if(G.component.invoke().setSuppressed(!1),G.shown&&J<G.zoom&&G.zoom<J+this.pinZoomDelta)G.component.invoke().setDisplayed(!0),G.component.invoke().setCollapsed(!1),G.component.invoke().setScale(this.pinFade?Math.max(0,1-(G.zoom-J)*0.2):1),G.marker.insert();else if(G.component.invoke().setCollapsed(!0),G.component.invoke().getCollapsed())G.component.invoke().setDisplayed(!1),G.marker.remove()}else G.component.invoke().setDisplayed(!1),G.marker.remove()}}import C2 from"@arenarium/maps-core/angles";class z0{tooltips=new Set;tooltipMaxWidth=0;tooltipMaxHeight=0;insert(x,q){this.update(x,q),this.tooltips.add(x)}update(x,q){if(q)x.zoom=q[0],x.states=q[1].map((J)=>[J[0],C2.DEGREES[J[1]]]);else x.zoom=NaN,x.states=[];x.marker.update(x.zIndex)}remove(x){x.shown=!0,x.zoom=NaN,x.angle=NaN,x.states=[],x.component.invoke().setAngle(NaN),x.component.invoke().setCollapsed(!0),x.component.invoke().setDisplayed(!1),x.marker.update(x.zIndex),x.marker.remove(),this.tooltips.delete(x)}clear(){this.tooltips.forEach((x)=>x.marker.remove()),this.tooltips.clear()}refresh(){let x=Array.from(this.tooltips);this.tooltipMaxWidth=x.reduce((q,J)=>Math.max(q,J.width),0),this.tooltipMaxHeight=x.reduce((q,J)=>Math.max(q,J.height),0)}render(x,q){let J=x.zoom,Q=q.mapSize,F=b.offset(x,Q,{top:this.tooltipMaxHeight,bottom:this.tooltipMaxHeight,right:this.tooltipMaxWidth,left:this.tooltipMaxWidth});for(let G of this.tooltips)if(F.contains(G.lat,G.lng)){if(Number.isNaN(G.zoom)==!1&&G.shown&&G.zoom<=J){let j=G.states.findLast((U)=>U[0]<=J)?.[1];if(j==null)throw Error("Angle not found");G.angle=j,G.component.invoke().setDisplayed(!0),G.component.invoke().setCollapsed(!1),G.component.invoke().setAngle(j),G.marker.insert()}else if(G.component.invoke().setCollapsed(!0),G.component.invoke().getCollapsed())G.component.invoke().setDisplayed(!1),G.marker.remove()}else G.component.invoke().setDisplayed(!1),G.marker.remove()}}import A0 from"@arenarium/maps-core/mercator";import T2 from"@arenarium/maps-core/rectangle";class B0{popups=new Set;pan=!0;set configuration(x){this.pan=x?.popup?.pan??!0}insert(x){this.popups.add(x)}remove(x){x.angle=NaN,x.shown=!1,x.marker.remove(),x.component.invoke().setAngle(NaN),x.component.invoke().setCollapsed(!0),x.component.invoke().setDisplayed(!1),this.popups.delete(x)}clear(){this.popups.forEach((x)=>x.marker.remove()),this.popups.clear()}show(x,q){if(!x.popup||!x.tooltip||!x.pin)return;if(x.pin.shown=!1,x.tooltip.shown=!1,x.popup.angle=x.tooltip.angle,x.popup.shown=!0,this.pan==!1)return;let J=x.popup,Q=q.getViewport(),F=Q.bounds,G=Q.zoom,U=q.getParameters().mapSize*Math.pow(2,G),V=A0.project(F.ne.lat,F.sw.lng,U),O=A0.project(F.sw.lat,F.ne.lng,U),B=O.x-V.x,S=O.y-V.y,N=J.width+J.margin*8,I=J.height+J.margin*8,D=A0.project(J.lat,J.lng,U),X=T2.getOffsets(N,I,x.tooltip.angle),Z=D.x+X.x,M=Z+N,v=D.y+X.y,l=v+I,A=Z-V.x,C=O.x-M,P=v-V.y,H=O.y-l,z=0;if(B<N)z=(A-C)/2;else{if(A<0)z=A;if(C<0)z=-C}let y=0;if(S<I)y=(P-H)/2;else{if(P<0)y=P;if(H<0)y=-H}if(z!=0||y!=0)q.panBy(z,y)}hide(x){if(!x.popup||!x.tooltip||!x.pin)return;x.pin.shown=!0,x.tooltip.shown=!0,x.popup.shown=!1}render(){for(let x of this.popups)if(x.shown)x.component.invoke().setDisplayed(!0),x.component.invoke().setCollapsed(!1),x.component.invoke().setAngle(x.angle,!0),x.marker.insert();else if(x.component.invoke().setCollapsed(!0),x.component.invoke().getCollapsed())x.component.invoke().setDisplayed(!1),x.marker.remove()}}class N0{mapProvider;mapPinManager;mapTooltipManager;mapPopupManager;mapElements;constructor(x){this.mapProvider=x,this.mapPinManager=new O0,this.mapTooltipManager=new z0,this.mapPopupManager=new B0,this.mapElements=new Map}set configuration(x){this.mapPinManager.configuration=x,this.mapPopupManager.configuration=x}clearElements(){this.mapElements.clear(),this.mapPinManager.clear(),this.mapTooltipManager.clear(),this.mapPopupManager.clear()}removeElements(x){for(let q of x){let J=this.mapElements.get(q.data.id);if(J==null)continue;if(this.mapPinManager.remove(J.pin),this.mapTooltipManager.remove(J.tooltip),J.popup!=null)this.mapPopupManager.remove(J.popup)}this.mapPinManager.refresh(),this.mapTooltipManager.refresh()}updateElements(x){for(let q of x){let J=this.mapElements.get(q.data.id);if(J==null)continue;this.mapPinManager.update(J.pin,q.state),this.mapTooltipManager.update(J.tooltip,q.state)}}insertElements(x,q){for(let J of x){let Q=this.mapElements.get(J.data.id);if(Q==null)Q=new H0(J.data,this.mapProvider),Q.tooltip.marker.div.addEventListener("click",(F)=>q(F,J.data.id)),this.mapElements.set(J.data.id,Q);if(this.mapPinManager.insert(Q.pin,J.state),this.mapTooltipManager.insert(Q.tooltip,J.state),Q.popup!=null)this.mapPopupManager.insert(Q.popup)}this.mapPinManager.refresh(),this.mapTooltipManager.refresh()}renderElements(x,q){this.mapPopupManager.render(),this.mapTooltipManager.render(x,q),this.mapPinManager.render(x,q)}showPopup(x){let q=this.mapElements.values();for(let J of q)if(J.id==x)this.mapPopupManager.show(J,this.mapProvider);else this.mapPopupManager.hide(J)}hidePopup(x){let q=this.mapElements.get(x);if(q==null)return;this.mapPopupManager.hide(q)}hidePopups(){let x=this.mapElements.values();for(let q of x)this.mapPopupManager.hide(q)}}import f2 from"@arenarium/maps-core/hash";import Q2 from"@arenarium/maps-core/angles";var w2="https://maps.api.arenarium.dev/states",R2=3,k2=[500,1000,2000];class I0{apiKey;apiToken;apiDevEnvironment;mapMarkerStatesStore;constructor(x,q){this.apiKey=x,this.apiToken=q,this.apiDevEnvironment=window?.location.host.startsWith("localhost")||window?.location.host.startsWith("127.0.0.1"),this.mapMarkerStatesStore=new Map}clearStates(){this.mapMarkerStatesStore.clear()}resetStates(x){for(let q=0;q<x.length;q++){let J=x[q];J.state=void 0}}async updateStates(x,q){if(x.length==0)return;x.sort((G,j)=>G.data.id.localeCompare(j.data.id));let J=x.map((G)=>G.input),Q=f2.object(J),F=this.mapMarkerStatesStore.get(Q);if(F==null)F=await this.fetchStates(J,q),this.mapMarkerStatesStore.set(Q,F);for(let G=0;G<x.length;G++){let j=x[G];j.state=F[G]}}async fetchStates(x,q){if(x.length==0)return[];if(x.length==1)return[[0,[[0,Q2.DEGREES.indexOf(Q2.DEGREES_DEFAULT)]]]];let J={key:this.apiKey,token:this.apiToken,input:x,parameters:q},Q=await L.retry(async()=>await L.post(w2,J,{headers:{"Cache-Control":this.apiDevEnvironment?"no-cache":""},retry:R2,delay:k2}));if(Q.token)this.apiToken=Q.token;return Q.states}}import{apiKeySchema as S2,apiTokenSchema as M2,mapMarkerDataSchema as A2,mapProviderSchema as P2}from"@arenarium/maps-core/schemas";import*as c from"valibot";var G2="1.2.8",_2="https://maps.api.arenarium.dev/auth",$2="https://maps.api.arenarium.dev/log",E2=100,F2=500,c2=500;class P0{apiKey;mapProvider;mapMarkers;mapMarkersVisibilityManager;mapMarkerElementsManager;mapMarkerStatesManager;mapMarkerRenderProcessor;mapMarkerVisibilityProcessor;mapMarkerStateProcessor;mapMarkerStatesProcessDelay=500;mapMarkerStatesProcessTimeout=void 0;mapStateManager;constructor(x,q,J,Q){c.parse(S2,x),c.parse(M2,q),c.parse(P2,J),this.apiKey=x,this.mapProvider=J,this.mapProvider.getContainer().addEventListener("click",this.onMapClick.bind(this)),this.mapMarkers=new Map,this.mapMarkersVisibilityManager=new j0(this.mapProvider),this.mapMarkerElementsManager=new N0(this.mapProvider),this.mapMarkerStatesManager=new I0(x,q),this.mapMarkerRenderProcessor=new d(this.onMapMarkerRenderProcess.bind(this),F2),this.mapMarkerVisibilityProcessor=new d(this.onMapMarkerVisiblityProcess.bind(this),F2),this.mapMarkerStateProcessor=new d(this.onMapMarkerStateProcess.bind(this)),this.mapStateManager=new G0(this.mapProvider,E2/(navigator?.hardwareConcurrency??1),this.dettached.bind(this),this.error.bind(this),this.onMapMove.bind(this),this.onMapIdle.bind(this)),this.configuration=Q}static async create(x,q,J){let Q={key:x,version:G2},G=(await L.post(_2,Q)).token;if(!G)throw Error("Failed to get api token");return new P0(x,G,q,J)}set configuration(x){this.mapMarkerStatesProcessDelay=x?.process?.states?.delay??c2,this.mapMarkersVisibilityManager.configuration=x,this.mapMarkerElementsManager.configuration=x}clear(){this.mapMarkers.clear(),this.mapMarkersVisibilityManager.clearMarkers(),this.mapMarkerStatesManager.clearStates(),this.mapMarkerElementsManager.clearElements(),this.mapStateManager.stop(),this.mapMarkerVisibilityProcessor.stop(),this.mapMarkerStateProcessor.stop(),this.mapMarkerRenderProcessor.stop()}dettached(){return this.mapProvider.getContainer().parentElement==null}error(x,q){this.log("error",x,q),this.configuration?.events?.error?.(x,q)}async log(x,q,J){switch(x){case"info":console.info(J);break;case"warning":console.warn(J);break;case"error":console.error(J);break}if(J instanceof Error==!1)return;try{let Q={key:this.apiKey,title:q,level:x,content:{version:G2,...J}};await L.put($2,Q)}catch(Q){console.error(Q)}}onMapClick(){this.hidePopup()}onMapMarkerClick(x,q){x.stopPropagation(),this.showPopup(q)}onMapMove(){this.mapMarkerVisibilityProcessor.start()}onMapIdle(){if(this.mapMarkerStatesProcessTimeout)window.clearTimeout(this.mapMarkerStatesProcessTimeout);this.mapMarkerStatesProcessTimeout=window.setTimeout(()=>{this.mapMarkerStateProcessor.start()},this.mapMarkerStatesProcessDelay)}async onMapMarkerVisiblityProcess(){try{if(this.dettached())return!0;let x=this.mapProvider.getViewport(),q=this.mapProvider.getParameters(),J=new Set(this.mapMarkersVisibilityManager.markers);this.mapMarkersVisibilityManager.updateVisibleMarkers(x,q);let Q=new Set(this.mapMarkersVisibilityManager.markers),F=Array.from(J.difference(Q)),G=Array.from(Q.difference(J));return this.mapMarkerStatesManager.resetStates(F),this.mapMarkerElementsManager.removeElements(F),this.mapMarkerElementsManager.insertElements(G,this.onMapMarkerClick.bind(this)),this.mapMarkerRenderProcessor.start(),!1}catch(x){return this.clear(),this.error("Failed to process map move",x),!0}}async onMapMarkerStateProcess(){try{if(this.dettached())return!0;let x=this.mapMarkersVisibilityManager.markers,q=this.mapProvider.getParameters();return await this.mapMarkerStatesManager.updateStates(x,q),this.mapMarkerElementsManager.updateElements(x),this.mapMarkerRenderProcessor.start(),!1}catch(x){return this.clear(),this.error("Failed to process map idle",x),!0}}async onMapMarkerRenderProcess(){try{if(this.dettached())return!0;let x=this.mapProvider.getViewport(),q=this.mapProvider.getParameters();return this.mapMarkerElementsManager.renderElements(x,q),!1}catch(x){return this.clear(),this.error("Failed to process map render",x),!0}}updateMarkers(x){c.parse(c.array(A2),x);try{for(let J of x)if(this.mapMarkers.has(J.id)==!1)this.mapMarkers.set(J.id,new J0(J));let q=Array.from(this.mapMarkers.values());q.sort((J,Q)=>Q.data.rank-J.data.rank),this.mapMarkersVisibilityManager.insertMarkers(q),this.mapStateManager.start(),this.mapMarkerVisibilityProcessor.start(),this.mapMarkerStateProcessor.start(),this.mapMarkerRenderProcessor.start()}catch(q){throw this.clear(),this.error("Failed to update markers",q),q}}removeMarkers(){try{this.clear()}catch(x){throw this.error("Failed to remove markers",x),x}}showPopup(x){try{this.mapMarkerElementsManager.showPopup(x)}catch(q){throw this.mapMarkerElementsManager.hidePopups(),this.error("Failed to show popup",q),q}finally{this.mapMarkerRenderProcessor.start()}}hidePopup(){try{this.mapMarkerElementsManager.hidePopups()}catch(x){throw this.error("Failed to hide popup",x),x}finally{this.mapMarkerRenderProcessor.start()}}}export{P0 as MapManager};