@maplat/ui 0.10.0 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.js CHANGED
@@ -1,1754 +1,1754 @@
1
- import { absoluteUrl } from "./absolute_url";
2
- import { Swiper } from "./swiper_ex";
3
- import EventTarget from "ol/events/Target";
4
- import page from "../legacy/page";
5
- import bsn from "../legacy/bootstrap-native";
6
- import { MaplatApp as Core, createElement } from "@maplat/core";
7
- import ContextMenu from "./contextmenu";
8
- import iziToast from "../legacy/iziToast";
9
- import QRCode from "../legacy/qrcode";
10
- import { point, polygon } from "@turf/helpers";
11
- import booleanPointInPolygon from "@turf/boolean-point-in-polygon";
12
- import sprintf from "../legacy/sprintf";
13
- import { META_KEYS } from "@maplat/core/lib/source/mixin";
14
- import {
15
- Copyright,
16
- CompassRotate,
17
- SetGPS,
18
- GoHome,
19
- Maplat,
20
- Border,
21
- HideMarker,
22
- SliderCommon,
23
- Share,
24
- Zoom,
25
- setControlSettings
26
- } from "./maplat_control";
27
- import { asArray } from "ol/color";
28
- import { HistMap } from "@maplat/core/lib/source/histmap";
29
- import { TmsMap } from "@maplat/core/lib/source/tmsmap";
30
- import { NowMap } from "@maplat/core/lib/source/nowmap";
31
- import Weiwudi from "weiwudi";
32
- import { normalizeArg } from "./function";
33
- import pointer from "./pointer_images";
34
-
35
- // Maplat UI Class
36
- export class MaplatUi extends EventTarget {
37
- constructor(appOption) {
38
- super();
39
- appOption = normalizeArg(appOption);
40
- if (appOption.control) {
41
- setControlSettings(appOption.control);
42
- }
43
-
44
- const ui = this;
45
- ui.html_id_seed = `${Math.floor(Math.random() * 9000) + 1000}`;
46
-
47
- if (appOption.stateUrl) {
48
- page((ctx, _next) => {
49
- let pathes = ctx.canonicalPath.split("#!");
50
- let path = pathes.length > 1 ? pathes[1] : pathes[0];
51
- pathes = path.split("?");
52
- path = pathes[0];
53
- if (path === ui.pathThatSet) {
54
- delete ui.pathThatSet;
55
- return;
56
- }
57
- const restore = {
58
- transparency: 0,
59
- position: {
60
- rotation: 0
61
- }
62
- };
63
- path.split("/").map(state => {
64
- const line = state.split(":");
65
- switch (line[0]) {
66
- case "s":
67
- restore.mapID = line[1];
68
- break;
69
- case "b":
70
- restore.backgroundID = line[1];
71
- break;
72
- case "t":
73
- restore.transparency = parseFloat(line[1]);
74
- break;
75
- case "r":
76
- restore.position.rotation = parseFloat(line[1]);
77
- break;
78
- case "z":
79
- restore.position.zoom = parseFloat(line[1]);
80
- break;
81
- case "x":
82
- case "y":
83
- restore.position[line[0]] = parseFloat(line[1]);
84
- break;
85
- case "sb":
86
- restore.showBorder = !!parseInt(line[1]);
87
- break;
88
- case "hm":
89
- restore.hideMarker = !!parseInt(line[1]);
90
- break;
91
- case "hl":
92
- restore.hideLayer = line[1];
93
- break;
94
- case "c":
95
- if (ui.core) {
96
- const modalElm =
97
- ui.core.mapDivDocument.querySelector(".modalBase");
98
- const modal = new bsn.Modal(modalElm, {
99
- root: ui.core.mapDivDocument
100
- });
101
- modal.hide();
102
- }
103
- }
104
- });
105
- if (!ui.core) {
106
- if (restore.mapID) {
107
- appOption.restore = restore;
108
- }
109
- ui.initializer(appOption);
110
- } else if (restore.mapID) {
111
- ui.core.waitReady.then(() => {
112
- ui.core.changeMap(restore.mapID, restore);
113
- });
114
- }
115
- });
116
- page({
117
- hashbang: true
118
- });
119
- page();
120
- ui.waitReady = new Promise((resolve, _reject) => {
121
- ui.waitReadyBridge = resolve;
122
- });
123
- } else {
124
- ui.initializer(appOption);
125
- }
126
- }
127
-
128
- async initializer(appOption) {
129
- const ui = this;
130
- appOption.translateUI = true;
131
- ui.core = new Core(appOption);
132
- if (appOption.icon) {
133
- pointer["defaultpin.png"] = appOption.icon;
134
- }
135
-
136
- if (appOption.restore) {
137
- ui.setShowBorder(appOption.restore.showBorder || false);
138
- if (appOption.restore.hideMarker) {
139
- ui.core.mapDivDocument.classList.add("hide-marker");
140
- }
141
- } else if (appOption.restoreSession) {
142
- const lastEpoch = parseInt(localStorage.getItem("epoch") || 0); // eslint-disable-line no-undef
143
- const currentTime = Math.floor(new Date().getTime() / 1000);
144
- if (lastEpoch && currentTime - lastEpoch < 3600) {
145
- ui.setShowBorder(!!parseInt(localStorage.getItem("showBorder") || "0")); // eslint-disable-line no-undef
146
- }
147
- if (ui.core.initialRestore.hideMarker) {
148
- ui.core.mapDivDocument.classList.add("hide-marker");
149
- }
150
- } else {
151
- ui.setShowBorder(false);
152
- }
153
-
154
- const enableSplash = !ui.core.initialRestore.mapID;
155
- const restoreTransparency = ui.core.initialRestore.transparency;
156
- const enableOutOfMap = !appOption.presentation_mode;
157
-
158
- if (appOption.enableShare) {
159
- ui.core.mapDivDocument.classList.add("enable_share");
160
- ui.enableShare = true;
161
- }
162
- if (appOption.enableHideMarker) {
163
- ui.core.mapDivDocument.classList.add("enable_hide_marker");
164
- ui.enableHideMarker = true;
165
- }
166
- if (appOption.enableBorder) {
167
- ui.core.mapDivDocument.classList.add("enable_border");
168
- ui.enableBorder = true;
169
- }
170
- if (appOption.disableNoimage) {
171
- ui.disableNoimage = true;
172
- }
173
- if (appOption.stateUrl) {
174
- ui.core.mapDivDocument.classList.add("state_url");
175
- }
176
- if (ui.core.enableCache) {
177
- ui.core.mapDivDocument.classList.add("enable_cache");
178
- }
179
- if ("ontouchstart" in window) {
180
- // eslint-disable-line no-undef
181
- ui.core.mapDivDocument.classList.add("ol-touch");
182
- ui.isTouch = true;
183
- }
184
- if (appOption.mobileIF) {
185
- appOption.debug = true;
186
- }
187
- if (appOption.appEnvelope) {
188
- ui.appEnvelope = true;
189
- }
190
-
191
- let pwaManifest = appOption.pwaManifest;
192
- let pwaWorker = appOption.pwaWorker;
193
- let pwaScope = appOption.pwaScope;
194
-
195
- // Add UI HTML Element
196
- let newElems = createElement(`<d c="ol-control map-title"><s></s></d>
197
- <d c="swiper-container ol-control base-swiper prevent-default-ui">
198
- <d c="swiper-wrapper"></d>
199
- <d c="swiper-button-next base-next swiper-button-white"></d>
200
- <d c="swiper-button-prev base-prev swiper-button-white"></d>
201
- </d>
202
- <d c="swiper-container ol-control overlay-swiper prevent-default-ui">
203
- <d c="swiper-wrapper"></d>
204
- <d c="swiper-button-next overlay-next swiper-button-white"></d>
205
- <d c="swiper-button-prev overlay-prev swiper-button-white"></d>
206
- </d> `);
207
- for (let i = newElems.length - 1; i >= 0; i--) {
208
- ui.core.mapDivDocument.insertBefore(
209
- newElems[i],
210
- ui.core.mapDivDocument.firstChild
211
- );
212
- }
213
- const prevDefs = ui.core.mapDivDocument.querySelectorAll(
214
- ".prevent-default-ui"
215
- );
216
- for (let i = 0; i < prevDefs.length; i++) {
217
- const target = prevDefs[i];
218
- target.addEventListener("touchstart", evt => {
219
- evt.preventDefault();
220
- });
221
- }
222
-
223
- newElems = createElement(`<d c="modal modalBase" tabindex="-1" role="dialog"
224
- aria-labelledby="staticModalLabel" aria-hidden="true" data-show="true" data-keyboard="false"
225
- data-backdrop="static">
226
- <d c="modal-dialog">
227
- <d c="modal-content">
228
- <d c="modal-header">
229
- <button type="button" c="close" data-dismiss="modal">
230
- <s aria-hidden="true">&#215;</s><s c="sr-only" din="html.close"></s>
231
- </button>
232
- <h4 c="modal-title">
233
-
234
- <s c="modal_title"></s>
235
- <s c="modal_load_title"></s>
236
- <s c="modal_gpsW_title" din="html.acquiring_gps"></s>
237
- <s c="modal_help_title" din="html.help_title"></s>
238
- <s c="modal_share_title" din="html.share_title"></s>
239
- <s c="modal_hide_marker_title" din="html.hide_marker_title"></s>
240
-
241
- </h4>
242
- </d>
243
- <d c="modal-body">
244
-
245
- <d c="modal_help_content">
246
- <d c="help_content">
247
- <s dinh="html.help_using_maplat"></s>
248
- <p c="col-xs-12 help_img"><img src="${
249
- pointer["fullscreen.png"]
250
- }"></p>
251
- <h4 din="html.help_operation_title"></h4>
252
- <p dinh="html.help_operation_content" c="recipient"></p>
253
- <h4 din="html.help_selection_title"></h4>
254
- <p dinh="html.help_selection_content" c="recipient"></p>
255
- <h4 din="html.help_gps_title"></h4>
256
- <p dinh="html.help_gps_content" c="recipient"></p>
257
- <h4 din="html.help_poi_title"></h4>
258
- <p dinh="html.help_poi_content" c="recipient"></p>
259
- <h4 din="html.help_etc_title"></h4>
260
- <ul>
261
- <li dinh="html.help_etc_attr" c="recipient"></li>
262
- <li dinh="html.help_etc_help" c="recipient"></li>
263
- <s c="share_help"><li dinh="html.help_share_help" c="recipient"></li></s>
264
- <s c="border_help"><li dinh="html.help_etc_border" c="recipient"></li></s>
265
- <s c="hide_marker_help"><li dinh="html.help_etc_hide_marker" c="recipient"></li></s>
266
- <li dinh="html.help_etc_slider" c="recipient"></li>
267
- </ul>
268
- <p><a href="https://github.com/code4history/Maplat/wiki" target="_blank">Maplat</a>
269
- © 2015- Kohei Otsuka, Code for History</p>
270
- </d>
271
- </d>
272
-
273
- <d c="modal_poi_content">
274
- <d c="poi_web embed-responsive embed-responsive-60vh">
275
- <iframe c="poi_iframe iframe_poi" frameborder="0" src=""></iframe>
276
- </d>
277
- <d c="poi_data hide">
278
- <d c="col-xs-12 swiper-container poi_img_swiper">
279
- <d c="swiper-wrapper"></d>
280
- <d c="swiper-button-next poi-img-next"></d>
281
- <d c="swiper-button-prev poi-img-prev"></d>
282
- </d>
283
- <p c="recipient poi_address"></p>
284
- <p c="recipient poi_desc"></p>
285
- </d>
286
- </d>
287
-
288
- <d c="modal_share_content">
289
- <h4 din="html.share_app_title"></h4>
290
- <d id="___maplat_app_toast_${ui.html_id_seed}"></d>
291
- <d c="recipient row">
292
- <d c="form-group col-xs-4 text-center"><button title="Copy to clipboard" c="share btn btn-light" data="cp_app"><i c="fa fa-clipboard"></i>&nbsp;<small din="html.share_copy"></small></button></d>
293
- <d c="form-group col-xs-4 text-center"><button title="Twitter" c="share btn btn-light" data="tw_app"><i c="fa fa-twitter"></i>&nbsp;<small>Twitter</small></button></d>
294
- <d c="form-group col-xs-4 text-center"><button title="Facebook" c="share btn btn-light" data="fb_app"><i c="fa fa-facebook"></i>&nbsp;<small>Facebook</small></button></d>
295
- </d>
296
- <d c="qr_app center-block" style="width:128px;"></d>
297
- <d c="modal_share_state">
298
- <h4 din="html.share_state_title"></h4>
299
- <d id="___maplat_view_toast_${ui.html_id_seed}"></d>
300
- <d c="recipient row">
301
- <d c="form-group col-xs-4 text-center"><button title="Copy to clipboard" c="share btn btn-light" data="cp_view"><i c="fa fa-clipboard"></i>&nbsp;<small din="html.share_copy"></small></button></d>
302
- <d c="form-group col-xs-4 text-center"><button title="Twitter" c="share btn btn-light" data="tw_view"><i c="fa fa-twitter"></i>&nbsp;<small>Twitter</small></button></d>
303
- <d c="form-group col-xs-4 text-center"><button title="Facebook" c="share btn btn-light" data="fb_view"><i c="fa fa-facebook"></i>&nbsp;<small>Facebook</small></button></d>
304
- </d>
305
- <d c="qr_view center-block" style="width:128px;"></d>
306
- </d>
307
- <p><img src="" height="0px" width="0px"></p>
308
- </d>
309
-
310
- <d c="modal_map_content">
311
- ${META_KEYS.map(key => {
312
- if (key == "title" || key == "officialTitle") return "";
313
- return `<d c="recipients ${key}_div"><dl c="dl-horizontal">
314
- <dt din="html.${key}"></dt>
315
- <dd c="${key}_dd"></dd>
316
- </dl></d> `;
317
- }).join("")}
318
- <d c="recipients modal_cache_content"><dl c="dl-horizontal">
319
- <dt din="html.cache_handle"></dt>
320
- <dd><s c="cache_size"></s></dd>
321
- <dt></dt>
322
- <dd><s c="pull-right"><button c="cache_fetch btn btn-default" href="#" din="html.cache_fetch"></button>
323
- <button c="cache_delete btn btn-default" href="#" din="html.cache_delete"></button></s></dd>
324
- </dl></d>
325
- </d>
326
-
327
- <d c="modal_load_content">
328
- <p c="recipient"><img src="${
329
- pointer["loading.png"]
330
- }"><s din="html.app_loading_body"></s></p>
331
- <d c="splash_div hide row"><p c="col-xs-12 poi_img"><img c="splash_img" src=""></p></d>
332
- <p><img src="" height="0px" width="0px"></p>
333
- </d>
334
-
335
- <d c="modal_hide_marker_content">
336
- <ul c="list-group"></ul>
337
- </d>
338
-
339
- <p c="modal_gpsD_content" c="recipient"></p>
340
- <p c="modal_gpsW_content" c="recipient"></p>
341
-
342
- </d>
343
- </d>
344
- </d>
345
- </d> `);
346
- for (let i = newElems.length - 1; i >= 0; i--) {
347
- ui.core.mapDivDocument.insertBefore(
348
- newElems[i],
349
- ui.core.mapDivDocument.firstChild
350
- );
351
- }
352
-
353
- const shareBtns = ui.core.mapDivDocument.querySelectorAll(".btn.share");
354
- for (let i = 0; i < shareBtns.length; i++) {
355
- const shareBtn = shareBtns[i];
356
- shareBtn.addEventListener("click", evt => {
357
- let btn = evt.target;
358
- if (!btn.classList.contains("share")) btn = btn.parentElement;
359
- const cmd = btn.getAttribute("data");
360
- const cmds = cmd.split("_");
361
- let base = evt.target.baseURI;
362
- if (!base) base = window.location.href;
363
- const div1 = base.split("#!");
364
- const path = div1.length > 1 ? div1[1].split("?")[0] : "";
365
- const div2 = div1[0].split("?");
366
- let uri = div2[0];
367
- const query =
368
- div2.length > 1
369
- ? div2[1]
370
- .split("&")
371
- .filter(qs => qs !== "pwa")
372
- .join("&")
373
- : "";
374
-
375
- if (query) uri = `${uri}?${query}`;
376
- if (cmds[1] === "view") {
377
- if (path) uri = `${uri}#!${path}`;
378
- }
379
- if (cmds[0] === "cp") {
380
- const copyFrom = document.createElement("textarea"); // eslint-disable-line no-undef
381
- copyFrom.textContent = uri;
382
-
383
- const bodyElm = document.querySelector("body"); // eslint-disable-line no-undef
384
- bodyElm.appendChild(copyFrom);
385
-
386
- if (/iP(hone|[oa]d)/.test(navigator.userAgent)) {
387
- // eslint-disable-line no-undef
388
- const range = document.createRange(); // eslint-disable-line no-undef
389
- range.selectNode(copyFrom);
390
- window.getSelection().addRange(range); // eslint-disable-line no-undef
391
- } else {
392
- copyFrom.select();
393
- }
394
-
395
- document.execCommand("copy"); // eslint-disable-line no-undef
396
- bodyElm.removeChild(copyFrom);
397
- const toastParent = `#___maplat_${cmds[1]}_toast_${ui.html_id_seed}`;
398
- iziToast.show({
399
- message: ui.core.t("app.copy_toast", { ns: "translation" }),
400
- close: false,
401
- pauseOnHover: false,
402
- timeout: 1000,
403
- progressBar: false,
404
- target: toastParent
405
- });
406
- } else if (cmds[0] === "tw") {
407
- const twuri = `https://twitter.com/share?url=${encodeURIComponent(
408
- uri
409
- )}&hashtags=Maplat`;
410
- window.open(
411
- twuri,
412
- "_blank",
413
- "width=650,height=450,menubar=no,toolbar=no,scrollbars=yes"
414
- ); // eslint-disable-line no-undef
415
- } else if (cmds[0] === "fb") {
416
- // https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fdevelopers.facebook.com%2Fdocs%2Fplugins%2Fshare-button%2F&display=popup&ref=plugin&src=like&kid_directed_site=0&app_id=113869198637480
417
- const fburi = `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(
418
- uri
419
- )}&display=popup&ref=plugin&src=like&kid_directed_site=0`;
420
- window.open(
421
- fburi,
422
- "_blank",
423
- "width=650,height=450,menubar=no,toolbar=no,scrollbars=yes"
424
- ); // eslint-disable-line no-undef
425
- }
426
- });
427
- }
428
-
429
- // PWA対応: 非同期処理
430
- if (pwaManifest) {
431
- if (pwaManifest === true) {
432
- pwaManifest = `./pwa/${ui.core.appid}_manifest.json`;
433
- }
434
- if (!pwaWorker) {
435
- pwaWorker = "./service-worker.js";
436
- }
437
- if (!pwaScope) {
438
- pwaScope = "./";
439
- }
440
-
441
- const head = document.querySelector("head"); // eslint-disable-line no-undef
442
- if (!head.querySelector('link[rel="manifest"]')) {
443
- head.appendChild(
444
- createElement(`<link rel="manifest" href="${pwaManifest}">`)[0]
445
- );
446
- }
447
- // service workerが有効なら、service-worker.js を登録します
448
- try {
449
- Weiwudi.registerSW(pwaWorker, { scope: pwaScope });
450
- } catch (e) {} // eslint-disable-line no-empty
451
-
452
- if (!head.querySelector('link[rel="apple-touch-icon"]')) {
453
- const xhr = new XMLHttpRequest(); // eslint-disable-line no-undef
454
- xhr.open("GET", pwaManifest, true);
455
- xhr.responseType = "json";
456
-
457
- xhr.onload = function (_e) {
458
- let value = this.response;
459
- if (!value) return;
460
- if (typeof value != "object") value = JSON.parse(value);
461
-
462
- if (value.icons) {
463
- for (let i = 0; i < value.icons.length; i++) {
464
- const src = absoluteUrl(pwaManifest, value.icons[i].src);
465
- const sizes = value.icons[i].sizes;
466
- const tag = `<link rel="apple-touch-icon" sizes="${sizes}" href="${src}">`;
467
- head.appendChild(createElement(tag)[0]);
468
- }
469
- }
470
- };
471
- xhr.send();
472
- }
473
- }
474
-
475
- ui.core.addEventListener("uiPrepare", _evt => {
476
- const imageExtractor = function (text) {
477
- const regexp = /\$\{([a-zA-Z0-9_\.\/\-]+)\}/g; // eslint-disable-line no-useless-escape
478
- let ret = text;
479
- let match;
480
- while ((match = regexp.exec(text)) != null) {
481
- ret = ret.replace(match[0], pointer[match[1]]);
482
- }
483
- return ret;
484
- };
485
- let i18nTargets = ui.core.mapDivDocument.querySelectorAll("[data-i18n]");
486
- for (let i = 0; i < i18nTargets.length; i++) {
487
- const target = i18nTargets[i];
488
- const key = target.getAttribute("data-i18n");
489
- target.innerText = imageExtractor(ui.core.t(key));
490
- }
491
- i18nTargets = ui.core.mapDivDocument.querySelectorAll("[data-i18n-html]");
492
- for (let i = 0; i < i18nTargets.length; i++) {
493
- const target = i18nTargets[i];
494
- const key = target.getAttribute("data-i18n-html");
495
- target.innerHTML = imageExtractor(ui.core.t(key));
496
- }
497
-
498
- const options = {
499
- reverse: true,
500
- tipLabel: ui.core.t("control.trans", { ns: "translation" })
501
- };
502
- if (restoreTransparency) {
503
- options.initialValue = restoreTransparency / 100;
504
- }
505
- ui.sliderCommon = new SliderCommon(options);
506
- ui.core.appData.controls = [
507
- new Copyright({
508
- tipLabel: ui.core.t("control.info", { ns: "translation" })
509
- }),
510
- new CompassRotate({
511
- tipLabel: ui.core.t("control.compass", { ns: "translation" })
512
- }),
513
- new Zoom({
514
- tipLabel: ui.core.t("control.zoom", { ns: "translation" })
515
- }),
516
- new SetGPS({
517
- tipLabel: ui.core.t("control.gps", { ns: "translation" })
518
- }),
519
- new GoHome({
520
- tipLabel: ui.core.t("control.home", { ns: "translation" })
521
- }),
522
- ui.sliderCommon,
523
- new Maplat({
524
- tipLabel: ui.core.t("control.help", { ns: "translation" })
525
- })
526
- ];
527
- if (ui.enableShare) {
528
- ui.core.appData.controls.push(
529
- new Share({
530
- tipLabel: ui.core.t("control.share", { ns: "translation" })
531
- })
532
- );
533
- }
534
- if (ui.enableBorder) {
535
- ui.core.appData.controls.push(
536
- new Border({
537
- tipLabel: ui.core.t("control.border", { ns: "translation" })
538
- })
539
- );
540
- }
541
- if (ui.enableHideMarker) {
542
- ui.core.appData.controls.push(
543
- new HideMarker({
544
- tipLabel: ui.core.t("control.hide_marker", { ns: "translation" })
545
- })
546
- );
547
- }
548
-
549
- // Contextmenu
550
- ui.contextMenu = new ContextMenu({
551
- eventType: "__dummy__",
552
- width: 170,
553
- defaultItems: false,
554
- items: []
555
- });
556
- ui.core.appData.controls.push(ui.contextMenu);
557
-
558
- if (ui.core.mapObject) {
559
- ui.core.appData.controls.map(control => {
560
- ui.core.mapObject.addControl(control);
561
- });
562
- }
563
-
564
- ui.sliderCommon.on("propertychange", evt => {
565
- if (evt.key === "slidervalue") {
566
- ui.core.setTransparency(ui.sliderCommon.get(evt.key) * 100);
567
- }
568
- });
569
-
570
- if (enableSplash) {
571
- // Check Splash data
572
- let splash = false;
573
- if (ui.core.appData.splash) splash = true;
574
-
575
- const modalElm = ui.core.mapDivDocument.querySelector(".modalBase");
576
- const modal = new bsn.Modal(modalElm, { root: ui.core.mapDivDocument });
577
- ui.core.mapDivDocument.querySelector(".modal_load_title").innerText =
578
- ui.core.translate(ui.core.appData.appName);
579
- if (splash) {
580
- ui.core.mapDivDocument
581
- .querySelector(".splash_img")
582
- .setAttribute("src", `img/${ui.core.appData.splash}`);
583
- ui.core.mapDivDocument
584
- .querySelector(".splash_div")
585
- .classList.remove("hide");
586
- }
587
- ui.modalSetting("load");
588
- modal.show();
589
-
590
- const fadeTime = splash ? 1000 : 200;
591
- ui.splashPromise = new Promise(resolve => {
592
- setTimeout(() => {
593
- // eslint-disable-line no-undef
594
- resolve();
595
- }, fadeTime);
596
- });
597
- }
598
-
599
- document.querySelector("title").innerHTML = ui.core.translate(
600
- ui.core.appName
601
- ); // eslint-disable-line no-undef
602
- });
603
-
604
- ui.core.addEventListener("sourceLoaded", evt => {
605
- const sources = evt.detail;
606
-
607
- const colors = [
608
- "maroon",
609
- "deeppink",
610
- "indigo",
611
- "olive",
612
- "royalblue",
613
- "red",
614
- "hotpink",
615
- "green",
616
- "yellow",
617
- "navy",
618
- "saddlebrown",
619
- "fuchsia",
620
- "darkslategray",
621
- "yellowgreen",
622
- "blue",
623
- "mediumvioletred",
624
- "purple",
625
- "lime",
626
- "darkorange",
627
- "teal",
628
- "crimson",
629
- "darkviolet",
630
- "darkolivegreen",
631
- "steelblue",
632
- "aqua"
633
- ];
634
- const appBbox = [];
635
- let cIndex = 0;
636
- for (let i = 0; i < sources.length; i++) {
637
- const source = sources[i];
638
- if (source.envelope) {
639
- if (ui.appEnvelope)
640
- source.envelope.geometry.coordinates[0].map(xy => {
641
- if (appBbox.length === 0) {
642
- appBbox[0] = appBbox[2] = xy[0];
643
- appBbox[1] = appBbox[3] = xy[1];
644
- } else {
645
- if (xy[0] < appBbox[0]) appBbox[0] = xy[0];
646
- if (xy[0] > appBbox[2]) appBbox[2] = xy[0];
647
- if (xy[1] < appBbox[1]) appBbox[1] = xy[1];
648
- if (xy[1] > appBbox[3]) appBbox[3] = xy[1];
649
- }
650
- });
651
- source.envelopeColor = colors[cIndex];
652
- cIndex = cIndex + 1;
653
- if (cIndex === colors.length) cIndex = 0;
654
-
655
- const xys = source.envelope.geometry.coordinates[0];
656
- // http://blog.arq.name/wp-content/uploads/2018/02/Rectangle_Area.pdf
657
- source.envelopeAreaIndex = ui.areaIndex(xys);
658
- }
659
- }
660
- if (ui.appEnvelope) console.log(`This app's envelope is: ${appBbox}`);
661
-
662
- if (ui.splashPromise) {
663
- ui.splashPromise.then(() => {
664
- const modalElm = ui.core.mapDivDocument.querySelector(".modalBase");
665
- const modal = new bsn.Modal(modalElm, {
666
- root: ui.core.mapDivDocument
667
- });
668
- ui.modalSetting("load");
669
- modal.hide();
670
- });
671
- }
672
-
673
- const baseSources = [];
674
- const overlaySources = [];
675
- for (let i = 0; i < sources.length; i++) {
676
- const source = sources[i];
677
- if (source instanceof NowMap && !(source instanceof TmsMap)) {
678
- baseSources.push(source);
679
- } else {
680
- overlaySources.push(source);
681
- }
682
- }
683
-
684
- const baseSwiper = (ui.baseSwiper = new Swiper(".base-swiper", {
685
- slidesPerView: 2,
686
- spaceBetween: 15,
687
- breakpoints: {
688
- // when window width is <= 480px
689
- 480: {
690
- slidesPerView: 1.4,
691
- spaceBetween: 10
692
- }
693
- },
694
- centeredSlides: true,
695
- threshold: 2,
696
- loop: baseSources.length >= 2,
697
- navigation: {
698
- nextEl: ".base-next",
699
- prevEl: ".base-prev"
700
- }
701
- }));
702
- baseSwiper.on("click", _e => {
703
- if (!baseSwiper.clickedSlide) return;
704
- const slide = baseSwiper.clickedSlide;
705
- ui.core.changeMap(slide.getAttribute("data"));
706
- delete ui._selectCandidateSources;
707
- baseSwiper.setSlideIndexAsSelected(
708
- slide.getAttribute("data-swiper-slide-index")
709
- );
710
- });
711
- if (baseSources.length < 2) {
712
- ui.core.mapDivDocument
713
- .querySelector(".base-swiper")
714
- .classList.add("single-map");
715
- }
716
- const overlaySwiper = (ui.overlaySwiper = new Swiper(".overlay-swiper", {
717
- slidesPerView: 2,
718
- spaceBetween: 15,
719
- breakpoints: {
720
- // when window width is <= 480px
721
- 480: {
722
- slidesPerView: 1.4,
723
- spaceBetween: 10
724
- }
725
- },
726
- centeredSlides: true,
727
- threshold: 2,
728
- loop: overlaySources.length >= 2,
729
- navigation: {
730
- nextEl: ".overlay-next",
731
- prevEl: ".overlay-prev"
732
- }
733
- }));
734
- overlaySwiper.on("click", _e => {
735
- if (!overlaySwiper.clickedSlide) return;
736
- const slide = overlaySwiper.clickedSlide;
737
- ui.core.changeMap(slide.getAttribute("data"));
738
- delete ui._selectCandidateSources;
739
- overlaySwiper.setSlideIndexAsSelected(
740
- slide.getAttribute("data-swiper-slide-index")
741
- );
742
- });
743
- if (overlaySources.length < 2) {
744
- ui.core.mapDivDocument
745
- .querySelector(".overlay-swiper")
746
- .classList.add("single-map");
747
- }
748
-
749
- for (let i = 0; i < baseSources.length; i++) {
750
- const source = baseSources[i];
751
- baseSwiper.appendSlide(
752
- `<div class="swiper-slide" data="${source.mapID}">` +
753
- `<img crossorigin="anonymous" src="${
754
- source.thumbnail
755
- }"><div> ${ui.core.translate(source.label)}</div> </div> `
756
- );
757
- }
758
- for (let i = 0; i < overlaySources.length; i++) {
759
- const source = overlaySources[i];
760
- const colorCss = source.envelope ? ` ${source.envelopeColor}` : "";
761
- overlaySwiper.appendSlide(
762
- `<div class="swiper-slide${colorCss}" data="${source.mapID}">` +
763
- `<img crossorigin="anonymous" src="${
764
- source.thumbnail
765
- }"><div> ${ui.core.translate(source.label)}</div> </div> `
766
- );
767
- }
768
-
769
- baseSwiper.on;
770
- overlaySwiper.on;
771
- baseSwiper.slideToLoop(0);
772
- overlaySwiper.slideToLoop(0);
773
- ui.ellips();
774
- });
775
-
776
- ui.core.addEventListener("mapChanged", evt => {
777
- const map = evt.detail;
778
-
779
- ui.baseSwiper.setSlideMapID(map.mapID);
780
- ui.overlaySwiper.setSlideMapID(map.mapID);
781
-
782
- const title = map.officialTitle || map.title || map.label;
783
- ui.core.mapDivDocument.querySelector(".map-title span").innerText =
784
- ui.core.translate(title);
785
-
786
- if (ui.checkOverlayID(map.mapID)) {
787
- ui.sliderCommon.setEnable(true);
788
- } else {
789
- ui.sliderCommon.setEnable(false);
790
- }
791
- const transparency = ui.sliderCommon.get("slidervalue") * 100;
792
- ui.core.mapObject.setTransparency(transparency);
793
-
794
- ui.updateEnvelope();
795
- });
796
-
797
- ui.core.addEventListener("poi_number", evt => {
798
- const number = evt.detail;
799
- if (number) {
800
- ui.core.mapDivDocument.classList.remove("no_poi");
801
- } else {
802
- ui.core.mapDivDocument.classList.add("no_poi");
803
- }
804
- });
805
-
806
- ui.core.addEventListener("outOfMap", _evt => {
807
- if (enableOutOfMap) {
808
- ui.core.mapDivDocument.querySelector(".modal_title").innerText =
809
- ui.core.t("app.out_of_map");
810
- ui.core.mapDivDocument.querySelector(".modal_gpsD_content").innerText =
811
- ui.core.t("app.out_of_map_area");
812
- const modalElm = ui.core.mapDivDocument.querySelector(".modalBase");
813
- const modal = new bsn.Modal(modalElm, { root: ui.core.mapDivDocument });
814
- ui.modalSetting("gpsD");
815
- modal.show();
816
- }
817
- });
818
-
819
- ui.core.mapDivDocument.addEventListener("mouseout", _evt => {
820
- if (ui._selectCandidateSources) {
821
- Object.keys(ui._selectCandidateSources).forEach(key =>
822
- ui.core.mapObject.removeEnvelope(ui._selectCandidateSources[key])
823
- );
824
- delete ui._selectCandidateSources;
825
- }
826
- });
827
-
828
- ui.core.addEventListener("pointerMoveOnMapXy", async evt => {
829
- if (!ui.core.stateBuffer.showBorder) {
830
- if (ui._selectCandidateSources) {
831
- Object.keys(ui._selectCandidateSources).forEach(key =>
832
- ui.core.mapObject.removeEnvelope(ui._selectCandidateSources[key])
833
- );
834
- delete ui._selectCandidateSources;
835
- }
836
- return;
837
- }
838
-
839
- const mapIDs = await ui.xyToMapIDs(evt.detail);
840
- ui.showFillEnvelope(mapIDs);
841
- });
842
-
843
- ui.core.addEventListener("clickMapXy", async evt => {
844
- if (!ui.core.stateBuffer.showBorder) {
845
- return;
846
- }
847
-
848
- const mapIDs = await ui.xyToMapIDs(evt.detail);
849
- if (mapIDs.length > 0) {
850
- let currentID;
851
- showContextMenu(
852
- mapIDs.map(mapID => {
853
- const source = ui.core.cacheHash[mapID];
854
- const hexColor = source.envelopeColor;
855
- let iconSVG = `<?xml version="1.0" encoding="utf-8"?><svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
856
- x="0px" y="0px" width="10px" height="10px" viewBox="0 0 10 10"
857
- enable-background="new 0 0 10 10" xml:space="preserve">
858
- <polygon x="0" y="0" points="2,2 2,8 8,8 8,2
859
- 2,2" stroke="${hexColor}" fill="${hexColor}" stroke-width="2" style="fill-opacity: .25;"></polygon></svg>`;
860
- iconSVG = `data:image/svg+xml,${encodeURIComponent(iconSVG)}`;
861
- return {
862
- icon: iconSVG,
863
- text: ui.core.translate(source.title),
864
- callback: () => {
865
- const lis = [
866
- ...ui.core.mapDivDocument.querySelectorAll(
867
- ".ol-ctx-menu-container ul li"
868
- )
869
- ];
870
- lis.forEach(li => li.classList.remove("selected"));
871
- if (currentID && currentID === mapID) {
872
- delete ui._selectCandidateSources;
873
- ui.core.changeMap(mapID);
874
- } else {
875
- currentID = mapID;
876
- ui.showFillEnvelope([mapID]);
877
- ui.overlaySwiper.slideToMapID(mapID);
878
- const index = mapIDs.indexOf(mapID);
879
- if (index > -1) {
880
- const li = lis[index];
881
- li.classList.add("selected");
882
- }
883
- return true;
884
- }
885
- },
886
- mouseOnTask(_evt) {
887
- if (!ui.isTouch) {
888
- currentID = mapID;
889
- ui.showFillEnvelope([mapID]);
890
- ui.overlaySwiper.slideToMapID(mapID);
891
- }
892
- },
893
- mouseOutTask(_evt) {
894
- if (!ui.isTouch) {
895
- currentID = undefined;
896
- ui.showFillEnvelope([]);
897
- }
898
- }
899
- };
900
- })
901
- );
902
- ui.showFillEnvelope(mapIDs);
903
- }
904
- });
905
-
906
- function showContextMenu(menues) {
907
- ui.contextMenu.clear();
908
- const mouseOnTasks = [];
909
- menues.forEach(menu => {
910
- ui.contextMenu.push(menu);
911
- if (menu.mouseOnTask)
912
- mouseOnTasks.push([menu.mouseOnTask, menu.mouseOutTask]);
913
- });
914
-
915
- const coordinate = ui.core.lastClickEvent.coordinate;
916
- const pixel = ui.core.lastClickEvent.pixel;
917
-
918
- if (ui.contextMenu.disabled) return;
919
-
920
- const openHandler = () => {
921
- ui.contextMenu.removeEventListener("open", openHandler);
922
- if (mouseOnTasks.length > 0) {
923
- const lis = [
924
- ...ui.core.mapDivDocument.querySelectorAll(
925
- ".ol-ctx-menu-container ul li"
926
- )
927
- ];
928
- const events = lis.map((li, i) => {
929
- const tasks = mouseOnTasks[i];
930
- li.addEventListener("mouseover", tasks[0]);
931
- li.addEventListener("mouseout", tasks[1]);
932
- return [li, tasks[0], tasks[1]];
933
- });
934
- const closeHandler = () => {
935
- ui.contextMenu.removeEventListener("close", closeHandler);
936
- events.forEach(event => {
937
- event[0].removeEventListener("mouseover", event[1]);
938
- event[0].removeEventListener("mouseout", event[2]);
939
- });
940
- };
941
- ui.contextMenu.on("close", closeHandler);
942
- }
943
- };
944
- ui.contextMenu.on("open", openHandler);
945
- ui.contextMenu.Internal.openMenu(pixel, coordinate);
946
-
947
- //one-time fire
948
- ui.core.mapObject.getViewport().addEventListener(
949
- "pointerdown",
950
- {
951
- handleEvent(e) {
952
- if (ui.contextMenu.Internal.opened) {
953
- ui.contextMenu.Internal.closeMenu();
954
- e.stopPropagation();
955
- ui.core.mapObject
956
- .getViewport()
957
- .removeEventListener(e.type, this, false);
958
- }
959
- }
960
- },
961
- false
962
- );
963
- }
964
-
965
- ui.core.addEventListener("clickMarkers", evt => {
966
- const data = evt.detail;
967
- if (data.length === 1) {
968
- ui.handleMarkerAction(data[0]);
969
- } else {
970
- showContextMenu(
971
- data.map(datum => ({
972
- icon: datum.icon || pointer["defaultpin.png"],
973
- text: ui.core.translate(datum.name),
974
- callback() {
975
- ui.handleMarkerAction(datum);
976
- }
977
- }))
978
- );
979
- }
980
- });
981
-
982
- if (appOption.stateUrl) {
983
- ui.core.addEventListener("updateState", evt => {
984
- const value = evt.detail;
985
- if (!value.position || !value.mapID) return;
986
- let link = `s:${value.mapID}`;
987
- if (value.backgroundID) link = `${link}/b:${value.backgroundID}`;
988
- if (value.transparency) link = `${link}/t:${value.transparency}`;
989
- link = `${link}/x:${value.position.x}/y:${value.position.y}`;
990
- link = `${link}/z:${value.position.zoom}`;
991
- if (value.position.rotation)
992
- link = `${link}/r:${value.position.rotation}`;
993
- if (value.showBorder) link = `${link}/sb:${value.showBorder}`;
994
- if (value.hideMarker) link = `${link}/hm:${value.hideMarker}`;
995
- if (value.hideLayer) link = `${link}/hl:${value.hideLayer}`;
996
-
997
- ui.pathThatSet = link;
998
- page(link);
999
- });
1000
- }
1001
-
1002
- ui.waitReady = ui.core.waitReady.then(() => {
1003
- const fakeGps = appOption.fake ? ui.core.appData.fake_gps : false;
1004
- const fakeCenter = appOption.fake ? ui.core.appData.fake_center : false;
1005
- const fakeRadius = appOption.fake ? ui.core.appData.fake_radius : false;
1006
-
1007
- let shown = false;
1008
- let gpsWaitPromise = null;
1009
- function showGPSresult(result) {
1010
- if (result && result.error) {
1011
- ui.core.currentPosition = null;
1012
- if (result.error === "gps_out" && shown) {
1013
- shown = false;
1014
- const modalElm = ui.core.mapDivDocument.querySelector(".modalBase");
1015
- const modal = new bsn.Modal(modalElm, {
1016
- root: ui.core.mapDivDocument
1017
- });
1018
- ui.core.mapDivDocument.querySelector(".modal_title").innerText =
1019
- ui.core.t("app.out_of_map");
1020
- ui.core.mapDivDocument.querySelector(
1021
- ".modal_gpsD_content"
1022
- ).innerText = ui.core.t("app.out_of_map_desc");
1023
- ui.modalSetting("gpsD");
1024
- modal.show();
1025
- }
1026
- } else {
1027
- ui.core.currentPosition = result;
1028
- }
1029
- if (shown) {
1030
- shown = false;
1031
- const modalElm = ui.core.mapDivDocument.querySelector(".modalBase");
1032
- const modal = new bsn.Modal(modalElm, {
1033
- root: ui.core.mapDivDocument
1034
- });
1035
- modal.hide();
1036
- }
1037
- }
1038
- ui.core.mapObject.on("gps_request", () => {
1039
- gpsWaitPromise = "gps_request";
1040
- const promises = [
1041
- new Promise(resolve => {
1042
- if (gpsWaitPromise !== "gps_request") {
1043
- resolve(gpsWaitPromise);
1044
- } else gpsWaitPromise = resolve;
1045
- })
1046
- ];
1047
- shown = true;
1048
- const modalElm = ui.core.mapDivDocument.querySelector(".modalBase");
1049
- const modal = new bsn.Modal(modalElm, { root: ui.core.mapDivDocument });
1050
- ui.modalSetting("gpsW");
1051
- modal.show();
1052
- // 200m秒以上最低待たないと、Modalがうまく動かない場合がある
1053
- promises.push(
1054
- new Promise(resolve => {
1055
- setTimeout(resolve, 200); // eslint-disable-line no-undef
1056
- })
1057
- );
1058
- Promise.all(promises).then(results => {
1059
- showGPSresult(results[0]);
1060
- });
1061
- });
1062
- ui.core.mapObject.on("gps_result", evt => {
1063
- if (gpsWaitPromise === "gps_request") {
1064
- gpsWaitPromise = evt.frameState;
1065
- } else if (gpsWaitPromise) {
1066
- gpsWaitPromise(evt.frameState);
1067
- gpsWaitPromise = null;
1068
- } else if (!shown) {
1069
- showGPSresult(evt.frameState);
1070
- }
1071
- });
1072
-
1073
- let qr_app;
1074
- let qr_view;
1075
- ui.core.mapObject.on("click_control", async evt => {
1076
- const control = evt.frameState.control;
1077
- const modalElm = ui.core.mapDivDocument.querySelector(".modalBase");
1078
- const modal = new bsn.Modal(modalElm, { root: ui.core.mapDivDocument });
1079
- if (control === "copyright") {
1080
- const from = ui.core.getMapMeta();
1081
-
1082
- if (
1083
- !META_KEYS.reduce((prev, curr) => {
1084
- if (curr === "title") return prev;
1085
- return from[curr] || prev;
1086
- }, false)
1087
- )
1088
- return;
1089
-
1090
- ui.core.mapDivDocument.querySelector(".modal_title").innerText =
1091
- ui.core.translate(from.officialTitle || from.title);
1092
- META_KEYS.map(key => {
1093
- if (key === "title" || key === "officialTitle") return;
1094
- if (!from[key] || from[key] === "") {
1095
- ui.core.mapDivDocument
1096
- .querySelector(`.${key}_div`)
1097
- .classList.add("hide");
1098
- } else {
1099
- ui.core.mapDivDocument
1100
- .querySelector(`.${key}_div`)
1101
- .classList.remove("hide");
1102
- ui.core.mapDivDocument.querySelector(`.${key}_dd`).innerHTML =
1103
- key === "license" || key === "dataLicense"
1104
- ? `<img src="${
1105
- pointer[
1106
- `${from[key].toLowerCase().replace(/ /g, "_")}.png`
1107
- ]
1108
- }">`
1109
- : ui.core.translate(from[key]);
1110
- }
1111
- });
1112
-
1113
- const deleteButton =
1114
- ui.core.mapDivDocument.querySelector(".cache_delete"); // eslint-disable-line no-undef
1115
- const fetchButton =
1116
- ui.core.mapDivDocument.querySelector(".cache_fetch"); // eslint-disable-line no-undef
1117
- const putTileCacheStats = function (stats) {
1118
- let size = stats.size || 0;
1119
- let unit = "Bytes";
1120
- if (size !== -1) {
1121
- if (size > 1024) {
1122
- size = Math.round((size * 10) / 1024) / 10;
1123
- unit = "KBytes";
1124
- }
1125
- if (size > 1024) {
1126
- size = Math.round((size * 10) / 1024) / 10;
1127
- unit = "MBytes";
1128
- }
1129
- if (size > 1024) {
1130
- size = Math.round((size * 10) / 1024) / 10;
1131
- unit = "GBytes";
1132
- }
1133
- }
1134
- let content =
1135
- size === -1
1136
- ? ui.core.t("html.cache_processing")
1137
- : `${size} ${unit}`;
1138
- if (stats.total) {
1139
- content = `${content} (${stats.count} / ${stats.total} tiles [${stats.percent}%])`;
1140
- } else {
1141
- content = `${content} (${stats.count} tiles)`;
1142
- }
1143
- ui.core.mapDivDocument.querySelector(".cache_size").innerHTML =
1144
- content;
1145
- if (stats.count != 0) {
1146
- deleteButton.removeAttribute("disabled");
1147
- } else {
1148
- deleteButton.setAttribute("disabled", true);
1149
- }
1150
- if (stats.total) {
1151
- fetchButton.classList.remove("hide");
1152
- if (stats.total === stats.count) {
1153
- fetchButton.setAttribute("disabled", true);
1154
- } else {
1155
- fetchButton.removeAttribute("disabled");
1156
- }
1157
- } else {
1158
- fetchButton.classList.add("hide");
1159
- }
1160
- };
1161
- ui.modalSetting("map");
1162
-
1163
- const cacheDiv = ui.core.mapDivDocument.querySelector(
1164
- ".modal_cache_content"
1165
- );
1166
- const cacheEnable = ui.core.getMapCacheEnable(from.mapID);
1167
-
1168
- if (cacheEnable) {
1169
- cacheDiv.classList.remove("hide");
1170
- const deleteFunc = async function (evt) {
1171
- evt.preventDefault();
1172
- const from = ui.core.getMapMeta();
1173
- await ui.core.clearMapTileCacheAsync(from.mapID);
1174
- putTileCacheStats(
1175
- await ui.core.getMapTileCacheStatsAsync(from.mapID)
1176
- );
1177
- };
1178
- const cancelFunc = async function (evt) {
1179
- if (evt) evt.preventDefault();
1180
- const from = ui.core.getMapMeta();
1181
- await ui.core.cancelMapTileCacheAsync(from.mapID);
1182
- };
1183
- const fetchFunc = async function (evt) {
1184
- const closeButton =
1185
- ui.core.mapDivDocument.querySelector(".close");
1186
- evt.preventDefault();
1187
- fetchButton.innerHTML = ui.core.t("html.cache_cancel");
1188
- fetchButton.removeEventListener("click", fetchFunc);
1189
- fetchButton.addEventListener("click", cancelFunc);
1190
- closeButton.classList.add("temp_no_close");
1191
- const from = ui.core.getMapMeta();
1192
- await ui.core.fetchAllMapTileCacheAsync(
1193
- from.mapID,
1194
- async (type, data) => {
1195
- switch (type) {
1196
- case "proceed":
1197
- putTileCacheStats({
1198
- count: data.processed,
1199
- total: data.total,
1200
- percent: data.percent,
1201
- size: -1
1202
- });
1203
- return;
1204
- case "canceled":
1205
- case "stop":
1206
- case "finish":
1207
- fetchButton.innerHTML = ui.core.t("html.cache_fetch");
1208
- fetchButton.removeEventListener("click", cancelFunc);
1209
- fetchButton.addEventListener("click", fetchFunc);
1210
- closeButton.classList.remove("temp_no_close");
1211
- putTileCacheStats(
1212
- await ui.core.getMapTileCacheStatsAsync(from.mapID)
1213
- );
1214
- }
1215
- }
1216
- );
1217
- };
1218
- const hideFunc = function (_event) {
1219
- deleteButton.removeEventListener("click", deleteFunc, false);
1220
- fetchButton.removeEventListener("click", fetchFunc, false);
1221
- fetchButton.removeEventListener("click", cancelFunc, false);
1222
- modalElm.removeEventListener("hide.bs.modal", hideFunc, false);
1223
- };
1224
- modalElm.addEventListener("hide.bs.modal", hideFunc, false);
1225
-
1226
- putTileCacheStats(
1227
- await ui.core.getMapTileCacheStatsAsync(from.mapID)
1228
- );
1229
-
1230
- setTimeout(() => {
1231
- // eslint-disable-line no-undef
1232
- deleteButton.addEventListener("click", deleteFunc, false);
1233
- fetchButton.addEventListener("click", fetchFunc, false);
1234
- fetchButton.innerHTML = ui.core.t("html.cache_fetch");
1235
- }, 200);
1236
- } else {
1237
- cacheDiv.classList.add("hide");
1238
- }
1239
- modal.show();
1240
- } else if (control === "help") {
1241
- ui.modalSetting("help");
1242
- modal.show();
1243
- } else if (control === "share") {
1244
- ui.modalSetting("share");
1245
-
1246
- const base = location.href; // eslint-disable-line no-undef
1247
- const div1 = base.split("#!");
1248
- const path = div1.length > 1 ? div1[1].split("?")[0] : "";
1249
- const div2 = div1[0].split("?");
1250
- let uri = div2[0];
1251
- const query =
1252
- div2.length > 1
1253
- ? div2[1]
1254
- .split("&")
1255
- .filter(qs => qs !== "pwa")
1256
- .join("&")
1257
- : "";
1258
-
1259
- if (query) uri = `${uri}?${query}`;
1260
- let view = uri;
1261
- if (path) view = `${view}#!${path}`;
1262
- if (!qr_app) {
1263
- qr_app = new QRCode(
1264
- ui.core.mapDivDocument.querySelector(".qr_app"),
1265
- {
1266
- text: uri,
1267
- width: 128,
1268
- height: 128,
1269
- colorDark: "#000000",
1270
- colorLight: "#ffffff",
1271
- correctLevel: QRCode.CorrectLevel.H
1272
- }
1273
- );
1274
- } else {
1275
- qr_app.makeCode(uri);
1276
- }
1277
- if (!qr_view) {
1278
- qr_view = new QRCode(
1279
- ui.core.mapDivDocument.querySelector(".qr_view"),
1280
- {
1281
- text: view,
1282
- width: 128,
1283
- height: 128,
1284
- colorDark: "#000000",
1285
- colorLight: "#ffffff",
1286
- correctLevel: QRCode.CorrectLevel.H
1287
- }
1288
- );
1289
- } else {
1290
- qr_view.makeCode(view);
1291
- }
1292
-
1293
- modal.show();
1294
- } else if (control === "border") {
1295
- const flag = !ui.core.stateBuffer.showBorder;
1296
- ui.setShowBorder(flag);
1297
- } else if (control === "hideMarker") {
1298
- const flag = !ui.core.stateBuffer.hideMarker;
1299
- ui.setHideMarker(flag);
1300
- } else if (control === "hideLayer") {
1301
- ui.modalSetting("hide_marker");
1302
- const layers = ui.core.listPoiLayers(false, true);
1303
- const elem = ui.core.mapDivDocument.querySelector("ul.list-group");
1304
- const modalElm = ui.core.mapDivDocument.querySelector(".modalBase");
1305
- elem.innerHTML = "";
1306
- layers.map((layer, index) => {
1307
- const icon = layer.icon || pointer["defaultpin.png"];
1308
- const title = ui.core.translate(layer.name);
1309
- const check = !layer.hide;
1310
- const id = layer.namespaceID;
1311
- const newElems = createElement(`<li c="list-group-item">
1312
- <d c="row">
1313
- <d c="col-sm-1"><img c="markerlist" src="${icon}"></d>
1314
- <d c="col-sm-9">${title}</d>
1315
- <d c="col-sm-2">
1316
- <input type="checkbox" c="markerlist" data="${id}" id="___maplat_marker_${index}_${
1317
- ui.html_id_seed
1318
- }"${check ? " checked" : ""}/>
1319
- <label c="check" for="___maplat_marker_${index}_${
1320
- ui.html_id_seed
1321
- }"><d> </d> </label>
1322
- </d>
1323
- </d>
1324
- </li>`);
1325
- for (let i = 0; i < newElems.length; i++) {
1326
- elem.appendChild(newElems[i]);
1327
- }
1328
- const checkbox = ui.core.mapDivDocument.querySelector(
1329
- `#___maplat_marker_${index}_${ui.html_id_seed}`
1330
- );
1331
- const checkFunc = function (event) {
1332
- const id = event.target.getAttribute("data");
1333
- const checked = event.target.checked;
1334
- if (checked) ui.core.showPoiLayer(id);
1335
- else ui.core.hidePoiLayer(id);
1336
- };
1337
- const hideFunc = function (_event) {
1338
- modalElm.removeEventListener("hide.bs.modal", hideFunc, false);
1339
- checkbox.removeEventListener("change", checkFunc, false);
1340
- };
1341
- modalElm.addEventListener("hide.bs.modal", hideFunc, false);
1342
- checkbox.addEventListener("change", checkFunc, false);
1343
- });
1344
- modal.show();
1345
- }
1346
- });
1347
- if (fakeGps) {
1348
- const newElem = createElement(
1349
- sprintf(
1350
- ui.core.t("app.fake_explanation"),
1351
- ui.core.translate(fakeCenter),
1352
- fakeRadius
1353
- )
1354
- )[0];
1355
- const elem = ui.core.mapDivDocument.querySelector(
1356
- ".modal_gpsW_content"
1357
- );
1358
- elem.appendChild(newElem);
1359
- } else {
1360
- const newElem = createElement(ui.core.t("app.acquiring_gps_desc"))[0];
1361
- const elem = ui.core.mapDivDocument.querySelector(
1362
- ".modal_gpsW_content"
1363
- );
1364
- elem.appendChild(newElem);
1365
- }
1366
- if (ui.waitReadyBridge) {
1367
- ui.waitReadyBridge();
1368
- delete ui.waitReadyBridge;
1369
- }
1370
- });
1371
- }
1372
-
1373
- // Modal記述の動作を調整する関数
1374
- modalSetting(target) {
1375
- const modalElm = this.core.mapDivDocument.querySelector(".modalBase");
1376
- ["poi", "map", "load", "gpsW", "gpsD", "help", "share", "hide_marker"].map(
1377
- target_ => {
1378
- const className = `modal_${target_}`;
1379
- if (target === target_) {
1380
- modalElm.classList.add(className);
1381
- } else {
1382
- modalElm.classList.remove(className);
1383
- }
1384
- }
1385
- );
1386
- }
1387
-
1388
- handleMarkerAction(data) {
1389
- if (data.directgo) {
1390
- let blank = false;
1391
- let href = "";
1392
- if (typeof data.directgo == "string") {
1393
- href = data.directgo;
1394
- } else {
1395
- href = data.directgo.href;
1396
- blank = data.directgo.blank || false;
1397
- }
1398
- if (blank) {
1399
- window.open(href, "_blank"); // eslint-disable-line no-undef
1400
- } else {
1401
- window.location.href = href; // eslint-disable-line no-undef
1402
- }
1403
- return;
1404
- }
1405
-
1406
- this.core.mapDivDocument.querySelector(".modal_title").innerText =
1407
- this.core.translate(data.name);
1408
- const modalElm = this.core.mapDivDocument.querySelector(".modalBase");
1409
- if (data.url || data.html) {
1410
- this.core.mapDivDocument
1411
- .querySelector(".poi_web")
1412
- .classList.remove("hide");
1413
- this.core.mapDivDocument.querySelector(".poi_data").classList.add("hide");
1414
- const iframe = this.core.mapDivDocument.querySelector(".poi_iframe");
1415
- if (data.html) {
1416
- iframe.addEventListener("load", function loadEvent(event) {
1417
- event.currentTarget.removeEventListener(event.type, loadEvent);
1418
- const cssLink = createElement(
1419
- '<style type="text/css">html, body { height: 100vh; }\n img { width: 100vw; }</style>'
1420
- );
1421
- console.log(cssLink); // eslint-disable-line no-undef
1422
- iframe.contentDocument.head.appendChild(cssLink[0]);
1423
- });
1424
- iframe.removeAttribute("src");
1425
- iframe.setAttribute("srcdoc", this.core.translate(data.html));
1426
- } else {
1427
- iframe.removeAttribute("srcdoc");
1428
- iframe.setAttribute("src", this.core.translate(data.url));
1429
- }
1430
- } else {
1431
- this.core.mapDivDocument
1432
- .querySelector(".poi_data")
1433
- .classList.remove("hide");
1434
- this.core.mapDivDocument.querySelector(".poi_web").classList.add("hide");
1435
-
1436
- const slides = [];
1437
- if (data.image && data.image !== "") {
1438
- const images = Array.isArray(data.image) ? data.image : [data.image];
1439
- images.forEach(image => {
1440
- if (typeof image === "string") {
1441
- image = { src: image };
1442
- }
1443
- const tmpImg = this.resolveRelativeLink(image.src, "img");
1444
- let slide = `<a target="_blank" href="${tmpImg}"><img src="${tmpImg}"></a>`;
1445
- if (image.desc) slide = `${slide}<div>${image.desc}</div>`;
1446
- slides.push(`<div class="swiper-slide">${slide}</div>`);
1447
- });
1448
- } else if (!this.disableNoimage) {
1449
- slides.push(
1450
- `<div class="swiper-slide"><img src="${pointer["no_image.png"]}"></div>`
1451
- );
1452
- }
1453
-
1454
- const imgShowFunc = _event => {
1455
- modalElm.removeEventListener("shown.bs.modal", imgShowFunc, false);
1456
- const swiperDiv = this.core.mapDivDocument.querySelector(
1457
- ".swiper-container.poi_img_swiper"
1458
- );
1459
- if (slides.length === 0) {
1460
- swiperDiv.classList.add("hide");
1461
- } else {
1462
- swiperDiv.classList.remove("hide");
1463
- if (!this.poiSwiper) {
1464
- this.poiSwiper = new Swiper(".swiper-container.poi_img_swiper", {
1465
- lazy: true,
1466
- pagination: {
1467
- el: ".swiper-pagination",
1468
- clickable: true
1469
- },
1470
- navigation: {
1471
- nextEl: ".poi-img-next",
1472
- prevEl: ".poi-img-prev"
1473
- }
1474
- });
1475
- }
1476
- slides.forEach(slide => this.poiSwiper.appendSlide(slide));
1477
- }
1478
- };
1479
- modalElm.addEventListener("shown.bs.modal", imgShowFunc, false);
1480
-
1481
- this.core.mapDivDocument.querySelector(".poi_address").innerText =
1482
- this.core.translate(data.address);
1483
- this.core.mapDivDocument.querySelector(".poi_desc").innerHTML = this.core
1484
- .translate(data.desc)
1485
- .replace(/\n/g, "<br>");
1486
- }
1487
- const modal = new bsn.Modal(modalElm, { root: this.core.mapDivDocument });
1488
- this.core.selectMarker(data.namespaceID);
1489
- const hideFunc = _event => {
1490
- modalElm.removeEventListener("hide.bs.modal", hideFunc, false);
1491
- this.core.unselectMarker();
1492
- };
1493
- const hiddenFunc = _event => {
1494
- modalElm.removeEventListener("hidden.bs.modal", hiddenFunc, false);
1495
- if (this.poiSwiper) {
1496
- this.poiSwiper.removeAllSlides();
1497
- this.poiSwiper = undefined;
1498
- }
1499
- };
1500
- modalElm.addEventListener("hide.bs.modal", hideFunc, false);
1501
- modalElm.addEventListener("hidden.bs.modal", hiddenFunc, false);
1502
- this.modalSetting("poi");
1503
- modal.show();
1504
- }
1505
-
1506
- showFillEnvelope(mapIDs) {
1507
- const ui = this;
1508
- if (mapIDs.length > 0) {
1509
- if (!ui._selectCandidateSources) ui._selectCandidateSources = {};
1510
- Object.keys(ui._selectCandidateSources).forEach(key => {
1511
- const index = mapIDs.indexOf(key);
1512
- if (index < 0) {
1513
- ui.core.mapObject.removeEnvelope(ui._selectCandidateSources[key]);
1514
- delete ui._selectCandidateSources[key];
1515
- } else mapIDs.splice(index, 1);
1516
- });
1517
-
1518
- mapIDs.forEach(mapID => {
1519
- if (mapID !== ui.core.from.mapID) {
1520
- const source = ui.core.cacheHash[mapID];
1521
- const xyPromises = source.envelope.geometry.coordinates[0].map(
1522
- coord => ui.core.from.merc2SysCoordAsync(coord)
1523
- );
1524
- const hexColor = source.envelopeColor;
1525
- let color = asArray(hexColor);
1526
- color = color.slice();
1527
- color[3] = 0.2;
1528
-
1529
- Promise.all(xyPromises).then(xys => {
1530
- ui._selectCandidateSources[mapID] =
1531
- ui.core.mapObject.setFillEnvelope(xys, null, { color });
1532
- });
1533
- }
1534
- });
1535
- } else {
1536
- if (ui._selectCandidateSources) {
1537
- Object.keys(ui._selectCandidateSources).forEach(key =>
1538
- ui.core.mapObject.removeEnvelope(ui._selectCandidateSources[key])
1539
- );
1540
- delete ui._selectCandidateSources;
1541
- }
1542
- }
1543
- }
1544
-
1545
- async xyToMapIDs(xy, threshold = 10) {
1546
- const ui = this;
1547
- const point_ = point(xy);
1548
-
1549
- const map = ui.core.mapObject;
1550
- const size = map.getSize();
1551
- const extent = [[0, 0], [size[0], 0], size, [0, size[1]], [0, 0]];
1552
- const sysCoords = extent.map(pixel => map.getCoordinateFromPixel(pixel));
1553
- const mercs = await (ui.core.from instanceof NowMap
1554
- ? Promise.resolve(sysCoords)
1555
- : Promise.all(
1556
- sysCoords.map(sysCoord => ui.core.from.sysCoord2MercAsync(sysCoord))
1557
- ));
1558
- const areaIndex = ui.areaIndex(mercs);
1559
-
1560
- return Promise.all(
1561
- Object.keys(ui.core.cacheHash)
1562
- .filter(key => ui.core.cacheHash[key].envelope)
1563
- .map(key => {
1564
- const source = ui.core.cacheHash[key];
1565
- return Promise.all([
1566
- Promise.resolve(source),
1567
- Promise.all(
1568
- source.envelope.geometry.coordinates[0].map(coord =>
1569
- ui.core.from.merc2SysCoordAsync(coord)
1570
- )
1571
- )
1572
- ]);
1573
- })
1574
- ).then(sources => {
1575
- const mapIDs = sources
1576
- .reduce((prev, curr) => {
1577
- const source = curr[0];
1578
- const mercXys = curr[1];
1579
- if (source.mapID !== ui.core.from.mapID) {
1580
- const polygon_ = polygon([mercXys]);
1581
- if (booleanPointInPolygon(point_, polygon_)) {
1582
- prev.push(source);
1583
- }
1584
- }
1585
- return prev;
1586
- }, [])
1587
- .filter(source => source.envelopeAreaIndex / areaIndex < threshold)
1588
- .sort((a, b) => a.envelopeAreaIndex - b.envelopeAreaIndex)
1589
- .map(source => source.mapID);
1590
- console.log(mapIDs);
1591
- return mapIDs;
1592
- });
1593
- }
1594
-
1595
- setShowBorder(flag) {
1596
- this.core.requestUpdateState({ showBorder: flag ? 1 : 0 });
1597
- this.updateEnvelope();
1598
- if (flag) {
1599
- this.core.mapDivDocument.classList.add("show-border");
1600
- } else {
1601
- this.core.mapDivDocument.classList.remove("show-border");
1602
- }
1603
- if (this.core.restoreSession) {
1604
- const currentTime = Math.floor(new Date().getTime() / 1000);
1605
- localStorage.setItem("epoch", currentTime); // eslint-disable-line no-undef
1606
- localStorage.setItem("showBorder", flag ? 1 : 0); // eslint-disable-line no-undef
1607
- }
1608
- }
1609
-
1610
- setHideMarker(flag) {
1611
- if (flag) {
1612
- this.core.hideAllMarkers();
1613
- this.core.mapDivDocument.classList.add("hide-marker");
1614
- } else {
1615
- this.core.showAllMarkers();
1616
- this.core.mapDivDocument.classList.remove("hide-marker");
1617
- }
1618
- }
1619
-
1620
- updateEnvelope() {
1621
- const ui = this;
1622
- if (!ui.core.mapObject) return;
1623
-
1624
- ui.core.mapObject.resetEnvelope();
1625
- delete ui._selectCandidateSources;
1626
-
1627
- if (ui.core.stateBuffer.showBorder) {
1628
- Object.keys(ui.core.cacheHash)
1629
- .filter(key => ui.core.cacheHash[key].envelope)
1630
- .map(key => {
1631
- const source = ui.core.cacheHash[key];
1632
- const xyPromises =
1633
- key === ui.core.from.mapID && source instanceof HistMap
1634
- ? [
1635
- [0, 0],
1636
- [source.width, 0],
1637
- [source.width, source.height],
1638
- [0, source.height],
1639
- [0, 0]
1640
- ].map(xy => Promise.resolve(source.xy2SysCoord(xy)))
1641
- : source.envelope.geometry.coordinates[0].map(coord =>
1642
- ui.core.from.merc2SysCoordAsync(coord)
1643
- );
1644
-
1645
- Promise.all(xyPromises).then(xys => {
1646
- ui.core.mapObject.setEnvelope(xys, {
1647
- color: source.envelopeColor,
1648
- width: 2,
1649
- lineDash: [6, 6]
1650
- });
1651
- });
1652
- });
1653
- }
1654
- }
1655
-
1656
- resolveRelativeLink(file, fallbackPath) {
1657
- if (!fallbackPath) fallbackPath = ".";
1658
- return file.match(/\//) ? file : `${fallbackPath}/${file}`;
1659
- }
1660
-
1661
- checkOverlayID(mapID) {
1662
- const ui = this;
1663
- const swiper = ui.overlaySwiper;
1664
- const sliders = swiper.$el[0].querySelectorAll(".swiper-slide");
1665
- for (let i = 0; i < sliders.length; i++) {
1666
- const slider = sliders[i];
1667
- if (slider.getAttribute("data") === mapID) {
1668
- return true;
1669
- }
1670
- }
1671
- return false;
1672
- }
1673
-
1674
- areaIndex(xys) {
1675
- return (
1676
- 0.5 *
1677
- Math.abs(
1678
- [0, 1, 2, 3].reduce((prev, curr, i) => {
1679
- const xy1 = xys[i];
1680
- const xy2 = xys[i + 1];
1681
- return prev + (xy1[0] - xy2[0]) * (xy1[1] + xy2[1]);
1682
- }, 0)
1683
- )
1684
- );
1685
- }
1686
-
1687
- ellips() {
1688
- const ui = this;
1689
- const omitMark = "…";
1690
- const omitLine = 2;
1691
- const stringSplit = function (element) {
1692
- const splitArr = element.innerText.split("");
1693
- let joinString = "";
1694
- for (let i = 0; i < splitArr.length; i++) {
1695
- joinString += `<span>${splitArr[i]}</span>`;
1696
- }
1697
- joinString += `<span class="omit-mark">${omitMark}</span>`;
1698
- element.innerHTML = joinString;
1699
- };
1700
- const omitCheck = function (element) {
1701
- const thisSpan = element.querySelectorAll("span");
1702
- const omitSpan = element.querySelector(".omit-mark");
1703
- let lineCount = 0;
1704
- let omitCount;
1705
-
1706
- if (omitLine <= 0) {
1707
- return;
1708
- }
1709
-
1710
- thisSpan[0].style.display = "";
1711
- for (let i = 1; i < thisSpan.length; i++) {
1712
- thisSpan[i].style.display = "none";
1713
- }
1714
- omitSpan.style.display = "";
1715
- let divHeight = element.offsetHeight;
1716
- let minimizeFont = false;
1717
- for (let i = 1; i < thisSpan.length - 1; i++) {
1718
- thisSpan[i].style.display = "";
1719
- if (element.offsetHeight > divHeight) {
1720
- if (!minimizeFont) {
1721
- minimizeFont = true;
1722
- element.classList.add("minimize");
1723
- } else {
1724
- divHeight = element.offsetHeight;
1725
- lineCount++;
1726
- }
1727
- }
1728
- if (lineCount >= omitLine) {
1729
- omitCount = i - 2;
1730
- break;
1731
- }
1732
- if (i >= thisSpan.length - 2) {
1733
- omitSpan.style.display = "none";
1734
- return;
1735
- }
1736
- }
1737
- for (let i = omitCount; i < thisSpan.length - 1; i++) {
1738
- thisSpan[i].style.display = "none";
1739
- }
1740
- };
1741
- const swiperItems =
1742
- ui.core.mapDivDocument.querySelectorAll(".swiper-slide div");
1743
- for (let i = 0; i < swiperItems.length; i++) {
1744
- const swiperItem = swiperItems[i];
1745
- stringSplit(swiperItem);
1746
- omitCheck(swiperItem);
1747
- }
1748
- }
1749
-
1750
- remove() {
1751
- this.core.remove();
1752
- delete this.core;
1753
- }
1754
- }
1
+ import { absoluteUrl } from "./absolute_url";
2
+ import { Swiper } from "./swiper_ex";
3
+ import EventTarget from "ol/events/Target";
4
+ import page from "../legacy/page";
5
+ import bsn from "../legacy/bootstrap-native";
6
+ import { MaplatApp as Core, createElement } from "@maplat/core";
7
+ import ContextMenu from "./contextmenu";
8
+ import iziToast from "../legacy/iziToast";
9
+ import QRCode from "../legacy/qrcode";
10
+ import { point, polygon } from "@turf/helpers";
11
+ import booleanPointInPolygon from "@turf/boolean-point-in-polygon";
12
+ import sprintf from "../legacy/sprintf";
13
+ import { META_KEYS } from "@maplat/core/lib/source/mixin";
14
+ import {
15
+ Copyright,
16
+ CompassRotate,
17
+ SetGPS,
18
+ GoHome,
19
+ Maplat,
20
+ Border,
21
+ HideMarker,
22
+ SliderCommon,
23
+ Share,
24
+ Zoom,
25
+ setControlSettings
26
+ } from "./maplat_control";
27
+ import { asArray } from "ol/color";
28
+ import { HistMap } from "@maplat/core/lib/source/histmap";
29
+ import { TmsMap } from "@maplat/core/lib/source/tmsmap";
30
+ import { NowMap } from "@maplat/core/lib/source/nowmap";
31
+ import Weiwudi from "weiwudi";
32
+ import { normalizeArg } from "./function";
33
+ import pointer from "./pointer_images";
34
+
35
+ // Maplat UI Class
36
+ export class MaplatUi extends EventTarget {
37
+ constructor(appOption) {
38
+ super();
39
+ appOption = normalizeArg(appOption);
40
+ if (appOption.control) {
41
+ setControlSettings(appOption.control);
42
+ }
43
+
44
+ const ui = this;
45
+ ui.html_id_seed = `${Math.floor(Math.random() * 9000) + 1000}`;
46
+
47
+ if (appOption.stateUrl) {
48
+ page((ctx, _next) => {
49
+ let pathes = ctx.canonicalPath.split("#!");
50
+ let path = pathes.length > 1 ? pathes[1] : pathes[0];
51
+ pathes = path.split("?");
52
+ path = pathes[0];
53
+ if (path === ui.pathThatSet) {
54
+ delete ui.pathThatSet;
55
+ return;
56
+ }
57
+ const restore = {
58
+ transparency: 0,
59
+ position: {
60
+ rotation: 0
61
+ }
62
+ };
63
+ path.split("/").map(state => {
64
+ const line = state.split(":");
65
+ switch (line[0]) {
66
+ case "s":
67
+ restore.mapID = line[1];
68
+ break;
69
+ case "b":
70
+ restore.backgroundID = line[1];
71
+ break;
72
+ case "t":
73
+ restore.transparency = parseFloat(line[1]);
74
+ break;
75
+ case "r":
76
+ restore.position.rotation = parseFloat(line[1]);
77
+ break;
78
+ case "z":
79
+ restore.position.zoom = parseFloat(line[1]);
80
+ break;
81
+ case "x":
82
+ case "y":
83
+ restore.position[line[0]] = parseFloat(line[1]);
84
+ break;
85
+ case "sb":
86
+ restore.showBorder = !!parseInt(line[1]);
87
+ break;
88
+ case "hm":
89
+ restore.hideMarker = !!parseInt(line[1]);
90
+ break;
91
+ case "hl":
92
+ restore.hideLayer = line[1];
93
+ break;
94
+ case "c":
95
+ if (ui.core) {
96
+ const modalElm =
97
+ ui.core.mapDivDocument.querySelector(".modalBase");
98
+ const modal = new bsn.Modal(modalElm, {
99
+ root: ui.core.mapDivDocument
100
+ });
101
+ modal.hide();
102
+ }
103
+ }
104
+ });
105
+ if (!ui.core) {
106
+ if (restore.mapID) {
107
+ appOption.restore = restore;
108
+ }
109
+ ui.initializer(appOption);
110
+ } else if (restore.mapID) {
111
+ ui.core.waitReady.then(() => {
112
+ ui.core.changeMap(restore.mapID, restore);
113
+ });
114
+ }
115
+ });
116
+ page({
117
+ hashbang: true
118
+ });
119
+ page();
120
+ ui.waitReady = new Promise((resolve, _reject) => {
121
+ ui.waitReadyBridge = resolve;
122
+ });
123
+ } else {
124
+ ui.initializer(appOption);
125
+ }
126
+ }
127
+
128
+ async initializer(appOption) {
129
+ const ui = this;
130
+ appOption.translateUI = true;
131
+ ui.core = new Core(appOption);
132
+ if (appOption.icon) {
133
+ pointer["defaultpin.png"] = appOption.icon;
134
+ }
135
+
136
+ if (appOption.restore) {
137
+ ui.setShowBorder(appOption.restore.showBorder || false);
138
+ if (appOption.restore.hideMarker) {
139
+ ui.core.mapDivDocument.classList.add("hide-marker");
140
+ }
141
+ } else if (appOption.restoreSession) {
142
+ const lastEpoch = parseInt(localStorage.getItem("epoch") || 0); // eslint-disable-line no-undef
143
+ const currentTime = Math.floor(new Date().getTime() / 1000);
144
+ if (lastEpoch && currentTime - lastEpoch < 3600) {
145
+ ui.setShowBorder(!!parseInt(localStorage.getItem("showBorder") || "0")); // eslint-disable-line no-undef
146
+ }
147
+ if (ui.core.initialRestore.hideMarker) {
148
+ ui.core.mapDivDocument.classList.add("hide-marker");
149
+ }
150
+ } else {
151
+ ui.setShowBorder(false);
152
+ }
153
+
154
+ const enableSplash = !ui.core.initialRestore.mapID;
155
+ const restoreTransparency = ui.core.initialRestore.transparency;
156
+ const enableOutOfMap = !appOption.presentation_mode;
157
+
158
+ if (appOption.enableShare) {
159
+ ui.core.mapDivDocument.classList.add("enable_share");
160
+ ui.enableShare = true;
161
+ }
162
+ if (appOption.enableHideMarker) {
163
+ ui.core.mapDivDocument.classList.add("enable_hide_marker");
164
+ ui.enableHideMarker = true;
165
+ }
166
+ if (appOption.enableBorder) {
167
+ ui.core.mapDivDocument.classList.add("enable_border");
168
+ ui.enableBorder = true;
169
+ }
170
+ if (appOption.disableNoimage) {
171
+ ui.disableNoimage = true;
172
+ }
173
+ if (appOption.stateUrl) {
174
+ ui.core.mapDivDocument.classList.add("state_url");
175
+ }
176
+ if (ui.core.enableCache) {
177
+ ui.core.mapDivDocument.classList.add("enable_cache");
178
+ }
179
+ if ("ontouchstart" in window) {
180
+ // eslint-disable-line no-undef
181
+ ui.core.mapDivDocument.classList.add("ol-touch");
182
+ ui.isTouch = true;
183
+ }
184
+ if (appOption.mobileIF) {
185
+ appOption.debug = true;
186
+ }
187
+ if (appOption.appEnvelope) {
188
+ ui.appEnvelope = true;
189
+ }
190
+
191
+ let pwaManifest = appOption.pwaManifest;
192
+ let pwaWorker = appOption.pwaWorker;
193
+ let pwaScope = appOption.pwaScope;
194
+
195
+ // Add UI HTML Element
196
+ let newElems = createElement(`<d c="ol-control map-title"><s></s></d>
197
+ <d c="swiper-container ol-control base-swiper prevent-default-ui">
198
+ <d c="swiper-wrapper"></d>
199
+ <d c="swiper-button-next base-next swiper-button-white"></d>
200
+ <d c="swiper-button-prev base-prev swiper-button-white"></d>
201
+ </d>
202
+ <d c="swiper-container ol-control overlay-swiper prevent-default-ui">
203
+ <d c="swiper-wrapper"></d>
204
+ <d c="swiper-button-next overlay-next swiper-button-white"></d>
205
+ <d c="swiper-button-prev overlay-prev swiper-button-white"></d>
206
+ </d> `);
207
+ for (let i = newElems.length - 1; i >= 0; i--) {
208
+ ui.core.mapDivDocument.insertBefore(
209
+ newElems[i],
210
+ ui.core.mapDivDocument.firstChild
211
+ );
212
+ }
213
+ const prevDefs = ui.core.mapDivDocument.querySelectorAll(
214
+ ".prevent-default-ui"
215
+ );
216
+ for (let i = 0; i < prevDefs.length; i++) {
217
+ const target = prevDefs[i];
218
+ target.addEventListener("touchstart", evt => {
219
+ evt.preventDefault();
220
+ });
221
+ }
222
+
223
+ newElems = createElement(`<d c="modal modalBase" tabindex="-1" role="dialog"
224
+ aria-labelledby="staticModalLabel" aria-hidden="true" data-show="true" data-keyboard="false"
225
+ data-backdrop="static">
226
+ <d c="modal-dialog">
227
+ <d c="modal-content">
228
+ <d c="modal-header">
229
+ <button type="button" c="close" data-dismiss="modal">
230
+ <s aria-hidden="true">&#215;</s><s c="sr-only" din="html.close"></s>
231
+ </button>
232
+ <h4 c="modal-title">
233
+
234
+ <s c="modal_title"></s>
235
+ <s c="modal_load_title"></s>
236
+ <s c="modal_gpsW_title" din="html.acquiring_gps"></s>
237
+ <s c="modal_help_title" din="html.help_title"></s>
238
+ <s c="modal_share_title" din="html.share_title"></s>
239
+ <s c="modal_hide_marker_title" din="html.hide_marker_title"></s>
240
+
241
+ </h4>
242
+ </d>
243
+ <d c="modal-body">
244
+
245
+ <d c="modal_help_content">
246
+ <d c="help_content">
247
+ <s dinh="html.help_using_maplat"></s>
248
+ <p c="col-xs-12 help_img"><img src="${
249
+ pointer["fullscreen.png"]
250
+ }"></p>
251
+ <h4 din="html.help_operation_title"></h4>
252
+ <p dinh="html.help_operation_content" c="recipient"></p>
253
+ <h4 din="html.help_selection_title"></h4>
254
+ <p dinh="html.help_selection_content" c="recipient"></p>
255
+ <h4 din="html.help_gps_title"></h4>
256
+ <p dinh="html.help_gps_content" c="recipient"></p>
257
+ <h4 din="html.help_poi_title"></h4>
258
+ <p dinh="html.help_poi_content" c="recipient"></p>
259
+ <h4 din="html.help_etc_title"></h4>
260
+ <ul>
261
+ <li dinh="html.help_etc_attr" c="recipient"></li>
262
+ <li dinh="html.help_etc_help" c="recipient"></li>
263
+ <s c="share_help"><li dinh="html.help_share_help" c="recipient"></li></s>
264
+ <s c="border_help"><li dinh="html.help_etc_border" c="recipient"></li></s>
265
+ <s c="hide_marker_help"><li dinh="html.help_etc_hide_marker" c="recipient"></li></s>
266
+ <li dinh="html.help_etc_slider" c="recipient"></li>
267
+ </ul>
268
+ <p><a href="https://github.com/code4history/Maplat/wiki" target="_blank">Maplat</a>
269
+ © 2015- Kohei Otsuka, Code for History</p>
270
+ </d>
271
+ </d>
272
+
273
+ <d c="modal_poi_content">
274
+ <d c="poi_web embed-responsive embed-responsive-60vh">
275
+ <iframe c="poi_iframe iframe_poi" frameborder="0" src=""></iframe>
276
+ </d>
277
+ <d c="poi_data hide">
278
+ <d c="col-xs-12 swiper-container poi_img_swiper">
279
+ <d c="swiper-wrapper"></d>
280
+ <d c="swiper-button-next poi-img-next"></d>
281
+ <d c="swiper-button-prev poi-img-prev"></d>
282
+ </d>
283
+ <p c="recipient poi_address"></p>
284
+ <p c="recipient poi_desc"></p>
285
+ </d>
286
+ </d>
287
+
288
+ <d c="modal_share_content">
289
+ <h4 din="html.share_app_title"></h4>
290
+ <d id="___maplat_app_toast_${ui.html_id_seed}"></d>
291
+ <d c="recipient row">
292
+ <d c="form-group col-xs-4 text-center"><button title="Copy to clipboard" c="share btn btn-light" data="cp_app"><i c="fa fa-clipboard"></i>&nbsp;<small din="html.share_copy"></small></button></d>
293
+ <d c="form-group col-xs-4 text-center"><button title="Twitter" c="share btn btn-light" data="tw_app"><i c="fa fa-twitter"></i>&nbsp;<small>Twitter</small></button></d>
294
+ <d c="form-group col-xs-4 text-center"><button title="Facebook" c="share btn btn-light" data="fb_app"><i c="fa fa-facebook"></i>&nbsp;<small>Facebook</small></button></d>
295
+ </d>
296
+ <d c="qr_app center-block" style="width:128px;"></d>
297
+ <d c="modal_share_state">
298
+ <h4 din="html.share_state_title"></h4>
299
+ <d id="___maplat_view_toast_${ui.html_id_seed}"></d>
300
+ <d c="recipient row">
301
+ <d c="form-group col-xs-4 text-center"><button title="Copy to clipboard" c="share btn btn-light" data="cp_view"><i c="fa fa-clipboard"></i>&nbsp;<small din="html.share_copy"></small></button></d>
302
+ <d c="form-group col-xs-4 text-center"><button title="Twitter" c="share btn btn-light" data="tw_view"><i c="fa fa-twitter"></i>&nbsp;<small>Twitter</small></button></d>
303
+ <d c="form-group col-xs-4 text-center"><button title="Facebook" c="share btn btn-light" data="fb_view"><i c="fa fa-facebook"></i>&nbsp;<small>Facebook</small></button></d>
304
+ </d>
305
+ <d c="qr_view center-block" style="width:128px;"></d>
306
+ </d>
307
+ <p><img src="" height="0px" width="0px"></p>
308
+ </d>
309
+
310
+ <d c="modal_map_content">
311
+ ${META_KEYS.map(key => {
312
+ if (key == "title" || key == "officialTitle") return "";
313
+ return `<d c="recipients ${key}_div"><dl c="dl-horizontal">
314
+ <dt din="html.${key}"></dt>
315
+ <dd c="${key}_dd"></dd>
316
+ </dl></d> `;
317
+ }).join("")}
318
+ <d c="recipients modal_cache_content"><dl c="dl-horizontal">
319
+ <dt din="html.cache_handle"></dt>
320
+ <dd><s c="cache_size"></s></dd>
321
+ <dt></dt>
322
+ <dd><s c="pull-right"><button c="cache_fetch btn btn-default" href="#" din="html.cache_fetch"></button>
323
+ <button c="cache_delete btn btn-default" href="#" din="html.cache_delete"></button></s></dd>
324
+ </dl></d>
325
+ </d>
326
+
327
+ <d c="modal_load_content">
328
+ <p c="recipient"><img src="${
329
+ pointer["loading.png"]
330
+ }"><s din="html.app_loading_body"></s></p>
331
+ <d c="splash_div hide row"><p c="col-xs-12 poi_img"><img c="splash_img" src=""></p></d>
332
+ <p><img src="" height="0px" width="0px"></p>
333
+ </d>
334
+
335
+ <d c="modal_hide_marker_content">
336
+ <ul c="list-group"></ul>
337
+ </d>
338
+
339
+ <p c="modal_gpsD_content" c="recipient"></p>
340
+ <p c="modal_gpsW_content" c="recipient"></p>
341
+
342
+ </d>
343
+ </d>
344
+ </d>
345
+ </d> `);
346
+ for (let i = newElems.length - 1; i >= 0; i--) {
347
+ ui.core.mapDivDocument.insertBefore(
348
+ newElems[i],
349
+ ui.core.mapDivDocument.firstChild
350
+ );
351
+ }
352
+
353
+ const shareBtns = ui.core.mapDivDocument.querySelectorAll(".btn.share");
354
+ for (let i = 0; i < shareBtns.length; i++) {
355
+ const shareBtn = shareBtns[i];
356
+ shareBtn.addEventListener("click", evt => {
357
+ let btn = evt.target;
358
+ if (!btn.classList.contains("share")) btn = btn.parentElement;
359
+ const cmd = btn.getAttribute("data");
360
+ const cmds = cmd.split("_");
361
+ let base = evt.target.baseURI;
362
+ if (!base) base = window.location.href;
363
+ const div1 = base.split("#!");
364
+ const path = div1.length > 1 ? div1[1].split("?")[0] : "";
365
+ const div2 = div1[0].split("?");
366
+ let uri = div2[0];
367
+ const query =
368
+ div2.length > 1
369
+ ? div2[1]
370
+ .split("&")
371
+ .filter(qs => qs !== "pwa")
372
+ .join("&")
373
+ : "";
374
+
375
+ if (query) uri = `${uri}?${query}`;
376
+ if (cmds[1] === "view") {
377
+ if (path) uri = `${uri}#!${path}`;
378
+ }
379
+ if (cmds[0] === "cp") {
380
+ const copyFrom = document.createElement("textarea"); // eslint-disable-line no-undef
381
+ copyFrom.textContent = uri;
382
+
383
+ const bodyElm = document.querySelector("body"); // eslint-disable-line no-undef
384
+ bodyElm.appendChild(copyFrom);
385
+
386
+ if (/iP(hone|[oa]d)/.test(navigator.userAgent)) {
387
+ // eslint-disable-line no-undef
388
+ const range = document.createRange(); // eslint-disable-line no-undef
389
+ range.selectNode(copyFrom);
390
+ window.getSelection().addRange(range); // eslint-disable-line no-undef
391
+ } else {
392
+ copyFrom.select();
393
+ }
394
+
395
+ document.execCommand("copy"); // eslint-disable-line no-undef
396
+ bodyElm.removeChild(copyFrom);
397
+ const toastParent = `#___maplat_${cmds[1]}_toast_${ui.html_id_seed}`;
398
+ iziToast.show({
399
+ message: ui.core.t("app.copy_toast", { ns: "translation" }),
400
+ close: false,
401
+ pauseOnHover: false,
402
+ timeout: 1000,
403
+ progressBar: false,
404
+ target: toastParent
405
+ });
406
+ } else if (cmds[0] === "tw") {
407
+ const twuri = `https://twitter.com/share?url=${encodeURIComponent(
408
+ uri
409
+ )}&hashtags=Maplat`;
410
+ window.open(
411
+ twuri,
412
+ "_blank",
413
+ "width=650,height=450,menubar=no,toolbar=no,scrollbars=yes"
414
+ ); // eslint-disable-line no-undef
415
+ } else if (cmds[0] === "fb") {
416
+ // https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fdevelopers.facebook.com%2Fdocs%2Fplugins%2Fshare-button%2F&display=popup&ref=plugin&src=like&kid_directed_site=0&app_id=113869198637480
417
+ const fburi = `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(
418
+ uri
419
+ )}&display=popup&ref=plugin&src=like&kid_directed_site=0`;
420
+ window.open(
421
+ fburi,
422
+ "_blank",
423
+ "width=650,height=450,menubar=no,toolbar=no,scrollbars=yes"
424
+ ); // eslint-disable-line no-undef
425
+ }
426
+ });
427
+ }
428
+
429
+ // PWA対応: 非同期処理
430
+ if (pwaManifest) {
431
+ if (pwaManifest === true) {
432
+ pwaManifest = `./pwa/${ui.core.appid}_manifest.json`;
433
+ }
434
+ if (!pwaWorker) {
435
+ pwaWorker = "./service-worker.js";
436
+ }
437
+ if (!pwaScope) {
438
+ pwaScope = "./";
439
+ }
440
+
441
+ const head = document.querySelector("head"); // eslint-disable-line no-undef
442
+ if (!head.querySelector('link[rel="manifest"]')) {
443
+ head.appendChild(
444
+ createElement(`<link rel="manifest" href="${pwaManifest}">`)[0]
445
+ );
446
+ }
447
+ // service workerが有効なら、service-worker.js を登録します
448
+ try {
449
+ Weiwudi.registerSW(pwaWorker, { scope: pwaScope });
450
+ } catch (e) {} // eslint-disable-line no-empty
451
+
452
+ if (!head.querySelector('link[rel="apple-touch-icon"]')) {
453
+ const xhr = new XMLHttpRequest(); // eslint-disable-line no-undef
454
+ xhr.open("GET", pwaManifest, true);
455
+ xhr.responseType = "json";
456
+
457
+ xhr.onload = function (_e) {
458
+ let value = this.response;
459
+ if (!value) return;
460
+ if (typeof value != "object") value = JSON.parse(value);
461
+
462
+ if (value.icons) {
463
+ for (let i = 0; i < value.icons.length; i++) {
464
+ const src = absoluteUrl(pwaManifest, value.icons[i].src);
465
+ const sizes = value.icons[i].sizes;
466
+ const tag = `<link rel="apple-touch-icon" sizes="${sizes}" href="${src}">`;
467
+ head.appendChild(createElement(tag)[0]);
468
+ }
469
+ }
470
+ };
471
+ xhr.send();
472
+ }
473
+ }
474
+
475
+ ui.core.addEventListener("uiPrepare", _evt => {
476
+ const imageExtractor = function (text) {
477
+ const regexp = /\$\{([a-zA-Z0-9_\.\/\-]+)\}/g; // eslint-disable-line no-useless-escape
478
+ let ret = text;
479
+ let match;
480
+ while ((match = regexp.exec(text)) != null) {
481
+ ret = ret.replace(match[0], pointer[match[1]]);
482
+ }
483
+ return ret;
484
+ };
485
+ let i18nTargets = ui.core.mapDivDocument.querySelectorAll("[data-i18n]");
486
+ for (let i = 0; i < i18nTargets.length; i++) {
487
+ const target = i18nTargets[i];
488
+ const key = target.getAttribute("data-i18n");
489
+ target.innerText = imageExtractor(ui.core.t(key));
490
+ }
491
+ i18nTargets = ui.core.mapDivDocument.querySelectorAll("[data-i18n-html]");
492
+ for (let i = 0; i < i18nTargets.length; i++) {
493
+ const target = i18nTargets[i];
494
+ const key = target.getAttribute("data-i18n-html");
495
+ target.innerHTML = imageExtractor(ui.core.t(key));
496
+ }
497
+
498
+ const options = {
499
+ reverse: true,
500
+ tipLabel: ui.core.t("control.trans", { ns: "translation" })
501
+ };
502
+ if (restoreTransparency) {
503
+ options.initialValue = restoreTransparency / 100;
504
+ }
505
+ ui.sliderCommon = new SliderCommon(options);
506
+ ui.core.appData.controls = [
507
+ new Copyright({
508
+ tipLabel: ui.core.t("control.info", { ns: "translation" })
509
+ }),
510
+ new CompassRotate({
511
+ tipLabel: ui.core.t("control.compass", { ns: "translation" })
512
+ }),
513
+ new Zoom({
514
+ tipLabel: ui.core.t("control.zoom", { ns: "translation" })
515
+ }),
516
+ new SetGPS({
517
+ tipLabel: ui.core.t("control.gps", { ns: "translation" })
518
+ }),
519
+ new GoHome({
520
+ tipLabel: ui.core.t("control.home", { ns: "translation" })
521
+ }),
522
+ ui.sliderCommon,
523
+ new Maplat({
524
+ tipLabel: ui.core.t("control.help", { ns: "translation" })
525
+ })
526
+ ];
527
+ if (ui.enableShare) {
528
+ ui.core.appData.controls.push(
529
+ new Share({
530
+ tipLabel: ui.core.t("control.share", { ns: "translation" })
531
+ })
532
+ );
533
+ }
534
+ if (ui.enableBorder) {
535
+ ui.core.appData.controls.push(
536
+ new Border({
537
+ tipLabel: ui.core.t("control.border", { ns: "translation" })
538
+ })
539
+ );
540
+ }
541
+ if (ui.enableHideMarker) {
542
+ ui.core.appData.controls.push(
543
+ new HideMarker({
544
+ tipLabel: ui.core.t("control.hide_marker", { ns: "translation" })
545
+ })
546
+ );
547
+ }
548
+
549
+ // Contextmenu
550
+ ui.contextMenu = new ContextMenu({
551
+ eventType: "__dummy__",
552
+ width: 170,
553
+ defaultItems: false,
554
+ items: []
555
+ });
556
+ ui.core.appData.controls.push(ui.contextMenu);
557
+
558
+ if (ui.core.mapObject) {
559
+ ui.core.appData.controls.map(control => {
560
+ ui.core.mapObject.addControl(control);
561
+ });
562
+ }
563
+
564
+ ui.sliderCommon.on("propertychange", evt => {
565
+ if (evt.key === "slidervalue") {
566
+ ui.core.setTransparency(ui.sliderCommon.get(evt.key) * 100);
567
+ }
568
+ });
569
+
570
+ if (enableSplash) {
571
+ // Check Splash data
572
+ let splash = false;
573
+ if (ui.core.appData.splash) splash = true;
574
+
575
+ const modalElm = ui.core.mapDivDocument.querySelector(".modalBase");
576
+ const modal = new bsn.Modal(modalElm, { root: ui.core.mapDivDocument });
577
+ ui.core.mapDivDocument.querySelector(".modal_load_title").innerText =
578
+ ui.core.translate(ui.core.appData.appName);
579
+ if (splash) {
580
+ ui.core.mapDivDocument
581
+ .querySelector(".splash_img")
582
+ .setAttribute("src", `img/${ui.core.appData.splash}`);
583
+ ui.core.mapDivDocument
584
+ .querySelector(".splash_div")
585
+ .classList.remove("hide");
586
+ }
587
+ ui.modalSetting("load");
588
+ modal.show();
589
+
590
+ const fadeTime = splash ? 1000 : 200;
591
+ ui.splashPromise = new Promise(resolve => {
592
+ setTimeout(() => {
593
+ // eslint-disable-line no-undef
594
+ resolve();
595
+ }, fadeTime);
596
+ });
597
+ }
598
+
599
+ document.querySelector("title").innerHTML = ui.core.translate(
600
+ ui.core.appName
601
+ ); // eslint-disable-line no-undef
602
+ });
603
+
604
+ ui.core.addEventListener("sourceLoaded", evt => {
605
+ const sources = evt.detail;
606
+
607
+ const colors = [
608
+ "maroon",
609
+ "deeppink",
610
+ "indigo",
611
+ "olive",
612
+ "royalblue",
613
+ "red",
614
+ "hotpink",
615
+ "green",
616
+ "yellow",
617
+ "navy",
618
+ "saddlebrown",
619
+ "fuchsia",
620
+ "darkslategray",
621
+ "yellowgreen",
622
+ "blue",
623
+ "mediumvioletred",
624
+ "purple",
625
+ "lime",
626
+ "darkorange",
627
+ "teal",
628
+ "crimson",
629
+ "darkviolet",
630
+ "darkolivegreen",
631
+ "steelblue",
632
+ "aqua"
633
+ ];
634
+ const appBbox = [];
635
+ let cIndex = 0;
636
+ for (let i = 0; i < sources.length; i++) {
637
+ const source = sources[i];
638
+ if (source.envelope) {
639
+ if (ui.appEnvelope)
640
+ source.envelope.geometry.coordinates[0].map(xy => {
641
+ if (appBbox.length === 0) {
642
+ appBbox[0] = appBbox[2] = xy[0];
643
+ appBbox[1] = appBbox[3] = xy[1];
644
+ } else {
645
+ if (xy[0] < appBbox[0]) appBbox[0] = xy[0];
646
+ if (xy[0] > appBbox[2]) appBbox[2] = xy[0];
647
+ if (xy[1] < appBbox[1]) appBbox[1] = xy[1];
648
+ if (xy[1] > appBbox[3]) appBbox[3] = xy[1];
649
+ }
650
+ });
651
+ source.envelopeColor = colors[cIndex];
652
+ cIndex = cIndex + 1;
653
+ if (cIndex === colors.length) cIndex = 0;
654
+
655
+ const xys = source.envelope.geometry.coordinates[0];
656
+ // http://blog.arq.name/wp-content/uploads/2018/02/Rectangle_Area.pdf
657
+ source.envelopeAreaIndex = ui.areaIndex(xys);
658
+ }
659
+ }
660
+ if (ui.appEnvelope) console.log(`This app's envelope is: ${appBbox}`);
661
+
662
+ if (ui.splashPromise) {
663
+ ui.splashPromise.then(() => {
664
+ const modalElm = ui.core.mapDivDocument.querySelector(".modalBase");
665
+ const modal = new bsn.Modal(modalElm, {
666
+ root: ui.core.mapDivDocument
667
+ });
668
+ ui.modalSetting("load");
669
+ modal.hide();
670
+ });
671
+ }
672
+
673
+ const baseSources = [];
674
+ const overlaySources = [];
675
+ for (let i = 0; i < sources.length; i++) {
676
+ const source = sources[i];
677
+ if (source instanceof NowMap && !(source instanceof TmsMap)) {
678
+ baseSources.push(source);
679
+ } else {
680
+ overlaySources.push(source);
681
+ }
682
+ }
683
+
684
+ const baseSwiper = (ui.baseSwiper = new Swiper(".base-swiper", {
685
+ slidesPerView: 2,
686
+ spaceBetween: 15,
687
+ breakpoints: {
688
+ // when window width is <= 480px
689
+ 480: {
690
+ slidesPerView: 1.4,
691
+ spaceBetween: 10
692
+ }
693
+ },
694
+ centeredSlides: true,
695
+ threshold: 2,
696
+ loop: baseSources.length >= 2,
697
+ navigation: {
698
+ nextEl: ".base-next",
699
+ prevEl: ".base-prev"
700
+ }
701
+ }));
702
+ baseSwiper.on("click", _e => {
703
+ if (!baseSwiper.clickedSlide) return;
704
+ const slide = baseSwiper.clickedSlide;
705
+ ui.core.changeMap(slide.getAttribute("data"));
706
+ delete ui._selectCandidateSources;
707
+ baseSwiper.setSlideIndexAsSelected(
708
+ slide.getAttribute("data-swiper-slide-index")
709
+ );
710
+ });
711
+ if (baseSources.length < 2) {
712
+ ui.core.mapDivDocument
713
+ .querySelector(".base-swiper")
714
+ .classList.add("single-map");
715
+ }
716
+ const overlaySwiper = (ui.overlaySwiper = new Swiper(".overlay-swiper", {
717
+ slidesPerView: 2,
718
+ spaceBetween: 15,
719
+ breakpoints: {
720
+ // when window width is <= 480px
721
+ 480: {
722
+ slidesPerView: 1.4,
723
+ spaceBetween: 10
724
+ }
725
+ },
726
+ centeredSlides: true,
727
+ threshold: 2,
728
+ loop: overlaySources.length >= 2,
729
+ navigation: {
730
+ nextEl: ".overlay-next",
731
+ prevEl: ".overlay-prev"
732
+ }
733
+ }));
734
+ overlaySwiper.on("click", _e => {
735
+ if (!overlaySwiper.clickedSlide) return;
736
+ const slide = overlaySwiper.clickedSlide;
737
+ ui.core.changeMap(slide.getAttribute("data"));
738
+ delete ui._selectCandidateSources;
739
+ overlaySwiper.setSlideIndexAsSelected(
740
+ slide.getAttribute("data-swiper-slide-index")
741
+ );
742
+ });
743
+ if (overlaySources.length < 2) {
744
+ ui.core.mapDivDocument
745
+ .querySelector(".overlay-swiper")
746
+ .classList.add("single-map");
747
+ }
748
+
749
+ for (let i = 0; i < baseSources.length; i++) {
750
+ const source = baseSources[i];
751
+ baseSwiper.appendSlide(
752
+ `<div class="swiper-slide" data="${source.mapID}">` +
753
+ `<img crossorigin="anonymous" src="${
754
+ source.thumbnail
755
+ }"><div> ${ui.core.translate(source.label)}</div> </div> `
756
+ );
757
+ }
758
+ for (let i = 0; i < overlaySources.length; i++) {
759
+ const source = overlaySources[i];
760
+ const colorCss = source.envelope ? ` ${source.envelopeColor}` : "";
761
+ overlaySwiper.appendSlide(
762
+ `<div class="swiper-slide${colorCss}" data="${source.mapID}">` +
763
+ `<img crossorigin="anonymous" src="${
764
+ source.thumbnail
765
+ }"><div> ${ui.core.translate(source.label)}</div> </div> `
766
+ );
767
+ }
768
+
769
+ baseSwiper.on;
770
+ overlaySwiper.on;
771
+ baseSwiper.slideToLoop(0);
772
+ overlaySwiper.slideToLoop(0);
773
+ ui.ellips();
774
+ });
775
+
776
+ ui.core.addEventListener("mapChanged", evt => {
777
+ const map = evt.detail;
778
+
779
+ ui.baseSwiper.setSlideMapID(map.mapID);
780
+ ui.overlaySwiper.setSlideMapID(map.mapID);
781
+
782
+ const title = map.officialTitle || map.title || map.label;
783
+ ui.core.mapDivDocument.querySelector(".map-title span").innerText =
784
+ ui.core.translate(title);
785
+
786
+ if (ui.checkOverlayID(map.mapID)) {
787
+ ui.sliderCommon.setEnable(true);
788
+ } else {
789
+ ui.sliderCommon.setEnable(false);
790
+ }
791
+ const transparency = ui.sliderCommon.get("slidervalue") * 100;
792
+ ui.core.mapObject.setTransparency(transparency);
793
+
794
+ ui.updateEnvelope();
795
+ });
796
+
797
+ ui.core.addEventListener("poi_number", evt => {
798
+ const number = evt.detail;
799
+ if (number) {
800
+ ui.core.mapDivDocument.classList.remove("no_poi");
801
+ } else {
802
+ ui.core.mapDivDocument.classList.add("no_poi");
803
+ }
804
+ });
805
+
806
+ ui.core.addEventListener("outOfMap", _evt => {
807
+ if (enableOutOfMap) {
808
+ ui.core.mapDivDocument.querySelector(".modal_title").innerText =
809
+ ui.core.t("app.out_of_map");
810
+ ui.core.mapDivDocument.querySelector(".modal_gpsD_content").innerText =
811
+ ui.core.t("app.out_of_map_area");
812
+ const modalElm = ui.core.mapDivDocument.querySelector(".modalBase");
813
+ const modal = new bsn.Modal(modalElm, { root: ui.core.mapDivDocument });
814
+ ui.modalSetting("gpsD");
815
+ modal.show();
816
+ }
817
+ });
818
+
819
+ ui.core.mapDivDocument.addEventListener("mouseout", _evt => {
820
+ if (ui._selectCandidateSources) {
821
+ Object.keys(ui._selectCandidateSources).forEach(key =>
822
+ ui.core.mapObject.removeEnvelope(ui._selectCandidateSources[key])
823
+ );
824
+ delete ui._selectCandidateSources;
825
+ }
826
+ });
827
+
828
+ ui.core.addEventListener("pointerMoveOnMapXy", async evt => {
829
+ if (!ui.core.stateBuffer.showBorder) {
830
+ if (ui._selectCandidateSources) {
831
+ Object.keys(ui._selectCandidateSources).forEach(key =>
832
+ ui.core.mapObject.removeEnvelope(ui._selectCandidateSources[key])
833
+ );
834
+ delete ui._selectCandidateSources;
835
+ }
836
+ return;
837
+ }
838
+
839
+ const mapIDs = await ui.xyToMapIDs(evt.detail);
840
+ ui.showFillEnvelope(mapIDs);
841
+ });
842
+
843
+ ui.core.addEventListener("clickMapXy", async evt => {
844
+ if (!ui.core.stateBuffer.showBorder) {
845
+ return;
846
+ }
847
+
848
+ const mapIDs = await ui.xyToMapIDs(evt.detail);
849
+ if (mapIDs.length > 0) {
850
+ let currentID;
851
+ showContextMenu(
852
+ mapIDs.map(mapID => {
853
+ const source = ui.core.cacheHash[mapID];
854
+ const hexColor = source.envelopeColor;
855
+ let iconSVG = `<?xml version="1.0" encoding="utf-8"?><svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
856
+ x="0px" y="0px" width="10px" height="10px" viewBox="0 0 10 10"
857
+ enable-background="new 0 0 10 10" xml:space="preserve">
858
+ <polygon x="0" y="0" points="2,2 2,8 8,8 8,2
859
+ 2,2" stroke="${hexColor}" fill="${hexColor}" stroke-width="2" style="fill-opacity: .25;"></polygon></svg>`;
860
+ iconSVG = `data:image/svg+xml,${encodeURIComponent(iconSVG)}`;
861
+ return {
862
+ icon: iconSVG,
863
+ text: ui.core.translate(source.title),
864
+ callback: () => {
865
+ const lis = [
866
+ ...ui.core.mapDivDocument.querySelectorAll(
867
+ ".ol-ctx-menu-container ul li"
868
+ )
869
+ ];
870
+ lis.forEach(li => li.classList.remove("selected"));
871
+ if (currentID && currentID === mapID) {
872
+ delete ui._selectCandidateSources;
873
+ ui.core.changeMap(mapID);
874
+ } else {
875
+ currentID = mapID;
876
+ ui.showFillEnvelope([mapID]);
877
+ ui.overlaySwiper.slideToMapID(mapID);
878
+ const index = mapIDs.indexOf(mapID);
879
+ if (index > -1) {
880
+ const li = lis[index];
881
+ li.classList.add("selected");
882
+ }
883
+ return true;
884
+ }
885
+ },
886
+ mouseOnTask(_evt) {
887
+ if (!ui.isTouch) {
888
+ currentID = mapID;
889
+ ui.showFillEnvelope([mapID]);
890
+ ui.overlaySwiper.slideToMapID(mapID);
891
+ }
892
+ },
893
+ mouseOutTask(_evt) {
894
+ if (!ui.isTouch) {
895
+ currentID = undefined;
896
+ ui.showFillEnvelope([]);
897
+ }
898
+ }
899
+ };
900
+ })
901
+ );
902
+ ui.showFillEnvelope(mapIDs);
903
+ }
904
+ });
905
+
906
+ function showContextMenu(menues) {
907
+ ui.contextMenu.clear();
908
+ const mouseOnTasks = [];
909
+ menues.forEach(menu => {
910
+ ui.contextMenu.push(menu);
911
+ if (menu.mouseOnTask)
912
+ mouseOnTasks.push([menu.mouseOnTask, menu.mouseOutTask]);
913
+ });
914
+
915
+ const coordinate = ui.core.lastClickEvent.coordinate;
916
+ const pixel = ui.core.lastClickEvent.pixel;
917
+
918
+ if (ui.contextMenu.disabled) return;
919
+
920
+ const openHandler = () => {
921
+ ui.contextMenu.removeEventListener("open", openHandler);
922
+ if (mouseOnTasks.length > 0) {
923
+ const lis = [
924
+ ...ui.core.mapDivDocument.querySelectorAll(
925
+ ".ol-ctx-menu-container ul li"
926
+ )
927
+ ];
928
+ const events = lis.map((li, i) => {
929
+ const tasks = mouseOnTasks[i];
930
+ li.addEventListener("mouseover", tasks[0]);
931
+ li.addEventListener("mouseout", tasks[1]);
932
+ return [li, tasks[0], tasks[1]];
933
+ });
934
+ const closeHandler = () => {
935
+ ui.contextMenu.removeEventListener("close", closeHandler);
936
+ events.forEach(event => {
937
+ event[0].removeEventListener("mouseover", event[1]);
938
+ event[0].removeEventListener("mouseout", event[2]);
939
+ });
940
+ };
941
+ ui.contextMenu.on("close", closeHandler);
942
+ }
943
+ };
944
+ ui.contextMenu.on("open", openHandler);
945
+ ui.contextMenu.Internal.openMenu(pixel, coordinate);
946
+
947
+ //one-time fire
948
+ ui.core.mapObject.getViewport().addEventListener(
949
+ "pointerdown",
950
+ {
951
+ handleEvent(e) {
952
+ if (ui.contextMenu.Internal.opened) {
953
+ ui.contextMenu.Internal.closeMenu();
954
+ e.stopPropagation();
955
+ ui.core.mapObject
956
+ .getViewport()
957
+ .removeEventListener(e.type, this, false);
958
+ }
959
+ }
960
+ },
961
+ false
962
+ );
963
+ }
964
+
965
+ ui.core.addEventListener("clickMarkers", evt => {
966
+ const data = evt.detail;
967
+ if (data.length === 1) {
968
+ ui.handleMarkerAction(data[0]);
969
+ } else {
970
+ showContextMenu(
971
+ data.map(datum => ({
972
+ icon: datum.icon || pointer["defaultpin.png"],
973
+ text: ui.core.translate(datum.name),
974
+ callback() {
975
+ ui.handleMarkerAction(datum);
976
+ }
977
+ }))
978
+ );
979
+ }
980
+ });
981
+
982
+ if (appOption.stateUrl) {
983
+ ui.core.addEventListener("updateState", evt => {
984
+ const value = evt.detail;
985
+ if (!value.position || !value.mapID) return;
986
+ let link = `s:${value.mapID}`;
987
+ if (value.backgroundID) link = `${link}/b:${value.backgroundID}`;
988
+ if (value.transparency) link = `${link}/t:${value.transparency}`;
989
+ link = `${link}/x:${value.position.x}/y:${value.position.y}`;
990
+ link = `${link}/z:${value.position.zoom}`;
991
+ if (value.position.rotation)
992
+ link = `${link}/r:${value.position.rotation}`;
993
+ if (value.showBorder) link = `${link}/sb:${value.showBorder}`;
994
+ if (value.hideMarker) link = `${link}/hm:${value.hideMarker}`;
995
+ if (value.hideLayer) link = `${link}/hl:${value.hideLayer}`;
996
+
997
+ ui.pathThatSet = link;
998
+ page(link);
999
+ });
1000
+ }
1001
+
1002
+ ui.waitReady = ui.core.waitReady.then(() => {
1003
+ const fakeGps = appOption.fake ? ui.core.appData.fake_gps : false;
1004
+ const fakeCenter = appOption.fake ? ui.core.appData.fake_center : false;
1005
+ const fakeRadius = appOption.fake ? ui.core.appData.fake_radius : false;
1006
+
1007
+ let shown = false;
1008
+ let gpsWaitPromise = null;
1009
+ function showGPSresult(result) {
1010
+ if (result && result.error) {
1011
+ ui.core.currentPosition = null;
1012
+ if (result.error === "gps_out" && shown) {
1013
+ shown = false;
1014
+ const modalElm = ui.core.mapDivDocument.querySelector(".modalBase");
1015
+ const modal = new bsn.Modal(modalElm, {
1016
+ root: ui.core.mapDivDocument
1017
+ });
1018
+ ui.core.mapDivDocument.querySelector(".modal_title").innerText =
1019
+ ui.core.t("app.out_of_map");
1020
+ ui.core.mapDivDocument.querySelector(
1021
+ ".modal_gpsD_content"
1022
+ ).innerText = ui.core.t("app.out_of_map_desc");
1023
+ ui.modalSetting("gpsD");
1024
+ modal.show();
1025
+ }
1026
+ } else {
1027
+ ui.core.currentPosition = result;
1028
+ }
1029
+ if (shown) {
1030
+ shown = false;
1031
+ const modalElm = ui.core.mapDivDocument.querySelector(".modalBase");
1032
+ const modal = new bsn.Modal(modalElm, {
1033
+ root: ui.core.mapDivDocument
1034
+ });
1035
+ modal.hide();
1036
+ }
1037
+ }
1038
+ ui.core.mapObject.on("gps_request", () => {
1039
+ gpsWaitPromise = "gps_request";
1040
+ const promises = [
1041
+ new Promise(resolve => {
1042
+ if (gpsWaitPromise !== "gps_request") {
1043
+ resolve(gpsWaitPromise);
1044
+ } else gpsWaitPromise = resolve;
1045
+ })
1046
+ ];
1047
+ shown = true;
1048
+ const modalElm = ui.core.mapDivDocument.querySelector(".modalBase");
1049
+ const modal = new bsn.Modal(modalElm, { root: ui.core.mapDivDocument });
1050
+ ui.modalSetting("gpsW");
1051
+ modal.show();
1052
+ // 200m秒以上最低待たないと、Modalがうまく動かない場合がある
1053
+ promises.push(
1054
+ new Promise(resolve => {
1055
+ setTimeout(resolve, 200); // eslint-disable-line no-undef
1056
+ })
1057
+ );
1058
+ Promise.all(promises).then(results => {
1059
+ showGPSresult(results[0]);
1060
+ });
1061
+ });
1062
+ ui.core.mapObject.on("gps_result", evt => {
1063
+ if (gpsWaitPromise === "gps_request") {
1064
+ gpsWaitPromise = evt.frameState;
1065
+ } else if (gpsWaitPromise) {
1066
+ gpsWaitPromise(evt.frameState);
1067
+ gpsWaitPromise = null;
1068
+ } else if (!shown) {
1069
+ showGPSresult(evt.frameState);
1070
+ }
1071
+ });
1072
+
1073
+ let qr_app;
1074
+ let qr_view;
1075
+ ui.core.mapObject.on("click_control", async evt => {
1076
+ const control = evt.frameState.control;
1077
+ const modalElm = ui.core.mapDivDocument.querySelector(".modalBase");
1078
+ const modal = new bsn.Modal(modalElm, { root: ui.core.mapDivDocument });
1079
+ if (control === "copyright") {
1080
+ const from = ui.core.getMapMeta();
1081
+
1082
+ if (
1083
+ !META_KEYS.reduce((prev, curr) => {
1084
+ if (curr === "title") return prev;
1085
+ return from[curr] || prev;
1086
+ }, false)
1087
+ )
1088
+ return;
1089
+
1090
+ ui.core.mapDivDocument.querySelector(".modal_title").innerText =
1091
+ ui.core.translate(from.officialTitle || from.title);
1092
+ META_KEYS.map(key => {
1093
+ if (key === "title" || key === "officialTitle") return;
1094
+ if (!from[key] || from[key] === "") {
1095
+ ui.core.mapDivDocument
1096
+ .querySelector(`.${key}_div`)
1097
+ .classList.add("hide");
1098
+ } else {
1099
+ ui.core.mapDivDocument
1100
+ .querySelector(`.${key}_div`)
1101
+ .classList.remove("hide");
1102
+ ui.core.mapDivDocument.querySelector(`.${key}_dd`).innerHTML =
1103
+ key === "license" || key === "dataLicense"
1104
+ ? `<img src="${
1105
+ pointer[
1106
+ `${from[key].toLowerCase().replace(/ /g, "_")}.png`
1107
+ ]
1108
+ }">`
1109
+ : ui.core.translate(from[key]);
1110
+ }
1111
+ });
1112
+
1113
+ const deleteButton =
1114
+ ui.core.mapDivDocument.querySelector(".cache_delete"); // eslint-disable-line no-undef
1115
+ const fetchButton =
1116
+ ui.core.mapDivDocument.querySelector(".cache_fetch"); // eslint-disable-line no-undef
1117
+ const putTileCacheStats = function (stats) {
1118
+ let size = stats.size || 0;
1119
+ let unit = "Bytes";
1120
+ if (size !== -1) {
1121
+ if (size > 1024) {
1122
+ size = Math.round((size * 10) / 1024) / 10;
1123
+ unit = "KBytes";
1124
+ }
1125
+ if (size > 1024) {
1126
+ size = Math.round((size * 10) / 1024) / 10;
1127
+ unit = "MBytes";
1128
+ }
1129
+ if (size > 1024) {
1130
+ size = Math.round((size * 10) / 1024) / 10;
1131
+ unit = "GBytes";
1132
+ }
1133
+ }
1134
+ let content =
1135
+ size === -1
1136
+ ? ui.core.t("html.cache_processing")
1137
+ : `${size} ${unit}`;
1138
+ if (stats.total) {
1139
+ content = `${content} (${stats.count} / ${stats.total} tiles [${stats.percent}%])`;
1140
+ } else {
1141
+ content = `${content} (${stats.count} tiles)`;
1142
+ }
1143
+ ui.core.mapDivDocument.querySelector(".cache_size").innerHTML =
1144
+ content;
1145
+ if (stats.count != 0) {
1146
+ deleteButton.removeAttribute("disabled");
1147
+ } else {
1148
+ deleteButton.setAttribute("disabled", true);
1149
+ }
1150
+ if (stats.total) {
1151
+ fetchButton.classList.remove("hide");
1152
+ if (stats.total === stats.count) {
1153
+ fetchButton.setAttribute("disabled", true);
1154
+ } else {
1155
+ fetchButton.removeAttribute("disabled");
1156
+ }
1157
+ } else {
1158
+ fetchButton.classList.add("hide");
1159
+ }
1160
+ };
1161
+ ui.modalSetting("map");
1162
+
1163
+ const cacheDiv = ui.core.mapDivDocument.querySelector(
1164
+ ".modal_cache_content"
1165
+ );
1166
+ const cacheEnable = ui.core.getMapCacheEnable(from.mapID);
1167
+
1168
+ if (cacheEnable) {
1169
+ cacheDiv.classList.remove("hide");
1170
+ const deleteFunc = async function (evt) {
1171
+ evt.preventDefault();
1172
+ const from = ui.core.getMapMeta();
1173
+ await ui.core.clearMapTileCacheAsync(from.mapID);
1174
+ putTileCacheStats(
1175
+ await ui.core.getMapTileCacheStatsAsync(from.mapID)
1176
+ );
1177
+ };
1178
+ const cancelFunc = async function (evt) {
1179
+ if (evt) evt.preventDefault();
1180
+ const from = ui.core.getMapMeta();
1181
+ await ui.core.cancelMapTileCacheAsync(from.mapID);
1182
+ };
1183
+ const fetchFunc = async function (evt) {
1184
+ const closeButton =
1185
+ ui.core.mapDivDocument.querySelector(".close");
1186
+ evt.preventDefault();
1187
+ fetchButton.innerHTML = ui.core.t("html.cache_cancel");
1188
+ fetchButton.removeEventListener("click", fetchFunc);
1189
+ fetchButton.addEventListener("click", cancelFunc);
1190
+ closeButton.classList.add("temp_no_close");
1191
+ const from = ui.core.getMapMeta();
1192
+ await ui.core.fetchAllMapTileCacheAsync(
1193
+ from.mapID,
1194
+ async (type, data) => {
1195
+ switch (type) {
1196
+ case "proceed":
1197
+ putTileCacheStats({
1198
+ count: data.processed,
1199
+ total: data.total,
1200
+ percent: data.percent,
1201
+ size: -1
1202
+ });
1203
+ return;
1204
+ case "canceled":
1205
+ case "stop":
1206
+ case "finish":
1207
+ fetchButton.innerHTML = ui.core.t("html.cache_fetch");
1208
+ fetchButton.removeEventListener("click", cancelFunc);
1209
+ fetchButton.addEventListener("click", fetchFunc);
1210
+ closeButton.classList.remove("temp_no_close");
1211
+ putTileCacheStats(
1212
+ await ui.core.getMapTileCacheStatsAsync(from.mapID)
1213
+ );
1214
+ }
1215
+ }
1216
+ );
1217
+ };
1218
+ const hideFunc = function (_event) {
1219
+ deleteButton.removeEventListener("click", deleteFunc, false);
1220
+ fetchButton.removeEventListener("click", fetchFunc, false);
1221
+ fetchButton.removeEventListener("click", cancelFunc, false);
1222
+ modalElm.removeEventListener("hide.bs.modal", hideFunc, false);
1223
+ };
1224
+ modalElm.addEventListener("hide.bs.modal", hideFunc, false);
1225
+
1226
+ putTileCacheStats(
1227
+ await ui.core.getMapTileCacheStatsAsync(from.mapID)
1228
+ );
1229
+
1230
+ setTimeout(() => {
1231
+ // eslint-disable-line no-undef
1232
+ deleteButton.addEventListener("click", deleteFunc, false);
1233
+ fetchButton.addEventListener("click", fetchFunc, false);
1234
+ fetchButton.innerHTML = ui.core.t("html.cache_fetch");
1235
+ }, 200);
1236
+ } else {
1237
+ cacheDiv.classList.add("hide");
1238
+ }
1239
+ modal.show();
1240
+ } else if (control === "help") {
1241
+ ui.modalSetting("help");
1242
+ modal.show();
1243
+ } else if (control === "share") {
1244
+ ui.modalSetting("share");
1245
+
1246
+ const base = location.href; // eslint-disable-line no-undef
1247
+ const div1 = base.split("#!");
1248
+ const path = div1.length > 1 ? div1[1].split("?")[0] : "";
1249
+ const div2 = div1[0].split("?");
1250
+ let uri = div2[0];
1251
+ const query =
1252
+ div2.length > 1
1253
+ ? div2[1]
1254
+ .split("&")
1255
+ .filter(qs => qs !== "pwa")
1256
+ .join("&")
1257
+ : "";
1258
+
1259
+ if (query) uri = `${uri}?${query}`;
1260
+ let view = uri;
1261
+ if (path) view = `${view}#!${path}`;
1262
+ if (!qr_app) {
1263
+ qr_app = new QRCode(
1264
+ ui.core.mapDivDocument.querySelector(".qr_app"),
1265
+ {
1266
+ text: uri,
1267
+ width: 128,
1268
+ height: 128,
1269
+ colorDark: "#000000",
1270
+ colorLight: "#ffffff",
1271
+ correctLevel: QRCode.CorrectLevel.H
1272
+ }
1273
+ );
1274
+ } else {
1275
+ qr_app.makeCode(uri);
1276
+ }
1277
+ if (!qr_view) {
1278
+ qr_view = new QRCode(
1279
+ ui.core.mapDivDocument.querySelector(".qr_view"),
1280
+ {
1281
+ text: view,
1282
+ width: 128,
1283
+ height: 128,
1284
+ colorDark: "#000000",
1285
+ colorLight: "#ffffff",
1286
+ correctLevel: QRCode.CorrectLevel.H
1287
+ }
1288
+ );
1289
+ } else {
1290
+ qr_view.makeCode(view);
1291
+ }
1292
+
1293
+ modal.show();
1294
+ } else if (control === "border") {
1295
+ const flag = !ui.core.stateBuffer.showBorder;
1296
+ ui.setShowBorder(flag);
1297
+ } else if (control === "hideMarker") {
1298
+ const flag = !ui.core.stateBuffer.hideMarker;
1299
+ ui.setHideMarker(flag);
1300
+ } else if (control === "hideLayer") {
1301
+ ui.modalSetting("hide_marker");
1302
+ const layers = ui.core.listPoiLayers(false, true);
1303
+ const elem = ui.core.mapDivDocument.querySelector("ul.list-group");
1304
+ const modalElm = ui.core.mapDivDocument.querySelector(".modalBase");
1305
+ elem.innerHTML = "";
1306
+ layers.map((layer, index) => {
1307
+ const icon = layer.icon || pointer["defaultpin.png"];
1308
+ const title = ui.core.translate(layer.name);
1309
+ const check = !layer.hide;
1310
+ const id = layer.namespaceID;
1311
+ const newElems = createElement(`<li c="list-group-item">
1312
+ <d c="row">
1313
+ <d c="col-sm-1"><img c="markerlist" src="${icon}"></d>
1314
+ <d c="col-sm-9">${title}</d>
1315
+ <d c="col-sm-2">
1316
+ <input type="checkbox" c="markerlist" data="${id}" id="___maplat_marker_${index}_${
1317
+ ui.html_id_seed
1318
+ }"${check ? " checked" : ""}/>
1319
+ <label c="check" for="___maplat_marker_${index}_${
1320
+ ui.html_id_seed
1321
+ }"><d> </d> </label>
1322
+ </d>
1323
+ </d>
1324
+ </li>`);
1325
+ for (let i = 0; i < newElems.length; i++) {
1326
+ elem.appendChild(newElems[i]);
1327
+ }
1328
+ const checkbox = ui.core.mapDivDocument.querySelector(
1329
+ `#___maplat_marker_${index}_${ui.html_id_seed}`
1330
+ );
1331
+ const checkFunc = function (event) {
1332
+ const id = event.target.getAttribute("data");
1333
+ const checked = event.target.checked;
1334
+ if (checked) ui.core.showPoiLayer(id);
1335
+ else ui.core.hidePoiLayer(id);
1336
+ };
1337
+ const hideFunc = function (_event) {
1338
+ modalElm.removeEventListener("hide.bs.modal", hideFunc, false);
1339
+ checkbox.removeEventListener("change", checkFunc, false);
1340
+ };
1341
+ modalElm.addEventListener("hide.bs.modal", hideFunc, false);
1342
+ checkbox.addEventListener("change", checkFunc, false);
1343
+ });
1344
+ modal.show();
1345
+ }
1346
+ });
1347
+ if (fakeGps) {
1348
+ const newElem = createElement(
1349
+ sprintf(
1350
+ ui.core.t("app.fake_explanation"),
1351
+ ui.core.translate(fakeCenter),
1352
+ fakeRadius
1353
+ )
1354
+ )[0];
1355
+ const elem = ui.core.mapDivDocument.querySelector(
1356
+ ".modal_gpsW_content"
1357
+ );
1358
+ elem.appendChild(newElem);
1359
+ } else {
1360
+ const newElem = createElement(ui.core.t("app.acquiring_gps_desc"))[0];
1361
+ const elem = ui.core.mapDivDocument.querySelector(
1362
+ ".modal_gpsW_content"
1363
+ );
1364
+ elem.appendChild(newElem);
1365
+ }
1366
+ if (ui.waitReadyBridge) {
1367
+ ui.waitReadyBridge();
1368
+ delete ui.waitReadyBridge;
1369
+ }
1370
+ });
1371
+ }
1372
+
1373
+ // Modal記述の動作を調整する関数
1374
+ modalSetting(target) {
1375
+ const modalElm = this.core.mapDivDocument.querySelector(".modalBase");
1376
+ ["poi", "map", "load", "gpsW", "gpsD", "help", "share", "hide_marker"].map(
1377
+ target_ => {
1378
+ const className = `modal_${target_}`;
1379
+ if (target === target_) {
1380
+ modalElm.classList.add(className);
1381
+ } else {
1382
+ modalElm.classList.remove(className);
1383
+ }
1384
+ }
1385
+ );
1386
+ }
1387
+
1388
+ handleMarkerAction(data) {
1389
+ if (data.directgo) {
1390
+ let blank = false;
1391
+ let href = "";
1392
+ if (typeof data.directgo == "string") {
1393
+ href = data.directgo;
1394
+ } else {
1395
+ href = data.directgo.href;
1396
+ blank = data.directgo.blank || false;
1397
+ }
1398
+ if (blank) {
1399
+ window.open(href, "_blank"); // eslint-disable-line no-undef
1400
+ } else {
1401
+ window.location.href = href; // eslint-disable-line no-undef
1402
+ }
1403
+ return;
1404
+ }
1405
+
1406
+ this.core.mapDivDocument.querySelector(".modal_title").innerText =
1407
+ this.core.translate(data.name);
1408
+ const modalElm = this.core.mapDivDocument.querySelector(".modalBase");
1409
+ if (data.url || data.html) {
1410
+ this.core.mapDivDocument
1411
+ .querySelector(".poi_web")
1412
+ .classList.remove("hide");
1413
+ this.core.mapDivDocument.querySelector(".poi_data").classList.add("hide");
1414
+ const iframe = this.core.mapDivDocument.querySelector(".poi_iframe");
1415
+ if (data.html) {
1416
+ iframe.addEventListener("load", function loadEvent(event) {
1417
+ event.currentTarget.removeEventListener(event.type, loadEvent);
1418
+ const cssLink = createElement(
1419
+ '<style type="text/css">html, body { height: 100vh; }\n img { width: 100vw; }</style>'
1420
+ );
1421
+ console.log(cssLink); // eslint-disable-line no-undef
1422
+ iframe.contentDocument.head.appendChild(cssLink[0]);
1423
+ });
1424
+ iframe.removeAttribute("src");
1425
+ iframe.setAttribute("srcdoc", this.core.translate(data.html));
1426
+ } else {
1427
+ iframe.removeAttribute("srcdoc");
1428
+ iframe.setAttribute("src", this.core.translate(data.url));
1429
+ }
1430
+ } else {
1431
+ this.core.mapDivDocument
1432
+ .querySelector(".poi_data")
1433
+ .classList.remove("hide");
1434
+ this.core.mapDivDocument.querySelector(".poi_web").classList.add("hide");
1435
+
1436
+ const slides = [];
1437
+ if (data.image && data.image !== "") {
1438
+ const images = Array.isArray(data.image) ? data.image : [data.image];
1439
+ images.forEach(image => {
1440
+ if (typeof image === "string") {
1441
+ image = { src: image };
1442
+ }
1443
+ const tmpImg = this.resolveRelativeLink(image.src, "img");
1444
+ let slide = `<a target="_blank" href="${tmpImg}"><img src="${tmpImg}"></a>`;
1445
+ if (image.desc) slide = `${slide}<div>${image.desc}</div>`;
1446
+ slides.push(`<div class="swiper-slide">${slide}</div>`);
1447
+ });
1448
+ } else if (!this.disableNoimage) {
1449
+ slides.push(
1450
+ `<div class="swiper-slide"><img src="${pointer["no_image.png"]}"></div>`
1451
+ );
1452
+ }
1453
+
1454
+ const imgShowFunc = _event => {
1455
+ modalElm.removeEventListener("shown.bs.modal", imgShowFunc, false);
1456
+ const swiperDiv = this.core.mapDivDocument.querySelector(
1457
+ ".swiper-container.poi_img_swiper"
1458
+ );
1459
+ if (slides.length === 0) {
1460
+ swiperDiv.classList.add("hide");
1461
+ } else {
1462
+ swiperDiv.classList.remove("hide");
1463
+ if (!this.poiSwiper) {
1464
+ this.poiSwiper = new Swiper(".swiper-container.poi_img_swiper", {
1465
+ lazy: true,
1466
+ pagination: {
1467
+ el: ".swiper-pagination",
1468
+ clickable: true
1469
+ },
1470
+ navigation: {
1471
+ nextEl: ".poi-img-next",
1472
+ prevEl: ".poi-img-prev"
1473
+ }
1474
+ });
1475
+ }
1476
+ slides.forEach(slide => this.poiSwiper.appendSlide(slide));
1477
+ }
1478
+ };
1479
+ modalElm.addEventListener("shown.bs.modal", imgShowFunc, false);
1480
+
1481
+ this.core.mapDivDocument.querySelector(".poi_address").innerText =
1482
+ this.core.translate(data.address);
1483
+ this.core.mapDivDocument.querySelector(".poi_desc").innerHTML = this.core
1484
+ .translate(data.desc)
1485
+ .replace(/\n/g, "<br>");
1486
+ }
1487
+ const modal = new bsn.Modal(modalElm, { root: this.core.mapDivDocument });
1488
+ this.core.selectMarker(data.namespaceID);
1489
+ const hideFunc = _event => {
1490
+ modalElm.removeEventListener("hide.bs.modal", hideFunc, false);
1491
+ this.core.unselectMarker();
1492
+ };
1493
+ const hiddenFunc = _event => {
1494
+ modalElm.removeEventListener("hidden.bs.modal", hiddenFunc, false);
1495
+ if (this.poiSwiper) {
1496
+ this.poiSwiper.removeAllSlides();
1497
+ this.poiSwiper = undefined;
1498
+ }
1499
+ };
1500
+ modalElm.addEventListener("hide.bs.modal", hideFunc, false);
1501
+ modalElm.addEventListener("hidden.bs.modal", hiddenFunc, false);
1502
+ this.modalSetting("poi");
1503
+ modal.show();
1504
+ }
1505
+
1506
+ showFillEnvelope(mapIDs) {
1507
+ const ui = this;
1508
+ if (mapIDs.length > 0) {
1509
+ if (!ui._selectCandidateSources) ui._selectCandidateSources = {};
1510
+ Object.keys(ui._selectCandidateSources).forEach(key => {
1511
+ const index = mapIDs.indexOf(key);
1512
+ if (index < 0) {
1513
+ ui.core.mapObject.removeEnvelope(ui._selectCandidateSources[key]);
1514
+ delete ui._selectCandidateSources[key];
1515
+ } else mapIDs.splice(index, 1);
1516
+ });
1517
+
1518
+ mapIDs.forEach(mapID => {
1519
+ if (mapID !== ui.core.from.mapID) {
1520
+ const source = ui.core.cacheHash[mapID];
1521
+ const xyPromises = source.envelope.geometry.coordinates[0].map(
1522
+ coord => ui.core.from.merc2SysCoordAsync(coord)
1523
+ );
1524
+ const hexColor = source.envelopeColor;
1525
+ let color = asArray(hexColor);
1526
+ color = color.slice();
1527
+ color[3] = 0.2;
1528
+
1529
+ Promise.all(xyPromises).then(xys => {
1530
+ ui._selectCandidateSources[mapID] =
1531
+ ui.core.mapObject.setFillEnvelope(xys, null, { color });
1532
+ });
1533
+ }
1534
+ });
1535
+ } else {
1536
+ if (ui._selectCandidateSources) {
1537
+ Object.keys(ui._selectCandidateSources).forEach(key =>
1538
+ ui.core.mapObject.removeEnvelope(ui._selectCandidateSources[key])
1539
+ );
1540
+ delete ui._selectCandidateSources;
1541
+ }
1542
+ }
1543
+ }
1544
+
1545
+ async xyToMapIDs(xy, threshold = 10) {
1546
+ const ui = this;
1547
+ const point_ = point(xy);
1548
+
1549
+ const map = ui.core.mapObject;
1550
+ const size = map.getSize();
1551
+ const extent = [[0, 0], [size[0], 0], size, [0, size[1]], [0, 0]];
1552
+ const sysCoords = extent.map(pixel => map.getCoordinateFromPixel(pixel));
1553
+ const mercs = await (ui.core.from instanceof NowMap
1554
+ ? Promise.resolve(sysCoords)
1555
+ : Promise.all(
1556
+ sysCoords.map(sysCoord => ui.core.from.sysCoord2MercAsync(sysCoord))
1557
+ ));
1558
+ const areaIndex = ui.areaIndex(mercs);
1559
+
1560
+ return Promise.all(
1561
+ Object.keys(ui.core.cacheHash)
1562
+ .filter(key => ui.core.cacheHash[key].envelope)
1563
+ .map(key => {
1564
+ const source = ui.core.cacheHash[key];
1565
+ return Promise.all([
1566
+ Promise.resolve(source),
1567
+ Promise.all(
1568
+ source.envelope.geometry.coordinates[0].map(coord =>
1569
+ ui.core.from.merc2SysCoordAsync(coord)
1570
+ )
1571
+ )
1572
+ ]);
1573
+ })
1574
+ ).then(sources => {
1575
+ const mapIDs = sources
1576
+ .reduce((prev, curr) => {
1577
+ const source = curr[0];
1578
+ const mercXys = curr[1];
1579
+ if (source.mapID !== ui.core.from.mapID) {
1580
+ const polygon_ = polygon([mercXys]);
1581
+ if (booleanPointInPolygon(point_, polygon_)) {
1582
+ prev.push(source);
1583
+ }
1584
+ }
1585
+ return prev;
1586
+ }, [])
1587
+ .filter(source => source.envelopeAreaIndex / areaIndex < threshold)
1588
+ .sort((a, b) => a.envelopeAreaIndex - b.envelopeAreaIndex)
1589
+ .map(source => source.mapID);
1590
+ console.log(mapIDs);
1591
+ return mapIDs;
1592
+ });
1593
+ }
1594
+
1595
+ setShowBorder(flag) {
1596
+ this.core.requestUpdateState({ showBorder: flag ? 1 : 0 });
1597
+ this.updateEnvelope();
1598
+ if (flag) {
1599
+ this.core.mapDivDocument.classList.add("show-border");
1600
+ } else {
1601
+ this.core.mapDivDocument.classList.remove("show-border");
1602
+ }
1603
+ if (this.core.restoreSession) {
1604
+ const currentTime = Math.floor(new Date().getTime() / 1000);
1605
+ localStorage.setItem("epoch", currentTime); // eslint-disable-line no-undef
1606
+ localStorage.setItem("showBorder", flag ? 1 : 0); // eslint-disable-line no-undef
1607
+ }
1608
+ }
1609
+
1610
+ setHideMarker(flag) {
1611
+ if (flag) {
1612
+ this.core.hideAllMarkers();
1613
+ this.core.mapDivDocument.classList.add("hide-marker");
1614
+ } else {
1615
+ this.core.showAllMarkers();
1616
+ this.core.mapDivDocument.classList.remove("hide-marker");
1617
+ }
1618
+ }
1619
+
1620
+ updateEnvelope() {
1621
+ const ui = this;
1622
+ if (!ui.core.mapObject) return;
1623
+
1624
+ ui.core.mapObject.resetEnvelope();
1625
+ delete ui._selectCandidateSources;
1626
+
1627
+ if (ui.core.stateBuffer.showBorder) {
1628
+ Object.keys(ui.core.cacheHash)
1629
+ .filter(key => ui.core.cacheHash[key].envelope)
1630
+ .map(key => {
1631
+ const source = ui.core.cacheHash[key];
1632
+ const xyPromises =
1633
+ key === ui.core.from.mapID && source instanceof HistMap
1634
+ ? [
1635
+ [0, 0],
1636
+ [source.width, 0],
1637
+ [source.width, source.height],
1638
+ [0, source.height],
1639
+ [0, 0]
1640
+ ].map(xy => Promise.resolve(source.xy2SysCoord(xy)))
1641
+ : source.envelope.geometry.coordinates[0].map(coord =>
1642
+ ui.core.from.merc2SysCoordAsync(coord)
1643
+ );
1644
+
1645
+ Promise.all(xyPromises).then(xys => {
1646
+ ui.core.mapObject.setEnvelope(xys, {
1647
+ color: source.envelopeColor,
1648
+ width: 2,
1649
+ lineDash: [6, 6]
1650
+ });
1651
+ });
1652
+ });
1653
+ }
1654
+ }
1655
+
1656
+ resolveRelativeLink(file, fallbackPath) {
1657
+ if (!fallbackPath) fallbackPath = ".";
1658
+ return file.match(/\//) ? file : `${fallbackPath}/${file}`;
1659
+ }
1660
+
1661
+ checkOverlayID(mapID) {
1662
+ const ui = this;
1663
+ const swiper = ui.overlaySwiper;
1664
+ const sliders = swiper.$el[0].querySelectorAll(".swiper-slide");
1665
+ for (let i = 0; i < sliders.length; i++) {
1666
+ const slider = sliders[i];
1667
+ if (slider.getAttribute("data") === mapID) {
1668
+ return true;
1669
+ }
1670
+ }
1671
+ return false;
1672
+ }
1673
+
1674
+ areaIndex(xys) {
1675
+ return (
1676
+ 0.5 *
1677
+ Math.abs(
1678
+ [0, 1, 2, 3].reduce((prev, curr, i) => {
1679
+ const xy1 = xys[i];
1680
+ const xy2 = xys[i + 1];
1681
+ return prev + (xy1[0] - xy2[0]) * (xy1[1] + xy2[1]);
1682
+ }, 0)
1683
+ )
1684
+ );
1685
+ }
1686
+
1687
+ ellips() {
1688
+ const ui = this;
1689
+ const omitMark = "…";
1690
+ const omitLine = 2;
1691
+ const stringSplit = function (element) {
1692
+ const splitArr = element.innerText.split("");
1693
+ let joinString = "";
1694
+ for (let i = 0; i < splitArr.length; i++) {
1695
+ joinString += `<span>${splitArr[i]}</span>`;
1696
+ }
1697
+ joinString += `<span class="omit-mark">${omitMark}</span>`;
1698
+ element.innerHTML = joinString;
1699
+ };
1700
+ const omitCheck = function (element) {
1701
+ const thisSpan = element.querySelectorAll("span");
1702
+ const omitSpan = element.querySelector(".omit-mark");
1703
+ let lineCount = 0;
1704
+ let omitCount;
1705
+
1706
+ if (omitLine <= 0) {
1707
+ return;
1708
+ }
1709
+
1710
+ thisSpan[0].style.display = "";
1711
+ for (let i = 1; i < thisSpan.length; i++) {
1712
+ thisSpan[i].style.display = "none";
1713
+ }
1714
+ omitSpan.style.display = "";
1715
+ let divHeight = element.offsetHeight;
1716
+ let minimizeFont = false;
1717
+ for (let i = 1; i < thisSpan.length - 1; i++) {
1718
+ thisSpan[i].style.display = "";
1719
+ if (element.offsetHeight > divHeight) {
1720
+ if (!minimizeFont) {
1721
+ minimizeFont = true;
1722
+ element.classList.add("minimize");
1723
+ } else {
1724
+ divHeight = element.offsetHeight;
1725
+ lineCount++;
1726
+ }
1727
+ }
1728
+ if (lineCount >= omitLine) {
1729
+ omitCount = i - 2;
1730
+ break;
1731
+ }
1732
+ if (i >= thisSpan.length - 2) {
1733
+ omitSpan.style.display = "none";
1734
+ return;
1735
+ }
1736
+ }
1737
+ for (let i = omitCount; i < thisSpan.length - 1; i++) {
1738
+ thisSpan[i].style.display = "none";
1739
+ }
1740
+ };
1741
+ const swiperItems =
1742
+ ui.core.mapDivDocument.querySelectorAll(".swiper-slide div");
1743
+ for (let i = 0; i < swiperItems.length; i++) {
1744
+ const swiperItem = swiperItems[i];
1745
+ stringSplit(swiperItem);
1746
+ omitCheck(swiperItem);
1747
+ }
1748
+ }
1749
+
1750
+ remove() {
1751
+ this.core.remove();
1752
+ delete this.core;
1753
+ }
1754
+ }