@maplat/ui 0.11.10 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts CHANGED
@@ -1,496 +1,536 @@
1
- import { MaplatApp as Core } from "@maplat/core";
2
- import "ol/ol.css";
3
- import EventTarget from "ol/events/Target.js";
4
- import { asArray } from "ol/color";
5
-
6
- import { Swiper } from "./swiper_ex";
7
- import { Navigation, Pagination } from "swiper";
8
- import "swiper/swiper-bundle.css";
9
- import page from "page";
10
- import * as bsn from "bootstrap.native";
11
- import "./styles/ui.scss";
12
-
13
- import { uiInit } from "./ui_init";
14
- import {
15
- handleMarkerAction,
16
- showContextMenu,
17
- xyToMapIDs,
18
- setHideMarker,
19
- checkOverlayID,
20
- handleMarkerActionById
21
- } from "./ui_marker";
22
- import type { SliderNew } from "./maplat_control";
23
- import type ContextMenu from "./contextmenu";
24
-
25
- import type { Pixel } from "ol/pixel";
26
- import type { Coordinate } from "ol/coordinate";
27
- import { resolveRelativeLink, ellips } from "./ui_utils";
28
- import type { MaplatAppOption, RestoreState, SwiperInstance } from "./types";
29
-
30
- Swiper.use([Navigation, Pagination]);
31
-
32
- export class MaplatUi extends EventTarget {
33
- static createObject(option: MaplatAppOption) {
34
- const app = new MaplatUi(option);
35
- return app.waitReady.then(() => app);
36
- }
37
-
38
- core?: Core;
39
- appOption: MaplatAppOption;
40
- waitReady!: Promise<void>;
41
- waitReadyBridge: unknown;
42
- pathThatSet?: string;
43
- swipers: Record<string, SwiperInstance> = {};
44
- mobile_if: boolean = false;
45
- ui_func: string = "default";
46
- datum: string = "default";
47
- selected_layer: string = "default";
48
- toms: number = 0;
49
- cache_messages: Record<string, string> = {};
50
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
51
- last_toast: any;
52
- share_enable!: boolean;
53
- sliderNew!: SliderNew;
54
- baseSwiper!: SwiperInstance;
55
- overlaySwiper!: SwiperInstance;
56
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
57
- sliderCommon: any;
58
- contextMenu!: ContextMenu;
59
- splashPromise!: Promise<void>;
60
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
61
- _selectCandidateSources?: Record<string, any>;
62
- appEnvelope?: boolean;
63
- restoring: boolean = false;
64
- poiSwiper: SwiperInstance | undefined;
65
- html!: string;
66
- enablePoiHtmlNoScroll: boolean = false;
67
- enableShare: boolean = false;
68
- enableHideMarker: boolean = false;
69
- enableBorder: boolean = false;
70
- enableMarkerList: boolean = false;
71
- disableNoimage: boolean = false;
72
- alwaysGpsOn: boolean = false;
73
- isTouch: boolean = false;
74
- html_id_seed: string;
75
- lastClickPixel: Pixel | undefined;
76
- lastClickCoordinate: Coordinate | undefined;
77
- lastGPSError: string | undefined;
78
- selectedMarkerNamespaceID: string | undefined;
79
-
80
- constructor(appOption: MaplatAppOption) {
81
- super();
82
- this.html_id_seed = `${Math.floor(Math.random() * 9000) + 1000}`;
83
- this.appOption = appOption;
84
-
85
- if (appOption.stateUrl) {
86
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
87
- page((ctx: any, _next: any) => {
88
- let pathes = ctx.canonicalPath.split("#!");
89
- let path = pathes.length > 1 ? pathes[1] : pathes[0];
90
-
91
- pathes = path.split("?");
92
- path = pathes[0];
93
- if (path === this.pathThatSet) {
94
- delete this.pathThatSet;
95
- return;
96
- }
97
- const restore: RestoreState = {
98
- transparency: 0,
99
- position: {
100
- rotation: 0
101
- }
102
- };
103
- // Parse "s:map/x:100/..."
104
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
105
- path.split("/").forEach((state: any) => {
106
- if (!state) return;
107
- const line = state.split(":");
108
- switch (line[0]) {
109
- case "s":
110
- restore.mapID = line[1];
111
- break;
112
- case "b":
113
- restore.backgroundID = line[1];
114
- break;
115
- case "t":
116
- restore.transparency = parseFloat(line[1]);
117
- break;
118
- case "r":
119
- restore.position!.rotation = parseFloat(line[1]);
120
- break;
121
- case "z":
122
- restore.position!.zoom = parseFloat(line[1]);
123
- break;
124
- case "x":
125
- restore.position!.x = parseFloat(line[1]);
126
- break;
127
- case "y":
128
- restore.position!.y = parseFloat(line[1]);
129
- break;
130
- case "sb":
131
- restore.showBorder = !!parseInt(line[1]);
132
- break;
133
- case "hm":
134
- restore.hideMarker = !!parseInt(line[1]);
135
- break;
136
- case "hl":
137
- restore.hideLayer = line[1];
138
- break;
139
- case "om":
140
- restore.openedMarker = line[1];
141
- break;
142
- case "c":
143
- if (this.core) {
144
- const modalElm =
145
- this.core!.mapDivDocument!.querySelector(".modalBase")!;
146
- const modal = new bsn.Modal(modalElm, {
147
- root: this.core!.mapDivDocument!
148
- });
149
- modal.hide();
150
- }
151
- break;
152
- case "mobile_if":
153
- this.mobile_if = line[1] === "true";
154
- break;
155
- }
156
- });
157
- if (!this.core) {
158
- if (restore.mapID) {
159
- appOption.restore = restore;
160
- this.restoring = true;
161
- }
162
-
163
- this.initializer(appOption).then(() => {
164
- this.core!.waitReady.then(() => {
165
- this.restoring = false;
166
- this.updateUrl();
167
- });
168
- });
169
- } else if (restore.mapID) {
170
- this.restoring = true;
171
-
172
- this.core!.waitReady.then(() => {
173
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
174
- const ret = this.core!.changeMap(restore.mapID!, restore as any);
175
- Promise.resolve(ret).then(() => {
176
- // Fix: Manually apply rotation after changeMap
177
- // if (restore.position && restore.position.rotation !== undefined) {
178
- // console.log(`[Debug] Manually applying rotation after changeMap: ${ restore.position.rotation } `);
179
- // this.core!.mapObject.getView().setRotation(restore.position.rotation);
180
- // }
181
-
182
- // Update transparency slider if needed
183
- if (this.sliderNew) {
184
- const t = restore.transparency || 0;
185
- const val = t / 100;
186
- this.sliderNew.set("slidervalue", val);
187
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
188
- if ((this.sliderNew as any).element) {
189
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
190
- (this.sliderNew as any).element.value = (1 - val).toString();
191
- }
192
- }
193
-
194
- this.restoring = false;
195
- console.log(`[Debug] Calling updateUrl from ChangeMap`);
196
- this.updateUrl();
197
- });
198
- });
199
- }
200
- });
201
- page({
202
- hashbang: true
203
- });
204
- page();
205
- this.waitReady = new Promise((resolve, _reject) => {
206
- this.waitReadyBridge = resolve;
207
- });
208
- } else {
209
- this.waitReady = this.initializer(appOption);
210
- }
211
- }
212
-
213
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
214
- async initializer(appOption: any) {
215
- return uiInit(this, appOption);
216
- }
217
-
218
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
219
- handleMarkerAction(data: any) {
220
- handleMarkerAction(this, data);
221
- }
222
-
223
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
224
- showContextMenu(list: any[]) {
225
- showContextMenu(this, list);
226
- }
227
-
228
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
229
- async xyToMapIDs(xy: any, threshold = 10) {
230
- return xyToMapIDs(this, xy, threshold);
231
- }
232
-
233
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
234
- setShowBorder(flag: any) {
235
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
236
- this.core!.requestUpdateState({ showBorder: flag ? 1 : 0 } as any);
237
- this.updateEnvelope();
238
- if (flag) {
239
- this.core!.mapDivDocument!.classList.add("show-border");
240
- } else {
241
- this.core!.mapDivDocument!.classList.remove("show-border");
242
- }
243
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
244
- if (this.core!.restoreSession as any) {
245
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
246
- this.core!.requestUpdateState({ showBorder: flag ? 1 : 0 } as any);
247
- }
248
- }
249
-
250
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
251
- setHideMarker(flag: any) {
252
- setHideMarker(this, flag);
253
- }
254
-
255
- handleMarkerActionById(markerId: string) {
256
- handleMarkerActionById(this, markerId);
257
- }
258
-
259
- updateUrl() {
260
- if (!this.appOption.stateUrl) return;
261
- if (this.restoring) return;
262
-
263
- const map = this.core!.mapObject;
264
- if (!map) return;
265
- const view = map.getView();
266
- const center = view.getCenter();
267
- const zoom = view.getZoom();
268
- const rotation = view.getRotation();
269
-
270
- const currentMap = this.core!.from ? this.core!.from.mapID : "";
271
- if (!currentMap) return;
272
-
273
- // Background ID
274
- let backMap = "";
275
- if (this.baseSwiper) {
276
- const slide = this.baseSwiper.slides[this.baseSwiper.activeIndex];
277
-
278
- if (slide) {
279
- backMap = slide.getAttribute("data") || "";
280
- }
281
- }
282
-
283
- const transparency = this.sliderNew
284
- ? this.sliderNew.get("slidervalue") * 100
285
- : 0;
286
-
287
- // Legacy format: s:map/b:back/... (no leading slash, prepended with #!)
288
- let path = `s:${currentMap}`;
289
-
290
- if (backMap && backMap !== currentMap) {
291
- path += `/b:${backMap}`;
292
- }
293
-
294
- if (transparency > 0) {
295
- path += `/t:${transparency}`;
296
- }
297
-
298
- path += `/x:${center[0]}`;
299
- path += `/y:${center[1]}`;
300
- path += `/z:${zoom}`;
301
-
302
- if (rotation !== 0) {
303
- path += `/r:${(rotation * 180) / Math.PI}`;
304
- }
305
-
306
- // Options
307
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
308
- if ((this.core!.stateBuffer as any).showBorder) path += `/sb:1`;
309
- if (this.core!.mapDivDocument!.classList.contains("hide-marker"))
310
- path += `/hm:1`;
311
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
312
- if (this.enableMarkerList && (this.core!.stateBuffer as any).markerList)
313
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
314
- path += `/om:${(this.core!.stateBuffer as any).markerList}`;
315
-
316
- // Add selected marker to URL
317
- if (this.selectedMarkerNamespaceID) {
318
- path += `/om:${this.selectedMarkerNamespaceID}`;
319
- }
320
-
321
- if (this.pathThatSet !== path) {
322
- this.pathThatSet = path;
323
- page(`#!${path}`);
324
- }
325
- }
326
-
327
- updateEnvelope() {
328
- if (!this.core!.mapObject) return;
329
-
330
- this.core!.mapObject.resetEnvelope();
331
- if (this._selectCandidateSources) {
332
- for (const key of Object.keys(this._selectCandidateSources)) {
333
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
334
- if ((this.core!.mapObject as any).removeEnvelope) {
335
- console.log(`[Debug] Removing envelope for ${key}`);
336
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
337
- (this.core!.mapObject as any).removeEnvelope(
338
- this._selectCandidateSources![key]
339
- );
340
- }
341
- }
342
- }
343
-
344
- this._selectCandidateSources = {};
345
-
346
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
347
- if ((this.core!.stateBuffer as any).showBorder) {
348
- if (!this.core!.from) return;
349
-
350
- let activeOverlayId: string | null = null;
351
- if (this.overlaySwiper) {
352
- const slide = this.overlaySwiper.slides[this.overlaySwiper.activeIndex];
353
- if (slide) activeOverlayId = slide.getAttribute("data");
354
- }
355
-
356
- Object.keys(this.core!.cacheHash!)
357
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
358
- .filter((key: any) => this.core!.cacheHash[key].envelope)
359
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
360
- .map((key: any) => {
361
- const source = this.core!.cacheHash[key];
362
- const isActive = key === activeOverlayId;
363
-
364
- const xyPromises =
365
- key === this.core!.from!.mapID &&
366
- typeof source.xy2SysCoord === "function"
367
- ? [
368
- [0, 0],
369
- [source.width, 0],
370
- [source.width, source.height],
371
- [0, source.height],
372
- [0, 0]
373
- ].map(xy => Promise.resolve(source.xy2SysCoord(xy)))
374
- : // eslint-disable-next-line @typescript-eslint/no-explicit-any
375
- source.envelope.geometry.coordinates[0].map((coord: any) =>
376
- this.core!.from!.merc2SysCoordAsync(coord)
377
- );
378
-
379
- Promise.all(xyPromises).then(xys => {
380
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
381
- const options: any = {
382
- color: source.envelopeColor,
383
- width: 2,
384
- lineDash: [6, 6]
385
- };
386
- this.core!.mapObject.setEnvelope(xys, options);
387
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
388
- if (isActive && (this.core!.mapObject as any).setFillEnvelope) {
389
- console.log(`[Debug] Setting fill envelope for ${key}`);
390
-
391
- const color = asArray(source.envelopeColor || "#000000");
392
-
393
- color[3] = 0.4;
394
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
395
- const fillHandle = (this.core!.mapObject as any).setFillEnvelope(
396
- xys,
397
- null,
398
- { color }
399
- );
400
- this._selectCandidateSources![key] = fillHandle;
401
- }
402
- });
403
- });
404
- }
405
- }
406
-
407
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
408
- resolveRelativeLink(file: any, fallbackPath: any) {
409
- return resolveRelativeLink(file, fallbackPath);
410
- }
411
-
412
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
413
- checkOverlayID(mapID: any) {
414
- return checkOverlayID(this, mapID);
415
- }
416
-
417
- areaIndex(xys: number[][]) {
418
- return (
419
- 0.5 *
420
- Math.abs(
421
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
422
- [0, 1, 2, 3].reduce((prev: any, _curr: any, i: any) => {
423
- const xy1 = xys[i];
424
- const xy2 = xys[i + 1];
425
- return prev + (xy1[0] - xy2[0]) * (xy1[1] + xy2[1]);
426
- }, 0)
427
- )
428
- );
429
- }
430
-
431
- getShareUrl(type: string) {
432
- if (type === "view") {
433
- return window.location.href;
434
- }
435
- // app
436
- return window.location.href.split("?")[0].split("#")[0];
437
- }
438
-
439
- showToast(message: string, target?: HTMLElement) {
440
- let toast = document.querySelector(".custom-toast") as HTMLElement;
441
- if (!toast) {
442
- toast = document.createElement("div");
443
- toast.className = "custom-toast";
444
- document.body.appendChild(toast);
445
- }
446
- (toast as HTMLElement).innerText = message;
447
-
448
- if (target) {
449
- const parent = target.closest(".recipient");
450
- const rect = (parent || target).getBoundingClientRect();
451
- toast.style.position = "fixed";
452
- toast.style.left = `${rect.left + rect.width / 2}px`;
453
- toast.style.top = `${rect.top + rect.height / 2}px`;
454
- toast.style.transform = "translate(-50%, -50%)";
455
- toast.style.bottom = "auto";
456
- toast.style.margin = "0";
457
- } else {
458
- toast.style.position = "fixed";
459
- toast.style.left = "50%";
460
- toast.style.bottom = "30px";
461
- toast.style.top = "auto";
462
- toast.style.transform = "";
463
- toast.style.marginLeft = "-125px";
464
- }
465
-
466
- toast.classList.add("show");
467
-
468
- setTimeout(() => {
469
- toast!.classList.remove("show");
470
- }, 1500);
471
- }
472
-
473
- modalSetting(type: string) {
474
- const modalElm = this.core!.mapDivDocument!.querySelector(".modalBase")!;
475
- modalElm.classList.remove(
476
- "modal_load",
477
- "modal_poi",
478
- "modal_share",
479
- "modal_help",
480
- "modal_gpsW",
481
- "modal_gpsD",
482
- "modal_map",
483
- "modal_marker_list"
484
- );
485
- modalElm.classList.add(`modal_${type}`);
486
- }
487
-
488
- ellips() {
489
- ellips(this.core!.mapDivDocument!);
490
- }
491
-
492
- remove() {
493
- this.core!.remove();
494
- delete this.core;
495
- }
496
- }
1
+ import { MaplatApp as Core } from "@maplat/core";
2
+ import "ol/ol.css";
3
+ import EventTarget from "ol/events/Target.js";
4
+ import { asArray } from "ol/color";
5
+
6
+ import { Swiper } from "./swiper_ex";
7
+ import { Navigation, Pagination } from "swiper";
8
+ import "swiper/swiper-bundle.css";
9
+ import page from "page";
10
+ import * as bsn from "bootstrap.native";
11
+ import "./styles/ui.scss";
12
+
13
+ import { uiInit } from "./ui_init";
14
+ import {
15
+ handleMarkerAction,
16
+ showContextMenu,
17
+ xyToMapIDs,
18
+ setHideMarker,
19
+ checkOverlayID,
20
+ handleMarkerActionById
21
+ } from "./ui_marker";
22
+ import type { SliderNew } from "./maplat_control";
23
+ import type ContextMenu from "./contextmenu";
24
+
25
+ import type { Pixel } from "ol/pixel";
26
+ import type { Coordinate } from "ol/coordinate";
27
+ import { resolveRelativeLink, ellips } from "./ui_utils";
28
+ import type { MaplatAppOption, RestoreState, SwiperInstance } from "./types";
29
+ import { i18n, TFunction } from "i18next";
30
+
31
+ Swiper.use([Navigation, Pagination]);
32
+
33
+ export class MaplatUi extends EventTarget {
34
+ static async createObject(option: MaplatAppOption) {
35
+ const app = new MaplatUi(option);
36
+ return app.waitReady!();
37
+ }
38
+
39
+ core?: Core;
40
+ appOption: MaplatAppOption;
41
+ waitReady?: () => Promise<MaplatUi>;
42
+ waitReadyBridge?: (arg: MaplatUi) => void;
43
+ pathThatSet?: string;
44
+ swipers: Record<string, SwiperInstance> = {};
45
+ mobile_if: boolean = false;
46
+ ui_func: string = "default";
47
+ datum: string = "default";
48
+ selected_layer: string = "default";
49
+ toms: number = 0;
50
+ cache_messages: Record<string, string> = {};
51
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
52
+ last_toast: any;
53
+ share_enable!: boolean;
54
+ sliderNew!: SliderNew;
55
+ baseSwiper!: SwiperInstance;
56
+ overlaySwiper!: SwiperInstance;
57
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
58
+ sliderCommon: any;
59
+ contextMenu!: ContextMenu;
60
+ splashPromise!: Promise<void>;
61
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
62
+ _selectCandidateSources?: Record<string, any>;
63
+ appEnvelope?: boolean;
64
+ restoring: boolean = false;
65
+ poiSwiper: SwiperInstance | undefined;
66
+ html!: string;
67
+ enablePoiHtmlNoScroll: boolean = false;
68
+ enableShare: boolean = false;
69
+ enableHideMarker: boolean = false;
70
+ enableBorder: boolean = false;
71
+ enableMarkerList: boolean = false;
72
+ disableNoimage: boolean = false;
73
+ alwaysGpsOn: boolean = false;
74
+ isTouch: boolean = false;
75
+ html_id_seed: string;
76
+ lastClickPixel: Pixel | undefined;
77
+ lastClickCoordinate: Coordinate | undefined;
78
+ lastGPSError: string | undefined;
79
+ selectedMarkerNamespaceID: string | undefined;
80
+ lang = "ja";
81
+
82
+ _t?: TFunction<"translation", undefined>;
83
+ i18n?: i18n;
84
+
85
+ constructor(appOption: MaplatAppOption) {
86
+ super();
87
+ this.html_id_seed = `${Math.floor(Math.random() * 9000) + 1000}`;
88
+ this.appOption = appOption;
89
+
90
+ if (appOption.stateUrl) {
91
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
92
+ page(async (ctx: any, _next: any) => {
93
+ let pathes = ctx.canonicalPath.split("#!");
94
+ let path = pathes.length > 1 ? pathes[1] : pathes[0];
95
+
96
+ pathes = path.split("?");
97
+ path = pathes[0];
98
+ if (path === this.pathThatSet) {
99
+ delete this.pathThatSet;
100
+ return;
101
+ }
102
+ const restore: RestoreState = {
103
+ transparency: 0,
104
+ position: {
105
+ rotation: 0
106
+ }
107
+ };
108
+
109
+ path.split("/").forEach((state: string) => {
110
+ if (!state) return;
111
+ const line = state.split(":");
112
+ switch (line[0]) {
113
+ case "s":
114
+ restore.mapID = line[1];
115
+ break;
116
+ case "b":
117
+ restore.backgroundID = line[1];
118
+ break;
119
+ case "t":
120
+ restore.transparency = parseFloat(line[1]);
121
+ break;
122
+ case "r":
123
+ restore.position!.rotation = parseFloat(line[1]);
124
+ break;
125
+ case "z":
126
+ restore.position!.zoom = parseFloat(line[1]);
127
+ break;
128
+ case "x":
129
+ restore.position!.x = parseFloat(line[1]);
130
+ break;
131
+ case "y":
132
+ restore.position!.y = parseFloat(line[1]);
133
+ break;
134
+ case "sb":
135
+ restore.showBorder = !!parseInt(line[1]);
136
+ break;
137
+ case "hm":
138
+ restore.hideMarker = !!parseInt(line[1]);
139
+ break;
140
+ case "hl":
141
+ restore.hideLayer = line[1];
142
+ break;
143
+ case "om":
144
+ restore.openedMarker = line[1];
145
+ break;
146
+ case "c":
147
+ if (this.core) {
148
+ const modalElm =
149
+ this.core!.mapDivDocument!.querySelector(".modalBase")!;
150
+ const modal = new bsn.Modal(modalElm, {
151
+ root: this.core!.mapDivDocument!
152
+ });
153
+ modal.hide();
154
+ }
155
+ break;
156
+ case "mobile_if":
157
+ this.mobile_if = line[1] === "true";
158
+ break;
159
+ }
160
+ });
161
+ if (!this.core) {
162
+ if (restore.mapID) {
163
+ appOption.restore = restore;
164
+ this.restoring = true;
165
+ }
166
+ await this.initializer(appOption);
167
+ await this.core!.waitReady;
168
+ this.restoring = false;
169
+ this.updateUrl();
170
+ } else if (restore.mapID) {
171
+ this.restoring = true;
172
+ await this.core!.waitReady;
173
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
174
+ this.core!.changeMap(restore.mapID!, restore as any);
175
+
176
+ // Update transparency slider if needed
177
+ if (this.sliderNew) {
178
+ const t = restore.transparency || 0;
179
+ const val = t / 100;
180
+ this.sliderNew.set("slidervalue", val);
181
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
182
+ if ((this.sliderNew as any).element) {
183
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
184
+ (this.sliderNew as any).element.value = (1 - val).toString();
185
+ }
186
+ }
187
+
188
+ this.restoring = false;
189
+ this.updateUrl();
190
+ }
191
+ if (this.waitReadyBridge) {
192
+ this.waitReadyBridge(this);
193
+ delete this.waitReadyBridge;
194
+ }
195
+ });
196
+ page({
197
+ hashbang: true
198
+ });
199
+ this.waitReady = () =>
200
+ new Promise<MaplatUi>((resolve: (arg: MaplatUi) => void, _reject) => {
201
+ this.waitReadyBridge = resolve;
202
+ });
203
+ } else {
204
+ this.waitReady = async () => this.initializer(appOption);
205
+ }
206
+ }
207
+
208
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
209
+ async initializer(appOption: any) {
210
+ await uiInit(this, appOption);
211
+ return this as MaplatUi;
212
+ }
213
+
214
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
215
+ t(x: string, option?: any): string {
216
+ if (this._t) return this._t(x, option) as string;
217
+ return x;
218
+ }
219
+
220
+ translate(
221
+ dataFragment?: Record<string, string> | string
222
+ ): string | undefined {
223
+ if (!dataFragment || typeof dataFragment === "string")
224
+ return dataFragment as string;
225
+ const langs = Object.keys(dataFragment);
226
+
227
+ let key = langs.reduce(
228
+ (
229
+ prev: string | [string, boolean] | undefined,
230
+ curr: string,
231
+ idx: number,
232
+ arr: string[]
233
+ ) => {
234
+ if (curr == this.lang) {
235
+ prev = [dataFragment[curr], true];
236
+ } else if (!prev || (curr == "en" && !prev[1])) {
237
+ prev = [dataFragment[curr], false];
238
+ }
239
+ if (idx == arr.length - 1) return prev[0];
240
+ return prev;
241
+ },
242
+ undefined
243
+ );
244
+
245
+ key = typeof key === "string" ? key : `${key}`;
246
+ if (
247
+ this.i18n!.exists(key, { ns: "translation", nsSeparator: "__X__yX__X__" })
248
+ )
249
+ return this.t(key, { ns: "translation", nsSeparator: "__X__yX__X__" });
250
+
251
+ for (let i = 0; i < langs.length; i++) {
252
+ const lang = langs[i];
253
+ this.i18n!.addResource(lang, "translation", key, dataFragment[lang]);
254
+ }
255
+ return this.t(key, { ns: "translation", nsSeparator: "__X__yX__X__" });
256
+ }
257
+
258
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
259
+ handleMarkerAction(data: any) {
260
+ handleMarkerAction(this, data);
261
+ }
262
+
263
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
264
+ showContextMenu(list: any[]) {
265
+ showContextMenu(this, list);
266
+ }
267
+
268
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
269
+ async xyToMapIDs(xy: any, threshold = 10) {
270
+ return xyToMapIDs(this, xy, threshold);
271
+ }
272
+
273
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
274
+ setShowBorder(flag: any) {
275
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
276
+ this.core!.requestUpdateState({ showBorder: flag ? 1 : 0 } as any);
277
+ this.updateEnvelope();
278
+ if (flag) {
279
+ this.core!.mapDivDocument!.classList.add("show-border");
280
+ } else {
281
+ this.core!.mapDivDocument!.classList.remove("show-border");
282
+ }
283
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
284
+ if (this.core!.restoreSession as any) {
285
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
286
+ this.core!.requestUpdateState({ showBorder: flag ? 1 : 0 } as any);
287
+ }
288
+ }
289
+
290
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
291
+ setHideMarker(flag: any) {
292
+ setHideMarker(this, flag);
293
+ }
294
+
295
+ handleMarkerActionById(markerId: string) {
296
+ handleMarkerActionById(this, markerId);
297
+ }
298
+
299
+ updateUrl() {
300
+ if (!this.appOption.stateUrl) return;
301
+ if (this.restoring) return;
302
+
303
+ const map = this.core!.mapObject;
304
+ if (!map) return;
305
+ const view = map.getView();
306
+ const center = view.getCenter();
307
+ const zoom = view.getZoom();
308
+ const rotation = view.getRotation();
309
+
310
+ const currentMap = this.core!.from ? this.core!.from.mapID : "";
311
+ if (!currentMap) return;
312
+
313
+ // Background ID
314
+ let backMap = "";
315
+ if (this.baseSwiper) {
316
+ const slide = this.baseSwiper.slides[this.baseSwiper.activeIndex];
317
+
318
+ if (slide) {
319
+ backMap = slide.getAttribute("data") || "";
320
+ }
321
+ }
322
+
323
+ const transparency = this.sliderNew
324
+ ? this.sliderNew.get("slidervalue") * 100
325
+ : 0;
326
+
327
+ // Legacy format: s:map/b:back/... (no leading slash, prepended with #!)
328
+ let path = `s:${currentMap}`;
329
+
330
+ if (backMap && backMap !== currentMap) {
331
+ path += `/b:${backMap}`;
332
+ }
333
+
334
+ if (transparency > 0) {
335
+ path += `/t:${transparency}`;
336
+ }
337
+
338
+ path += `/x:${center[0]}`;
339
+ path += `/y:${center[1]}`;
340
+ path += `/z:${zoom}`;
341
+
342
+ if (rotation !== 0) {
343
+ path += `/r:${(rotation * 180) / Math.PI}`;
344
+ }
345
+
346
+ // Options
347
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
348
+ if ((this.core!.stateBuffer as any).showBorder) path += `/sb:1`;
349
+ if (this.core!.mapDivDocument!.classList.contains("hide-marker"))
350
+ path += `/hm:1`;
351
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
352
+ if (this.enableMarkerList && (this.core!.stateBuffer as any).markerList)
353
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
354
+ path += `/om:${(this.core!.stateBuffer as any).markerList}`;
355
+
356
+ // Add selected marker to URL
357
+ if (this.selectedMarkerNamespaceID) {
358
+ path += `/om:${this.selectedMarkerNamespaceID}`;
359
+ }
360
+
361
+ if (this.pathThatSet !== path) {
362
+ this.pathThatSet = path;
363
+ page(`#!${path}`);
364
+ }
365
+ }
366
+
367
+ updateEnvelope() {
368
+ if (!this.core!.mapObject) return;
369
+
370
+ this.core!.mapObject.resetEnvelope();
371
+ if (this._selectCandidateSources) {
372
+ for (const key of Object.keys(this._selectCandidateSources)) {
373
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
374
+ if ((this.core!.mapObject as any).removeEnvelope) {
375
+ console.log(`[Debug] Removing envelope for ${key}`);
376
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
377
+ (this.core!.mapObject as any).removeEnvelope(
378
+ this._selectCandidateSources![key]
379
+ );
380
+ }
381
+ }
382
+ }
383
+
384
+ this._selectCandidateSources = {};
385
+
386
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
387
+ if ((this.core!.stateBuffer as any).showBorder) {
388
+ if (!this.core!.from) return;
389
+
390
+ let activeOverlayId: string | null = null;
391
+ if (this.overlaySwiper) {
392
+ const slide = this.overlaySwiper.slides[this.overlaySwiper.activeIndex];
393
+ if (slide) activeOverlayId = slide.getAttribute("data");
394
+ }
395
+
396
+ Object.keys(this.core!.cacheHash!)
397
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
398
+ .filter((key: any) => this.core!.cacheHash[key].envelope)
399
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
400
+ .map((key: any) => {
401
+ const source = this.core!.cacheHash[key];
402
+ const isActive = key === activeOverlayId;
403
+
404
+ const xyPromises =
405
+ key === this.core!.from!.mapID &&
406
+ typeof source.xy2SysCoord === "function"
407
+ ? [
408
+ [0, 0],
409
+ [source.width, 0],
410
+ [source.width, source.height],
411
+ [0, source.height],
412
+ [0, 0]
413
+ ].map(xy => Promise.resolve(source.xy2SysCoord(xy)))
414
+ : // eslint-disable-next-line @typescript-eslint/no-explicit-any
415
+ source.envelope.geometry.coordinates[0].map((coord: any) =>
416
+ this.core!.from!.merc2SysCoordAsync(coord)
417
+ );
418
+
419
+ Promise.all(xyPromises).then(xys => {
420
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
421
+ const options: any = {
422
+ color: source.envelopeColor,
423
+ width: 2,
424
+ lineDash: [6, 6]
425
+ };
426
+ this.core!.mapObject.setEnvelope(xys, options);
427
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
428
+ if (isActive && (this.core!.mapObject as any).setFillEnvelope) {
429
+ console.log(`[Debug] Setting fill envelope for ${key}`);
430
+
431
+ const color = asArray(source.envelopeColor || "#000000");
432
+
433
+ color[3] = 0.4;
434
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
435
+ const fillHandle = (this.core!.mapObject as any).setFillEnvelope(
436
+ xys,
437
+ null,
438
+ { color }
439
+ );
440
+ this._selectCandidateSources![key] = fillHandle;
441
+ }
442
+ });
443
+ });
444
+ }
445
+ }
446
+
447
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
448
+ resolveRelativeLink(file: any, fallbackPath: any) {
449
+ return resolveRelativeLink(file, fallbackPath);
450
+ }
451
+
452
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
453
+ checkOverlayID(mapID: any) {
454
+ return checkOverlayID(this, mapID);
455
+ }
456
+
457
+ areaIndex(xys: number[][]) {
458
+ return (
459
+ 0.5 *
460
+ Math.abs(
461
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
462
+ [0, 1, 2, 3].reduce((prev: any, _curr: any, i: any) => {
463
+ const xy1 = xys[i];
464
+ const xy2 = xys[i + 1];
465
+ return prev + (xy1[0] - xy2[0]) * (xy1[1] + xy2[1]);
466
+ }, 0)
467
+ )
468
+ );
469
+ }
470
+
471
+ getShareUrl(type: string) {
472
+ if (type === "view") {
473
+ return window.location.href;
474
+ }
475
+ // app
476
+ return window.location.href.split("?")[0].split("#")[0];
477
+ }
478
+
479
+ showToast(message: string, target?: HTMLElement) {
480
+ let toast = document.querySelector(".custom-toast") as HTMLElement;
481
+ if (!toast) {
482
+ toast = document.createElement("div");
483
+ toast.className = "custom-toast";
484
+ document.body.appendChild(toast);
485
+ }
486
+ (toast as HTMLElement).innerText = message;
487
+
488
+ if (target) {
489
+ const parent = target.closest(".recipient");
490
+ const rect = (parent || target).getBoundingClientRect();
491
+ toast.style.position = "fixed";
492
+ toast.style.left = `${rect.left + rect.width / 2}px`;
493
+ toast.style.top = `${rect.top + rect.height / 2}px`;
494
+ toast.style.transform = "translate(-50%, -50%)";
495
+ toast.style.bottom = "auto";
496
+ toast.style.margin = "0";
497
+ } else {
498
+ toast.style.position = "fixed";
499
+ toast.style.left = "50%";
500
+ toast.style.bottom = "30px";
501
+ toast.style.top = "auto";
502
+ toast.style.transform = "";
503
+ toast.style.marginLeft = "-125px";
504
+ }
505
+
506
+ toast.classList.add("show");
507
+
508
+ setTimeout(() => {
509
+ toast!.classList.remove("show");
510
+ }, 1500);
511
+ }
512
+
513
+ modalSetting(type: string) {
514
+ const modalElm = this.core!.mapDivDocument!.querySelector(".modalBase")!;
515
+ modalElm.classList.remove(
516
+ "modal_load",
517
+ "modal_poi",
518
+ "modal_share",
519
+ "modal_help",
520
+ "modal_gpsW",
521
+ "modal_gpsD",
522
+ "modal_map",
523
+ "modal_marker_list"
524
+ );
525
+ modalElm.classList.add(`modal_${type}`);
526
+ }
527
+
528
+ ellips() {
529
+ ellips(this.core!.mapDivDocument!);
530
+ }
531
+
532
+ remove() {
533
+ this.core!.remove();
534
+ delete this.core;
535
+ }
536
+ }