@trailstash/ultra 4.3.1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitlab-ci.yml +1 -0
- package/MapLibre-Examples/color-relief.ultra +58 -0
- package/components/button-modal.js +8 -9
- package/components/code-editor.js +2 -0
- package/components/export-modal.js +282 -0
- package/components/fontawesome-icon.js +4 -0
- package/components/share-modal.js +14 -0
- package/components/ultra-ide.js +55 -13
- package/components/ultra-map.js +38 -10
- package/config.mjs +1 -1
- package/docs/assets/MapLibre-Examples/color-relief.png +0 -0
- package/docs/further-reading.md +1 -1
- package/docs/open-with-ultra.md +94 -0
- package/docs/style.md +2 -2
- package/docs/url-parameters.md +1 -1
- package/docs/yaml.md +23 -1
- package/index.html +11 -3
- package/index.js +1 -1
- package/lib/htmlExport.js +74 -0
- package/lib/localStorage.js +0 -3
- package/lib/queryProviders/geojson.js +2 -2
- package/lib/queryProviders/gpx.js +2 -2
- package/lib/queryProviders/kml.js +2 -2
- package/lib/queryProviders/raster.js +2 -2
- package/lib/queryProviders/tcx.js +2 -2
- package/lib/queryProviders/util.js +2 -2
- package/lib/queryProviders/vector.js +21 -18
- package/lib/sandbox.js +93 -0
- package/lib/style.js +3 -3
- package/og:image.ultra +44 -0
- package/package.json +2 -1
- package/pages-config.mjs +12 -0
- package/static/og:image.png +0 -0
package/.gitlab-ci.yml
CHANGED
|
@@ -10,6 +10,7 @@ pages:
|
|
|
10
10
|
- npm ci
|
|
11
11
|
# Update version
|
|
12
12
|
- jq ".version = \"$(git describe --tags --dirty | sed -e 's/^v//')\"" package.json | sponge package.json
|
|
13
|
+
- mv pages-config.mjs config.mjs
|
|
13
14
|
- npm run build
|
|
14
15
|
- npm run build:examples-docs
|
|
15
16
|
- npm run build:maplibre-examples-docs
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Add a color relief layer
|
|
3
|
+
description: Add a color relief layer.
|
|
4
|
+
options:
|
|
5
|
+
center: [ 11.45, 47.2 ]
|
|
6
|
+
zoom: 10
|
|
7
|
+
pitch: 0
|
|
8
|
+
style:
|
|
9
|
+
version: 8
|
|
10
|
+
sources:
|
|
11
|
+
terrainSource:
|
|
12
|
+
type: raster-dem
|
|
13
|
+
url: https://demotiles.maplibre.org/terrain-tiles/tiles.json
|
|
14
|
+
tileSize: 256
|
|
15
|
+
layers:
|
|
16
|
+
- type: color-relief
|
|
17
|
+
source: terrainSource
|
|
18
|
+
color-relief-color:
|
|
19
|
+
- interpolate
|
|
20
|
+
- [linear]
|
|
21
|
+
- [elevation]
|
|
22
|
+
- 400
|
|
23
|
+
- rgb(4, 0, 108)
|
|
24
|
+
- 582.35
|
|
25
|
+
- rgb(5, 1, 154)
|
|
26
|
+
- 764.71
|
|
27
|
+
- rgb(10, 21, 189)
|
|
28
|
+
- 947.06
|
|
29
|
+
- rgb(16, 44, 218)
|
|
30
|
+
- 1129.41
|
|
31
|
+
- rgb(24, 69, 240)
|
|
32
|
+
- 1311.76
|
|
33
|
+
- rgb(20, 112, 193)
|
|
34
|
+
- 1494.12
|
|
35
|
+
- rgb(39, 144, 116)
|
|
36
|
+
- 1676.47
|
|
37
|
+
- rgb(57, 169, 29)
|
|
38
|
+
- 1858.82
|
|
39
|
+
- rgb(111, 186, 5)
|
|
40
|
+
- 2041.18
|
|
41
|
+
- rgb(160, 201, 4)
|
|
42
|
+
- 2223.53
|
|
43
|
+
- rgb(205, 216, 2)
|
|
44
|
+
- 2405.88
|
|
45
|
+
- rgb(244, 221, 4)
|
|
46
|
+
- 2588.24
|
|
47
|
+
- rgb(251, 194, 14)
|
|
48
|
+
- 2770.59
|
|
49
|
+
- rgb(252, 163, 21)
|
|
50
|
+
- 2952.94
|
|
51
|
+
- rgb(253, 128, 20)
|
|
52
|
+
- 3135.29
|
|
53
|
+
- rgb(254, 85, 14)
|
|
54
|
+
- 3317.65
|
|
55
|
+
- rgb(243, 36, 13)
|
|
56
|
+
- 3500
|
|
57
|
+
- rgb(215, 5, 13)
|
|
58
|
+
---
|
|
@@ -27,14 +27,14 @@ export class ButtonModal extends HTMLElement {
|
|
|
27
27
|
button {
|
|
28
28
|
position: relative;
|
|
29
29
|
}
|
|
30
|
-
button div span.close {
|
|
30
|
+
button + div.backdrop span.close {
|
|
31
31
|
cursor: pointer;
|
|
32
32
|
float: right;
|
|
33
33
|
}
|
|
34
34
|
button.button-modal:after {
|
|
35
35
|
content: " ${this.text}";
|
|
36
36
|
}
|
|
37
|
-
button
|
|
37
|
+
button + div.backdrop {
|
|
38
38
|
cursor: default;
|
|
39
39
|
display: none;
|
|
40
40
|
z-index: 1;
|
|
@@ -45,14 +45,14 @@ export class ButtonModal extends HTMLElement {
|
|
|
45
45
|
right: 0;
|
|
46
46
|
background: rgba(0,0,0,0.5);
|
|
47
47
|
}
|
|
48
|
-
button
|
|
48
|
+
button + div.backdrop.visible {
|
|
49
49
|
display: flex;
|
|
50
50
|
flex-direction: column;
|
|
51
51
|
justify-content: center;
|
|
52
52
|
align-items: center;
|
|
53
53
|
padding: 20px;
|
|
54
54
|
}
|
|
55
|
-
button
|
|
55
|
+
button + div.backdrop > div {
|
|
56
56
|
max-height: 100%;
|
|
57
57
|
max-width: 100%;
|
|
58
58
|
overflow: auto;
|
|
@@ -81,21 +81,19 @@ export class ButtonModal extends HTMLElement {
|
|
|
81
81
|
h("span", { class: "close" }, "×"),
|
|
82
82
|
h("slot", { name: "modal-content" }),
|
|
83
83
|
);
|
|
84
|
-
const backdrop = h("div", {}, div);
|
|
84
|
+
const backdrop = h("div", { className: "backdrop" }, div);
|
|
85
85
|
const button = h(
|
|
86
86
|
"button",
|
|
87
87
|
{ class: "button-modal" },
|
|
88
88
|
h("fa-icon", { icon: this.icon }),
|
|
89
|
-
backdrop,
|
|
90
89
|
);
|
|
91
90
|
this.refs = { button, div, backdrop };
|
|
92
91
|
|
|
93
92
|
button.addEventListener("click", () => {
|
|
94
93
|
this.toggle();
|
|
95
94
|
});
|
|
96
|
-
|
|
97
|
-
e.
|
|
98
|
-
e.stopPropagation();
|
|
95
|
+
backdrop.addEventListener("click", (e) => {
|
|
96
|
+
if (e.target.classList.contains("backdrop")) this.toggle();
|
|
99
97
|
});
|
|
100
98
|
div.querySelector("span.close").addEventListener("click", (e) => {
|
|
101
99
|
this.toggle();
|
|
@@ -104,6 +102,7 @@ export class ButtonModal extends HTMLElement {
|
|
|
104
102
|
});
|
|
105
103
|
|
|
106
104
|
shadow.appendChild(button);
|
|
105
|
+
shadow.appendChild(backdrop);
|
|
107
106
|
}
|
|
108
107
|
toggle() {
|
|
109
108
|
this.refs.backdrop.classList.toggle("visible");
|
|
@@ -45,6 +45,8 @@ export class CodeEditor extends HTMLElement {
|
|
|
45
45
|
value: this.source,
|
|
46
46
|
});
|
|
47
47
|
this.refs = { textarea };
|
|
48
|
+
this.refs.textarea.selectionStart = 0;
|
|
49
|
+
this.refs.textarea.selectionEnd = 0;
|
|
48
50
|
shadow.appendChild(textarea);
|
|
49
51
|
textarea.addEventListener("dragenter", (e) => {
|
|
50
52
|
e.preventDefault();
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { h, t } from "../lib/dom.js";
|
|
2
|
+
import { style as buttonCSS } from "./button.js";
|
|
3
|
+
import { normalizeCSS } from "../lib/normalize.js";
|
|
4
|
+
import { toQueryParams } from "../lib/queryParams.js";
|
|
5
|
+
import { htmlExport } from "../lib/htmlExport.js";
|
|
6
|
+
|
|
7
|
+
export class ExportModal extends HTMLElement {
|
|
8
|
+
#center;
|
|
9
|
+
#zoom;
|
|
10
|
+
#query;
|
|
11
|
+
#data;
|
|
12
|
+
#style;
|
|
13
|
+
|
|
14
|
+
constructor() {
|
|
15
|
+
super();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get center() {
|
|
19
|
+
return this.#center;
|
|
20
|
+
}
|
|
21
|
+
set center(value) {
|
|
22
|
+
this.#center = value;
|
|
23
|
+
this.update();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
get zoom() {
|
|
27
|
+
return this.#zoom;
|
|
28
|
+
}
|
|
29
|
+
set zoom(value) {
|
|
30
|
+
this.#zoom = value;
|
|
31
|
+
this.update();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get query() {
|
|
35
|
+
return this.#query;
|
|
36
|
+
}
|
|
37
|
+
set query(value) {
|
|
38
|
+
this.#query = value;
|
|
39
|
+
this.update();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
set data(data) {
|
|
43
|
+
this.#data = data;
|
|
44
|
+
this.update();
|
|
45
|
+
}
|
|
46
|
+
get data() {
|
|
47
|
+
return this.#data;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
set style(style) {
|
|
51
|
+
this.#style = style;
|
|
52
|
+
this.update();
|
|
53
|
+
}
|
|
54
|
+
get style() {
|
|
55
|
+
return this.#style
|
|
56
|
+
? {
|
|
57
|
+
...this.#style,
|
|
58
|
+
glyphs:
|
|
59
|
+
this.#style && this.#style.glyphs
|
|
60
|
+
? new URL(this.#style.glyphs).searchParams.get("url")
|
|
61
|
+
: undefined,
|
|
62
|
+
}
|
|
63
|
+
: null;
|
|
64
|
+
}
|
|
65
|
+
get html() {
|
|
66
|
+
return htmlExport(this.style, "Ultra Export", "", {
|
|
67
|
+
zoom: this.zoom,
|
|
68
|
+
center: this.center,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
connectedCallback() {
|
|
73
|
+
const shadow = this.attachShadow({ mode: "open" });
|
|
74
|
+
|
|
75
|
+
const dataDownloadButton = h("button", {}, t("download"));
|
|
76
|
+
dataDownloadButton.addEventListener("click", () =>
|
|
77
|
+
this.download(JSON.stringify(this.data), "ultra.geojson"),
|
|
78
|
+
);
|
|
79
|
+
const styleDownloadButton = h("button", {}, t("download"));
|
|
80
|
+
styleDownloadButton.addEventListener("click", () => {
|
|
81
|
+
this.download(JSON.stringify(this.style), "style.json");
|
|
82
|
+
});
|
|
83
|
+
const htmlDownloadButton = h("button", {}, t("download"));
|
|
84
|
+
htmlDownloadButton.addEventListener("click", () => {
|
|
85
|
+
this.download(this.html, "ultra.html");
|
|
86
|
+
});
|
|
87
|
+
const queryDownloadButton = h("button", {}, t("download"));
|
|
88
|
+
queryDownloadButton.addEventListener("click", () => {
|
|
89
|
+
this.download(this.query, "query.ultra");
|
|
90
|
+
});
|
|
91
|
+
const dataCopyButton = h("button", {}, t("copy"));
|
|
92
|
+
dataCopyButton.addEventListener("click", () => {
|
|
93
|
+
navigator.clipboard.writeText(JSON.stringify(this.data));
|
|
94
|
+
});
|
|
95
|
+
const styleCopyButton = h("button", {}, t("copy"));
|
|
96
|
+
styleCopyButton.addEventListener("click", () => {
|
|
97
|
+
navigator.clipboard.writeText(JSON.stringify(this.style));
|
|
98
|
+
});
|
|
99
|
+
const htmlCopyButton = h("button", {}, t("copy"));
|
|
100
|
+
htmlCopyButton.addEventListener("click", () => {
|
|
101
|
+
navigator.clipboard.writeText(this.html);
|
|
102
|
+
});
|
|
103
|
+
const queryCopyButton = h("button", {}, t("copy"));
|
|
104
|
+
queryCopyButton.addEventListener("click", () => {
|
|
105
|
+
navigator.clipboard.writeText(this.query);
|
|
106
|
+
});
|
|
107
|
+
const div = h(
|
|
108
|
+
"div",
|
|
109
|
+
{ style: "", slot: "modal-content" },
|
|
110
|
+
h(
|
|
111
|
+
"style",
|
|
112
|
+
{},
|
|
113
|
+
`
|
|
114
|
+
div {
|
|
115
|
+
padding: 0 8px 8px;
|
|
116
|
+
max-width: 100%;
|
|
117
|
+
width: 460px;
|
|
118
|
+
}
|
|
119
|
+
details, .note {
|
|
120
|
+
font-size: 0.8em;
|
|
121
|
+
}
|
|
122
|
+
h3, h5 {
|
|
123
|
+
margin-bottom: 0;
|
|
124
|
+
}
|
|
125
|
+
input[type=text] {
|
|
126
|
+
width: 100%;
|
|
127
|
+
padding: 0;
|
|
128
|
+
margin: 0;
|
|
129
|
+
}
|
|
130
|
+
label {
|
|
131
|
+
display: block;
|
|
132
|
+
}
|
|
133
|
+
button {
|
|
134
|
+
cursor: pointer;
|
|
135
|
+
}
|
|
136
|
+
`,
|
|
137
|
+
),
|
|
138
|
+
h(
|
|
139
|
+
"div",
|
|
140
|
+
{ className: "data" },
|
|
141
|
+
h("h3", {}, "Data"),
|
|
142
|
+
h("p", {}, "Export the query result as GeoJSON"),
|
|
143
|
+
dataDownloadButton,
|
|
144
|
+
t(" "),
|
|
145
|
+
dataCopyButton,
|
|
146
|
+
),
|
|
147
|
+
h(
|
|
148
|
+
"div",
|
|
149
|
+
{ className: "map" },
|
|
150
|
+
h("h3", {}, "Map"),
|
|
151
|
+
h("fa-icon", { icon: "triangle-exclamation" }),
|
|
152
|
+
h(
|
|
153
|
+
"span",
|
|
154
|
+
{ className: "note" },
|
|
155
|
+
t(" Note: some styles' tiles have CORS restrictions"),
|
|
156
|
+
),
|
|
157
|
+
h(
|
|
158
|
+
"p",
|
|
159
|
+
{},
|
|
160
|
+
t("Export the map as a MapLibre style "),
|
|
161
|
+
h(
|
|
162
|
+
"details",
|
|
163
|
+
{},
|
|
164
|
+
h(
|
|
165
|
+
"summary",
|
|
166
|
+
{},
|
|
167
|
+
h("fa-icon", { icon: "triangle-exclamation" }),
|
|
168
|
+
t(" usage notes"),
|
|
169
|
+
),
|
|
170
|
+
t("Ultra's support for "),
|
|
171
|
+
h(
|
|
172
|
+
"a",
|
|
173
|
+
{
|
|
174
|
+
href: "https://overpass-ultra.us/docs/style/#png-sprites-via-https",
|
|
175
|
+
target: "_blank",
|
|
176
|
+
},
|
|
177
|
+
"HTTPS PNG sprites",
|
|
178
|
+
),
|
|
179
|
+
t(", "),
|
|
180
|
+
h(
|
|
181
|
+
"a",
|
|
182
|
+
{
|
|
183
|
+
href: "https://overpass-ultra.us/docs/style/#fallback-fontstack",
|
|
184
|
+
target: "_blank",
|
|
185
|
+
},
|
|
186
|
+
"Fallback glyphs",
|
|
187
|
+
),
|
|
188
|
+
t(", and interactive popups"),
|
|
189
|
+
t(" are run-time features and aren't included in the generated "),
|
|
190
|
+
h("code", {}, "style.json"),
|
|
191
|
+
t(". You may experience issues with missing icons or text."),
|
|
192
|
+
),
|
|
193
|
+
),
|
|
194
|
+
styleDownloadButton,
|
|
195
|
+
t(" "),
|
|
196
|
+
styleCopyButton,
|
|
197
|
+
/*
|
|
198
|
+
h(
|
|
199
|
+
"p",
|
|
200
|
+
{},
|
|
201
|
+
t("Export an interactive map"),
|
|
202
|
+
h(
|
|
203
|
+
"details",
|
|
204
|
+
{},
|
|
205
|
+
h(
|
|
206
|
+
"summary",
|
|
207
|
+
{},
|
|
208
|
+
h("fa-icon", { icon: "triangle-exclamation" }),
|
|
209
|
+
t(" usage notes"),
|
|
210
|
+
),
|
|
211
|
+
t(
|
|
212
|
+
"Ultra's interactive popups are not yet supported in exported HTML.",
|
|
213
|
+
),
|
|
214
|
+
),
|
|
215
|
+
),
|
|
216
|
+
htmlDownloadButton,
|
|
217
|
+
t(" "),
|
|
218
|
+
htmlCopyButton,
|
|
219
|
+
*/
|
|
220
|
+
),
|
|
221
|
+
/*
|
|
222
|
+
h(
|
|
223
|
+
"div",
|
|
224
|
+
{ className: "query" },
|
|
225
|
+
h("h3", {}, "Query"),
|
|
226
|
+
h("p", {}, "Export the Ultra query"),
|
|
227
|
+
queryDownloadButton,
|
|
228
|
+
t(" "),
|
|
229
|
+
queryCopyButton,
|
|
230
|
+
),
|
|
231
|
+
*/
|
|
232
|
+
);
|
|
233
|
+
const button = h(
|
|
234
|
+
"button-modal",
|
|
235
|
+
{ text: "Export", icon: "file-export" },
|
|
236
|
+
div,
|
|
237
|
+
);
|
|
238
|
+
this.refs = {
|
|
239
|
+
button,
|
|
240
|
+
div,
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
shadow.appendChild(button);
|
|
244
|
+
|
|
245
|
+
this.update();
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
update() {
|
|
249
|
+
if (this.data) {
|
|
250
|
+
this.refs.div.querySelector(".data").style.display = "block";
|
|
251
|
+
} else {
|
|
252
|
+
this.refs.div.querySelector(".data").style.display = "none";
|
|
253
|
+
}
|
|
254
|
+
if (this.style) {
|
|
255
|
+
this.refs.button.refs.button.disabled = false;
|
|
256
|
+
} else {
|
|
257
|
+
this.refs.button.refs.button.disabled = true;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
download(data, filename) {
|
|
262
|
+
const blob = new Blob([data], { type: "octet/stream" });
|
|
263
|
+
const url = window.URL.createObjectURL(blob);
|
|
264
|
+
|
|
265
|
+
const link = h("a", { download: filename, href: url });
|
|
266
|
+
|
|
267
|
+
// this is necessary as link.click() does not work on the latest firefox
|
|
268
|
+
link.dispatchEvent(
|
|
269
|
+
new MouseEvent("click", {
|
|
270
|
+
bubbles: true,
|
|
271
|
+
cancelable: true,
|
|
272
|
+
view: window,
|
|
273
|
+
}),
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
setTimeout(() => {
|
|
277
|
+
// For Firefox it is necessary to delay revoking the ObjectURL
|
|
278
|
+
window.URL.revokeObjectURL(url);
|
|
279
|
+
link.remove();
|
|
280
|
+
}, 100);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
faDownLeftAndUpRightToCenter,
|
|
11
11
|
faPaintbrush,
|
|
12
12
|
faPenToSquare,
|
|
13
|
+
faFileExport,
|
|
14
|
+
faTriangleExclamation,
|
|
13
15
|
} from "@fortawesome/free-solid-svg-icons";
|
|
14
16
|
|
|
15
17
|
import { h } from "../lib/dom.js";
|
|
@@ -27,6 +29,8 @@ library.add(faUpRightAndDownLeftFromCenter);
|
|
|
27
29
|
library.add(faDownLeftAndUpRightToCenter);
|
|
28
30
|
library.add(faPaintbrush);
|
|
29
31
|
library.add(faPenToSquare);
|
|
32
|
+
library.add(faFileExport);
|
|
33
|
+
library.add(faTriangleExclamation);
|
|
30
34
|
|
|
31
35
|
export const css = new CSSStyleSheet();
|
|
32
36
|
css.replaceSync(`
|
|
@@ -2,6 +2,7 @@ import { h, t } from "../lib/dom.js";
|
|
|
2
2
|
import { style as buttonCSS } from "./button.js";
|
|
3
3
|
import { normalizeCSS } from "../lib/normalize.js";
|
|
4
4
|
import { toQueryParams } from "../lib/queryParams.js";
|
|
5
|
+
import { parseSettings } from "../lib/settings.js";
|
|
5
6
|
|
|
6
7
|
export class ShareModal extends HTMLElement {
|
|
7
8
|
#center;
|
|
@@ -90,6 +91,9 @@ export class ShareModal extends HTMLElement {
|
|
|
90
91
|
label {
|
|
91
92
|
display: block;
|
|
92
93
|
}
|
|
94
|
+
label:has(input:disabled) {
|
|
95
|
+
color: grey;
|
|
96
|
+
}
|
|
93
97
|
`,
|
|
94
98
|
),
|
|
95
99
|
h("h3", {}, "Query"),
|
|
@@ -128,6 +132,16 @@ export class ShareModal extends HTMLElement {
|
|
|
128
132
|
opts.center = this.center;
|
|
129
133
|
opts.zoom = this.zoom;
|
|
130
134
|
}
|
|
135
|
+
let transform;
|
|
136
|
+
try {
|
|
137
|
+
({ transform } = parseSettings(this.query));
|
|
138
|
+
} catch {}
|
|
139
|
+
if (transform) {
|
|
140
|
+
this.refs.autoRunCheckBox.checked = false;
|
|
141
|
+
this.refs.autoRunCheckBox.disabled = true;
|
|
142
|
+
} else {
|
|
143
|
+
this.refs.autoRunCheckBox.disabled = false;
|
|
144
|
+
}
|
|
131
145
|
opts.autoRun = this.refs.autoRunCheckBox.checked;
|
|
132
146
|
this.refs.queryInput.value = toQueryParams(opts);
|
|
133
147
|
delete opts.autoRun;
|
package/components/ultra-ide.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import equal from "deep-equal";
|
|
2
2
|
import bbox from "@turf/bbox";
|
|
3
3
|
import pick from "lodash.pick";
|
|
4
|
+
import { compressToEncodedURIComponent } from "lz-string";
|
|
4
5
|
import { h } from "../lib/dom.js";
|
|
5
6
|
import { setBaseStyle } from "../lib/style.js";
|
|
6
7
|
import { setSetting, parseSettings } from "../lib/settings.js";
|
|
@@ -10,11 +11,7 @@ import {
|
|
|
10
11
|
getQueryFromQueryParams,
|
|
11
12
|
toQueryParams,
|
|
12
13
|
} from "../lib/queryParams.js";
|
|
13
|
-
import {
|
|
14
|
-
localStorage,
|
|
15
|
-
optionsFromStorage,
|
|
16
|
-
queryFromStorage,
|
|
17
|
-
} from "../lib/localStorage.js";
|
|
14
|
+
import { localStorage } from "../lib/localStorage.js";
|
|
18
15
|
import { UltraMap } from "./ultra-map.js";
|
|
19
16
|
import { HelpModal } from "./help-modal.js";
|
|
20
17
|
import { StylePicker } from "./style-picker.js";
|
|
@@ -89,6 +86,10 @@ export class UltraIDE extends HTMLElement {
|
|
|
89
86
|
settings = {};
|
|
90
87
|
styles;
|
|
91
88
|
help;
|
|
89
|
+
queryStorage = {
|
|
90
|
+
get: () => localStorage.getItem("query"),
|
|
91
|
+
set: (query) => localStorage.setItem("query", query),
|
|
92
|
+
};
|
|
92
93
|
|
|
93
94
|
static MAP_INIT_SETTINGS = [
|
|
94
95
|
"loadSettingsFromQueryParams",
|
|
@@ -114,7 +115,7 @@ export class UltraIDE extends HTMLElement {
|
|
|
114
115
|
this.onExitFullscreen = this.onExitFullscreen.bind(this);
|
|
115
116
|
}
|
|
116
117
|
|
|
117
|
-
connectedCallback() {
|
|
118
|
+
async connectedCallback() {
|
|
118
119
|
// Create & populate Shadow DOM
|
|
119
120
|
const shadow = this.attachShadow({ mode: "open" });
|
|
120
121
|
shadow.adoptedStyleSheets.push(style);
|
|
@@ -144,7 +145,14 @@ export class UltraIDE extends HTMLElement {
|
|
|
144
145
|
);
|
|
145
146
|
|
|
146
147
|
// Get initial query and center&zoom
|
|
147
|
-
|
|
148
|
+
try {
|
|
149
|
+
this.query =
|
|
150
|
+
(await Promise.resolve(getQueryFromQueryParams())) ||
|
|
151
|
+
this.queryStorage.get() ||
|
|
152
|
+
this.query;
|
|
153
|
+
} catch (e) {
|
|
154
|
+
alert(e.message);
|
|
155
|
+
}
|
|
148
156
|
this.autoRun = getAutoRunFromQueryParams();
|
|
149
157
|
this.settings = {
|
|
150
158
|
persistState: true,
|
|
@@ -195,12 +203,14 @@ export class UltraIDE extends HTMLElement {
|
|
|
195
203
|
|
|
196
204
|
// initialize share values
|
|
197
205
|
this.refs.shareButton.query = this.query;
|
|
206
|
+
// this.refs.downloadButton.query = this.query;
|
|
198
207
|
|
|
199
208
|
// set query when resolved if a promise
|
|
200
209
|
if (this.query.then) {
|
|
201
210
|
this.query.then((query) => {
|
|
202
211
|
this.refs.codeEditor.source = query;
|
|
203
212
|
this.refs.shareButton.query = this.query;
|
|
213
|
+
// this.refs.downloadButton.query = this.query;
|
|
204
214
|
if (this.autoRun) {
|
|
205
215
|
this.onClickRun();
|
|
206
216
|
}
|
|
@@ -210,9 +220,36 @@ export class UltraIDE extends HTMLElement {
|
|
|
210
220
|
}
|
|
211
221
|
}
|
|
212
222
|
|
|
223
|
+
async updateHash() {
|
|
224
|
+
if (this.query === (await Promise.resolve(getQueryFromQueryParams())))
|
|
225
|
+
return;
|
|
226
|
+
// mostly cribbed from https://github.com/maplibre/maplibre-gl-js/blob/main/src/ui/hash.ts
|
|
227
|
+
// not using URlSearchParams because it URL-enodes / characters
|
|
228
|
+
const q = compressToEncodedURIComponent(this.query);
|
|
229
|
+
let found = false;
|
|
230
|
+
const parts = window.location.hash
|
|
231
|
+
.slice(1)
|
|
232
|
+
.split("&")
|
|
233
|
+
.map((part) => {
|
|
234
|
+
const key = part.split("=")[0];
|
|
235
|
+
if (key === "q" || key === "query") {
|
|
236
|
+
found = true;
|
|
237
|
+
return `q=${q}`;
|
|
238
|
+
}
|
|
239
|
+
return part;
|
|
240
|
+
})
|
|
241
|
+
.filter((a) => a);
|
|
242
|
+
if (!found) {
|
|
243
|
+
parts.push(`q=${q}`);
|
|
244
|
+
}
|
|
245
|
+
const hash = `#${parts.join("&")}`;
|
|
246
|
+
const location = window.location.href.replace(/(#.*)?$/, hash);
|
|
247
|
+
window.history.pushState(window.history.state, null, location);
|
|
248
|
+
}
|
|
213
249
|
async onClickRun() {
|
|
214
250
|
this.refs.runButton.loading = true; // Loading button state
|
|
215
251
|
this.resetMap(); // clear settings from previous run
|
|
252
|
+
await this.updateHash();
|
|
216
253
|
try {
|
|
217
254
|
// basic query/option parsing
|
|
218
255
|
const settings = {
|
|
@@ -228,10 +265,11 @@ export class UltraIDE extends HTMLElement {
|
|
|
228
265
|
});
|
|
229
266
|
|
|
230
267
|
this.refs.downloadButton.data = null;
|
|
268
|
+
this.refs.downloadButton.style = null;
|
|
231
269
|
this.controller = new AbortController();
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
270
|
+
const { data, mapStyle } = await this.refs.ultraMap.run(this.controller);
|
|
271
|
+
this.refs.downloadButton.data = data;
|
|
272
|
+
this.refs.downloadButton.style = mapStyle;
|
|
235
273
|
delete this.controller;
|
|
236
274
|
|
|
237
275
|
this.refs.runButton.loading = false;
|
|
@@ -282,15 +320,18 @@ export class UltraIDE extends HTMLElement {
|
|
|
282
320
|
onChangeCode() {
|
|
283
321
|
this.query = this.refs.codeEditor.source;
|
|
284
322
|
this.refs.shareButton.query = this.query;
|
|
285
|
-
|
|
323
|
+
// this.refs.downloadButton.query = this.query;
|
|
324
|
+
this.queryStorage.set(this.query);
|
|
286
325
|
}
|
|
287
326
|
onMoveEnd() {
|
|
288
327
|
const zoom = this.refs.ultraMap.zoom;
|
|
289
328
|
const center = this.refs.ultraMap.center.toArray();
|
|
290
329
|
this.refs.shareButton.zoom = zoom;
|
|
291
330
|
this.refs.shareButton.center = center;
|
|
331
|
+
this.refs.downloadButton.zoom = zoom;
|
|
332
|
+
this.refs.downloadButton.center = center;
|
|
292
333
|
}
|
|
293
|
-
onChangeStyle(e) {
|
|
334
|
+
async onChangeStyle(e) {
|
|
294
335
|
this.refs.codeEditor.source = setSetting(this.query, {
|
|
295
336
|
style: e.detail.value,
|
|
296
337
|
});
|
|
@@ -299,7 +340,8 @@ export class UltraIDE extends HTMLElement {
|
|
|
299
340
|
settings.mapStyle,
|
|
300
341
|
this.settings.mapStyle || UltraMap.defaults.mapStyle,
|
|
301
342
|
);
|
|
302
|
-
this.refs.ultraMap.run();
|
|
343
|
+
const { mapStyle } = await this.refs.ultraMap.run();
|
|
344
|
+
this.refs.downloadButton.style = mapStyle;
|
|
303
345
|
}
|
|
304
346
|
|
|
305
347
|
onEnterFullscreen() {
|