@panoramax/web-viewer 3.0.2-develop-a8ea8e60
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/.dockerignore +6 -0
- package/.gitlab-ci.yml +71 -0
- package/CHANGELOG.md +428 -0
- package/CODE_OF_CONDUCT.md +134 -0
- package/Dockerfile +14 -0
- package/LICENSE +21 -0
- package/README.md +39 -0
- package/build/editor.html +1 -0
- package/build/index.css +36 -0
- package/build/index.css.map +1 -0
- package/build/index.html +1 -0
- package/build/index.js +25 -0
- package/build/index.js.map +1 -0
- package/build/map.html +1 -0
- package/build/viewer.html +1 -0
- package/config/env.js +104 -0
- package/config/getHttpsConfig.js +66 -0
- package/config/getPackageJson.js +25 -0
- package/config/jest/babelTransform.js +29 -0
- package/config/jest/cssTransform.js +14 -0
- package/config/jest/fileTransform.js +40 -0
- package/config/modules.js +134 -0
- package/config/paths.js +72 -0
- package/config/pnpTs.js +35 -0
- package/config/webpack/persistentCache/createEnvironmentHash.js +9 -0
- package/config/webpack.config.js +885 -0
- package/config/webpackDevServer.config.js +127 -0
- package/docs/01_Start.md +149 -0
- package/docs/02_Usage.md +828 -0
- package/docs/03_URL_settings.md +140 -0
- package/docs/04_Advanced_examples.md +214 -0
- package/docs/05_Compatibility.md +85 -0
- package/docs/09_Develop.md +62 -0
- package/docs/90_Releases.md +27 -0
- package/docs/images/class_diagram.drawio +129 -0
- package/docs/images/class_diagram.jpg +0 -0
- package/docs/images/screenshot.jpg +0 -0
- package/mkdocs.yml +45 -0
- package/package.json +254 -0
- package/public/editor.html +54 -0
- package/public/favicon.ico +0 -0
- package/public/index.html +59 -0
- package/public/map.html +53 -0
- package/public/viewer.html +67 -0
- package/scripts/build.js +217 -0
- package/scripts/start.js +176 -0
- package/scripts/test.js +52 -0
- package/src/Editor.css +37 -0
- package/src/Editor.js +359 -0
- package/src/StandaloneMap.js +114 -0
- package/src/Viewer.css +203 -0
- package/src/Viewer.js +1186 -0
- package/src/components/CoreView.css +64 -0
- package/src/components/CoreView.js +159 -0
- package/src/components/Loader.css +56 -0
- package/src/components/Loader.js +111 -0
- package/src/components/Map.css +65 -0
- package/src/components/Map.js +841 -0
- package/src/components/Photo.css +36 -0
- package/src/components/Photo.js +687 -0
- package/src/img/arrow_360.svg +14 -0
- package/src/img/arrow_flat.svg +11 -0
- package/src/img/arrow_triangle.svg +10 -0
- package/src/img/arrow_turn.svg +9 -0
- package/src/img/bg_aerial.jpg +0 -0
- package/src/img/bg_streets.jpg +0 -0
- package/src/img/loader_base.jpg +0 -0
- package/src/img/loader_hd.jpg +0 -0
- package/src/img/logo_dead.svg +91 -0
- package/src/img/marker.svg +17 -0
- package/src/img/marker_blue.svg +20 -0
- package/src/img/switch_big.svg +44 -0
- package/src/img/switch_mini.svg +48 -0
- package/src/index.js +10 -0
- package/src/translations/de.json +163 -0
- package/src/translations/en.json +164 -0
- package/src/translations/eo.json +6 -0
- package/src/translations/es.json +164 -0
- package/src/translations/fi.json +1 -0
- package/src/translations/fr.json +164 -0
- package/src/translations/hu.json +133 -0
- package/src/translations/nl.json +1 -0
- package/src/translations/zh_Hant.json +136 -0
- package/src/utils/API.js +709 -0
- package/src/utils/Exif.js +198 -0
- package/src/utils/I18n.js +75 -0
- package/src/utils/Map.js +382 -0
- package/src/utils/PhotoAdapter.js +45 -0
- package/src/utils/Utils.js +568 -0
- package/src/utils/Widgets.js +477 -0
- package/src/viewer/URLHash.js +334 -0
- package/src/viewer/Widgets.css +711 -0
- package/src/viewer/Widgets.js +1196 -0
- package/tests/Editor.test.js +125 -0
- package/tests/StandaloneMap.test.js +44 -0
- package/tests/Viewer.test.js +363 -0
- package/tests/__snapshots__/Editor.test.js.snap +300 -0
- package/tests/__snapshots__/StandaloneMap.test.js.snap +30 -0
- package/tests/__snapshots__/Viewer.test.js.snap +195 -0
- package/tests/components/CoreView.test.js +91 -0
- package/tests/components/Loader.test.js +38 -0
- package/tests/components/Map.test.js +230 -0
- package/tests/components/Photo.test.js +335 -0
- package/tests/components/__snapshots__/Loader.test.js.snap +15 -0
- package/tests/components/__snapshots__/Map.test.js.snap +767 -0
- package/tests/components/__snapshots__/Photo.test.js.snap +205 -0
- package/tests/data/Map_geocoder_ban.json +36 -0
- package/tests/data/Map_geocoder_nominatim.json +56 -0
- package/tests/data/Viewer_pictures_1.json +148 -0
- package/tests/setupTests.js +5 -0
- package/tests/utils/API.test.js +906 -0
- package/tests/utils/Exif.test.js +124 -0
- package/tests/utils/I18n.test.js +28 -0
- package/tests/utils/Map.test.js +105 -0
- package/tests/utils/Utils.test.js +300 -0
- package/tests/utils/Widgets.test.js +107 -0
- package/tests/utils/__snapshots__/API.test.js.snap +132 -0
- package/tests/utils/__snapshots__/Exif.test.js.snap +43 -0
- package/tests/utils/__snapshots__/Map.test.js.snap +48 -0
- package/tests/utils/__snapshots__/Utils.test.js.snap +41 -0
- package/tests/utils/__snapshots__/Widgets.test.js.snap +44 -0
- package/tests/viewer/URLHash.test.js +537 -0
- package/tests/viewer/Widgets.test.js +127 -0
- package/tests/viewer/__snapshots__/URLHash.test.js.snap +98 -0
- package/tests/viewer/__snapshots__/Widgets.test.js.snap +393 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/* Main container */
|
|
2
|
+
.gvs {
|
|
3
|
+
container-type: inline-size;
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.gvs * { box-sizing: border-box; }
|
|
8
|
+
|
|
9
|
+
/* Colors */
|
|
10
|
+
:root {
|
|
11
|
+
--white: #ffffff;
|
|
12
|
+
--black: #181818;
|
|
13
|
+
--black-pale: #1b1a17;
|
|
14
|
+
--red: #f70000;
|
|
15
|
+
--red-pale: #ff726f;
|
|
16
|
+
--grey: #f5f5f5;
|
|
17
|
+
--grey-pale: #cfd2cf;
|
|
18
|
+
--grey-semi-dark: #808080;
|
|
19
|
+
--grey-dark: #3e3e3e;
|
|
20
|
+
--blue: #2954e9;
|
|
21
|
+
--blue-dark: #0a1f69;
|
|
22
|
+
--blue-semi: #d7dffc;
|
|
23
|
+
--blue-pale: #f2f5ff;
|
|
24
|
+
--blue-geovisio: #34495e;
|
|
25
|
+
--beige: #f5f3ec;
|
|
26
|
+
--yellow: #fec868;
|
|
27
|
+
--orange: #ff6f00;
|
|
28
|
+
--orange-pale: #fffafa;
|
|
29
|
+
--green: #7ec636;
|
|
30
|
+
--green-pale: #f0ffee;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* Titles */
|
|
34
|
+
.gvs h3 {
|
|
35
|
+
font-size: 1.1em;
|
|
36
|
+
line-height: 1.1em;
|
|
37
|
+
font-weight: 500;
|
|
38
|
+
margin: 10px 0 10px 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.gvs h4 {
|
|
42
|
+
font-size: 1.0em;
|
|
43
|
+
line-height: 1.0em;
|
|
44
|
+
font-weight: 500;
|
|
45
|
+
margin: 15px 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.gvs h4:first-of-type { margin-top: 0; }
|
|
49
|
+
|
|
50
|
+
.gvs h4 svg {
|
|
51
|
+
height: 18px;
|
|
52
|
+
vertical-align: sub;
|
|
53
|
+
margin-right: 2px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* Hidden elements on mobile */
|
|
57
|
+
@container (max-width: 576px) {
|
|
58
|
+
.gvs-mobile-hidden { display: none !important; }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Hidden elements on print */
|
|
62
|
+
@media print {
|
|
63
|
+
.gvs-print-hidden { display: none !important; }
|
|
64
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import "./CoreView.css";
|
|
2
|
+
import API from "../utils/API";
|
|
3
|
+
import { getTranslations } from "../utils/I18n";
|
|
4
|
+
import { DEFAULT_TILES } from "../utils/Map";
|
|
5
|
+
import { isInIframe, isInternetFast } from "../utils/Utils";
|
|
6
|
+
import PACKAGE_JSON from "../../package.json";
|
|
7
|
+
import Loader from "./Loader";
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Core view is an abstract class used for setting up any of the main Panoramax JS view components.
|
|
12
|
+
*
|
|
13
|
+
* It is used to prepare API, internationalization, options checks... for Viewer, StandaloneMap and Editor classes.
|
|
14
|
+
*
|
|
15
|
+
* @param {string|Element} container The DOM element to create viewer into
|
|
16
|
+
* @param {string} endpoint URL to API to use (must be a [STAC API](https://github.com/radiantearth/stac-api-spec/blob/main/overview.md))
|
|
17
|
+
* @param {object} [options] View options.
|
|
18
|
+
* @param {string} [options.selectedSequence] The ID of sequence to highlight on load (defaults to none)
|
|
19
|
+
* @param {string} [options.selectedPicture] The ID of picture to highlight on load (defaults to none)
|
|
20
|
+
* @param {object} [options.fetchOptions=null] Set custom options for fetch calls made against API ([same syntax as fetch options parameter](https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters))
|
|
21
|
+
* @param {string|string[]} [options.users] List of user IDs to default use for display. Defaults to all users.
|
|
22
|
+
* @param {string|object} [options.style] The map's MapLibre style. This can be an a JSON object conforming to the schema described in the [MapLibre Style Specification](https://maplibre.org/maplibre-gl-js-docs/style-spec/), or a URL string pointing to one. Defaults to OSMFR vector tiles.
|
|
23
|
+
*
|
|
24
|
+
* @property {object} _t The translations labels
|
|
25
|
+
* @property {string} _selectedSeqId The selected sequence ID
|
|
26
|
+
* @property {string} _selectedPicId The selected picture ID
|
|
27
|
+
* @property {API} _api The API handler
|
|
28
|
+
* @property {Loader} _loader The initial loader message
|
|
29
|
+
* @property {object} _options The stored options
|
|
30
|
+
* @property {Element} container The DOM container
|
|
31
|
+
*/
|
|
32
|
+
export default class CoreView extends EventTarget {
|
|
33
|
+
constructor(container, endpoint, options = {}) {
|
|
34
|
+
super();
|
|
35
|
+
|
|
36
|
+
this._options = options;
|
|
37
|
+
if(this._options == null) { this._options = {}; }
|
|
38
|
+
if(!this._options.users) { this._options.users = ["geovisio"]; }
|
|
39
|
+
if(typeof this._options.users === "string") { this._options.users = [this._options.users]; }
|
|
40
|
+
if(!this._options.style) { this._options.style = DEFAULT_TILES; }
|
|
41
|
+
|
|
42
|
+
if(!this._options.testing) {
|
|
43
|
+
// Display version in logs
|
|
44
|
+
console.info(`📷 Panoramax ${this.getClassName()} - Version ${PACKAGE_JSON.version} (${__COMMIT_HASH__})
|
|
45
|
+
|
|
46
|
+
🆘 Issues can be reported at ${PACKAGE_JSON.repository.url}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Translations
|
|
50
|
+
this._t = getTranslations(this._options.lang);
|
|
51
|
+
|
|
52
|
+
// Internet speed check
|
|
53
|
+
this._isInternetFast = null;
|
|
54
|
+
isInternetFast().then(isFast => this._isInternetFast = isFast);
|
|
55
|
+
|
|
56
|
+
// Selected IDs
|
|
57
|
+
this._selectedSeqId = this._options.selectedSequence || null;
|
|
58
|
+
this._selectedPicId = this._options.selectedPicture || null;
|
|
59
|
+
|
|
60
|
+
// Container init
|
|
61
|
+
this.container = typeof container === "string" ? document.getElementById(container) : container;
|
|
62
|
+
if(!(this.container instanceof Element)) { throw new Error("Container is not a valid HTML element, does it exist in your page ?"); }
|
|
63
|
+
this.container.classList.add("gvs", `gvs-${this.getClassName().toLocaleLowerCase()}`);
|
|
64
|
+
if(isInIframe()) { this.container.classList.add("gvs-iframed"); }
|
|
65
|
+
|
|
66
|
+
// Loader init
|
|
67
|
+
this.loaderContainer = document.createElement("div");
|
|
68
|
+
this.container.appendChild(this.loaderContainer);
|
|
69
|
+
this._loader = new Loader(this, this.loaderContainer);
|
|
70
|
+
|
|
71
|
+
// API init
|
|
72
|
+
endpoint = endpoint.replace("/api/search", "/api");
|
|
73
|
+
this._api = new API(endpoint, {
|
|
74
|
+
users: this._options.users,
|
|
75
|
+
fetch: this._options?.fetchOptions,
|
|
76
|
+
style: this._options.style,
|
|
77
|
+
});
|
|
78
|
+
this._api.onceReady()
|
|
79
|
+
.then(() => console.info(`🌐 Connected to API "${this._api._metadata.name}" (${this._api._endpoint})\nℹ️ API runs STAC ${this._api._metadata.stac_version} & GeoVisio ${this._api._metadata.geovisio_version}`))
|
|
80
|
+
.catch(e => this._loader.dismiss(e, this._t.gvs.error_api));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* This allows to retrieve an always correct class name.
|
|
85
|
+
* This is crap, but avoids issues with Webpack & so on.
|
|
86
|
+
*
|
|
87
|
+
* Each inheriting class must override this method.
|
|
88
|
+
*/
|
|
89
|
+
getClassName() {
|
|
90
|
+
return "CoreView";
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Ends all form of life in this object.
|
|
95
|
+
*
|
|
96
|
+
* This is useful for Single Page Applications (SPA), to remove various event listeners.
|
|
97
|
+
*/
|
|
98
|
+
destroy() {
|
|
99
|
+
delete this._options;
|
|
100
|
+
delete this._t;
|
|
101
|
+
delete this._api;
|
|
102
|
+
delete this._loader;
|
|
103
|
+
this.loaderContainer.remove();
|
|
104
|
+
delete this.loaderContainer;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Is the view running in a small container (small embed or smartphone)
|
|
109
|
+
* @returns {boolean} True if container is small
|
|
110
|
+
*/
|
|
111
|
+
isWidthSmall() {
|
|
112
|
+
return this.container?.offsetWidth < 576;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Is the view running in a small-height container (small embed or smartphone)
|
|
117
|
+
* @returns {boolean} True if container height is small
|
|
118
|
+
*/
|
|
119
|
+
isHeightSmall() {
|
|
120
|
+
return this.container?.offsetHeight < 400;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Change the currently picture and/or sequence.
|
|
125
|
+
* Calling the method without parameters unselects.
|
|
126
|
+
* @param {string} [seqId] The sequence UUID
|
|
127
|
+
* @param {string} [picId] The picture UUID
|
|
128
|
+
* @param {boolean} [force=false] Force select even if already selected
|
|
129
|
+
*/
|
|
130
|
+
select(seqId = null, picId = null, force = false) {
|
|
131
|
+
const prevSeqId = this._selectedSeqId || null;
|
|
132
|
+
const prevPicId = this._selectedPicId || null;
|
|
133
|
+
if(!force && prevPicId == picId) { return; } // Avoid running if already selected
|
|
134
|
+
|
|
135
|
+
this._selectedSeqId = seqId;
|
|
136
|
+
this._selectedPicId = picId;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Event for sequence/picture selection
|
|
140
|
+
*
|
|
141
|
+
* @event select
|
|
142
|
+
* @memberof CoreView
|
|
143
|
+
* @type {object}
|
|
144
|
+
* @property {object} detail Event information
|
|
145
|
+
* @property {string} detail.seqId The selected sequence ID
|
|
146
|
+
* @property {string} detail.picId The selected picture ID (or null if not a precise picture clicked)
|
|
147
|
+
* @property {string} [detail.prevSeqId] The previously selected sequence ID (or null if none)
|
|
148
|
+
* @property {string} [detail.prevPicId] The previously selected picture ID (or null if none)
|
|
149
|
+
*/
|
|
150
|
+
this.dispatchEvent(new CustomEvent("select", {
|
|
151
|
+
detail: {
|
|
152
|
+
seqId,
|
|
153
|
+
picId,
|
|
154
|
+
prevSeqId,
|
|
155
|
+
prevPicId,
|
|
156
|
+
}
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
.gvs .gvs-loader {
|
|
2
|
+
position: relative;
|
|
3
|
+
width: 100%;
|
|
4
|
+
height: 100%;
|
|
5
|
+
z-index: 0;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.gvs .gvs-loader.gvs-loader-visible {
|
|
9
|
+
visibility: visible;
|
|
10
|
+
opacity: 1;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/* Loader overlay */
|
|
14
|
+
.gvs .gvs-loader {
|
|
15
|
+
visibility: hidden;
|
|
16
|
+
position: absolute;
|
|
17
|
+
top: 0;
|
|
18
|
+
right: 0;
|
|
19
|
+
left: 0;
|
|
20
|
+
bottom: 0;
|
|
21
|
+
opacity: 0;
|
|
22
|
+
display: flex;
|
|
23
|
+
flex-direction: column;
|
|
24
|
+
justify-content: center;
|
|
25
|
+
gap: 40px;
|
|
26
|
+
align-items: center;
|
|
27
|
+
background: #37474F;
|
|
28
|
+
z-index: 9000;
|
|
29
|
+
transition: all 0.5s;
|
|
30
|
+
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
|
|
31
|
+
font-weight: 550;
|
|
32
|
+
color: white;
|
|
33
|
+
font-size: 1.4em;
|
|
34
|
+
text-align: center;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.gvs .gvs-loader a {
|
|
38
|
+
color: white !important;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* Flashing text */
|
|
42
|
+
.gvs .gvs-loader > div > span {
|
|
43
|
+
animation: blinker 2s linear infinite;
|
|
44
|
+
}
|
|
45
|
+
@keyframes blinker { 50% { opacity: 0.3; } }
|
|
46
|
+
|
|
47
|
+
/* Rotating logo */
|
|
48
|
+
.gvs .gvs-loader .gvs-loader-img {
|
|
49
|
+
width: 150px;
|
|
50
|
+
animation: rotating 1.4s linear infinite;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@keyframes rotating {
|
|
54
|
+
from { transform: rotate(0deg); }
|
|
55
|
+
to { transform: rotate(360deg); }
|
|
56
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import "./Loader.css";
|
|
2
|
+
import LogoDead from "../img/logo_dead.svg";
|
|
3
|
+
import LoaderImg from "../img/marker.svg";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Loader is a full-screen loading message.
|
|
7
|
+
* @private
|
|
8
|
+
*
|
|
9
|
+
* @param {CoreView} parent The parent view
|
|
10
|
+
* @param {Element} container The DOM element to create loader into
|
|
11
|
+
*/
|
|
12
|
+
export default class Loader {
|
|
13
|
+
constructor(parent, container) {
|
|
14
|
+
this._parent = parent;
|
|
15
|
+
this.container = container;
|
|
16
|
+
this.container.classList.add("gvs-loader", "gvs-loader-visible");
|
|
17
|
+
|
|
18
|
+
// Logo
|
|
19
|
+
const logo = document.createElement("img");
|
|
20
|
+
logo.src = LoaderImg;
|
|
21
|
+
logo.title = this._parent._t.map.loading;
|
|
22
|
+
logo.classList.add("gvs-loader-img");
|
|
23
|
+
this.container.appendChild(logo);
|
|
24
|
+
|
|
25
|
+
// Label (1 serious, then fun ones)
|
|
26
|
+
const labelWrapper = document.createElement("div");
|
|
27
|
+
const label = document.createElement("span");
|
|
28
|
+
const nextLabelFun = () => (
|
|
29
|
+
this._parent._t.gvs.loading_labels_fun[
|
|
30
|
+
Math.floor(Math.random() * this._parent._t.gvs.loading_labels_fun.length)
|
|
31
|
+
]
|
|
32
|
+
);
|
|
33
|
+
label.innerHTML = this._parent._t.gvs.loading_labels_serious[
|
|
34
|
+
Math.floor(Math.random() * this._parent._t.gvs.loading_labels_serious.length)
|
|
35
|
+
];
|
|
36
|
+
const nextLabelFct = () => setTimeout(() => {
|
|
37
|
+
label.innerHTML = nextLabelFun();
|
|
38
|
+
this._loaderLabelChanger = nextLabelFct();
|
|
39
|
+
}, 500 + Math.random() * 1000);
|
|
40
|
+
this._loaderLabelChanger = nextLabelFct();
|
|
41
|
+
labelWrapper.appendChild(label);
|
|
42
|
+
|
|
43
|
+
this.container.appendChild(labelWrapper);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Is the loader visible ?
|
|
48
|
+
* @returns {boolean} True if visible
|
|
49
|
+
*/
|
|
50
|
+
isVisible() {
|
|
51
|
+
return this.container.classList.contains("gvs-loader-visible");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Dismiss loader, or show error
|
|
56
|
+
* @param {object} [err] Optional error object to show in browser console
|
|
57
|
+
* @param {str} [errMeaningful] Optional error message to show to user
|
|
58
|
+
* @param {fct} [next] Optional function to run after loader dismiss
|
|
59
|
+
*/
|
|
60
|
+
dismiss(err = null, errMeaningful = null, next = null) {
|
|
61
|
+
clearTimeout(this._loaderLabelChanger);
|
|
62
|
+
|
|
63
|
+
if(!err) {
|
|
64
|
+
this.container.classList.remove("gvs-loader-visible");
|
|
65
|
+
setTimeout(() => this.container.remove(), 2000);
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Event for viewer being ready to use (API loaded)
|
|
69
|
+
*
|
|
70
|
+
* @event ready
|
|
71
|
+
* @memberof CoreView
|
|
72
|
+
*/
|
|
73
|
+
const readyEvt = new CustomEvent("ready");
|
|
74
|
+
this._parent.dispatchEvent(readyEvt);
|
|
75
|
+
|
|
76
|
+
if(next) { next(); }
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
if(err !== true) { console.error(err); }
|
|
80
|
+
|
|
81
|
+
// Change content
|
|
82
|
+
this.container.children[0].src = LogoDead;
|
|
83
|
+
this.container.children[0].style.width = "200px";
|
|
84
|
+
this.container.children[0].style.animation = "unset";
|
|
85
|
+
let errHtml = `<small>${next ? this._parent._t.gvs.error_click : this._parent._t.gvs.error_retry}</small>`;
|
|
86
|
+
if(errMeaningful) { errHtml = errMeaningful + "<br />" + errHtml; }
|
|
87
|
+
this.container.children[1].innerHTML = `${this._parent._t.gvs.error}<br />${errHtml}`;
|
|
88
|
+
if(next) {
|
|
89
|
+
this.container.addEventListener("click", next);
|
|
90
|
+
}
|
|
91
|
+
const errLabel = errMeaningful || "Panoramax JS had a blocking exception";
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Event for viewer failing to initially load
|
|
95
|
+
*
|
|
96
|
+
* @event broken
|
|
97
|
+
* @memberof CoreView
|
|
98
|
+
* @type {object}
|
|
99
|
+
* @property {object} detail Event information
|
|
100
|
+
* @property {string} detail.error The user-friendly error message to display
|
|
101
|
+
*/
|
|
102
|
+
const brokenEvt = new CustomEvent("broken", {
|
|
103
|
+
detail: { error: errLabel }
|
|
104
|
+
});
|
|
105
|
+
this._parent.dispatchEvent(brokenEvt);
|
|
106
|
+
|
|
107
|
+
// Throw error
|
|
108
|
+
throw new Error(errLabel);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/* Force maplibre to fill all available space */
|
|
2
|
+
.gvs-map.maplibregl-map {
|
|
3
|
+
width: 100%;
|
|
4
|
+
height: 100%;
|
|
5
|
+
background-color: white;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/* Picture thumbnail on map */
|
|
9
|
+
.maplibregl-popup-content {
|
|
10
|
+
padding: 5px !important;
|
|
11
|
+
position: relative;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.gvs-map-thumb {
|
|
15
|
+
display: inline-block;
|
|
16
|
+
text-align: center;
|
|
17
|
+
vertical-align: middle;
|
|
18
|
+
max-width: 130px;
|
|
19
|
+
max-height: 130px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@keyframes rotating {
|
|
23
|
+
from { transform: rotate(0deg); }
|
|
24
|
+
to { transform: rotate(360deg); }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.gvs-map-thumb-loader {
|
|
28
|
+
background-color: rgb(230,230,230);
|
|
29
|
+
border-radius: 65px;
|
|
30
|
+
max-height: 60px;
|
|
31
|
+
margin: 5px 35px;
|
|
32
|
+
animation: rotating 2s linear infinite;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.gvs-map-thumb-legend {
|
|
36
|
+
display: block;
|
|
37
|
+
position: absolute;
|
|
38
|
+
bottom: 5px;
|
|
39
|
+
right: 5px;
|
|
40
|
+
left: 5px;
|
|
41
|
+
background-color: rgba(0,0,0,0.8);
|
|
42
|
+
color: white;
|
|
43
|
+
text-align: center;
|
|
44
|
+
font-style: italic;
|
|
45
|
+
font-size: 0.8em;
|
|
46
|
+
margin: 0;
|
|
47
|
+
padding: 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Max size for geocoder search bar */
|
|
51
|
+
.maplibregl-ctrl-geocoder {
|
|
52
|
+
max-width: 60%;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.maplibregl-marker {
|
|
56
|
+
width: 60px;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* Resize canvas for print */
|
|
60
|
+
@media print {
|
|
61
|
+
.gvs-map.maplibregl-map canvas {
|
|
62
|
+
width: 100% !important;
|
|
63
|
+
height: 100% !important;
|
|
64
|
+
}
|
|
65
|
+
}
|