@tileflow/core 0.1.0-alpha.20 → 0.1.0-alpha.21
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/GENERATED_OUTPUT_LICENSE.md +21 -0
- package/LICENSE +201 -0
- package/NOTICE +9 -0
- package/README.md +969 -142
- package/THIRD_PARTY_NOTICES.md +185 -0
- package/TRADEMARKS.md +10 -0
- package/dist/browser.d.ts +105 -2
- package/dist/browser.js +3135 -11
- package/dist/build.d.ts +195 -0
- package/dist/build.js +12254 -0
- package/dist/capture-scene-BK_0J2oR.d.ts +161 -0
- package/dist/capture.d.ts +9 -0
- package/dist/capture.js +206 -0
- package/dist/domains-CPSrdTik.d.ts +4 -0
- package/dist/index.d.ts +180 -182
- package/dist/index.js +12259 -4245
- package/dist/manifest.d.ts +3 -0
- package/dist/manifest.js +229 -0
- package/dist/recipe.d.ts +66 -0
- package/dist/recipe.js +577 -0
- package/dist/requirements-BV77ZVhR.d.ts +491 -0
- package/dist/runtime-C4MtSzkB.d.ts +223 -0
- package/dist/runtime.d.ts +3 -0
- package/dist/runtime.js +1117 -0
- package/dist/types-DlUGI6LC.d.ts +525 -0
- package/dist/visual-semantics-DTC-8Hsb.d.ts +479 -0
- package/package.json +40 -5
- package/dist/runtime-DroKDIuB.d.ts +0 -1069
package/dist/browser.js
CHANGED
|
@@ -1,9 +1,2121 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __esm = (fn, res, err) => function __init() {
|
|
4
|
+
if (err) throw err[0];
|
|
5
|
+
try {
|
|
6
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
7
|
+
} catch (e) {
|
|
8
|
+
throw err = [e], e;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// src/portable-identity-rules.ts
|
|
17
|
+
function isTileflowPortableId(value) {
|
|
18
|
+
return typeof value === "string" && value.length <= tileflowPortableIdMaximumLength && tileflowPortableIdPattern.test(value) && !["constructor", "prototype"].includes(value) && !/^(?:AUX|CON|NUL|PRN|COM[1-9]|LPT[1-9])$/i.test(value);
|
|
19
|
+
}
|
|
20
|
+
function isTileflowThemeName(value) {
|
|
21
|
+
return isTileflowPortableId(value) && value !== "system";
|
|
22
|
+
}
|
|
23
|
+
var tileflowPortableIdMaximumLength, tileflowPortableIdPattern;
|
|
24
|
+
var init_portable_identity_rules = __esm({
|
|
25
|
+
"src/portable-identity-rules.ts"() {
|
|
26
|
+
"use strict";
|
|
27
|
+
tileflowPortableIdMaximumLength = 64;
|
|
28
|
+
tileflowPortableIdPattern = /^[a-z][a-z0-9-]{0,63}$/u;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// ../../node_modules/.pnpm/maplibre-contour@0.1.0/node_modules/maplibre-contour/dist/index.mjs
|
|
33
|
+
var dist_exports = {};
|
|
34
|
+
__export(dist_exports, {
|
|
35
|
+
default: () => mlcontour$1
|
|
36
|
+
});
|
|
37
|
+
function define(_, chunk) {
|
|
38
|
+
if (!shared) {
|
|
39
|
+
shared = chunk;
|
|
40
|
+
} else if (!worker) {
|
|
41
|
+
worker = chunk;
|
|
42
|
+
} else {
|
|
43
|
+
var workerBundleString = "var sharedChunk = {}; (" + shared + ")(sharedChunk); (" + worker + ")(sharedChunk);";
|
|
44
|
+
var sharedChunk = {};
|
|
45
|
+
shared(sharedChunk);
|
|
46
|
+
mlcontour = chunk(sharedChunk);
|
|
47
|
+
if (typeof window !== "undefined") {
|
|
48
|
+
mlcontour.workerUrl = window.URL.createObjectURL(
|
|
49
|
+
new Blob([workerBundleString], { type: "text/javascript" })
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
var shared, worker, mlcontour, mlcontour$1;
|
|
55
|
+
var init_dist = __esm({
|
|
56
|
+
"../../node_modules/.pnpm/maplibre-contour@0.1.0/node_modules/maplibre-contour/dist/index.mjs"() {
|
|
57
|
+
"use strict";
|
|
58
|
+
define(["exports"], (function(exports) {
|
|
59
|
+
"use strict";
|
|
60
|
+
class Fragment {
|
|
61
|
+
constructor(start, end) {
|
|
62
|
+
this.start = start;
|
|
63
|
+
this.end = end;
|
|
64
|
+
this.points = [];
|
|
65
|
+
this.append = this.append.bind(this);
|
|
66
|
+
this.prepend = this.prepend.bind(this);
|
|
67
|
+
}
|
|
68
|
+
append(x, y) {
|
|
69
|
+
this.points.push(Math.round(x), Math.round(y));
|
|
70
|
+
}
|
|
71
|
+
prepend(x, y) {
|
|
72
|
+
this.points.splice(0, 0, Math.round(x), Math.round(y));
|
|
73
|
+
}
|
|
74
|
+
lineString() {
|
|
75
|
+
return this.toArray();
|
|
76
|
+
}
|
|
77
|
+
isEmpty() {
|
|
78
|
+
return this.points.length < 2;
|
|
79
|
+
}
|
|
80
|
+
appendFragment(other) {
|
|
81
|
+
this.points.push(...other.points);
|
|
82
|
+
this.end = other.end;
|
|
83
|
+
}
|
|
84
|
+
toArray() {
|
|
85
|
+
return this.points;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const CASES = [
|
|
89
|
+
[],
|
|
90
|
+
[
|
|
91
|
+
[
|
|
92
|
+
[1, 2],
|
|
93
|
+
[0, 1]
|
|
94
|
+
]
|
|
95
|
+
],
|
|
96
|
+
[
|
|
97
|
+
[
|
|
98
|
+
[2, 1],
|
|
99
|
+
[1, 2]
|
|
100
|
+
]
|
|
101
|
+
],
|
|
102
|
+
[
|
|
103
|
+
[
|
|
104
|
+
[2, 1],
|
|
105
|
+
[0, 1]
|
|
106
|
+
]
|
|
107
|
+
],
|
|
108
|
+
[
|
|
109
|
+
[
|
|
110
|
+
[1, 0],
|
|
111
|
+
[2, 1]
|
|
112
|
+
]
|
|
113
|
+
],
|
|
114
|
+
[
|
|
115
|
+
[
|
|
116
|
+
[1, 2],
|
|
117
|
+
[0, 1]
|
|
118
|
+
],
|
|
119
|
+
[
|
|
120
|
+
[1, 0],
|
|
121
|
+
[2, 1]
|
|
122
|
+
]
|
|
123
|
+
],
|
|
124
|
+
[
|
|
125
|
+
[
|
|
126
|
+
[1, 0],
|
|
127
|
+
[1, 2]
|
|
128
|
+
]
|
|
129
|
+
],
|
|
130
|
+
[
|
|
131
|
+
[
|
|
132
|
+
[1, 0],
|
|
133
|
+
[0, 1]
|
|
134
|
+
]
|
|
135
|
+
],
|
|
136
|
+
[
|
|
137
|
+
[
|
|
138
|
+
[0, 1],
|
|
139
|
+
[1, 0]
|
|
140
|
+
]
|
|
141
|
+
],
|
|
142
|
+
[
|
|
143
|
+
[
|
|
144
|
+
[1, 2],
|
|
145
|
+
[1, 0]
|
|
146
|
+
]
|
|
147
|
+
],
|
|
148
|
+
[
|
|
149
|
+
[
|
|
150
|
+
[0, 1],
|
|
151
|
+
[1, 0]
|
|
152
|
+
],
|
|
153
|
+
[
|
|
154
|
+
[2, 1],
|
|
155
|
+
[1, 2]
|
|
156
|
+
]
|
|
157
|
+
],
|
|
158
|
+
[
|
|
159
|
+
[
|
|
160
|
+
[2, 1],
|
|
161
|
+
[1, 0]
|
|
162
|
+
]
|
|
163
|
+
],
|
|
164
|
+
[
|
|
165
|
+
[
|
|
166
|
+
[0, 1],
|
|
167
|
+
[2, 1]
|
|
168
|
+
]
|
|
169
|
+
],
|
|
170
|
+
[
|
|
171
|
+
[
|
|
172
|
+
[1, 2],
|
|
173
|
+
[2, 1]
|
|
174
|
+
]
|
|
175
|
+
],
|
|
176
|
+
[
|
|
177
|
+
[
|
|
178
|
+
[0, 1],
|
|
179
|
+
[1, 2]
|
|
180
|
+
]
|
|
181
|
+
],
|
|
182
|
+
[]
|
|
183
|
+
];
|
|
184
|
+
function index(width, x, y, point) {
|
|
185
|
+
x = x * 2 + point[0];
|
|
186
|
+
y = y * 2 + point[1];
|
|
187
|
+
return x + y * (width + 1) * 2;
|
|
188
|
+
}
|
|
189
|
+
function ratio(a, b, c) {
|
|
190
|
+
return (b - a) / (c - a);
|
|
191
|
+
}
|
|
192
|
+
function generateIsolines(interval, tile, extent = 4096, buffer = 1) {
|
|
193
|
+
if (!interval) {
|
|
194
|
+
return {};
|
|
195
|
+
}
|
|
196
|
+
const multiplier = extent / (tile.width - 1);
|
|
197
|
+
let tld, trd, bld, brd;
|
|
198
|
+
let r, c;
|
|
199
|
+
const segments = {};
|
|
200
|
+
const fragmentByStartByLevel = /* @__PURE__ */ new Map();
|
|
201
|
+
const fragmentByEndByLevel = /* @__PURE__ */ new Map();
|
|
202
|
+
function interpolate(point, threshold, accept) {
|
|
203
|
+
if (point[0] === 0) {
|
|
204
|
+
accept(multiplier * (c - 1), multiplier * (r - ratio(bld, threshold, tld)));
|
|
205
|
+
} else if (point[0] === 2) {
|
|
206
|
+
accept(multiplier * c, multiplier * (r - ratio(brd, threshold, trd)));
|
|
207
|
+
} else if (point[1] === 0) {
|
|
208
|
+
accept(multiplier * (c - ratio(trd, threshold, tld)), multiplier * (r - 1));
|
|
209
|
+
} else {
|
|
210
|
+
accept(multiplier * (c - ratio(brd, threshold, bld)), multiplier * r);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
for (r = 1 - buffer; r < tile.height + buffer; r++) {
|
|
214
|
+
trd = tile.get(0, r - 1);
|
|
215
|
+
brd = tile.get(0, r);
|
|
216
|
+
let minR = Math.min(trd, brd);
|
|
217
|
+
let maxR = Math.max(trd, brd);
|
|
218
|
+
for (c = 1 - buffer; c < tile.width + buffer; c++) {
|
|
219
|
+
tld = trd;
|
|
220
|
+
bld = brd;
|
|
221
|
+
trd = tile.get(c, r - 1);
|
|
222
|
+
brd = tile.get(c, r);
|
|
223
|
+
const minL = minR;
|
|
224
|
+
const maxL = maxR;
|
|
225
|
+
minR = Math.min(trd, brd);
|
|
226
|
+
maxR = Math.max(trd, brd);
|
|
227
|
+
if (isNaN(tld) || isNaN(trd) || isNaN(brd) || isNaN(bld)) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
const min = Math.min(minL, minR);
|
|
231
|
+
const max = Math.max(maxL, maxR);
|
|
232
|
+
const start = Math.ceil(min / interval) * interval;
|
|
233
|
+
const end = Math.floor(max / interval) * interval;
|
|
234
|
+
for (let threshold = start; threshold <= end; threshold += interval) {
|
|
235
|
+
const tl = tld > threshold;
|
|
236
|
+
const tr = trd > threshold;
|
|
237
|
+
const bl = bld > threshold;
|
|
238
|
+
const br = brd > threshold;
|
|
239
|
+
for (const segment of CASES[(tl ? 8 : 0) | (tr ? 4 : 0) | (br ? 2 : 0) | (bl ? 1 : 0)]) {
|
|
240
|
+
let fragmentByStart = fragmentByStartByLevel.get(threshold);
|
|
241
|
+
if (!fragmentByStart)
|
|
242
|
+
fragmentByStartByLevel.set(threshold, fragmentByStart = /* @__PURE__ */ new Map());
|
|
243
|
+
let fragmentByEnd = fragmentByEndByLevel.get(threshold);
|
|
244
|
+
if (!fragmentByEnd)
|
|
245
|
+
fragmentByEndByLevel.set(threshold, fragmentByEnd = /* @__PURE__ */ new Map());
|
|
246
|
+
const start2 = segment[0];
|
|
247
|
+
const end2 = segment[1];
|
|
248
|
+
const startIndex = index(tile.width, c, r, start2);
|
|
249
|
+
const endIndex = index(tile.width, c, r, end2);
|
|
250
|
+
let f, g;
|
|
251
|
+
if (f = fragmentByEnd.get(startIndex)) {
|
|
252
|
+
fragmentByEnd.delete(startIndex);
|
|
253
|
+
if (g = fragmentByStart.get(endIndex)) {
|
|
254
|
+
fragmentByStart.delete(endIndex);
|
|
255
|
+
if (f === g) {
|
|
256
|
+
interpolate(end2, threshold, f.append);
|
|
257
|
+
if (!f.isEmpty()) {
|
|
258
|
+
let list = segments[threshold];
|
|
259
|
+
if (!list) {
|
|
260
|
+
segments[threshold] = list = [];
|
|
261
|
+
}
|
|
262
|
+
list.push(f.lineString());
|
|
263
|
+
}
|
|
264
|
+
} else {
|
|
265
|
+
f.appendFragment(g);
|
|
266
|
+
fragmentByEnd.set(f.end = g.end, f);
|
|
267
|
+
}
|
|
268
|
+
} else {
|
|
269
|
+
interpolate(end2, threshold, f.append);
|
|
270
|
+
fragmentByEnd.set(f.end = endIndex, f);
|
|
271
|
+
}
|
|
272
|
+
} else if (f = fragmentByStart.get(endIndex)) {
|
|
273
|
+
fragmentByStart.delete(endIndex);
|
|
274
|
+
interpolate(start2, threshold, f.prepend);
|
|
275
|
+
fragmentByStart.set(f.start = startIndex, f);
|
|
276
|
+
} else {
|
|
277
|
+
const newFrag = new Fragment(startIndex, endIndex);
|
|
278
|
+
interpolate(start2, threshold, newFrag.append);
|
|
279
|
+
interpolate(end2, threshold, newFrag.append);
|
|
280
|
+
fragmentByStart.set(startIndex, newFrag);
|
|
281
|
+
fragmentByEnd.set(endIndex, newFrag);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
for (const [level, fragmentByStart] of fragmentByStartByLevel.entries()) {
|
|
288
|
+
let list = null;
|
|
289
|
+
for (const value of fragmentByStart.values()) {
|
|
290
|
+
if (!value.isEmpty()) {
|
|
291
|
+
if (list == null) {
|
|
292
|
+
list = segments[level] || (segments[level] = []);
|
|
293
|
+
}
|
|
294
|
+
list.push(value.lineString());
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return segments;
|
|
299
|
+
}
|
|
300
|
+
function __rest(s, e) {
|
|
301
|
+
var t = {};
|
|
302
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
303
|
+
t[p] = s[p];
|
|
304
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
305
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
306
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
307
|
+
t[p[i]] = s[p[i]];
|
|
308
|
+
}
|
|
309
|
+
return t;
|
|
310
|
+
}
|
|
311
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
312
|
+
function adopt(value) {
|
|
313
|
+
return value instanceof P ? value : new P(function(resolve) {
|
|
314
|
+
resolve(value);
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
return new (P || (P = Promise))(function(resolve, reject) {
|
|
318
|
+
function fulfilled(value) {
|
|
319
|
+
try {
|
|
320
|
+
step(generator.next(value));
|
|
321
|
+
} catch (e) {
|
|
322
|
+
reject(e);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
function rejected(value) {
|
|
326
|
+
try {
|
|
327
|
+
step(generator["throw"](value));
|
|
328
|
+
} catch (e) {
|
|
329
|
+
reject(e);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
function step(result) {
|
|
333
|
+
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
334
|
+
}
|
|
335
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
function sortedEntries(object) {
|
|
339
|
+
const entries = Object.entries(object);
|
|
340
|
+
entries.sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
|
|
341
|
+
return entries;
|
|
342
|
+
}
|
|
343
|
+
function encodeThresholds(thresholds) {
|
|
344
|
+
return sortedEntries(thresholds).map(([key, value]) => [key, ...typeof value === "number" ? [value] : value].join("*")).join("~");
|
|
345
|
+
}
|
|
346
|
+
function decodeThresholds(thresholds) {
|
|
347
|
+
return Object.fromEntries(thresholds.split("~").map((part) => part.split("*").map(Number)).map(([key, ...values]) => [key, values]));
|
|
348
|
+
}
|
|
349
|
+
function encodeOptions(_a) {
|
|
350
|
+
var { thresholds } = _a, rest = __rest(_a, ["thresholds"]);
|
|
351
|
+
return sortedEntries(Object.assign({ thresholds: encodeThresholds(thresholds) }, rest)).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
|
|
352
|
+
}
|
|
353
|
+
function decodeOptions(options) {
|
|
354
|
+
return Object.fromEntries(options.replace(/^.*\?/, "").split("&").map((part) => {
|
|
355
|
+
const parts = part.split("=").map(decodeURIComponent);
|
|
356
|
+
const k = parts[0];
|
|
357
|
+
let v = parts[1];
|
|
358
|
+
switch (k) {
|
|
359
|
+
case "thresholds":
|
|
360
|
+
v = decodeThresholds(v);
|
|
361
|
+
break;
|
|
362
|
+
case "extent":
|
|
363
|
+
case "multiplier":
|
|
364
|
+
case "overzoom":
|
|
365
|
+
case "buffer":
|
|
366
|
+
v = Number(v);
|
|
367
|
+
}
|
|
368
|
+
return [k, v];
|
|
369
|
+
}));
|
|
370
|
+
}
|
|
371
|
+
function encodeIndividualOptions(options) {
|
|
372
|
+
return sortedEntries(options).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join(",");
|
|
373
|
+
}
|
|
374
|
+
function getOptionsForZoom(options, zoom) {
|
|
375
|
+
const { thresholds } = options, rest = __rest(options, ["thresholds"]);
|
|
376
|
+
let levels = [];
|
|
377
|
+
let maxLessThanOrEqualTo = -Infinity;
|
|
378
|
+
Object.entries(thresholds).forEach(([zString, value]) => {
|
|
379
|
+
const z = Number(zString);
|
|
380
|
+
if (z <= zoom && z > maxLessThanOrEqualTo) {
|
|
381
|
+
maxLessThanOrEqualTo = z;
|
|
382
|
+
levels = typeof value === "number" ? [value] : value;
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
return Object.assign({ levels }, rest);
|
|
386
|
+
}
|
|
387
|
+
function copy(src) {
|
|
388
|
+
const dst = new ArrayBuffer(src.byteLength);
|
|
389
|
+
new Uint8Array(dst).set(new Uint8Array(src));
|
|
390
|
+
return dst;
|
|
391
|
+
}
|
|
392
|
+
function prepareDemTile(promise, copy2) {
|
|
393
|
+
return promise.then((_a) => {
|
|
394
|
+
var { data } = _a, rest = __rest(_a, ["data"]);
|
|
395
|
+
let newData = data;
|
|
396
|
+
if (copy2) {
|
|
397
|
+
newData = new Float32Array(data.length);
|
|
398
|
+
newData.set(data);
|
|
399
|
+
}
|
|
400
|
+
return Object.assign(Object.assign({}, rest), { data: newData, transferrables: [newData.buffer] });
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
function prepareContourTile(promise) {
|
|
404
|
+
return promise.then(({ arrayBuffer }) => {
|
|
405
|
+
const clone = copy(arrayBuffer);
|
|
406
|
+
return {
|
|
407
|
+
arrayBuffer: clone,
|
|
408
|
+
transferrables: [clone]
|
|
409
|
+
};
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
let supportsOffscreenCanvas = null;
|
|
413
|
+
function offscreenCanvasSupported() {
|
|
414
|
+
if (supportsOffscreenCanvas == null) {
|
|
415
|
+
supportsOffscreenCanvas = typeof OffscreenCanvas !== "undefined" && new OffscreenCanvas(1, 1).getContext("2d") && typeof createImageBitmap === "function";
|
|
416
|
+
}
|
|
417
|
+
return supportsOffscreenCanvas || false;
|
|
418
|
+
}
|
|
419
|
+
let useVideoFrame = null;
|
|
420
|
+
function shouldUseVideoFrame() {
|
|
421
|
+
if (useVideoFrame == null) {
|
|
422
|
+
useVideoFrame = false;
|
|
423
|
+
if (offscreenCanvasSupported() && typeof VideoFrame !== "undefined") {
|
|
424
|
+
const size = 5;
|
|
425
|
+
const canvas2 = new OffscreenCanvas(5, 5);
|
|
426
|
+
const context = canvas2.getContext("2d", { willReadFrequently: true });
|
|
427
|
+
if (context) {
|
|
428
|
+
for (let i = 0; i < size * size; i++) {
|
|
429
|
+
const base = i * 4;
|
|
430
|
+
context.fillStyle = `rgb(${base},${base + 1},${base + 2})`;
|
|
431
|
+
context.fillRect(i % size, Math.floor(i / size), 1, 1);
|
|
432
|
+
}
|
|
433
|
+
const data = context.getImageData(0, 0, size, size).data;
|
|
434
|
+
for (let i = 0; i < size * size * 4; i++) {
|
|
435
|
+
if (i % 4 !== 3 && data[i] !== i) {
|
|
436
|
+
useVideoFrame = true;
|
|
437
|
+
break;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return useVideoFrame || false;
|
|
444
|
+
}
|
|
445
|
+
function withTimeout(timeoutMs, value, abortController) {
|
|
446
|
+
let reject = () => {
|
|
447
|
+
};
|
|
448
|
+
const timeout = setTimeout(() => {
|
|
449
|
+
reject(new Error("timed out"));
|
|
450
|
+
abortController === null || abortController === void 0 ? void 0 : abortController.abort();
|
|
451
|
+
}, timeoutMs);
|
|
452
|
+
onAbort(abortController, () => {
|
|
453
|
+
reject(new Error("aborted"));
|
|
454
|
+
clearTimeout(timeout);
|
|
455
|
+
});
|
|
456
|
+
const cancelPromise = new Promise((_, rej) => {
|
|
457
|
+
reject = rej;
|
|
458
|
+
});
|
|
459
|
+
return Promise.race([
|
|
460
|
+
cancelPromise,
|
|
461
|
+
value.finally(() => clearTimeout(timeout))
|
|
462
|
+
]);
|
|
463
|
+
}
|
|
464
|
+
function onAbort(abortController, action) {
|
|
465
|
+
if (action) {
|
|
466
|
+
abortController === null || abortController === void 0 ? void 0 : abortController.signal.addEventListener("abort", action);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
function isAborted(abortController) {
|
|
470
|
+
var _a;
|
|
471
|
+
return Boolean((_a = abortController === null || abortController === void 0 ? void 0 : abortController.signal) === null || _a === void 0 ? void 0 : _a.aborted);
|
|
472
|
+
}
|
|
473
|
+
let num = 0;
|
|
474
|
+
class AsyncCache {
|
|
475
|
+
constructor(maxSize = 100) {
|
|
476
|
+
this.size = () => this.items.size;
|
|
477
|
+
this.get = (key, supplier, abortController) => {
|
|
478
|
+
let result = this.items.get(key);
|
|
479
|
+
if (!result) {
|
|
480
|
+
const sharedAbortController = new AbortController();
|
|
481
|
+
const value2 = supplier(key, sharedAbortController);
|
|
482
|
+
result = {
|
|
483
|
+
abortController: sharedAbortController,
|
|
484
|
+
item: value2,
|
|
485
|
+
lastUsed: ++num,
|
|
486
|
+
waiting: 1
|
|
487
|
+
};
|
|
488
|
+
this.items.set(key, result);
|
|
489
|
+
this.prune();
|
|
490
|
+
} else {
|
|
491
|
+
result.lastUsed = ++num;
|
|
492
|
+
result.waiting++;
|
|
493
|
+
}
|
|
494
|
+
const items = this.items;
|
|
495
|
+
const value = result.item.then((r) => r, (e) => {
|
|
496
|
+
items.delete(key);
|
|
497
|
+
return Promise.reject(e);
|
|
498
|
+
});
|
|
499
|
+
let canceled = false;
|
|
500
|
+
onAbort(abortController, () => {
|
|
501
|
+
var _a;
|
|
502
|
+
if (result && result.abortController && !canceled) {
|
|
503
|
+
canceled = true;
|
|
504
|
+
if (--result.waiting <= 0) {
|
|
505
|
+
(_a = result.abortController) === null || _a === void 0 ? void 0 : _a.abort();
|
|
506
|
+
items.delete(key);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
return value;
|
|
511
|
+
};
|
|
512
|
+
this.clear = () => this.items.clear();
|
|
513
|
+
this.maxSize = maxSize;
|
|
514
|
+
this.items = /* @__PURE__ */ new Map();
|
|
515
|
+
}
|
|
516
|
+
prune() {
|
|
517
|
+
if (this.items.size > this.maxSize) {
|
|
518
|
+
let minKey;
|
|
519
|
+
let minUse = Infinity;
|
|
520
|
+
this.items.forEach((value, key) => {
|
|
521
|
+
if (value.lastUsed < minUse) {
|
|
522
|
+
minUse = value.lastUsed;
|
|
523
|
+
minKey = key;
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
if (typeof minKey !== "undefined") {
|
|
527
|
+
this.items.delete(minKey);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
let offscreenCanvas;
|
|
533
|
+
let offscreenContext;
|
|
534
|
+
let canvas;
|
|
535
|
+
let canvasContext;
|
|
536
|
+
function decodeImageModern(blob, encoding, abortController) {
|
|
537
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
538
|
+
const img = yield createImageBitmap(blob);
|
|
539
|
+
if (isAborted(abortController))
|
|
540
|
+
return null;
|
|
541
|
+
return decodeImageUsingOffscreenCanvas(img, encoding);
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
function decodeImageUsingOffscreenCanvas(img, encoding) {
|
|
545
|
+
if (!offscreenCanvas) {
|
|
546
|
+
offscreenCanvas = new OffscreenCanvas(img.width, img.height);
|
|
547
|
+
offscreenContext = offscreenCanvas.getContext("2d", {
|
|
548
|
+
willReadFrequently: true
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
return getElevations(img, encoding, offscreenCanvas, offscreenContext);
|
|
552
|
+
}
|
|
553
|
+
function decodeImageVideoFrame(blob, encoding, abortController) {
|
|
554
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
555
|
+
var _a, _b, _c;
|
|
556
|
+
const img = yield createImageBitmap(blob);
|
|
557
|
+
if (isAborted(abortController))
|
|
558
|
+
return null;
|
|
559
|
+
const vf = new VideoFrame(img, { timestamp: 0 });
|
|
560
|
+
try {
|
|
561
|
+
const valid = ((_a = vf === null || vf === void 0 ? void 0 : vf.format) === null || _a === void 0 ? void 0 : _a.startsWith("BGR")) || ((_b = vf === null || vf === void 0 ? void 0 : vf.format) === null || _b === void 0 ? void 0 : _b.startsWith("RGB"));
|
|
562
|
+
if (!valid) {
|
|
563
|
+
throw new Error(`Unrecognized format: ${vf === null || vf === void 0 ? void 0 : vf.format}`);
|
|
564
|
+
}
|
|
565
|
+
const swapBR = (_c = vf === null || vf === void 0 ? void 0 : vf.format) === null || _c === void 0 ? void 0 : _c.startsWith("BGR");
|
|
566
|
+
const size = vf.allocationSize();
|
|
567
|
+
const data = new Uint8ClampedArray(size);
|
|
568
|
+
yield vf.copyTo(data);
|
|
569
|
+
if (swapBR) {
|
|
570
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
571
|
+
const tmp = data[i];
|
|
572
|
+
data[i] = data[i + 2];
|
|
573
|
+
data[i + 2] = tmp;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
return decodeParsedImage(img.width, img.height, encoding, data);
|
|
577
|
+
} catch (_) {
|
|
578
|
+
if (isAborted(abortController))
|
|
579
|
+
return null;
|
|
580
|
+
return decodeImageUsingOffscreenCanvas(img, encoding);
|
|
581
|
+
} finally {
|
|
582
|
+
vf.close();
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
function decodeImageOld(blob, encoding, abortController) {
|
|
587
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
588
|
+
if (!canvas) {
|
|
589
|
+
canvas = document.createElement("canvas");
|
|
590
|
+
canvasContext = canvas.getContext("2d", {
|
|
591
|
+
willReadFrequently: true
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
const img = new Image();
|
|
595
|
+
onAbort(abortController, () => img.src = "");
|
|
596
|
+
const fetchedImage = yield new Promise((resolve, reject) => {
|
|
597
|
+
img.onload = () => {
|
|
598
|
+
if (!isAborted(abortController))
|
|
599
|
+
resolve(img);
|
|
600
|
+
URL.revokeObjectURL(img.src);
|
|
601
|
+
img.onload = null;
|
|
602
|
+
};
|
|
603
|
+
img.onerror = () => reject(new Error("Could not load image."));
|
|
604
|
+
img.src = blob.size ? URL.createObjectURL(blob) : "";
|
|
605
|
+
});
|
|
606
|
+
return getElevations(fetchedImage, encoding, canvas, canvasContext);
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
function decodeImageOnMainThread(blob, encoding, abortController) {
|
|
610
|
+
return self.actor.send("decodeImage", [], abortController, void 0, blob, encoding);
|
|
611
|
+
}
|
|
612
|
+
function isWorker() {
|
|
613
|
+
return (
|
|
614
|
+
// @ts-expect-error WorkerGlobalScope defined
|
|
615
|
+
typeof WorkerGlobalScope !== "undefined" && typeof self !== "undefined" && // @ts-expect-error WorkerGlobalScope defined
|
|
616
|
+
self instanceof WorkerGlobalScope
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
const defaultDecoder = shouldUseVideoFrame() ? decodeImageVideoFrame : offscreenCanvasSupported() ? decodeImageModern : isWorker() ? decodeImageOnMainThread : decodeImageOld;
|
|
620
|
+
function getElevations(img, encoding, canvas2, canvasContext2) {
|
|
621
|
+
canvas2.width = img.width;
|
|
622
|
+
canvas2.height = img.height;
|
|
623
|
+
if (!canvasContext2)
|
|
624
|
+
throw new Error("failed to get context");
|
|
625
|
+
canvasContext2.drawImage(img, 0, 0, img.width, img.height);
|
|
626
|
+
const rgba = canvasContext2.getImageData(0, 0, img.width, img.height).data;
|
|
627
|
+
return decodeParsedImage(img.width, img.height, encoding, rgba);
|
|
628
|
+
}
|
|
629
|
+
function decodeParsedImage(width, height, encoding, input) {
|
|
630
|
+
const decoder = encoding === "mapbox" ? (r, g, b) => -1e4 + (r * 256 * 256 + g * 256 + b) * 0.1 : (r, g, b) => r * 256 + g + b / 256 - 32768;
|
|
631
|
+
const data = new Float32Array(width * height);
|
|
632
|
+
for (let i = 0; i < input.length; i += 4) {
|
|
633
|
+
data[i / 4] = decoder(input[i], input[i + 1], input[i + 2]);
|
|
634
|
+
}
|
|
635
|
+
return { width, height, data };
|
|
636
|
+
}
|
|
637
|
+
const MIN_VALID_M = -12e3;
|
|
638
|
+
const MAX_VALID_M = 9e3;
|
|
639
|
+
function defaultIsValid(number) {
|
|
640
|
+
return !isNaN(number) && number >= MIN_VALID_M && number <= MAX_VALID_M;
|
|
641
|
+
}
|
|
642
|
+
class HeightTile {
|
|
643
|
+
constructor(width, height, get) {
|
|
644
|
+
this.split = (subz, subx, suby) => {
|
|
645
|
+
if (subz === 0)
|
|
646
|
+
return this;
|
|
647
|
+
const by = 1 << subz;
|
|
648
|
+
const dx = subx * this.width / by;
|
|
649
|
+
const dy = suby * this.height / by;
|
|
650
|
+
return new HeightTile(this.width / by, this.height / by, (x, y) => this.get(x + dx, y + dy));
|
|
651
|
+
};
|
|
652
|
+
this.subsamplePixelCenters = (factor) => {
|
|
653
|
+
const lerp = (a, b, f) => isNaN(a) ? b : isNaN(b) ? a : a + (b - a) * f;
|
|
654
|
+
if (factor <= 1)
|
|
655
|
+
return this;
|
|
656
|
+
const sub = 0.5 - 1 / (2 * factor);
|
|
657
|
+
const blerper = (x, y) => {
|
|
658
|
+
const dx = x / factor - sub;
|
|
659
|
+
const dy = y / factor - sub;
|
|
660
|
+
const ox = Math.floor(dx);
|
|
661
|
+
const oy = Math.floor(dy);
|
|
662
|
+
const a = this.get(ox, oy);
|
|
663
|
+
const b = this.get(ox + 1, oy);
|
|
664
|
+
const c = this.get(ox, oy + 1);
|
|
665
|
+
const d = this.get(ox + 1, oy + 1);
|
|
666
|
+
const fx = dx - ox;
|
|
667
|
+
const fy = dy - oy;
|
|
668
|
+
const top = lerp(a, b, fx);
|
|
669
|
+
const bottom = lerp(c, d, fx);
|
|
670
|
+
return lerp(top, bottom, fy);
|
|
671
|
+
};
|
|
672
|
+
return new HeightTile(this.width * factor, this.height * factor, blerper);
|
|
673
|
+
};
|
|
674
|
+
this.averagePixelCentersToGrid = (radius = 1) => new HeightTile(this.width + 1, this.height + 1, (x, y) => {
|
|
675
|
+
let sum = 0, count = 0, v = 0;
|
|
676
|
+
for (let newX = x - radius; newX < x + radius; newX++) {
|
|
677
|
+
for (let newY = y - radius; newY < y + radius; newY++) {
|
|
678
|
+
if (!isNaN(v = this.get(newX, newY))) {
|
|
679
|
+
count++;
|
|
680
|
+
sum += v;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
return count === 0 ? NaN : sum / count;
|
|
685
|
+
});
|
|
686
|
+
this.scaleElevation = (multiplier) => multiplier === 1 ? this : new HeightTile(this.width, this.height, (x, y) => this.get(x, y) * multiplier);
|
|
687
|
+
this.materialize = (buffer = 2) => {
|
|
688
|
+
const stride = this.width + 2 * buffer;
|
|
689
|
+
const data = new Float32Array(stride * (this.height + 2 * buffer));
|
|
690
|
+
let idx = 0;
|
|
691
|
+
for (let y = -buffer; y < this.height + buffer; y++) {
|
|
692
|
+
for (let x = -buffer; x < this.width + buffer; x++) {
|
|
693
|
+
data[idx++] = this.get(x, y);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
return new HeightTile(this.width, this.height, (x, y) => data[(y + buffer) * stride + x + buffer]);
|
|
697
|
+
};
|
|
698
|
+
this.get = get;
|
|
699
|
+
this.width = width;
|
|
700
|
+
this.height = height;
|
|
701
|
+
}
|
|
702
|
+
/** Construct a height tile from raw DEM pixel values */
|
|
703
|
+
static fromRawDem(demTile) {
|
|
704
|
+
return new HeightTile(demTile.width, demTile.height, (x, y) => {
|
|
705
|
+
const value = demTile.data[y * demTile.width + x];
|
|
706
|
+
return defaultIsValid(value) ? value : NaN;
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
/**
|
|
710
|
+
* Construct a height tile from a DEM tile plus it's 8 neighbors, so that
|
|
711
|
+
* you can request `x` or `y` outside the bounds of the original tile.
|
|
712
|
+
*
|
|
713
|
+
* @param neighbors An array containing tiles: `[nw, n, ne, w, c, e, sw, s, se]`
|
|
714
|
+
*/
|
|
715
|
+
static combineNeighbors(neighbors) {
|
|
716
|
+
if (neighbors.length !== 9) {
|
|
717
|
+
throw new Error("Must include a tile plus 8 neighbors");
|
|
718
|
+
}
|
|
719
|
+
const mainTile = neighbors[4];
|
|
720
|
+
if (!mainTile) {
|
|
721
|
+
return void 0;
|
|
722
|
+
}
|
|
723
|
+
const width = mainTile.width;
|
|
724
|
+
const height = mainTile.height;
|
|
725
|
+
return new HeightTile(width, height, (x, y) => {
|
|
726
|
+
let gridIdx = 0;
|
|
727
|
+
if (y < 0) {
|
|
728
|
+
y += height;
|
|
729
|
+
} else if (y < height) {
|
|
730
|
+
gridIdx += 3;
|
|
731
|
+
} else {
|
|
732
|
+
y -= height;
|
|
733
|
+
gridIdx += 6;
|
|
734
|
+
}
|
|
735
|
+
if (x < 0) {
|
|
736
|
+
x += width;
|
|
737
|
+
} else if (x < width) {
|
|
738
|
+
gridIdx += 1;
|
|
739
|
+
} else {
|
|
740
|
+
x -= width;
|
|
741
|
+
gridIdx += 2;
|
|
742
|
+
}
|
|
743
|
+
const grid = neighbors[gridIdx];
|
|
744
|
+
return grid ? grid.get(x, y) : NaN;
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
const SHIFT_LEFT_32 = (1 << 16) * (1 << 16);
|
|
749
|
+
const SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32;
|
|
750
|
+
const TEXT_DECODER_MIN_LENGTH = 12;
|
|
751
|
+
const utf8TextDecoder = typeof TextDecoder === "undefined" ? null : new TextDecoder("utf-8");
|
|
752
|
+
const PBF_VARINT = 0;
|
|
753
|
+
const PBF_FIXED64 = 1;
|
|
754
|
+
const PBF_BYTES = 2;
|
|
755
|
+
const PBF_FIXED32 = 5;
|
|
756
|
+
class Pbf {
|
|
757
|
+
/**
|
|
758
|
+
* @param {Uint8Array | ArrayBuffer} [buf]
|
|
759
|
+
*/
|
|
760
|
+
constructor(buf = new Uint8Array(16)) {
|
|
761
|
+
this.buf = ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf);
|
|
762
|
+
this.dataView = new DataView(this.buf.buffer);
|
|
763
|
+
this.pos = 0;
|
|
764
|
+
this.type = 0;
|
|
765
|
+
this.length = this.buf.length;
|
|
766
|
+
}
|
|
767
|
+
// === READING =================================================================
|
|
768
|
+
/**
|
|
769
|
+
* @template T
|
|
770
|
+
* @param {(tag: number, result: T, pbf: Pbf) => void} readField
|
|
771
|
+
* @param {T} result
|
|
772
|
+
* @param {number} [end]
|
|
773
|
+
*/
|
|
774
|
+
readFields(readField, result, end = this.length) {
|
|
775
|
+
while (this.pos < end) {
|
|
776
|
+
const val = this.readVarint(), tag = val >> 3, startPos = this.pos;
|
|
777
|
+
this.type = val & 7;
|
|
778
|
+
readField(tag, result, this);
|
|
779
|
+
if (this.pos === startPos) this.skip(val);
|
|
780
|
+
}
|
|
781
|
+
return result;
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* @template T
|
|
785
|
+
* @param {(tag: number, result: T, pbf: Pbf) => void} readField
|
|
786
|
+
* @param {T} result
|
|
787
|
+
*/
|
|
788
|
+
readMessage(readField, result) {
|
|
789
|
+
return this.readFields(readField, result, this.readVarint() + this.pos);
|
|
790
|
+
}
|
|
791
|
+
readFixed32() {
|
|
792
|
+
const val = this.dataView.getUint32(this.pos, true);
|
|
793
|
+
this.pos += 4;
|
|
794
|
+
return val;
|
|
795
|
+
}
|
|
796
|
+
readSFixed32() {
|
|
797
|
+
const val = this.dataView.getInt32(this.pos, true);
|
|
798
|
+
this.pos += 4;
|
|
799
|
+
return val;
|
|
800
|
+
}
|
|
801
|
+
// 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed)
|
|
802
|
+
readFixed64() {
|
|
803
|
+
const val = this.dataView.getUint32(this.pos, true) + this.dataView.getUint32(this.pos + 4, true) * SHIFT_LEFT_32;
|
|
804
|
+
this.pos += 8;
|
|
805
|
+
return val;
|
|
806
|
+
}
|
|
807
|
+
readSFixed64() {
|
|
808
|
+
const val = this.dataView.getUint32(this.pos, true) + this.dataView.getInt32(this.pos + 4, true) * SHIFT_LEFT_32;
|
|
809
|
+
this.pos += 8;
|
|
810
|
+
return val;
|
|
811
|
+
}
|
|
812
|
+
readFloat() {
|
|
813
|
+
const val = this.dataView.getFloat32(this.pos, true);
|
|
814
|
+
this.pos += 4;
|
|
815
|
+
return val;
|
|
816
|
+
}
|
|
817
|
+
readDouble() {
|
|
818
|
+
const val = this.dataView.getFloat64(this.pos, true);
|
|
819
|
+
this.pos += 8;
|
|
820
|
+
return val;
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* @param {boolean} [isSigned]
|
|
824
|
+
*/
|
|
825
|
+
readVarint(isSigned) {
|
|
826
|
+
const buf = this.buf;
|
|
827
|
+
let val, b;
|
|
828
|
+
b = buf[this.pos++];
|
|
829
|
+
val = b & 127;
|
|
830
|
+
if (b < 128) return val;
|
|
831
|
+
b = buf[this.pos++];
|
|
832
|
+
val |= (b & 127) << 7;
|
|
833
|
+
if (b < 128) return val;
|
|
834
|
+
b = buf[this.pos++];
|
|
835
|
+
val |= (b & 127) << 14;
|
|
836
|
+
if (b < 128) return val;
|
|
837
|
+
b = buf[this.pos++];
|
|
838
|
+
val |= (b & 127) << 21;
|
|
839
|
+
if (b < 128) return val;
|
|
840
|
+
b = buf[this.pos];
|
|
841
|
+
val |= (b & 15) << 28;
|
|
842
|
+
return readVarintRemainder(val, isSigned, this);
|
|
843
|
+
}
|
|
844
|
+
readVarint64() {
|
|
845
|
+
return this.readVarint(true);
|
|
846
|
+
}
|
|
847
|
+
readSVarint() {
|
|
848
|
+
const num2 = this.readVarint();
|
|
849
|
+
return num2 % 2 === 1 ? (num2 + 1) / -2 : num2 / 2;
|
|
850
|
+
}
|
|
851
|
+
readBoolean() {
|
|
852
|
+
return Boolean(this.readVarint());
|
|
853
|
+
}
|
|
854
|
+
readString() {
|
|
855
|
+
const end = this.readVarint() + this.pos;
|
|
856
|
+
const pos = this.pos;
|
|
857
|
+
this.pos = end;
|
|
858
|
+
if (end - pos >= TEXT_DECODER_MIN_LENGTH && utf8TextDecoder) {
|
|
859
|
+
return utf8TextDecoder.decode(this.buf.subarray(pos, end));
|
|
860
|
+
}
|
|
861
|
+
return readUtf8(this.buf, pos, end);
|
|
862
|
+
}
|
|
863
|
+
readBytes() {
|
|
864
|
+
const end = this.readVarint() + this.pos, buffer = this.buf.subarray(this.pos, end);
|
|
865
|
+
this.pos = end;
|
|
866
|
+
return buffer;
|
|
867
|
+
}
|
|
868
|
+
// verbose for performance reasons; doesn't affect gzipped size
|
|
869
|
+
/**
|
|
870
|
+
* @param {number[]} [arr]
|
|
871
|
+
* @param {boolean} [isSigned]
|
|
872
|
+
*/
|
|
873
|
+
readPackedVarint(arr = [], isSigned) {
|
|
874
|
+
const end = this.readPackedEnd();
|
|
875
|
+
while (this.pos < end) arr.push(this.readVarint(isSigned));
|
|
876
|
+
return arr;
|
|
877
|
+
}
|
|
878
|
+
/** @param {number[]} [arr] */
|
|
879
|
+
readPackedSVarint(arr = []) {
|
|
880
|
+
const end = this.readPackedEnd();
|
|
881
|
+
while (this.pos < end) arr.push(this.readSVarint());
|
|
882
|
+
return arr;
|
|
883
|
+
}
|
|
884
|
+
/** @param {boolean[]} [arr] */
|
|
885
|
+
readPackedBoolean(arr = []) {
|
|
886
|
+
const end = this.readPackedEnd();
|
|
887
|
+
while (this.pos < end) arr.push(this.readBoolean());
|
|
888
|
+
return arr;
|
|
889
|
+
}
|
|
890
|
+
/** @param {number[]} [arr] */
|
|
891
|
+
readPackedFloat(arr = []) {
|
|
892
|
+
const end = this.readPackedEnd();
|
|
893
|
+
while (this.pos < end) arr.push(this.readFloat());
|
|
894
|
+
return arr;
|
|
895
|
+
}
|
|
896
|
+
/** @param {number[]} [arr] */
|
|
897
|
+
readPackedDouble(arr = []) {
|
|
898
|
+
const end = this.readPackedEnd();
|
|
899
|
+
while (this.pos < end) arr.push(this.readDouble());
|
|
900
|
+
return arr;
|
|
901
|
+
}
|
|
902
|
+
/** @param {number[]} [arr] */
|
|
903
|
+
readPackedFixed32(arr = []) {
|
|
904
|
+
const end = this.readPackedEnd();
|
|
905
|
+
while (this.pos < end) arr.push(this.readFixed32());
|
|
906
|
+
return arr;
|
|
907
|
+
}
|
|
908
|
+
/** @param {number[]} [arr] */
|
|
909
|
+
readPackedSFixed32(arr = []) {
|
|
910
|
+
const end = this.readPackedEnd();
|
|
911
|
+
while (this.pos < end) arr.push(this.readSFixed32());
|
|
912
|
+
return arr;
|
|
913
|
+
}
|
|
914
|
+
/** @param {number[]} [arr] */
|
|
915
|
+
readPackedFixed64(arr = []) {
|
|
916
|
+
const end = this.readPackedEnd();
|
|
917
|
+
while (this.pos < end) arr.push(this.readFixed64());
|
|
918
|
+
return arr;
|
|
919
|
+
}
|
|
920
|
+
/** @param {number[]} [arr] */
|
|
921
|
+
readPackedSFixed64(arr = []) {
|
|
922
|
+
const end = this.readPackedEnd();
|
|
923
|
+
while (this.pos < end) arr.push(this.readSFixed64());
|
|
924
|
+
return arr;
|
|
925
|
+
}
|
|
926
|
+
readPackedEnd() {
|
|
927
|
+
return this.type === PBF_BYTES ? this.readVarint() + this.pos : this.pos + 1;
|
|
928
|
+
}
|
|
929
|
+
/** @param {number} val */
|
|
930
|
+
skip(val) {
|
|
931
|
+
const type = val & 7;
|
|
932
|
+
if (type === PBF_VARINT) while (this.buf[this.pos++] > 127) {
|
|
933
|
+
}
|
|
934
|
+
else if (type === PBF_BYTES) this.pos = this.readVarint() + this.pos;
|
|
935
|
+
else if (type === PBF_FIXED32) this.pos += 4;
|
|
936
|
+
else if (type === PBF_FIXED64) this.pos += 8;
|
|
937
|
+
else throw new Error(`Unimplemented type: ${type}`);
|
|
938
|
+
}
|
|
939
|
+
// === WRITING =================================================================
|
|
940
|
+
/**
|
|
941
|
+
* @param {number} tag
|
|
942
|
+
* @param {number} type
|
|
943
|
+
*/
|
|
944
|
+
writeTag(tag, type) {
|
|
945
|
+
this.writeVarint(tag << 3 | type);
|
|
946
|
+
}
|
|
947
|
+
/** @param {number} min */
|
|
948
|
+
realloc(min) {
|
|
949
|
+
let length = this.length || 16;
|
|
950
|
+
while (length < this.pos + min) length *= 2;
|
|
951
|
+
if (length !== this.length) {
|
|
952
|
+
const buf = new Uint8Array(length);
|
|
953
|
+
buf.set(this.buf);
|
|
954
|
+
this.buf = buf;
|
|
955
|
+
this.dataView = new DataView(buf.buffer);
|
|
956
|
+
this.length = length;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
finish() {
|
|
960
|
+
this.length = this.pos;
|
|
961
|
+
this.pos = 0;
|
|
962
|
+
return this.buf.subarray(0, this.length);
|
|
963
|
+
}
|
|
964
|
+
/** @param {number} val */
|
|
965
|
+
writeFixed32(val) {
|
|
966
|
+
this.realloc(4);
|
|
967
|
+
this.dataView.setInt32(this.pos, val, true);
|
|
968
|
+
this.pos += 4;
|
|
969
|
+
}
|
|
970
|
+
/** @param {number} val */
|
|
971
|
+
writeSFixed32(val) {
|
|
972
|
+
this.realloc(4);
|
|
973
|
+
this.dataView.setInt32(this.pos, val, true);
|
|
974
|
+
this.pos += 4;
|
|
975
|
+
}
|
|
976
|
+
/** @param {number} val */
|
|
977
|
+
writeFixed64(val) {
|
|
978
|
+
this.realloc(8);
|
|
979
|
+
this.dataView.setInt32(this.pos, val & -1, true);
|
|
980
|
+
this.dataView.setInt32(this.pos + 4, Math.floor(val * SHIFT_RIGHT_32), true);
|
|
981
|
+
this.pos += 8;
|
|
982
|
+
}
|
|
983
|
+
/** @param {number} val */
|
|
984
|
+
writeSFixed64(val) {
|
|
985
|
+
this.realloc(8);
|
|
986
|
+
this.dataView.setInt32(this.pos, val & -1, true);
|
|
987
|
+
this.dataView.setInt32(this.pos + 4, Math.floor(val * SHIFT_RIGHT_32), true);
|
|
988
|
+
this.pos += 8;
|
|
989
|
+
}
|
|
990
|
+
/** @param {number} val */
|
|
991
|
+
writeVarint(val) {
|
|
992
|
+
val = +val || 0;
|
|
993
|
+
if (val > 268435455 || val < 0) {
|
|
994
|
+
writeBigVarint(val, this);
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
this.realloc(4);
|
|
998
|
+
this.buf[this.pos++] = val & 127 | (val > 127 ? 128 : 0);
|
|
999
|
+
if (val <= 127) return;
|
|
1000
|
+
this.buf[this.pos++] = (val >>>= 7) & 127 | (val > 127 ? 128 : 0);
|
|
1001
|
+
if (val <= 127) return;
|
|
1002
|
+
this.buf[this.pos++] = (val >>>= 7) & 127 | (val > 127 ? 128 : 0);
|
|
1003
|
+
if (val <= 127) return;
|
|
1004
|
+
this.buf[this.pos++] = val >>> 7 & 127;
|
|
1005
|
+
}
|
|
1006
|
+
/** @param {number} val */
|
|
1007
|
+
writeSVarint(val) {
|
|
1008
|
+
this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);
|
|
1009
|
+
}
|
|
1010
|
+
/** @param {boolean} val */
|
|
1011
|
+
writeBoolean(val) {
|
|
1012
|
+
this.writeVarint(+val);
|
|
1013
|
+
}
|
|
1014
|
+
/** @param {string} str */
|
|
1015
|
+
writeString(str) {
|
|
1016
|
+
str = String(str);
|
|
1017
|
+
this.realloc(str.length * 4);
|
|
1018
|
+
this.pos++;
|
|
1019
|
+
const startPos = this.pos;
|
|
1020
|
+
this.pos = writeUtf8(this.buf, str, this.pos);
|
|
1021
|
+
const len = this.pos - startPos;
|
|
1022
|
+
if (len >= 128) makeRoomForExtraLength(startPos, len, this);
|
|
1023
|
+
this.pos = startPos - 1;
|
|
1024
|
+
this.writeVarint(len);
|
|
1025
|
+
this.pos += len;
|
|
1026
|
+
}
|
|
1027
|
+
/** @param {number} val */
|
|
1028
|
+
writeFloat(val) {
|
|
1029
|
+
this.realloc(4);
|
|
1030
|
+
this.dataView.setFloat32(this.pos, val, true);
|
|
1031
|
+
this.pos += 4;
|
|
1032
|
+
}
|
|
1033
|
+
/** @param {number} val */
|
|
1034
|
+
writeDouble(val) {
|
|
1035
|
+
this.realloc(8);
|
|
1036
|
+
this.dataView.setFloat64(this.pos, val, true);
|
|
1037
|
+
this.pos += 8;
|
|
1038
|
+
}
|
|
1039
|
+
/** @param {Uint8Array} buffer */
|
|
1040
|
+
writeBytes(buffer) {
|
|
1041
|
+
const len = buffer.length;
|
|
1042
|
+
this.writeVarint(len);
|
|
1043
|
+
this.realloc(len);
|
|
1044
|
+
for (let i = 0; i < len; i++) this.buf[this.pos++] = buffer[i];
|
|
1045
|
+
}
|
|
1046
|
+
/**
|
|
1047
|
+
* @template T
|
|
1048
|
+
* @param {(obj: T, pbf: Pbf) => void} fn
|
|
1049
|
+
* @param {T} obj
|
|
1050
|
+
*/
|
|
1051
|
+
writeRawMessage(fn, obj) {
|
|
1052
|
+
this.pos++;
|
|
1053
|
+
const startPos = this.pos;
|
|
1054
|
+
fn(obj, this);
|
|
1055
|
+
const len = this.pos - startPos;
|
|
1056
|
+
if (len >= 128) makeRoomForExtraLength(startPos, len, this);
|
|
1057
|
+
this.pos = startPos - 1;
|
|
1058
|
+
this.writeVarint(len);
|
|
1059
|
+
this.pos += len;
|
|
1060
|
+
}
|
|
1061
|
+
/**
|
|
1062
|
+
* @template T
|
|
1063
|
+
* @param {number} tag
|
|
1064
|
+
* @param {(obj: T, pbf: Pbf) => void} fn
|
|
1065
|
+
* @param {T} obj
|
|
1066
|
+
*/
|
|
1067
|
+
writeMessage(tag, fn, obj) {
|
|
1068
|
+
this.writeTag(tag, PBF_BYTES);
|
|
1069
|
+
this.writeRawMessage(fn, obj);
|
|
1070
|
+
}
|
|
1071
|
+
/**
|
|
1072
|
+
* @param {number} tag
|
|
1073
|
+
* @param {number[]} arr
|
|
1074
|
+
*/
|
|
1075
|
+
writePackedVarint(tag, arr) {
|
|
1076
|
+
if (arr.length) this.writeMessage(tag, writePackedVarint, arr);
|
|
1077
|
+
}
|
|
1078
|
+
/**
|
|
1079
|
+
* @param {number} tag
|
|
1080
|
+
* @param {number[]} arr
|
|
1081
|
+
*/
|
|
1082
|
+
writePackedSVarint(tag, arr) {
|
|
1083
|
+
if (arr.length) this.writeMessage(tag, writePackedSVarint, arr);
|
|
1084
|
+
}
|
|
1085
|
+
/**
|
|
1086
|
+
* @param {number} tag
|
|
1087
|
+
* @param {boolean[]} arr
|
|
1088
|
+
*/
|
|
1089
|
+
writePackedBoolean(tag, arr) {
|
|
1090
|
+
if (arr.length) this.writeMessage(tag, writePackedBoolean, arr);
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* @param {number} tag
|
|
1094
|
+
* @param {number[]} arr
|
|
1095
|
+
*/
|
|
1096
|
+
writePackedFloat(tag, arr) {
|
|
1097
|
+
if (arr.length) this.writeMessage(tag, writePackedFloat, arr);
|
|
1098
|
+
}
|
|
1099
|
+
/**
|
|
1100
|
+
* @param {number} tag
|
|
1101
|
+
* @param {number[]} arr
|
|
1102
|
+
*/
|
|
1103
|
+
writePackedDouble(tag, arr) {
|
|
1104
|
+
if (arr.length) this.writeMessage(tag, writePackedDouble, arr);
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
* @param {number} tag
|
|
1108
|
+
* @param {number[]} arr
|
|
1109
|
+
*/
|
|
1110
|
+
writePackedFixed32(tag, arr) {
|
|
1111
|
+
if (arr.length) this.writeMessage(tag, writePackedFixed32, arr);
|
|
1112
|
+
}
|
|
1113
|
+
/**
|
|
1114
|
+
* @param {number} tag
|
|
1115
|
+
* @param {number[]} arr
|
|
1116
|
+
*/
|
|
1117
|
+
writePackedSFixed32(tag, arr) {
|
|
1118
|
+
if (arr.length) this.writeMessage(tag, writePackedSFixed32, arr);
|
|
1119
|
+
}
|
|
1120
|
+
/**
|
|
1121
|
+
* @param {number} tag
|
|
1122
|
+
* @param {number[]} arr
|
|
1123
|
+
*/
|
|
1124
|
+
writePackedFixed64(tag, arr) {
|
|
1125
|
+
if (arr.length) this.writeMessage(tag, writePackedFixed64, arr);
|
|
1126
|
+
}
|
|
1127
|
+
/**
|
|
1128
|
+
* @param {number} tag
|
|
1129
|
+
* @param {number[]} arr
|
|
1130
|
+
*/
|
|
1131
|
+
writePackedSFixed64(tag, arr) {
|
|
1132
|
+
if (arr.length) this.writeMessage(tag, writePackedSFixed64, arr);
|
|
1133
|
+
}
|
|
1134
|
+
/**
|
|
1135
|
+
* @param {number} tag
|
|
1136
|
+
* @param {Uint8Array} buffer
|
|
1137
|
+
*/
|
|
1138
|
+
writeBytesField(tag, buffer) {
|
|
1139
|
+
this.writeTag(tag, PBF_BYTES);
|
|
1140
|
+
this.writeBytes(buffer);
|
|
1141
|
+
}
|
|
1142
|
+
/**
|
|
1143
|
+
* @param {number} tag
|
|
1144
|
+
* @param {number} val
|
|
1145
|
+
*/
|
|
1146
|
+
writeFixed32Field(tag, val) {
|
|
1147
|
+
this.writeTag(tag, PBF_FIXED32);
|
|
1148
|
+
this.writeFixed32(val);
|
|
1149
|
+
}
|
|
1150
|
+
/**
|
|
1151
|
+
* @param {number} tag
|
|
1152
|
+
* @param {number} val
|
|
1153
|
+
*/
|
|
1154
|
+
writeSFixed32Field(tag, val) {
|
|
1155
|
+
this.writeTag(tag, PBF_FIXED32);
|
|
1156
|
+
this.writeSFixed32(val);
|
|
1157
|
+
}
|
|
1158
|
+
/**
|
|
1159
|
+
* @param {number} tag
|
|
1160
|
+
* @param {number} val
|
|
1161
|
+
*/
|
|
1162
|
+
writeFixed64Field(tag, val) {
|
|
1163
|
+
this.writeTag(tag, PBF_FIXED64);
|
|
1164
|
+
this.writeFixed64(val);
|
|
1165
|
+
}
|
|
1166
|
+
/**
|
|
1167
|
+
* @param {number} tag
|
|
1168
|
+
* @param {number} val
|
|
1169
|
+
*/
|
|
1170
|
+
writeSFixed64Field(tag, val) {
|
|
1171
|
+
this.writeTag(tag, PBF_FIXED64);
|
|
1172
|
+
this.writeSFixed64(val);
|
|
1173
|
+
}
|
|
1174
|
+
/**
|
|
1175
|
+
* @param {number} tag
|
|
1176
|
+
* @param {number} val
|
|
1177
|
+
*/
|
|
1178
|
+
writeVarintField(tag, val) {
|
|
1179
|
+
this.writeTag(tag, PBF_VARINT);
|
|
1180
|
+
this.writeVarint(val);
|
|
1181
|
+
}
|
|
1182
|
+
/**
|
|
1183
|
+
* @param {number} tag
|
|
1184
|
+
* @param {number} val
|
|
1185
|
+
*/
|
|
1186
|
+
writeSVarintField(tag, val) {
|
|
1187
|
+
this.writeTag(tag, PBF_VARINT);
|
|
1188
|
+
this.writeSVarint(val);
|
|
1189
|
+
}
|
|
1190
|
+
/**
|
|
1191
|
+
* @param {number} tag
|
|
1192
|
+
* @param {string} str
|
|
1193
|
+
*/
|
|
1194
|
+
writeStringField(tag, str) {
|
|
1195
|
+
this.writeTag(tag, PBF_BYTES);
|
|
1196
|
+
this.writeString(str);
|
|
1197
|
+
}
|
|
1198
|
+
/**
|
|
1199
|
+
* @param {number} tag
|
|
1200
|
+
* @param {number} val
|
|
1201
|
+
*/
|
|
1202
|
+
writeFloatField(tag, val) {
|
|
1203
|
+
this.writeTag(tag, PBF_FIXED32);
|
|
1204
|
+
this.writeFloat(val);
|
|
1205
|
+
}
|
|
1206
|
+
/**
|
|
1207
|
+
* @param {number} tag
|
|
1208
|
+
* @param {number} val
|
|
1209
|
+
*/
|
|
1210
|
+
writeDoubleField(tag, val) {
|
|
1211
|
+
this.writeTag(tag, PBF_FIXED64);
|
|
1212
|
+
this.writeDouble(val);
|
|
1213
|
+
}
|
|
1214
|
+
/**
|
|
1215
|
+
* @param {number} tag
|
|
1216
|
+
* @param {boolean} val
|
|
1217
|
+
*/
|
|
1218
|
+
writeBooleanField(tag, val) {
|
|
1219
|
+
this.writeVarintField(tag, +val);
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
function readVarintRemainder(l, s, p) {
|
|
1223
|
+
const buf = p.buf;
|
|
1224
|
+
let h, b;
|
|
1225
|
+
b = buf[p.pos++];
|
|
1226
|
+
h = (b & 112) >> 4;
|
|
1227
|
+
if (b < 128) return toNum(l, h, s);
|
|
1228
|
+
b = buf[p.pos++];
|
|
1229
|
+
h |= (b & 127) << 3;
|
|
1230
|
+
if (b < 128) return toNum(l, h, s);
|
|
1231
|
+
b = buf[p.pos++];
|
|
1232
|
+
h |= (b & 127) << 10;
|
|
1233
|
+
if (b < 128) return toNum(l, h, s);
|
|
1234
|
+
b = buf[p.pos++];
|
|
1235
|
+
h |= (b & 127) << 17;
|
|
1236
|
+
if (b < 128) return toNum(l, h, s);
|
|
1237
|
+
b = buf[p.pos++];
|
|
1238
|
+
h |= (b & 127) << 24;
|
|
1239
|
+
if (b < 128) return toNum(l, h, s);
|
|
1240
|
+
b = buf[p.pos++];
|
|
1241
|
+
h |= (b & 1) << 31;
|
|
1242
|
+
if (b < 128) return toNum(l, h, s);
|
|
1243
|
+
throw new Error("Expected varint not more than 10 bytes");
|
|
1244
|
+
}
|
|
1245
|
+
function toNum(low, high, isSigned) {
|
|
1246
|
+
return isSigned ? high * 4294967296 + (low >>> 0) : (high >>> 0) * 4294967296 + (low >>> 0);
|
|
1247
|
+
}
|
|
1248
|
+
function writeBigVarint(val, pbf) {
|
|
1249
|
+
let low, high;
|
|
1250
|
+
if (val >= 0) {
|
|
1251
|
+
low = val % 4294967296 | 0;
|
|
1252
|
+
high = val / 4294967296 | 0;
|
|
1253
|
+
} else {
|
|
1254
|
+
low = ~(-val % 4294967296);
|
|
1255
|
+
high = ~(-val / 4294967296);
|
|
1256
|
+
if (low ^ 4294967295) {
|
|
1257
|
+
low = low + 1 | 0;
|
|
1258
|
+
} else {
|
|
1259
|
+
low = 0;
|
|
1260
|
+
high = high + 1 | 0;
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
if (val >= 18446744073709552e3 || val < -18446744073709552e3) {
|
|
1264
|
+
throw new Error("Given varint doesn't fit into 10 bytes");
|
|
1265
|
+
}
|
|
1266
|
+
pbf.realloc(10);
|
|
1267
|
+
writeBigVarintLow(low, high, pbf);
|
|
1268
|
+
writeBigVarintHigh(high, pbf);
|
|
1269
|
+
}
|
|
1270
|
+
function writeBigVarintLow(low, high, pbf) {
|
|
1271
|
+
pbf.buf[pbf.pos++] = low & 127 | 128;
|
|
1272
|
+
low >>>= 7;
|
|
1273
|
+
pbf.buf[pbf.pos++] = low & 127 | 128;
|
|
1274
|
+
low >>>= 7;
|
|
1275
|
+
pbf.buf[pbf.pos++] = low & 127 | 128;
|
|
1276
|
+
low >>>= 7;
|
|
1277
|
+
pbf.buf[pbf.pos++] = low & 127 | 128;
|
|
1278
|
+
low >>>= 7;
|
|
1279
|
+
pbf.buf[pbf.pos] = low & 127;
|
|
1280
|
+
}
|
|
1281
|
+
function writeBigVarintHigh(high, pbf) {
|
|
1282
|
+
const lsb = (high & 7) << 4;
|
|
1283
|
+
pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 128 : 0);
|
|
1284
|
+
if (!high) return;
|
|
1285
|
+
pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
|
|
1286
|
+
if (!high) return;
|
|
1287
|
+
pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
|
|
1288
|
+
if (!high) return;
|
|
1289
|
+
pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
|
|
1290
|
+
if (!high) return;
|
|
1291
|
+
pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
|
|
1292
|
+
if (!high) return;
|
|
1293
|
+
pbf.buf[pbf.pos++] = high & 127;
|
|
1294
|
+
}
|
|
1295
|
+
function makeRoomForExtraLength(startPos, len, pbf) {
|
|
1296
|
+
const extraLen = len <= 16383 ? 1 : len <= 2097151 ? 2 : len <= 268435455 ? 3 : Math.floor(Math.log(len) / (Math.LN2 * 7));
|
|
1297
|
+
pbf.realloc(extraLen);
|
|
1298
|
+
for (let i = pbf.pos - 1; i >= startPos; i--) pbf.buf[i + extraLen] = pbf.buf[i];
|
|
1299
|
+
}
|
|
1300
|
+
function writePackedVarint(arr, pbf) {
|
|
1301
|
+
for (let i = 0; i < arr.length; i++) pbf.writeVarint(arr[i]);
|
|
1302
|
+
}
|
|
1303
|
+
function writePackedSVarint(arr, pbf) {
|
|
1304
|
+
for (let i = 0; i < arr.length; i++) pbf.writeSVarint(arr[i]);
|
|
1305
|
+
}
|
|
1306
|
+
function writePackedFloat(arr, pbf) {
|
|
1307
|
+
for (let i = 0; i < arr.length; i++) pbf.writeFloat(arr[i]);
|
|
1308
|
+
}
|
|
1309
|
+
function writePackedDouble(arr, pbf) {
|
|
1310
|
+
for (let i = 0; i < arr.length; i++) pbf.writeDouble(arr[i]);
|
|
1311
|
+
}
|
|
1312
|
+
function writePackedBoolean(arr, pbf) {
|
|
1313
|
+
for (let i = 0; i < arr.length; i++) pbf.writeBoolean(arr[i]);
|
|
1314
|
+
}
|
|
1315
|
+
function writePackedFixed32(arr, pbf) {
|
|
1316
|
+
for (let i = 0; i < arr.length; i++) pbf.writeFixed32(arr[i]);
|
|
1317
|
+
}
|
|
1318
|
+
function writePackedSFixed32(arr, pbf) {
|
|
1319
|
+
for (let i = 0; i < arr.length; i++) pbf.writeSFixed32(arr[i]);
|
|
1320
|
+
}
|
|
1321
|
+
function writePackedFixed64(arr, pbf) {
|
|
1322
|
+
for (let i = 0; i < arr.length; i++) pbf.writeFixed64(arr[i]);
|
|
1323
|
+
}
|
|
1324
|
+
function writePackedSFixed64(arr, pbf) {
|
|
1325
|
+
for (let i = 0; i < arr.length; i++) pbf.writeSFixed64(arr[i]);
|
|
1326
|
+
}
|
|
1327
|
+
function readUtf8(buf, pos, end) {
|
|
1328
|
+
let str = "";
|
|
1329
|
+
let i = pos;
|
|
1330
|
+
while (i < end) {
|
|
1331
|
+
const b0 = buf[i];
|
|
1332
|
+
let c = null;
|
|
1333
|
+
let bytesPerSequence = b0 > 239 ? 4 : b0 > 223 ? 3 : b0 > 191 ? 2 : 1;
|
|
1334
|
+
if (i + bytesPerSequence > end) break;
|
|
1335
|
+
let b1, b2, b3;
|
|
1336
|
+
if (bytesPerSequence === 1) {
|
|
1337
|
+
if (b0 < 128) {
|
|
1338
|
+
c = b0;
|
|
1339
|
+
}
|
|
1340
|
+
} else if (bytesPerSequence === 2) {
|
|
1341
|
+
b1 = buf[i + 1];
|
|
1342
|
+
if ((b1 & 192) === 128) {
|
|
1343
|
+
c = (b0 & 31) << 6 | b1 & 63;
|
|
1344
|
+
if (c <= 127) {
|
|
1345
|
+
c = null;
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
} else if (bytesPerSequence === 3) {
|
|
1349
|
+
b1 = buf[i + 1];
|
|
1350
|
+
b2 = buf[i + 2];
|
|
1351
|
+
if ((b1 & 192) === 128 && (b2 & 192) === 128) {
|
|
1352
|
+
c = (b0 & 15) << 12 | (b1 & 63) << 6 | b2 & 63;
|
|
1353
|
+
if (c <= 2047 || c >= 55296 && c <= 57343) {
|
|
1354
|
+
c = null;
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
} else if (bytesPerSequence === 4) {
|
|
1358
|
+
b1 = buf[i + 1];
|
|
1359
|
+
b2 = buf[i + 2];
|
|
1360
|
+
b3 = buf[i + 3];
|
|
1361
|
+
if ((b1 & 192) === 128 && (b2 & 192) === 128 && (b3 & 192) === 128) {
|
|
1362
|
+
c = (b0 & 15) << 18 | (b1 & 63) << 12 | (b2 & 63) << 6 | b3 & 63;
|
|
1363
|
+
if (c <= 65535 || c >= 1114112) {
|
|
1364
|
+
c = null;
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
if (c === null) {
|
|
1369
|
+
c = 65533;
|
|
1370
|
+
bytesPerSequence = 1;
|
|
1371
|
+
} else if (c > 65535) {
|
|
1372
|
+
c -= 65536;
|
|
1373
|
+
str += String.fromCharCode(c >>> 10 & 1023 | 55296);
|
|
1374
|
+
c = 56320 | c & 1023;
|
|
1375
|
+
}
|
|
1376
|
+
str += String.fromCharCode(c);
|
|
1377
|
+
i += bytesPerSequence;
|
|
1378
|
+
}
|
|
1379
|
+
return str;
|
|
1380
|
+
}
|
|
1381
|
+
function writeUtf8(buf, str, pos) {
|
|
1382
|
+
for (let i = 0, c, lead; i < str.length; i++) {
|
|
1383
|
+
c = str.charCodeAt(i);
|
|
1384
|
+
if (c > 55295 && c < 57344) {
|
|
1385
|
+
if (lead) {
|
|
1386
|
+
if (c < 56320) {
|
|
1387
|
+
buf[pos++] = 239;
|
|
1388
|
+
buf[pos++] = 191;
|
|
1389
|
+
buf[pos++] = 189;
|
|
1390
|
+
lead = c;
|
|
1391
|
+
continue;
|
|
1392
|
+
} else {
|
|
1393
|
+
c = lead - 55296 << 10 | c - 56320 | 65536;
|
|
1394
|
+
lead = null;
|
|
1395
|
+
}
|
|
1396
|
+
} else {
|
|
1397
|
+
if (c > 56319 || i + 1 === str.length) {
|
|
1398
|
+
buf[pos++] = 239;
|
|
1399
|
+
buf[pos++] = 191;
|
|
1400
|
+
buf[pos++] = 189;
|
|
1401
|
+
} else {
|
|
1402
|
+
lead = c;
|
|
1403
|
+
}
|
|
1404
|
+
continue;
|
|
1405
|
+
}
|
|
1406
|
+
} else if (lead) {
|
|
1407
|
+
buf[pos++] = 239;
|
|
1408
|
+
buf[pos++] = 191;
|
|
1409
|
+
buf[pos++] = 189;
|
|
1410
|
+
lead = null;
|
|
1411
|
+
}
|
|
1412
|
+
if (c < 128) {
|
|
1413
|
+
buf[pos++] = c;
|
|
1414
|
+
} else {
|
|
1415
|
+
if (c < 2048) {
|
|
1416
|
+
buf[pos++] = c >> 6 | 192;
|
|
1417
|
+
} else {
|
|
1418
|
+
if (c < 65536) {
|
|
1419
|
+
buf[pos++] = c >> 12 | 224;
|
|
1420
|
+
} else {
|
|
1421
|
+
buf[pos++] = c >> 18 | 240;
|
|
1422
|
+
buf[pos++] = c >> 12 & 63 | 128;
|
|
1423
|
+
}
|
|
1424
|
+
buf[pos++] = c >> 6 & 63 | 128;
|
|
1425
|
+
}
|
|
1426
|
+
buf[pos++] = c & 63 | 128;
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
return pos;
|
|
1430
|
+
}
|
|
1431
|
+
var GeomType;
|
|
1432
|
+
(function(GeomType2) {
|
|
1433
|
+
GeomType2[GeomType2["UNKNOWN"] = 0] = "UNKNOWN";
|
|
1434
|
+
GeomType2[GeomType2["POINT"] = 1] = "POINT";
|
|
1435
|
+
GeomType2[GeomType2["LINESTRING"] = 2] = "LINESTRING";
|
|
1436
|
+
GeomType2[GeomType2["POLYGON"] = 3] = "POLYGON";
|
|
1437
|
+
})(GeomType || (GeomType = {}));
|
|
1438
|
+
function encodeVectorTile(tile) {
|
|
1439
|
+
const pbf = new Pbf();
|
|
1440
|
+
for (const id2 in tile.layers) {
|
|
1441
|
+
const layer = tile.layers[id2];
|
|
1442
|
+
if (!layer.extent) {
|
|
1443
|
+
layer.extent = tile.extent;
|
|
1444
|
+
}
|
|
1445
|
+
pbf.writeMessage(3, writeLayer, Object.assign(Object.assign({}, layer), { id: id2 }));
|
|
1446
|
+
}
|
|
1447
|
+
return pbf.finish();
|
|
1448
|
+
}
|
|
1449
|
+
function writeLayer(layer, pbf) {
|
|
1450
|
+
if (!pbf)
|
|
1451
|
+
throw new Error("pbf undefined");
|
|
1452
|
+
pbf.writeVarintField(15, 2);
|
|
1453
|
+
pbf.writeStringField(1, layer.id || "");
|
|
1454
|
+
pbf.writeVarintField(5, layer.extent || 4096);
|
|
1455
|
+
const context = {
|
|
1456
|
+
keys: [],
|
|
1457
|
+
values: [],
|
|
1458
|
+
keycache: {},
|
|
1459
|
+
valuecache: {}
|
|
1460
|
+
};
|
|
1461
|
+
for (const feature of layer.features) {
|
|
1462
|
+
context.feature = feature;
|
|
1463
|
+
pbf.writeMessage(2, writeFeature, context);
|
|
1464
|
+
}
|
|
1465
|
+
for (const key of context.keys) {
|
|
1466
|
+
pbf.writeStringField(3, key);
|
|
1467
|
+
}
|
|
1468
|
+
for (const value of context.values) {
|
|
1469
|
+
pbf.writeMessage(4, writeValue, value);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
function writeFeature(context, pbf) {
|
|
1473
|
+
const feature = context.feature;
|
|
1474
|
+
if (!feature || !pbf)
|
|
1475
|
+
throw new Error();
|
|
1476
|
+
pbf.writeMessage(2, writeProperties, context);
|
|
1477
|
+
pbf.writeVarintField(3, feature.type);
|
|
1478
|
+
pbf.writeMessage(4, writeGeometry, feature);
|
|
1479
|
+
}
|
|
1480
|
+
function writeProperties(context, pbf) {
|
|
1481
|
+
const feature = context.feature;
|
|
1482
|
+
if (!feature || !pbf)
|
|
1483
|
+
throw new Error();
|
|
1484
|
+
const keys = context.keys;
|
|
1485
|
+
const values = context.values;
|
|
1486
|
+
const keycache = context.keycache;
|
|
1487
|
+
const valuecache = context.valuecache;
|
|
1488
|
+
for (const key in feature.properties) {
|
|
1489
|
+
let value = feature.properties[key];
|
|
1490
|
+
let keyIndex = keycache[key];
|
|
1491
|
+
if (value === null)
|
|
1492
|
+
continue;
|
|
1493
|
+
if (typeof keyIndex === "undefined") {
|
|
1494
|
+
keys.push(key);
|
|
1495
|
+
keyIndex = keys.length - 1;
|
|
1496
|
+
keycache[key] = keyIndex;
|
|
1497
|
+
}
|
|
1498
|
+
pbf.writeVarint(keyIndex);
|
|
1499
|
+
const type = typeof value;
|
|
1500
|
+
if (type !== "string" && type !== "boolean" && type !== "number") {
|
|
1501
|
+
value = JSON.stringify(value);
|
|
1502
|
+
}
|
|
1503
|
+
const valueKey = `${type}:${value}`;
|
|
1504
|
+
let valueIndex = valuecache[valueKey];
|
|
1505
|
+
if (typeof valueIndex === "undefined") {
|
|
1506
|
+
values.push(value);
|
|
1507
|
+
valueIndex = values.length - 1;
|
|
1508
|
+
valuecache[valueKey] = valueIndex;
|
|
1509
|
+
}
|
|
1510
|
+
pbf.writeVarint(valueIndex);
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
function command(cmd, length) {
|
|
1514
|
+
return (length << 3) + (cmd & 7);
|
|
1515
|
+
}
|
|
1516
|
+
function zigzag(num2) {
|
|
1517
|
+
return num2 << 1 ^ num2 >> 31;
|
|
1518
|
+
}
|
|
1519
|
+
function writeGeometry(feature, pbf) {
|
|
1520
|
+
if (!pbf)
|
|
1521
|
+
throw new Error();
|
|
1522
|
+
const geometry = feature.geometry;
|
|
1523
|
+
const type = feature.type;
|
|
1524
|
+
let x = 0;
|
|
1525
|
+
let y = 0;
|
|
1526
|
+
for (const ring of geometry) {
|
|
1527
|
+
let count = 1;
|
|
1528
|
+
if (type === GeomType.POINT) {
|
|
1529
|
+
count = ring.length / 2;
|
|
1530
|
+
}
|
|
1531
|
+
pbf.writeVarint(command(1, count));
|
|
1532
|
+
const length = ring.length / 2;
|
|
1533
|
+
const lineCount = type === GeomType.POLYGON ? length - 1 : length;
|
|
1534
|
+
for (let i = 0; i < lineCount; i++) {
|
|
1535
|
+
if (i === 1 && type !== 1) {
|
|
1536
|
+
pbf.writeVarint(command(2, lineCount - 1));
|
|
1537
|
+
}
|
|
1538
|
+
const dx = ring[i * 2] - x;
|
|
1539
|
+
const dy = ring[i * 2 + 1] - y;
|
|
1540
|
+
pbf.writeVarint(zigzag(dx));
|
|
1541
|
+
pbf.writeVarint(zigzag(dy));
|
|
1542
|
+
x += dx;
|
|
1543
|
+
y += dy;
|
|
1544
|
+
}
|
|
1545
|
+
if (type === GeomType.POLYGON) {
|
|
1546
|
+
pbf.writeVarint(command(7, 1));
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
function writeValue(value, pbf) {
|
|
1551
|
+
if (!pbf)
|
|
1552
|
+
throw new Error();
|
|
1553
|
+
if (typeof value === "string") {
|
|
1554
|
+
pbf.writeStringField(1, value);
|
|
1555
|
+
} else if (typeof value === "boolean") {
|
|
1556
|
+
pbf.writeBooleanField(7, value);
|
|
1557
|
+
} else if (typeof value === "number") {
|
|
1558
|
+
if (value % 1 !== 0) {
|
|
1559
|
+
pbf.writeDoubleField(3, value);
|
|
1560
|
+
} else if (value < 0) {
|
|
1561
|
+
pbf.writeSVarintField(6, value);
|
|
1562
|
+
} else {
|
|
1563
|
+
pbf.writeVarintField(5, value);
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
const perf = typeof performance !== "undefined" ? performance : void 0;
|
|
1568
|
+
const timeOrigin = perf ? perf.timeOrigin || (/* @__PURE__ */ new Date()).getTime() - perf.now() : (/* @__PURE__ */ new Date()).getTime();
|
|
1569
|
+
function getResourceTiming(url) {
|
|
1570
|
+
var _a;
|
|
1571
|
+
return JSON.parse(JSON.stringify(((_a = perf === null || perf === void 0 ? void 0 : perf.getEntriesByName) === null || _a === void 0 ? void 0 : _a.call(perf, url)) || []));
|
|
1572
|
+
}
|
|
1573
|
+
function now() {
|
|
1574
|
+
return perf ? perf.now() : (/* @__PURE__ */ new Date()).getTime();
|
|
1575
|
+
}
|
|
1576
|
+
function flatten(input) {
|
|
1577
|
+
const result = [];
|
|
1578
|
+
for (const list of input) {
|
|
1579
|
+
result.push(...list);
|
|
1580
|
+
}
|
|
1581
|
+
return result;
|
|
1582
|
+
}
|
|
1583
|
+
class Timer {
|
|
1584
|
+
constructor(name) {
|
|
1585
|
+
this.marks = {};
|
|
1586
|
+
this.urls = [];
|
|
1587
|
+
this.fetched = [];
|
|
1588
|
+
this.resources = [];
|
|
1589
|
+
this.tilesFetched = 0;
|
|
1590
|
+
this.timeOrigin = timeOrigin;
|
|
1591
|
+
this.finish = (url) => {
|
|
1592
|
+
this.markFinish();
|
|
1593
|
+
const get = (type) => {
|
|
1594
|
+
const all = this.marks[type] || [];
|
|
1595
|
+
const max = Math.max(...all.map((ns) => Math.max(...ns)));
|
|
1596
|
+
const min = Math.min(...all.map((ns) => Math.min(...ns)));
|
|
1597
|
+
return Number.isFinite(max) ? max - min : void 0;
|
|
1598
|
+
};
|
|
1599
|
+
const duration = get("main") || 0;
|
|
1600
|
+
const fetch2 = get("fetch");
|
|
1601
|
+
const decode = get("decode");
|
|
1602
|
+
const process = get("isoline");
|
|
1603
|
+
return {
|
|
1604
|
+
url,
|
|
1605
|
+
tilesUsed: this.tilesFetched,
|
|
1606
|
+
origin: this.timeOrigin,
|
|
1607
|
+
marks: this.marks,
|
|
1608
|
+
resources: [
|
|
1609
|
+
...this.resources,
|
|
1610
|
+
...flatten(this.fetched.map(getResourceTiming))
|
|
1611
|
+
],
|
|
1612
|
+
duration,
|
|
1613
|
+
fetch: fetch2,
|
|
1614
|
+
decode,
|
|
1615
|
+
process,
|
|
1616
|
+
wait: duration - (fetch2 || 0) - (decode || 0) - (process || 0)
|
|
1617
|
+
};
|
|
1618
|
+
};
|
|
1619
|
+
this.error = (url) => Object.assign(Object.assign({}, this.finish(url)), { error: true });
|
|
1620
|
+
this.marker = (category) => {
|
|
1621
|
+
var _a;
|
|
1622
|
+
if (!this.marks[category]) {
|
|
1623
|
+
this.marks[category] = [];
|
|
1624
|
+
}
|
|
1625
|
+
const marks = [now()];
|
|
1626
|
+
(_a = this.marks[category]) === null || _a === void 0 ? void 0 : _a.push(marks);
|
|
1627
|
+
return () => marks.push(now());
|
|
1628
|
+
};
|
|
1629
|
+
this.useTile = (url) => {
|
|
1630
|
+
if (this.urls.indexOf(url) < 0) {
|
|
1631
|
+
this.urls.push(url);
|
|
1632
|
+
this.tilesFetched++;
|
|
1633
|
+
}
|
|
1634
|
+
};
|
|
1635
|
+
this.fetchTile = (url) => {
|
|
1636
|
+
if (this.fetched.indexOf(url) < 0) {
|
|
1637
|
+
this.fetched.push(url);
|
|
1638
|
+
}
|
|
1639
|
+
};
|
|
1640
|
+
this.addAll = (timings) => {
|
|
1641
|
+
var _a;
|
|
1642
|
+
this.tilesFetched += timings.tilesUsed;
|
|
1643
|
+
const offset = timings.origin - this.timeOrigin;
|
|
1644
|
+
for (const category in timings.marks) {
|
|
1645
|
+
const key = category;
|
|
1646
|
+
const ourList = this.marks[key] || (this.marks[key] = []);
|
|
1647
|
+
ourList.push(...((_a = timings.marks[key]) === null || _a === void 0 ? void 0 : _a.map((ns) => ns.map((n) => n + offset))) || []);
|
|
1648
|
+
}
|
|
1649
|
+
this.resources.push(...timings.resources.map((rt) => applyOffset(rt, offset)));
|
|
1650
|
+
};
|
|
1651
|
+
this.markFinish = this.marker(name);
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
const startOrEnd = /(Start$|End$|^start|^end)/;
|
|
1655
|
+
function applyOffset(obj, offset) {
|
|
1656
|
+
const result = {};
|
|
1657
|
+
for (const key in obj) {
|
|
1658
|
+
if (obj[key] !== 0 && startOrEnd.test(key)) {
|
|
1659
|
+
result[key] = Number(obj[key]) + offset;
|
|
1660
|
+
} else {
|
|
1661
|
+
result[key] = obj[key];
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
return result;
|
|
1665
|
+
}
|
|
1666
|
+
const defaultGetTile = (url, abortController) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1667
|
+
const options = {
|
|
1668
|
+
signal: abortController.signal
|
|
1669
|
+
};
|
|
1670
|
+
const response = yield fetch(url, options);
|
|
1671
|
+
if (!response.ok) {
|
|
1672
|
+
throw new Error(`Bad response: ${response.status} for ${url}`);
|
|
1673
|
+
}
|
|
1674
|
+
return {
|
|
1675
|
+
data: yield response.blob(),
|
|
1676
|
+
expires: response.headers.get("expires") || void 0,
|
|
1677
|
+
cacheControl: response.headers.get("cache-control") || void 0
|
|
1678
|
+
};
|
|
1679
|
+
});
|
|
1680
|
+
class LocalDemManager {
|
|
1681
|
+
constructor(options) {
|
|
1682
|
+
this.loaded = Promise.resolve();
|
|
1683
|
+
this.fetchAndParseTile = (z, x, y, abortController, timer) => {
|
|
1684
|
+
const self2 = this;
|
|
1685
|
+
const url = this.demUrlPattern.replace("{z}", z.toString()).replace("{x}", x.toString()).replace("{y}", y.toString());
|
|
1686
|
+
timer === null || timer === void 0 ? void 0 : timer.useTile(url);
|
|
1687
|
+
return this.parsedCache.get(url, (_, childAbortController) => __awaiter(this, void 0, void 0, function* () {
|
|
1688
|
+
const response = yield self2.fetchTile(z, x, y, childAbortController, timer);
|
|
1689
|
+
if (isAborted(childAbortController))
|
|
1690
|
+
throw new Error("canceled");
|
|
1691
|
+
const promise = self2.decodeImage(response.data, self2.encoding, childAbortController);
|
|
1692
|
+
const mark = timer === null || timer === void 0 ? void 0 : timer.marker("decode");
|
|
1693
|
+
const result = yield promise;
|
|
1694
|
+
mark === null || mark === void 0 ? void 0 : mark();
|
|
1695
|
+
return result;
|
|
1696
|
+
}), abortController);
|
|
1697
|
+
};
|
|
1698
|
+
this.tileCache = new AsyncCache(options.cacheSize);
|
|
1699
|
+
this.parsedCache = new AsyncCache(options.cacheSize);
|
|
1700
|
+
this.contourCache = new AsyncCache(options.cacheSize);
|
|
1701
|
+
this.timeoutMs = options.timeoutMs;
|
|
1702
|
+
this.demUrlPattern = options.demUrlPattern;
|
|
1703
|
+
this.encoding = options.encoding;
|
|
1704
|
+
this.maxzoom = options.maxzoom;
|
|
1705
|
+
this.decodeImage = options.decodeImage || defaultDecoder;
|
|
1706
|
+
this.getTile = options.getTile || defaultGetTile;
|
|
1707
|
+
}
|
|
1708
|
+
fetchTile(z, x, y, parentAbortController, timer) {
|
|
1709
|
+
const url = this.demUrlPattern.replace("{z}", z.toString()).replace("{x}", x.toString()).replace("{y}", y.toString());
|
|
1710
|
+
timer === null || timer === void 0 ? void 0 : timer.useTile(url);
|
|
1711
|
+
return this.tileCache.get(url, (_, childAbortController) => {
|
|
1712
|
+
timer === null || timer === void 0 ? void 0 : timer.fetchTile(url);
|
|
1713
|
+
const mark = timer === null || timer === void 0 ? void 0 : timer.marker("fetch");
|
|
1714
|
+
return withTimeout(this.timeoutMs, this.getTile(url, childAbortController).finally(() => mark === null || mark === void 0 ? void 0 : mark()), childAbortController);
|
|
1715
|
+
}, parentAbortController);
|
|
1716
|
+
}
|
|
1717
|
+
fetchDem(z, x, y, options, abortController, timer) {
|
|
1718
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1719
|
+
const zoom = Math.min(z - (options.overzoom || 0), this.maxzoom);
|
|
1720
|
+
const subZ = z - zoom;
|
|
1721
|
+
const div = 1 << subZ;
|
|
1722
|
+
const newX = Math.floor(x / div);
|
|
1723
|
+
const newY = Math.floor(y / div);
|
|
1724
|
+
const tile = yield this.fetchAndParseTile(zoom, newX, newY, abortController, timer);
|
|
1725
|
+
return HeightTile.fromRawDem(tile).split(subZ, x % div, y % div);
|
|
1726
|
+
});
|
|
1727
|
+
}
|
|
1728
|
+
fetchContourTile(z, x, y, options, parentAbortController, timer) {
|
|
1729
|
+
const { levels, multiplier = 1, buffer = 1, extent = 4096, contourLayer = "contours", elevationKey = "ele", levelKey = "level", subsampleBelow = 100 } = options;
|
|
1730
|
+
if (!levels || levels.length === 0) {
|
|
1731
|
+
return Promise.resolve({ arrayBuffer: new ArrayBuffer(0) });
|
|
1732
|
+
}
|
|
1733
|
+
const key = [z, x, y, encodeIndividualOptions(options)].join("/");
|
|
1734
|
+
return this.contourCache.get(key, (_, childAbortController) => __awaiter(this, void 0, void 0, function* () {
|
|
1735
|
+
const max = 1 << z;
|
|
1736
|
+
const neighborPromises = [];
|
|
1737
|
+
for (let iy = y - 1; iy <= y + 1; iy++) {
|
|
1738
|
+
for (let ix = x - 1; ix <= x + 1; ix++) {
|
|
1739
|
+
neighborPromises.push(iy < 0 || iy >= max ? void 0 : this.fetchDem(z, (ix + max) % max, iy, options, childAbortController, timer));
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
const neighbors = yield Promise.all(neighborPromises);
|
|
1743
|
+
let virtualTile = HeightTile.combineNeighbors(neighbors);
|
|
1744
|
+
if (!virtualTile || isAborted(childAbortController)) {
|
|
1745
|
+
return { arrayBuffer: new Uint8Array().buffer };
|
|
1746
|
+
}
|
|
1747
|
+
const mark = timer === null || timer === void 0 ? void 0 : timer.marker("isoline");
|
|
1748
|
+
if (virtualTile.width >= subsampleBelow) {
|
|
1749
|
+
virtualTile = virtualTile.materialize(2);
|
|
1750
|
+
} else {
|
|
1751
|
+
while (virtualTile.width < subsampleBelow) {
|
|
1752
|
+
virtualTile = virtualTile.subsamplePixelCenters(2).materialize(2);
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
virtualTile = virtualTile.averagePixelCentersToGrid().scaleElevation(multiplier).materialize(1);
|
|
1756
|
+
const isolines = generateIsolines(levels[0], virtualTile, extent, buffer);
|
|
1757
|
+
mark === null || mark === void 0 ? void 0 : mark();
|
|
1758
|
+
const result = encodeVectorTile({
|
|
1759
|
+
extent,
|
|
1760
|
+
layers: {
|
|
1761
|
+
[contourLayer]: {
|
|
1762
|
+
features: Object.entries(isolines).map(([eleString, geom]) => {
|
|
1763
|
+
const ele = Number(eleString);
|
|
1764
|
+
return {
|
|
1765
|
+
type: GeomType.LINESTRING,
|
|
1766
|
+
geometry: geom,
|
|
1767
|
+
properties: {
|
|
1768
|
+
[elevationKey]: ele,
|
|
1769
|
+
[levelKey]: Math.max(...levels.map((l, i) => ele % l === 0 ? i : 0))
|
|
1770
|
+
}
|
|
1771
|
+
};
|
|
1772
|
+
})
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
});
|
|
1776
|
+
mark === null || mark === void 0 ? void 0 : mark();
|
|
1777
|
+
return { arrayBuffer: result.buffer };
|
|
1778
|
+
}), parentAbortController);
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
let id = 0;
|
|
1782
|
+
class Actor {
|
|
1783
|
+
constructor(dest, dispatcher, timeoutMs = 2e4) {
|
|
1784
|
+
this.callbacks = {};
|
|
1785
|
+
this.cancels = {};
|
|
1786
|
+
this.dest = dest;
|
|
1787
|
+
this.timeoutMs = timeoutMs;
|
|
1788
|
+
this.dest.onmessage = (_a) => __awaiter(this, [_a], void 0, function* ({ data }) {
|
|
1789
|
+
const message = data;
|
|
1790
|
+
if (message.type === "cancel") {
|
|
1791
|
+
const cancel = this.cancels[message.id];
|
|
1792
|
+
delete this.cancels[message.id];
|
|
1793
|
+
cancel === null || cancel === void 0 ? void 0 : cancel.abort();
|
|
1794
|
+
} else if (message.type === "response") {
|
|
1795
|
+
const callback = this.callbacks[message.id];
|
|
1796
|
+
delete this.callbacks[message.id];
|
|
1797
|
+
if (callback) {
|
|
1798
|
+
callback(message.error ? new Error(message.error) : void 0, message.response, message.timings);
|
|
1799
|
+
}
|
|
1800
|
+
} else if (message.type === "request") {
|
|
1801
|
+
const timer = new Timer("worker");
|
|
1802
|
+
const handler = dispatcher[message.name];
|
|
1803
|
+
const abortController = new AbortController();
|
|
1804
|
+
const request = handler.apply(handler, [
|
|
1805
|
+
...message.args,
|
|
1806
|
+
abortController,
|
|
1807
|
+
timer
|
|
1808
|
+
]);
|
|
1809
|
+
const url = `${message.name}_${message.id}`;
|
|
1810
|
+
if (message.id && request) {
|
|
1811
|
+
this.cancels[message.id] = abortController;
|
|
1812
|
+
try {
|
|
1813
|
+
const response = yield request;
|
|
1814
|
+
const transferrables = response === null || response === void 0 ? void 0 : response.transferrables;
|
|
1815
|
+
this.postMessage({
|
|
1816
|
+
id: message.id,
|
|
1817
|
+
type: "response",
|
|
1818
|
+
response,
|
|
1819
|
+
timings: timer.finish(url)
|
|
1820
|
+
}, transferrables);
|
|
1821
|
+
} catch (e) {
|
|
1822
|
+
this.postMessage({
|
|
1823
|
+
id: message.id,
|
|
1824
|
+
type: "response",
|
|
1825
|
+
error: (e === null || e === void 0 ? void 0 : e.toString()) || "error",
|
|
1826
|
+
timings: timer.finish(url)
|
|
1827
|
+
});
|
|
1828
|
+
}
|
|
1829
|
+
delete this.cancels[message.id];
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
});
|
|
1833
|
+
}
|
|
1834
|
+
postMessage(message, transferrables) {
|
|
1835
|
+
this.dest.postMessage(message, transferrables || []);
|
|
1836
|
+
}
|
|
1837
|
+
/** Invokes a method by name with a set of arguments in the remote context. */
|
|
1838
|
+
send(name, transferrables, abortController, timer, ...args) {
|
|
1839
|
+
const thisId = ++id;
|
|
1840
|
+
const value = new Promise((resolve, reject) => {
|
|
1841
|
+
this.postMessage({ id: thisId, type: "request", name, args }, transferrables);
|
|
1842
|
+
this.callbacks[thisId] = (error, result, timings) => {
|
|
1843
|
+
timer === null || timer === void 0 ? void 0 : timer.addAll(timings);
|
|
1844
|
+
if (error)
|
|
1845
|
+
reject(error);
|
|
1846
|
+
else
|
|
1847
|
+
resolve(result);
|
|
1848
|
+
};
|
|
1849
|
+
});
|
|
1850
|
+
onAbort(abortController, () => {
|
|
1851
|
+
delete this.callbacks[thisId];
|
|
1852
|
+
this.postMessage({ id: thisId, type: "cancel" });
|
|
1853
|
+
});
|
|
1854
|
+
return withTimeout(this.timeoutMs, value, abortController);
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
exports.A = Actor;
|
|
1858
|
+
exports.H = HeightTile;
|
|
1859
|
+
exports.L = LocalDemManager;
|
|
1860
|
+
exports.T = Timer;
|
|
1861
|
+
exports._ = __awaiter;
|
|
1862
|
+
exports.a = decodeOptions;
|
|
1863
|
+
exports.b = generateIsolines;
|
|
1864
|
+
exports.c = decodeParsedImage;
|
|
1865
|
+
exports.d = defaultDecoder;
|
|
1866
|
+
exports.e = encodeOptions;
|
|
1867
|
+
exports.f = prepareContourTile;
|
|
1868
|
+
exports.g = getOptionsForZoom;
|
|
1869
|
+
exports.p = prepareDemTile;
|
|
1870
|
+
}));
|
|
1871
|
+
define(["./shared"], (function(actor) {
|
|
1872
|
+
"use strict";
|
|
1873
|
+
const noManager = (managerId) => Promise.reject(new Error(`No manager registered for ${managerId}`));
|
|
1874
|
+
class WorkerDispatch {
|
|
1875
|
+
constructor() {
|
|
1876
|
+
this.managers = {};
|
|
1877
|
+
this.init = (message, _) => {
|
|
1878
|
+
this.managers[message.managerId] = new actor.L(message);
|
|
1879
|
+
return Promise.resolve();
|
|
1880
|
+
};
|
|
1881
|
+
this.fetchTile = (managerId, z, x, y, abortController, timer) => {
|
|
1882
|
+
var _a;
|
|
1883
|
+
return ((_a = this.managers[managerId]) === null || _a === void 0 ? void 0 : _a.fetchTile(z, x, y, abortController, timer)) || noManager(managerId);
|
|
1884
|
+
};
|
|
1885
|
+
this.fetchAndParseTile = (managerId, z, x, y, abortController, timer) => {
|
|
1886
|
+
var _a;
|
|
1887
|
+
return actor.p(((_a = this.managers[managerId]) === null || _a === void 0 ? void 0 : _a.fetchAndParseTile(z, x, y, abortController, timer)) || noManager(managerId), true);
|
|
1888
|
+
};
|
|
1889
|
+
this.fetchContourTile = (managerId, z, x, y, options, abortController, timer) => {
|
|
1890
|
+
var _a;
|
|
1891
|
+
return actor.f(((_a = this.managers[managerId]) === null || _a === void 0 ? void 0 : _a.fetchContourTile(z, x, y, options, abortController, timer)) || noManager(managerId));
|
|
1892
|
+
};
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
const g = typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : global;
|
|
1896
|
+
g.actor = new actor.A(g, new WorkerDispatch());
|
|
1897
|
+
}));
|
|
1898
|
+
define(["./shared"], (function(actor) {
|
|
1899
|
+
"use strict";
|
|
1900
|
+
const CONFIG = { workerUrl: "" };
|
|
1901
|
+
let _actor;
|
|
1902
|
+
let id = 0;
|
|
1903
|
+
class MainThreadDispatch {
|
|
1904
|
+
constructor() {
|
|
1905
|
+
this.decodeImage = (blob, encoding, abortController) => actor.p(actor.d(blob, encoding, abortController), false);
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
function defaultActor() {
|
|
1909
|
+
if (!_actor) {
|
|
1910
|
+
const worker2 = new Worker(CONFIG.workerUrl);
|
|
1911
|
+
const dispatch = new MainThreadDispatch();
|
|
1912
|
+
_actor = new actor.A(worker2, dispatch);
|
|
1913
|
+
}
|
|
1914
|
+
return _actor;
|
|
1915
|
+
}
|
|
1916
|
+
class RemoteDemManager {
|
|
1917
|
+
constructor(options) {
|
|
1918
|
+
this.fetchTile = (z, x, y, abortController, timer) => this.actor.send("fetchTile", [], abortController, timer, this.managerId, z, x, y);
|
|
1919
|
+
this.fetchAndParseTile = (z, x, y, abortController, timer) => this.actor.send("fetchAndParseTile", [], abortController, timer, this.managerId, z, x, y);
|
|
1920
|
+
this.fetchContourTile = (z, x, y, options2, abortController, timer) => this.actor.send("fetchContourTile", [], abortController, timer, this.managerId, z, x, y, options2);
|
|
1921
|
+
const managerId = this.managerId = ++id;
|
|
1922
|
+
this.actor = options.actor || defaultActor();
|
|
1923
|
+
this.loaded = this.actor.send("init", [], new AbortController(), void 0, Object.assign(Object.assign({}, options), { managerId }));
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
if (!Blob.prototype.arrayBuffer) {
|
|
1927
|
+
Blob.prototype.arrayBuffer = function arrayBuffer() {
|
|
1928
|
+
return new Promise((resolve, reject) => {
|
|
1929
|
+
const fileReader = new FileReader();
|
|
1930
|
+
fileReader.onload = (event) => {
|
|
1931
|
+
var _a;
|
|
1932
|
+
return resolve((_a = event.target) === null || _a === void 0 ? void 0 : _a.result);
|
|
1933
|
+
};
|
|
1934
|
+
fileReader.onerror = reject;
|
|
1935
|
+
fileReader.readAsArrayBuffer(this);
|
|
1936
|
+
});
|
|
1937
|
+
};
|
|
1938
|
+
}
|
|
1939
|
+
const v3compat = (v4) => (requestParameters, arg2) => {
|
|
1940
|
+
if (arg2 instanceof AbortController) {
|
|
1941
|
+
return v4(requestParameters, arg2);
|
|
1942
|
+
} else {
|
|
1943
|
+
const abortController = new AbortController();
|
|
1944
|
+
v4(requestParameters, abortController).then((result) => arg2(void 0, result.data, result.cacheControl, result.expires), (err) => arg2(err)).catch((err) => arg2(err));
|
|
1945
|
+
return { cancel: () => abortController.abort() };
|
|
1946
|
+
}
|
|
1947
|
+
};
|
|
1948
|
+
const used = /* @__PURE__ */ new Set();
|
|
1949
|
+
class DemSource {
|
|
1950
|
+
constructor({ url, cacheSize = 100, id: id2 = "dem", encoding = "terrarium", maxzoom = 12, worker: worker2 = true, timeoutMs = 1e4, actor: actor$1 }) {
|
|
1951
|
+
this.timingCallbacks = [];
|
|
1952
|
+
this.onTiming = (callback) => {
|
|
1953
|
+
this.timingCallbacks.push(callback);
|
|
1954
|
+
};
|
|
1955
|
+
this.setupMaplibre = (maplibre) => {
|
|
1956
|
+
maplibre.addProtocol(this.sharedDemProtocolId, this.sharedDemProtocol);
|
|
1957
|
+
maplibre.addProtocol(this.contourProtocolId, this.contourProtocol);
|
|
1958
|
+
};
|
|
1959
|
+
this.sharedDemProtocolV4 = (request, abortController) => actor._(this, void 0, void 0, function* () {
|
|
1960
|
+
const [z, x, y] = this.parseUrl(request.url);
|
|
1961
|
+
const timer = new actor.T("main");
|
|
1962
|
+
let timing;
|
|
1963
|
+
try {
|
|
1964
|
+
const data = yield this.manager.fetchTile(z, x, y, abortController, timer);
|
|
1965
|
+
timing = timer.finish(request.url);
|
|
1966
|
+
const arrayBuffer = yield data.data.arrayBuffer();
|
|
1967
|
+
return {
|
|
1968
|
+
data: arrayBuffer,
|
|
1969
|
+
cacheControl: data.cacheControl,
|
|
1970
|
+
expires: data.expires
|
|
1971
|
+
};
|
|
1972
|
+
} catch (error) {
|
|
1973
|
+
timing = timer.error(request.url);
|
|
1974
|
+
throw error;
|
|
1975
|
+
} finally {
|
|
1976
|
+
this.timingCallbacks.forEach((cb) => cb(timing));
|
|
1977
|
+
}
|
|
1978
|
+
});
|
|
1979
|
+
this.contourProtocolV4 = (request, abortController) => actor._(this, void 0, void 0, function* () {
|
|
1980
|
+
const timer = new actor.T("main");
|
|
1981
|
+
let timing;
|
|
1982
|
+
try {
|
|
1983
|
+
const [z, x, y] = this.parseUrl(request.url);
|
|
1984
|
+
const options = actor.a(request.url);
|
|
1985
|
+
const data = yield this.manager.fetchContourTile(z, x, y, actor.g(options, z), abortController, timer);
|
|
1986
|
+
timing = timer.finish(request.url);
|
|
1987
|
+
return { data: data.arrayBuffer };
|
|
1988
|
+
} catch (error) {
|
|
1989
|
+
timing = timer.error(request.url);
|
|
1990
|
+
throw error;
|
|
1991
|
+
} finally {
|
|
1992
|
+
this.timingCallbacks.forEach((cb) => cb(timing));
|
|
1993
|
+
}
|
|
1994
|
+
});
|
|
1995
|
+
this.contourProtocol = v3compat(this.contourProtocolV4);
|
|
1996
|
+
this.sharedDemProtocol = v3compat(this.sharedDemProtocolV4);
|
|
1997
|
+
this.contourProtocolUrl = (options) => `${this.contourProtocolUrlBase}?${actor.e(options)}`;
|
|
1998
|
+
let protocolPrefix = id2;
|
|
1999
|
+
let i = 1;
|
|
2000
|
+
while (used.has(protocolPrefix)) {
|
|
2001
|
+
protocolPrefix = id2 + i++;
|
|
2002
|
+
}
|
|
2003
|
+
used.add(protocolPrefix);
|
|
2004
|
+
this.sharedDemProtocolId = `${protocolPrefix}-shared`;
|
|
2005
|
+
this.contourProtocolId = `${protocolPrefix}-contour`;
|
|
2006
|
+
this.sharedDemProtocolUrl = `${this.sharedDemProtocolId}://{z}/{x}/{y}`;
|
|
2007
|
+
this.contourProtocolUrlBase = `${this.contourProtocolId}://{z}/{x}/{y}`;
|
|
2008
|
+
const ManagerClass = worker2 ? RemoteDemManager : actor.L;
|
|
2009
|
+
this.manager = new ManagerClass({
|
|
2010
|
+
demUrlPattern: url,
|
|
2011
|
+
cacheSize,
|
|
2012
|
+
encoding,
|
|
2013
|
+
maxzoom,
|
|
2014
|
+
timeoutMs,
|
|
2015
|
+
actor: actor$1
|
|
2016
|
+
});
|
|
2017
|
+
}
|
|
2018
|
+
getDemTile(z, x, y, abortController) {
|
|
2019
|
+
return this.manager.fetchAndParseTile(z, x, y, abortController || new AbortController());
|
|
2020
|
+
}
|
|
2021
|
+
parseUrl(url) {
|
|
2022
|
+
const [, z, x, y] = /\/\/(\d+)\/(\d+)\/(\d+)/.exec(url) || [];
|
|
2023
|
+
return [Number(z), Number(x), Number(y)];
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
const exported = {
|
|
2027
|
+
generateIsolines: actor.b,
|
|
2028
|
+
DemSource,
|
|
2029
|
+
HeightTile: actor.H,
|
|
2030
|
+
LocalDemManager: actor.L,
|
|
2031
|
+
decodeParsedImage: actor.c,
|
|
2032
|
+
set workerUrl(url) {
|
|
2033
|
+
CONFIG.workerUrl = url;
|
|
2034
|
+
},
|
|
2035
|
+
get workerUrl() {
|
|
2036
|
+
return CONFIG.workerUrl;
|
|
2037
|
+
}
|
|
2038
|
+
};
|
|
2039
|
+
return exported;
|
|
2040
|
+
}));
|
|
2041
|
+
mlcontour$1 = mlcontour;
|
|
2042
|
+
}
|
|
2043
|
+
});
|
|
2044
|
+
|
|
2045
|
+
// src/browser.ts
|
|
2046
|
+
init_portable_identity_rules();
|
|
2047
|
+
|
|
1
2048
|
// src/runtime.ts
|
|
2049
|
+
var defaultTileflowRuntimeView = Object.freeze({
|
|
2050
|
+
bearing: 0,
|
|
2051
|
+
center: [0, 20],
|
|
2052
|
+
pitch: 0,
|
|
2053
|
+
zoom: 2
|
|
2054
|
+
});
|
|
2055
|
+
var tileflowStyleFontFacesMetadataKey = "tileflow:fontFaces";
|
|
2056
|
+
var tileflowStyleFontFaceLimits = Object.freeze({
|
|
2057
|
+
maximumCount: 16,
|
|
2058
|
+
maximumSourceLength: 2048
|
|
2059
|
+
});
|
|
2
2060
|
var maxStaticImagePixels = 1280 * 1280;
|
|
2061
|
+
var maximumManifestBytes = 1024 * 1024;
|
|
2062
|
+
var maximumSessionGrantBytes = 64 * 1024;
|
|
3
2063
|
var manifestCache = new globalThis.Map();
|
|
2064
|
+
function getTileflowStyleFontFaces(style) {
|
|
2065
|
+
const input = style.metadata?.[tileflowStyleFontFacesMetadataKey];
|
|
2066
|
+
if (input === void 0) return [];
|
|
2067
|
+
if (!Array.isArray(input) || input.length > tileflowStyleFontFaceLimits.maximumCount) {
|
|
2068
|
+
throw new TypeError("Invalid Tileflow style fontFaces metadata.");
|
|
2069
|
+
}
|
|
2070
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2071
|
+
return input.map((value) => {
|
|
2072
|
+
if (!isPlainRuntimeRecord(value)) {
|
|
2073
|
+
throw new TypeError("Invalid Tileflow style fontFaces metadata.");
|
|
2074
|
+
}
|
|
2075
|
+
const keys = Object.keys(value);
|
|
2076
|
+
if (keys.some((key2) => !["family", "source", "style", "weight"].includes(key2))) {
|
|
2077
|
+
throw new TypeError("Invalid Tileflow style fontFaces metadata.");
|
|
2078
|
+
}
|
|
2079
|
+
const family = value.family;
|
|
2080
|
+
const source = value.source;
|
|
2081
|
+
const fontStyle = value.style;
|
|
2082
|
+
const weight = value.weight;
|
|
2083
|
+
if (typeof family !== "string" || family.length === 0 || family.length > 100 || family !== family.trim() || /[\p{Cc}\\]/u.test(family) || typeof source !== "string" || source.length === 0 || source.length > tileflowStyleFontFaceLimits.maximumSourceLength || source !== source.trim() || /[\p{Cc}\\]/u.test(source) || !isTileflowPublicFontUrl(source) || fontStyle !== void 0 && !["italic", "normal", "oblique"].includes(String(fontStyle)) || weight !== void 0 && !/^[1-9]00$/u.test(String(weight))) {
|
|
2084
|
+
throw new TypeError("Invalid Tileflow style fontFaces metadata.");
|
|
2085
|
+
}
|
|
2086
|
+
const face = {
|
|
2087
|
+
family,
|
|
2088
|
+
source,
|
|
2089
|
+
...fontStyle === void 0 ? {} : { style: fontStyle },
|
|
2090
|
+
...weight === void 0 ? {} : { weight }
|
|
2091
|
+
};
|
|
2092
|
+
const key = `${face.family}\0${face.style ?? "normal"}\0${face.weight ?? "400"}`;
|
|
2093
|
+
if (seen.has(key)) throw new TypeError("Invalid duplicate Tileflow style fontFace metadata.");
|
|
2094
|
+
seen.add(key);
|
|
2095
|
+
return face;
|
|
2096
|
+
});
|
|
2097
|
+
}
|
|
4
2098
|
function normalizeTileflowUrl(value) {
|
|
5
2099
|
return value.replace(/\/+$/, "");
|
|
6
2100
|
}
|
|
2101
|
+
function isRecord(value) {
|
|
2102
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
2103
|
+
}
|
|
2104
|
+
function isPlainRuntimeRecord(value) {
|
|
2105
|
+
if (!isRecord(value)) return false;
|
|
2106
|
+
const prototype = Object.getPrototypeOf(value);
|
|
2107
|
+
return prototype === Object.prototype || prototype === null;
|
|
2108
|
+
}
|
|
2109
|
+
function isTileflowPublicFontUrl(value) {
|
|
2110
|
+
if (value.startsWith("//")) return false;
|
|
2111
|
+
if (value.startsWith("/") || value.startsWith("./") || value.startsWith("../")) return true;
|
|
2112
|
+
try {
|
|
2113
|
+
const url = new URL(value);
|
|
2114
|
+
return (url.protocol === "http:" || url.protocol === "https:") && !url.username && !url.password && !url.hash;
|
|
2115
|
+
} catch {
|
|
2116
|
+
return false;
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
7
2119
|
function resolveTileflowAnalyticsRequestUrl(url, analytics, sessionId) {
|
|
8
2120
|
if (!analytics || analytics.enabled === false) {
|
|
9
2121
|
return void 0;
|
|
@@ -84,7 +2196,979 @@ function getTileflowLocationOrigin() {
|
|
|
84
2196
|
return window.location.origin;
|
|
85
2197
|
}
|
|
86
2198
|
|
|
2199
|
+
// src/data/world-release-id-values.ts
|
|
2200
|
+
var tileflowWorldReleaseIdMinimumLength = 12;
|
|
2201
|
+
var tileflowWorldReleaseIdMaximumLength = 128;
|
|
2202
|
+
var tileflowWorldReleaseIdPatternSource = "^world-v1-[a-z0-9][a-z0-9._-]*[a-z0-9]$";
|
|
2203
|
+
var tileflowWorldReleaseIdPattern = new RegExp(tileflowWorldReleaseIdPatternSource, "u");
|
|
2204
|
+
function isTileflowWorldReleaseId(value) {
|
|
2205
|
+
return typeof value === "string" && value.length >= tileflowWorldReleaseIdMinimumLength && value.length <= tileflowWorldReleaseIdMaximumLength && tileflowWorldReleaseIdPattern.test(value);
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
// src/fair-use-browser.ts
|
|
2209
|
+
var protocol = "tileflow-world";
|
|
2210
|
+
var defaultHelpUrl = "https://tileflow.dev/world/claim";
|
|
2211
|
+
var ownerAction = "Site owner: manage this map with Tileflow.";
|
|
2212
|
+
var maximumWorldTileBytes = 16 * 1024 * 1024;
|
|
2213
|
+
var oversizedWorldTileMessage = "Tileflow World tile exceeds the maximum response size";
|
|
2214
|
+
var unreadableWorldTileMessage = "Tileflow World tile response could not be read";
|
|
2215
|
+
var registrations = /* @__PURE__ */ new Map();
|
|
2216
|
+
var installed = false;
|
|
2217
|
+
var channelSequence = 0;
|
|
2218
|
+
function registerTileflowWorldRequestBridge(input) {
|
|
2219
|
+
if (!installed) {
|
|
2220
|
+
input.addProtocol(protocol, loadTileflowWorldRequest);
|
|
2221
|
+
installed = true;
|
|
2222
|
+
}
|
|
2223
|
+
const channel = createChannel();
|
|
2224
|
+
registrations.set(channel, {
|
|
2225
|
+
currentNoticeState: null,
|
|
2226
|
+
fetch: input.fetch ?? globalThis.fetch,
|
|
2227
|
+
lastNoticeSequence: 0,
|
|
2228
|
+
nextRequestSequence: 0,
|
|
2229
|
+
onNotice: input.onNotice
|
|
2230
|
+
});
|
|
2231
|
+
let disposed = false;
|
|
2232
|
+
return Object.freeze({
|
|
2233
|
+
dispose() {
|
|
2234
|
+
if (disposed) return;
|
|
2235
|
+
disposed = true;
|
|
2236
|
+
registrations.delete(channel);
|
|
2237
|
+
},
|
|
2238
|
+
rewriteUrl(url) {
|
|
2239
|
+
if (disposed || !isCanonicalWorldTileUrl(url)) return url;
|
|
2240
|
+
return `${protocol}://request/${channel}?url=${encodeURIComponent(url)}`;
|
|
2241
|
+
}
|
|
2242
|
+
});
|
|
2243
|
+
}
|
|
2244
|
+
function tileflowFairUseNoticeMessage(state) {
|
|
2245
|
+
return state === "CLAIM_REQUIRED" ? "Map usage is temporarily limited." : "Map usage is approaching its temporary limit.";
|
|
2246
|
+
}
|
|
2247
|
+
function attachTileflowFairUseNotice(container) {
|
|
2248
|
+
let element = null;
|
|
2249
|
+
let current = null;
|
|
2250
|
+
let disposed = false;
|
|
2251
|
+
const remove = () => {
|
|
2252
|
+
element?.remove();
|
|
2253
|
+
element = null;
|
|
2254
|
+
current = null;
|
|
2255
|
+
};
|
|
2256
|
+
return Object.freeze({
|
|
2257
|
+
dispose() {
|
|
2258
|
+
if (disposed) return;
|
|
2259
|
+
disposed = true;
|
|
2260
|
+
remove();
|
|
2261
|
+
},
|
|
2262
|
+
update(notice) {
|
|
2263
|
+
if (disposed) return;
|
|
2264
|
+
if (!notice) {
|
|
2265
|
+
remove();
|
|
2266
|
+
return;
|
|
2267
|
+
}
|
|
2268
|
+
if (current?.state === "CLAIM_REQUIRED" && notice.state === "GRACE") return;
|
|
2269
|
+
if (element && current?.state !== notice.state) {
|
|
2270
|
+
element.remove();
|
|
2271
|
+
element = null;
|
|
2272
|
+
}
|
|
2273
|
+
current = notice;
|
|
2274
|
+
if (!element) {
|
|
2275
|
+
element = container.ownerDocument.createElement("div");
|
|
2276
|
+
element.dataset.tileflowFairUseNotice = "";
|
|
2277
|
+
element.setAttribute("aria-atomic", "true");
|
|
2278
|
+
element.setAttribute("aria-live", "polite");
|
|
2279
|
+
element.setAttribute("role", "status");
|
|
2280
|
+
Object.assign(element.style, noticeContainerStyles(notice.state));
|
|
2281
|
+
container.append(element);
|
|
2282
|
+
}
|
|
2283
|
+
element.dataset.tileflowFairUseNotice = notice.state.toLowerCase().replace("_", "-");
|
|
2284
|
+
element.replaceChildren();
|
|
2285
|
+
const indicator = container.ownerDocument.createElement("span");
|
|
2286
|
+
indicator.setAttribute("aria-hidden", "true");
|
|
2287
|
+
indicator.textContent = notice.state === "CLAIM_REQUIRED" ? "!" : "";
|
|
2288
|
+
Object.assign(indicator.style, noticeIndicatorStyles(notice.state));
|
|
2289
|
+
element.append(indicator);
|
|
2290
|
+
const copy = container.ownerDocument.createElement("span");
|
|
2291
|
+
copy.textContent = `${notice.message} `;
|
|
2292
|
+
const link = container.ownerDocument.createElement("a");
|
|
2293
|
+
link.href = notice.helpUrl;
|
|
2294
|
+
link.rel = "noopener noreferrer";
|
|
2295
|
+
link.target = "_blank";
|
|
2296
|
+
link.textContent = notice.action;
|
|
2297
|
+
Object.assign(link.style, {
|
|
2298
|
+
color: "inherit",
|
|
2299
|
+
fontWeight: "700",
|
|
2300
|
+
textDecoration: "underline",
|
|
2301
|
+
textDecorationThickness: "1px",
|
|
2302
|
+
textUnderlineOffset: "2px"
|
|
2303
|
+
});
|
|
2304
|
+
copy.append(link);
|
|
2305
|
+
element.append(copy);
|
|
2306
|
+
}
|
|
2307
|
+
});
|
|
2308
|
+
}
|
|
2309
|
+
async function loadTileflowWorldRequest(request, abortController) {
|
|
2310
|
+
const wrapped = new URL(request.url);
|
|
2311
|
+
const channel = wrapped.pathname.slice(1);
|
|
2312
|
+
const registration = wrapped.hostname === "request" ? registrations.get(channel) : void 0;
|
|
2313
|
+
const original = wrapped.searchParams.get("url") ?? "";
|
|
2314
|
+
if (!registration || !isCanonicalWorldTileUrl(original)) {
|
|
2315
|
+
throw new Error("Invalid Tileflow World request bridge");
|
|
2316
|
+
}
|
|
2317
|
+
registration.nextRequestSequence += 1;
|
|
2318
|
+
const requestSequence = registration.nextRequestSequence;
|
|
2319
|
+
const response = await registration.fetch(original, {
|
|
2320
|
+
credentials: "omit",
|
|
2321
|
+
method: "GET",
|
|
2322
|
+
signal: abortController.signal
|
|
2323
|
+
});
|
|
2324
|
+
const registrationStillActive = registrations.get(channel) === registration;
|
|
2325
|
+
const fairUse = parseFairUseState(response.headers.get("Tileflow-Fair-Use"));
|
|
2326
|
+
const ownerNotice = response.headers.get("Tileflow-Fair-Use-Notice") === "owner";
|
|
2327
|
+
if (registrationStillActive && fairUse !== null && requestSequence >= registration.lastNoticeSequence) {
|
|
2328
|
+
if (fairUse === "OPEN") {
|
|
2329
|
+
if (response.ok) {
|
|
2330
|
+
registration.lastNoticeSequence = requestSequence;
|
|
2331
|
+
registration.currentNoticeState = null;
|
|
2332
|
+
registration.onNotice(null);
|
|
2333
|
+
}
|
|
2334
|
+
} else if (fairUse === "CLAIM_REQUIRED" || fairUse === "GRACE" && (ownerNotice || response.status === 429)) {
|
|
2335
|
+
registration.lastNoticeSequence = requestSequence;
|
|
2336
|
+
if (!(registration.currentNoticeState === "CLAIM_REQUIRED" && fairUse === "GRACE")) {
|
|
2337
|
+
registration.currentNoticeState = fairUse;
|
|
2338
|
+
registration.onNotice(
|
|
2339
|
+
Object.freeze({
|
|
2340
|
+
action: ownerAction,
|
|
2341
|
+
helpUrl: parseHelpUrl(response.headers.get("Link")),
|
|
2342
|
+
message: tileflowFairUseNoticeMessage(fairUse),
|
|
2343
|
+
state: fairUse
|
|
2344
|
+
})
|
|
2345
|
+
);
|
|
2346
|
+
}
|
|
2347
|
+
} else if (fairUse === "GRACE" && response.ok) {
|
|
2348
|
+
registration.lastNoticeSequence = requestSequence;
|
|
2349
|
+
if (registration.currentNoticeState !== "CLAIM_REQUIRED") {
|
|
2350
|
+
registration.currentNoticeState = null;
|
|
2351
|
+
registration.onNotice(null);
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
if (response.status === 404 || response.status === 429 && (fairUse === "GRACE" || fairUse === "CLAIM_REQUIRED")) {
|
|
2356
|
+
await cancelResponseBody(response.body);
|
|
2357
|
+
return Object.freeze({
|
|
2358
|
+
cacheControl: "private, no-store",
|
|
2359
|
+
data: new ArrayBuffer(0)
|
|
2360
|
+
});
|
|
2361
|
+
}
|
|
2362
|
+
if (!response.ok) {
|
|
2363
|
+
await cancelResponseBody(response.body);
|
|
2364
|
+
throw new Error(`Tileflow World request failed: ${response.status}`);
|
|
2365
|
+
}
|
|
2366
|
+
return Object.freeze({
|
|
2367
|
+
...response.headers.get("Cache-Control") ? { cacheControl: response.headers.get("Cache-Control") } : {},
|
|
2368
|
+
data: await readWorldTileBody(response, abortController.signal),
|
|
2369
|
+
...response.headers.get("ETag") ? { etag: response.headers.get("ETag") } : {},
|
|
2370
|
+
...response.headers.get("Expires") ? { expires: response.headers.get("Expires") } : {}
|
|
2371
|
+
});
|
|
2372
|
+
}
|
|
2373
|
+
async function readWorldTileBody(response, signal) {
|
|
2374
|
+
if (signal.aborted) {
|
|
2375
|
+
await cancelResponseBody(response.body);
|
|
2376
|
+
throw abortReason(signal);
|
|
2377
|
+
}
|
|
2378
|
+
const declaredLength = parseContentLength(response.headers.get("Content-Length"));
|
|
2379
|
+
if (declaredLength !== null && declaredLength > maximumWorldTileBytes) {
|
|
2380
|
+
await cancelResponseBody(response.body);
|
|
2381
|
+
throw new Error(oversizedWorldTileMessage);
|
|
2382
|
+
}
|
|
2383
|
+
if (!response.body) return new ArrayBuffer(0);
|
|
2384
|
+
const reader = response.body.getReader();
|
|
2385
|
+
const chunks = [];
|
|
2386
|
+
let byteLength = 0;
|
|
2387
|
+
let abortCancellation = null;
|
|
2388
|
+
const cancelForAbort = () => {
|
|
2389
|
+
abortCancellation ??= cancelReader(reader, signal.reason);
|
|
2390
|
+
};
|
|
2391
|
+
signal.addEventListener("abort", cancelForAbort, { once: true });
|
|
2392
|
+
try {
|
|
2393
|
+
while (true) {
|
|
2394
|
+
const { done, value } = await reader.read();
|
|
2395
|
+
throwIfWorldRequestAborted(signal);
|
|
2396
|
+
if (done) break;
|
|
2397
|
+
if (value.byteLength > maximumWorldTileBytes - byteLength) {
|
|
2398
|
+
await cancelReader(reader);
|
|
2399
|
+
throw new Error(oversizedWorldTileMessage);
|
|
2400
|
+
}
|
|
2401
|
+
byteLength += value.byteLength;
|
|
2402
|
+
chunks.push(Uint8Array.from(value));
|
|
2403
|
+
}
|
|
2404
|
+
} catch (error) {
|
|
2405
|
+
if (signal.aborted) {
|
|
2406
|
+
await (abortCancellation ?? cancelReader(reader, signal.reason));
|
|
2407
|
+
throw abortReason(signal);
|
|
2408
|
+
}
|
|
2409
|
+
await cancelReader(reader);
|
|
2410
|
+
if (error instanceof Error && error.message === oversizedWorldTileMessage) throw error;
|
|
2411
|
+
throw new Error(unreadableWorldTileMessage);
|
|
2412
|
+
} finally {
|
|
2413
|
+
signal.removeEventListener("abort", cancelForAbort);
|
|
2414
|
+
reader.releaseLock();
|
|
2415
|
+
}
|
|
2416
|
+
const data = new ArrayBuffer(byteLength);
|
|
2417
|
+
const output = new Uint8Array(data);
|
|
2418
|
+
let offset = 0;
|
|
2419
|
+
for (const chunk of chunks) {
|
|
2420
|
+
output.set(chunk, offset);
|
|
2421
|
+
offset += chunk.byteLength;
|
|
2422
|
+
}
|
|
2423
|
+
return data;
|
|
2424
|
+
}
|
|
2425
|
+
function parseContentLength(value) {
|
|
2426
|
+
const normalized = value?.trim();
|
|
2427
|
+
if (!normalized || !/^\d+$/u.test(normalized)) return null;
|
|
2428
|
+
const length = Number(normalized);
|
|
2429
|
+
return Number.isSafeInteger(length) ? length : maximumWorldTileBytes + 1;
|
|
2430
|
+
}
|
|
2431
|
+
async function cancelResponseBody(body) {
|
|
2432
|
+
if (!body) return;
|
|
2433
|
+
try {
|
|
2434
|
+
await body.cancel();
|
|
2435
|
+
} catch {
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
2438
|
+
async function cancelReader(reader, reason) {
|
|
2439
|
+
try {
|
|
2440
|
+
await reader.cancel(reason);
|
|
2441
|
+
} catch {
|
|
2442
|
+
}
|
|
2443
|
+
}
|
|
2444
|
+
function throwIfWorldRequestAborted(signal) {
|
|
2445
|
+
if (signal.aborted) throw abortReason(signal);
|
|
2446
|
+
}
|
|
2447
|
+
function abortReason(signal) {
|
|
2448
|
+
if (signal.reason !== void 0) return signal.reason;
|
|
2449
|
+
return new DOMException("The Tileflow World request was aborted", "AbortError");
|
|
2450
|
+
}
|
|
2451
|
+
function parseFairUseState(value) {
|
|
2452
|
+
if (value === "open") return "OPEN";
|
|
2453
|
+
if (value === "grace") return "GRACE";
|
|
2454
|
+
if (value === "claim-required") return "CLAIM_REQUIRED";
|
|
2455
|
+
return null;
|
|
2456
|
+
}
|
|
2457
|
+
function noticeContainerStyles(state) {
|
|
2458
|
+
const shared2 = {
|
|
2459
|
+
display: "flex",
|
|
2460
|
+
left: "50%",
|
|
2461
|
+
position: "absolute",
|
|
2462
|
+
transform: "translateX(-50%)",
|
|
2463
|
+
zIndex: "3"
|
|
2464
|
+
};
|
|
2465
|
+
if (state === "GRACE") {
|
|
2466
|
+
return {
|
|
2467
|
+
...shared2,
|
|
2468
|
+
alignItems: "center",
|
|
2469
|
+
background: "rgba(252, 250, 244, 0.96)",
|
|
2470
|
+
border: "1px solid rgba(189, 138, 43, 0.28)",
|
|
2471
|
+
borderRadius: "999px",
|
|
2472
|
+
bottom: "24px",
|
|
2473
|
+
boxSizing: "border-box",
|
|
2474
|
+
boxShadow: "0 1px 5px rgba(17, 24, 39, 0.15)",
|
|
2475
|
+
color: "#38433d",
|
|
2476
|
+
font: "560 12px/1.35 system-ui, sans-serif",
|
|
2477
|
+
gap: "7px",
|
|
2478
|
+
maxWidth: "calc(100% - 24px)",
|
|
2479
|
+
padding: "7px 11px 7px 9px",
|
|
2480
|
+
textAlign: "center",
|
|
2481
|
+
width: "max-content"
|
|
2482
|
+
};
|
|
2483
|
+
}
|
|
2484
|
+
return {
|
|
2485
|
+
...shared2,
|
|
2486
|
+
alignItems: "flex-start",
|
|
2487
|
+
background: "rgba(25, 34, 29, 0.96)",
|
|
2488
|
+
border: "1px solid rgba(255, 255, 255, 0.2)",
|
|
2489
|
+
borderRadius: "8px",
|
|
2490
|
+
boxShadow: "0 4px 18px rgba(0, 0, 0, 0.28)",
|
|
2491
|
+
color: "#fff",
|
|
2492
|
+
font: "500 13px/1.45 system-ui, sans-serif",
|
|
2493
|
+
gap: "10px",
|
|
2494
|
+
maxWidth: "min(39rem, calc(100% - 32px))",
|
|
2495
|
+
padding: "12px 14px",
|
|
2496
|
+
textAlign: "left",
|
|
2497
|
+
top: "14px"
|
|
2498
|
+
};
|
|
2499
|
+
}
|
|
2500
|
+
function noticeIndicatorStyles(state) {
|
|
2501
|
+
if (state === "GRACE") {
|
|
2502
|
+
return {
|
|
2503
|
+
background: "#c58c28",
|
|
2504
|
+
borderRadius: "999px",
|
|
2505
|
+
flex: "0 0 auto",
|
|
2506
|
+
height: "7px",
|
|
2507
|
+
width: "7px"
|
|
2508
|
+
};
|
|
2509
|
+
}
|
|
2510
|
+
return {
|
|
2511
|
+
alignItems: "center",
|
|
2512
|
+
background: "#d69e39",
|
|
2513
|
+
borderRadius: "999px",
|
|
2514
|
+
color: "#17201b",
|
|
2515
|
+
display: "inline-flex",
|
|
2516
|
+
flex: "0 0 auto",
|
|
2517
|
+
font: "800 12px/1 system-ui, sans-serif",
|
|
2518
|
+
height: "18px",
|
|
2519
|
+
justifyContent: "center",
|
|
2520
|
+
marginTop: "1px",
|
|
2521
|
+
width: "18px"
|
|
2522
|
+
};
|
|
2523
|
+
}
|
|
2524
|
+
function parseHelpUrl(value) {
|
|
2525
|
+
const match = value?.match(/<([^>]+)>\s*;\s*rel=(?:"help"|help)(?:\s*;|\s*$)/iu);
|
|
2526
|
+
if (!match?.[1]) return defaultHelpUrl;
|
|
2527
|
+
try {
|
|
2528
|
+
const url = new URL(match[1]);
|
|
2529
|
+
if (url.protocol !== "https:" || url.username || url.password || url.hostname !== "tileflow.dev" && !url.hostname.endsWith(".tileflow.dev")) {
|
|
2530
|
+
return defaultHelpUrl;
|
|
2531
|
+
}
|
|
2532
|
+
return url.toString();
|
|
2533
|
+
} catch {
|
|
2534
|
+
return defaultHelpUrl;
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
function isCanonicalWorldTileUrl(value) {
|
|
2538
|
+
try {
|
|
2539
|
+
const url = new URL(value);
|
|
2540
|
+
const exactPath = url.pathname.match(
|
|
2541
|
+
/^\/tiles\/world\/([^/]+)\/(?:0|[1-9]\d*)\/(?:0|[1-9]\d*)\/(?:0|[1-9]\d*)\.pbf$/u
|
|
2542
|
+
);
|
|
2543
|
+
if (url.protocol !== "https:" || url.hostname !== "tileflow.dev" && !url.hostname.endsWith(".tileflow.dev") || url.port || url.username || url.password || url.hash || !exactPath || !isTileflowWorldReleaseId(exactPath[1])) {
|
|
2544
|
+
return false;
|
|
2545
|
+
}
|
|
2546
|
+
const allowedQueryKeys = /* @__PURE__ */ new Set([
|
|
2547
|
+
"grant",
|
|
2548
|
+
"map",
|
|
2549
|
+
"renderExpires",
|
|
2550
|
+
"renderSignature",
|
|
2551
|
+
"session",
|
|
2552
|
+
"styleId",
|
|
2553
|
+
"worldDescriptorSha256"
|
|
2554
|
+
]);
|
|
2555
|
+
if ([...url.searchParams.keys()].some((key) => !allowedQueryKeys.has(key))) return false;
|
|
2556
|
+
const descriptorDigests = url.searchParams.getAll("worldDescriptorSha256");
|
|
2557
|
+
return descriptorDigests.length === 1 && /^[0-9a-f]{64}$/u.test(descriptorDigests[0] ?? "");
|
|
2558
|
+
} catch {
|
|
2559
|
+
return false;
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2562
|
+
function createChannel() {
|
|
2563
|
+
channelSequence += 1;
|
|
2564
|
+
if (typeof crypto !== "undefined" && "randomUUID" in crypto) {
|
|
2565
|
+
return `bridge_${crypto.randomUUID().replaceAll("-", "_")}`;
|
|
2566
|
+
}
|
|
2567
|
+
return `bridge_${Date.now().toString(36)}_${channelSequence.toString(36)}`;
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
// src/terrain/contour-protocol.ts
|
|
2571
|
+
var tileflowContourProtocol = "tileflow-contour";
|
|
2572
|
+
var tileflowContourSourceLayer = "contours";
|
|
2573
|
+
function minimumTileflowContourSourceInterval(zoom) {
|
|
2574
|
+
if (zoom <= 4) return 250;
|
|
2575
|
+
if (zoom <= 7) return 100;
|
|
2576
|
+
if (zoom <= 10) return 50;
|
|
2577
|
+
if (zoom <= 12) return 20;
|
|
2578
|
+
return 10;
|
|
2579
|
+
}
|
|
2580
|
+
function isTileflowContourDensityWithinBudget(minorInterval, multiplier, zoom) {
|
|
2581
|
+
const minimumScaledInterval = minimumTileflowContourSourceInterval(zoom) * multiplier;
|
|
2582
|
+
const tolerance = Number.EPSILON * Math.max(1, minorInterval, minimumScaledInterval) * 8;
|
|
2583
|
+
return minorInterval + tolerance >= minimumScaledInterval;
|
|
2584
|
+
}
|
|
2585
|
+
var maximumDemUrlLength = 2048;
|
|
2586
|
+
var maximumProtocolUrlLength = 8192;
|
|
2587
|
+
var contourTilePathPattern = /^\/(\d{1,2})\/(\d{1,8})\/(\d{1,8})\.pbf$/u;
|
|
2588
|
+
var allowedParameters = /* @__PURE__ */ new Set([
|
|
2589
|
+
"demMaxzoom",
|
|
2590
|
+
"demUrl",
|
|
2591
|
+
"encoding",
|
|
2592
|
+
"maxzoom",
|
|
2593
|
+
"multiplier",
|
|
2594
|
+
"overzoom",
|
|
2595
|
+
"thresholds"
|
|
2596
|
+
]);
|
|
2597
|
+
function parseTileflowContourProtocolRequest(value) {
|
|
2598
|
+
if (value.length > maximumProtocolUrlLength || /[\\\p{Cc}]/u.test(value)) {
|
|
2599
|
+
throw new Error("Invalid Tileflow contour protocol URL.");
|
|
2600
|
+
}
|
|
2601
|
+
let url;
|
|
2602
|
+
try {
|
|
2603
|
+
url = new URL(value);
|
|
2604
|
+
} catch {
|
|
2605
|
+
throw new Error("Invalid Tileflow contour protocol URL.");
|
|
2606
|
+
}
|
|
2607
|
+
if (url.protocol !== `${tileflowContourProtocol}:` || url.hostname !== "tiles" || url.username || url.password || url.hash) {
|
|
2608
|
+
throw new Error("Invalid Tileflow contour protocol URL.");
|
|
2609
|
+
}
|
|
2610
|
+
for (const key of url.searchParams.keys()) {
|
|
2611
|
+
if (!allowedParameters.has(key) || url.searchParams.getAll(key).length !== 1) {
|
|
2612
|
+
throw new Error("Invalid Tileflow contour protocol URL parameters.");
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
if ([...allowedParameters].some((key) => !url.searchParams.has(key))) {
|
|
2616
|
+
throw new Error("Incomplete Tileflow contour protocol URL parameters.");
|
|
2617
|
+
}
|
|
2618
|
+
const tile = contourTilePathPattern.exec(url.pathname);
|
|
2619
|
+
if (!tile) throw new Error("Invalid Tileflow contour tile coordinates.");
|
|
2620
|
+
const z = Number(tile[1]);
|
|
2621
|
+
const x = Number(tile[2]);
|
|
2622
|
+
const y = Number(tile[3]);
|
|
2623
|
+
const config = {
|
|
2624
|
+
demMaxzoom: parseBoundedInteger(url.searchParams.get("demMaxzoom"), 0, 24),
|
|
2625
|
+
demUrl: url.searchParams.get("demUrl") ?? "",
|
|
2626
|
+
encoding: parseEncoding(url.searchParams.get("encoding")),
|
|
2627
|
+
maxzoom: parseBoundedInteger(url.searchParams.get("maxzoom"), 0, 24),
|
|
2628
|
+
multiplier: parseBoundedNumber(url.searchParams.get("multiplier"), 1e-3, 100),
|
|
2629
|
+
overzoom: parseBoundedInteger(url.searchParams.get("overzoom"), 0, 8),
|
|
2630
|
+
thresholds: parseThresholds(url.searchParams.get("thresholds") ?? "")
|
|
2631
|
+
};
|
|
2632
|
+
assertTileflowContourProtocolConfig(config);
|
|
2633
|
+
const axisLimit = 2 ** z;
|
|
2634
|
+
const minimumThresholdZoom = Math.min(...Object.keys(config.thresholds).map(Number));
|
|
2635
|
+
if (z < minimumThresholdZoom || z > config.maxzoom || x >= axisLimit || y >= axisLimit) {
|
|
2636
|
+
throw new Error("Invalid Tileflow contour tile coordinates.");
|
|
2637
|
+
}
|
|
2638
|
+
return { config, x, y, z };
|
|
2639
|
+
}
|
|
2640
|
+
function isSafeTileflowDemUrlTemplate(value) {
|
|
2641
|
+
if (value.length === 0 || value.length > maximumDemUrlLength || value.startsWith("//") || value.includes("#") || /[\\\p{Cc}]/u.test(value)) {
|
|
2642
|
+
return false;
|
|
2643
|
+
}
|
|
2644
|
+
for (const placeholder of ["{z}", "{x}", "{y}"]) {
|
|
2645
|
+
if (value.split(placeholder).length !== 2) return false;
|
|
2646
|
+
}
|
|
2647
|
+
if (/\{[^{}]*\}/u.test(value.replaceAll("{z}", "").replaceAll("{x}", "").replaceAll("{y}", ""))) {
|
|
2648
|
+
return false;
|
|
2649
|
+
}
|
|
2650
|
+
try {
|
|
2651
|
+
const url = new URL(value.replaceAll("{z}", "0").replaceAll("{x}", "0").replaceAll("{y}", "0"));
|
|
2652
|
+
return (url.protocol === "https:" || url.protocol === "http:" && isLoopbackHostname(url.hostname)) && !url.username && !url.password && !url.hash;
|
|
2653
|
+
} catch {
|
|
2654
|
+
return false;
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
function assertTileflowContourProtocolConfig(config) {
|
|
2658
|
+
if (!isSafeTileflowDemUrlTemplate(config.demUrl)) {
|
|
2659
|
+
throw new Error(
|
|
2660
|
+
"Tileflow contour demUrl must be a safe HTTP(S) template containing {z}, {x}, and {y}."
|
|
2661
|
+
);
|
|
2662
|
+
}
|
|
2663
|
+
if (config.encoding !== "mapbox" && config.encoding !== "terrarium") {
|
|
2664
|
+
throw new Error("Tileflow contour encoding must be mapbox or terrarium.");
|
|
2665
|
+
}
|
|
2666
|
+
assertBoundedInteger(config.demMaxzoom, 0, 24, "demMaxzoom");
|
|
2667
|
+
assertBoundedInteger(config.maxzoom, 0, 24, "maxzoom");
|
|
2668
|
+
assertBoundedInteger(config.overzoom, 0, 8, "overzoom");
|
|
2669
|
+
assertBoundedNumber(config.multiplier, 1e-3, 100, "multiplier");
|
|
2670
|
+
const entries = Object.entries(config.thresholds);
|
|
2671
|
+
if (entries.length === 0 || entries.length > 25) {
|
|
2672
|
+
throw new Error("Tileflow contour thresholds must contain between 1 and 25 zoom entries.");
|
|
2673
|
+
}
|
|
2674
|
+
for (const [zoom, pair] of entries) {
|
|
2675
|
+
if (!/^(?:0|[1-9]\d?)$/u.test(zoom)) {
|
|
2676
|
+
throw new Error("Tileflow contour threshold zooms must be integers from 0 to 24.");
|
|
2677
|
+
}
|
|
2678
|
+
assertBoundedInteger(Number(zoom), 0, 24, "threshold zoom");
|
|
2679
|
+
if (!Array.isArray(pair) || pair.length !== 2) {
|
|
2680
|
+
throw new Error("Tileflow contour thresholds must be [minor, index] pairs.");
|
|
2681
|
+
}
|
|
2682
|
+
const [minor, index] = pair;
|
|
2683
|
+
assertBoundedNumber(minor, 1e-3, 1e5, "minor threshold");
|
|
2684
|
+
assertBoundedNumber(index, minor, 1e5, "index threshold");
|
|
2685
|
+
if (!isTileflowContourDensityWithinBudget(minor, config.multiplier, Number(zoom))) {
|
|
2686
|
+
throw new Error("Tileflow contour threshold exceeds the supported density budget.");
|
|
2687
|
+
}
|
|
2688
|
+
if (!isWholeContourMultiple(index, minor)) {
|
|
2689
|
+
throw new Error(
|
|
2690
|
+
"Tileflow contour index threshold must be a whole multiple of the minor threshold."
|
|
2691
|
+
);
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
const thresholdZooms = entries.map(([zoom]) => Number(zoom));
|
|
2695
|
+
if (Math.max(...thresholdZooms) > config.maxzoom) {
|
|
2696
|
+
throw new Error("Tileflow contour maxzoom must include every threshold zoom.");
|
|
2697
|
+
}
|
|
2698
|
+
if (config.overzoom > Math.min(...thresholdZooms)) {
|
|
2699
|
+
throw new Error("Tileflow contour overzoom must not produce a negative DEM zoom.");
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
function parseThresholds(value) {
|
|
2703
|
+
if (!value || value.length > 1024) {
|
|
2704
|
+
throw new Error("Invalid Tileflow contour thresholds.");
|
|
2705
|
+
}
|
|
2706
|
+
const result = {};
|
|
2707
|
+
for (const entry of value.split(";")) {
|
|
2708
|
+
const match = /^(0|[1-9]\d?):([^,]+),([^,]+)$/u.exec(entry);
|
|
2709
|
+
if (!match) throw new Error("Invalid Tileflow contour thresholds.");
|
|
2710
|
+
const zoom = parseBoundedInteger(match[1], 0, 24);
|
|
2711
|
+
if (Object.hasOwn(result, zoom)) throw new Error("Duplicate Tileflow contour threshold zoom.");
|
|
2712
|
+
result[zoom] = [
|
|
2713
|
+
parseBoundedNumber(match[2], 1e-3, 1e5),
|
|
2714
|
+
parseBoundedNumber(match[3], 1e-3, 1e5)
|
|
2715
|
+
];
|
|
2716
|
+
}
|
|
2717
|
+
return result;
|
|
2718
|
+
}
|
|
2719
|
+
function parseEncoding(value) {
|
|
2720
|
+
if (value !== "mapbox" && value !== "terrarium") {
|
|
2721
|
+
throw new Error("Invalid Tileflow contour encoding.");
|
|
2722
|
+
}
|
|
2723
|
+
return value;
|
|
2724
|
+
}
|
|
2725
|
+
function parseBoundedInteger(value, minimum, maximum) {
|
|
2726
|
+
if (value === null || !/^(?:0|[1-9]\d*)$/u.test(value)) {
|
|
2727
|
+
throw new Error("Invalid Tileflow contour integer.");
|
|
2728
|
+
}
|
|
2729
|
+
const parsed = Number(value);
|
|
2730
|
+
assertBoundedInteger(parsed, minimum, maximum, "integer");
|
|
2731
|
+
return parsed;
|
|
2732
|
+
}
|
|
2733
|
+
function parseBoundedNumber(value, minimum, maximum) {
|
|
2734
|
+
if (value === null || value.trim() !== value || value === "") {
|
|
2735
|
+
throw new Error("Invalid Tileflow contour number.");
|
|
2736
|
+
}
|
|
2737
|
+
const parsed = Number(value);
|
|
2738
|
+
assertBoundedNumber(parsed, minimum, maximum, "number");
|
|
2739
|
+
return parsed;
|
|
2740
|
+
}
|
|
2741
|
+
function assertBoundedInteger(value, minimum, maximum, name) {
|
|
2742
|
+
if (!Number.isInteger(value) || value < minimum || value > maximum) {
|
|
2743
|
+
throw new Error(`Tileflow contour ${name} is outside its supported range.`);
|
|
2744
|
+
}
|
|
2745
|
+
}
|
|
2746
|
+
function assertBoundedNumber(value, minimum, maximum, name) {
|
|
2747
|
+
if (!Number.isFinite(value) || value < minimum || value > maximum) {
|
|
2748
|
+
throw new Error(`Tileflow contour ${name} is outside its supported range.`);
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2751
|
+
function isWholeContourMultiple(value, interval) {
|
|
2752
|
+
const ratio = value / interval;
|
|
2753
|
+
return Math.abs(ratio - Math.round(ratio)) <= Number.EPSILON * Math.max(1, ratio) * 8;
|
|
2754
|
+
}
|
|
2755
|
+
function isLoopbackHostname(hostname) {
|
|
2756
|
+
const normalized = hostname.toLowerCase().replace(/^\[|\]$/gu, "");
|
|
2757
|
+
return normalized === "localhost" || normalized === "::1" || normalized === "0:0:0:0:0:0:0:1" || /^127(?:\.\d{1,3}){3}$/u.test(normalized);
|
|
2758
|
+
}
|
|
2759
|
+
|
|
2760
|
+
// src/contour-browser.ts
|
|
2761
|
+
var tileflowMaplibreContourVersion = "0.1.0";
|
|
2762
|
+
var registeredContourProtocols = /* @__PURE__ */ new WeakSet();
|
|
2763
|
+
function registerTileflowContourProtocol(registry, options = {}) {
|
|
2764
|
+
if (registeredContourProtocols.has(registry.addProtocol)) return;
|
|
2765
|
+
const handler = createTileflowContourProtocolHandler(
|
|
2766
|
+
options.loadMaplibreContour ?? loadPinnedMaplibreContour
|
|
2767
|
+
);
|
|
2768
|
+
registry.addProtocol(tileflowContourProtocol, handler);
|
|
2769
|
+
registeredContourProtocols.add(registry.addProtocol);
|
|
2770
|
+
}
|
|
2771
|
+
function createTileflowContourProtocolHandler(loadModule) {
|
|
2772
|
+
let library;
|
|
2773
|
+
const sources = /* @__PURE__ */ new Map();
|
|
2774
|
+
return async (request, abortController) => {
|
|
2775
|
+
if (abortController.signal.aborted) throw new Error("Tileflow contour request aborted.");
|
|
2776
|
+
const { config, x, y, z } = parseTileflowContourProtocolRequest(request.url);
|
|
2777
|
+
const sourceKey = JSON.stringify([config.demUrl, config.encoding, config.demMaxzoom]);
|
|
2778
|
+
let source = sources.get(sourceKey);
|
|
2779
|
+
if (!source) {
|
|
2780
|
+
if (sources.size >= 16) sources.delete(sources.keys().next().value);
|
|
2781
|
+
library ??= loadModule().then(resolveMaplibreContourLibrary);
|
|
2782
|
+
source = library.then(
|
|
2783
|
+
(module) => new module.DemSource({
|
|
2784
|
+
encoding: config.encoding,
|
|
2785
|
+
maxzoom: config.demMaxzoom,
|
|
2786
|
+
url: config.demUrl,
|
|
2787
|
+
// Upstream workers use a generated `blob:` URL. The main-thread manager keeps the
|
|
2788
|
+
// protocol usable in strict-CSP applications and deterministic local captures.
|
|
2789
|
+
worker: false
|
|
2790
|
+
})
|
|
2791
|
+
);
|
|
2792
|
+
source = source.catch((error) => {
|
|
2793
|
+
sources.delete(sourceKey);
|
|
2794
|
+
library = void 0;
|
|
2795
|
+
throw error;
|
|
2796
|
+
});
|
|
2797
|
+
sources.set(sourceKey, source);
|
|
2798
|
+
}
|
|
2799
|
+
const contourSource = await source;
|
|
2800
|
+
if (abortController.signal.aborted) throw new Error("Tileflow contour request aborted.");
|
|
2801
|
+
const contourUrl = contourSource.contourProtocolUrl({
|
|
2802
|
+
contourLayer: tileflowContourSourceLayer,
|
|
2803
|
+
elevationKey: "ele",
|
|
2804
|
+
levelKey: "level",
|
|
2805
|
+
multiplier: config.multiplier,
|
|
2806
|
+
overzoom: config.overzoom,
|
|
2807
|
+
thresholds: mutableThresholds(config.thresholds)
|
|
2808
|
+
}).replace("{z}", String(z)).replace("{x}", String(x)).replace("{y}", String(y));
|
|
2809
|
+
return contourSource.contourProtocolV4({ url: contourUrl }, abortController);
|
|
2810
|
+
};
|
|
2811
|
+
}
|
|
2812
|
+
async function loadPinnedMaplibreContour() {
|
|
2813
|
+
return Promise.resolve().then(() => (init_dist(), dist_exports));
|
|
2814
|
+
}
|
|
2815
|
+
function resolveMaplibreContourLibrary(module) {
|
|
2816
|
+
if (!module || typeof module !== "object") {
|
|
2817
|
+
throw new Error("maplibre-contour 0.1.0 did not expose its browser module.");
|
|
2818
|
+
}
|
|
2819
|
+
const library = module.default;
|
|
2820
|
+
if (!library || typeof library !== "object" || typeof library.DemSource !== "function") {
|
|
2821
|
+
throw new Error("maplibre-contour 0.1.0 did not expose DemSource.");
|
|
2822
|
+
}
|
|
2823
|
+
return library;
|
|
2824
|
+
}
|
|
2825
|
+
function mutableThresholds(thresholds) {
|
|
2826
|
+
return Object.fromEntries(
|
|
2827
|
+
Object.entries(thresholds).map(([zoom, [minor, index]]) => [Number(zoom), [minor, index]])
|
|
2828
|
+
);
|
|
2829
|
+
}
|
|
2830
|
+
|
|
87
2831
|
// src/browser.ts
|
|
2832
|
+
var systemColorSchemeListeners = /* @__PURE__ */ new Set();
|
|
2833
|
+
var systemColorSchemeQuery;
|
|
2834
|
+
var systemColorScheme = "light";
|
|
2835
|
+
function getTileflowSystemColorScheme() {
|
|
2836
|
+
ensureSystemColorSchemeQuery();
|
|
2837
|
+
return systemColorScheme;
|
|
2838
|
+
}
|
|
2839
|
+
function subscribeTileflowSystemColorScheme(listener) {
|
|
2840
|
+
ensureSystemColorSchemeQuery();
|
|
2841
|
+
systemColorSchemeListeners.add(listener);
|
|
2842
|
+
return () => {
|
|
2843
|
+
systemColorSchemeListeners.delete(listener);
|
|
2844
|
+
if (systemColorSchemeListeners.size === 0 && systemColorSchemeQuery) {
|
|
2845
|
+
systemColorSchemeQuery.removeEventListener?.("change", handleSystemColorSchemeChange);
|
|
2846
|
+
systemColorSchemeQuery.removeListener?.(handleSystemColorSchemeChange);
|
|
2847
|
+
systemColorSchemeQuery = void 0;
|
|
2848
|
+
}
|
|
2849
|
+
};
|
|
2850
|
+
}
|
|
2851
|
+
function ensureSystemColorSchemeQuery() {
|
|
2852
|
+
if (systemColorSchemeQuery) return;
|
|
2853
|
+
const browser = globalThis;
|
|
2854
|
+
if (!browser.matchMedia) {
|
|
2855
|
+
systemColorScheme = "light";
|
|
2856
|
+
return;
|
|
2857
|
+
}
|
|
2858
|
+
systemColorSchemeQuery = browser.matchMedia("(prefers-color-scheme: dark)");
|
|
2859
|
+
systemColorScheme = systemColorSchemeQuery.matches ? "dark" : "light";
|
|
2860
|
+
systemColorSchemeQuery.addEventListener?.("change", handleSystemColorSchemeChange);
|
|
2861
|
+
if (!systemColorSchemeQuery.addEventListener) {
|
|
2862
|
+
systemColorSchemeQuery.addListener?.(handleSystemColorSchemeChange);
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2865
|
+
function handleSystemColorSchemeChange() {
|
|
2866
|
+
if (!systemColorSchemeQuery) return;
|
|
2867
|
+
const next = systemColorSchemeQuery.matches ? "dark" : "light";
|
|
2868
|
+
if (next === systemColorScheme) return;
|
|
2869
|
+
systemColorScheme = next;
|
|
2870
|
+
for (const listener of systemColorSchemeListeners) listener(next);
|
|
2871
|
+
}
|
|
2872
|
+
function createTileflowThemeController(options) {
|
|
2873
|
+
assertConcreteRuntimeTheme(options.initial, "initial");
|
|
2874
|
+
const loadFonts = options.loadFonts ?? ((runtimeStyle) => loadTileflowStyleFonts(runtimeStyle.style, { fontFaces: runtimeStyle.fontFaces }));
|
|
2875
|
+
const timeoutMs = normalizeThemeTransitionTimeout(options.timeoutMs);
|
|
2876
|
+
let current = options.initial;
|
|
2877
|
+
let disposed = false;
|
|
2878
|
+
let requestId = 0;
|
|
2879
|
+
let applyQueue = Promise.resolve();
|
|
2880
|
+
return {
|
|
2881
|
+
dispose() {
|
|
2882
|
+
disposed = true;
|
|
2883
|
+
requestId += 1;
|
|
2884
|
+
},
|
|
2885
|
+
getCurrent() {
|
|
2886
|
+
return current;
|
|
2887
|
+
},
|
|
2888
|
+
setTheme(style) {
|
|
2889
|
+
const invalidTheme = validateConcreteRuntimeTheme(style, "target");
|
|
2890
|
+
if (invalidTheme) {
|
|
2891
|
+
return Promise.resolve({ error: invalidTheme, status: "failed", theme: style.theme });
|
|
2892
|
+
}
|
|
2893
|
+
if (disposed) {
|
|
2894
|
+
return Promise.resolve({
|
|
2895
|
+
error: new Error("Tileflow theme controller is disposed."),
|
|
2896
|
+
status: "failed",
|
|
2897
|
+
theme: style.theme
|
|
2898
|
+
});
|
|
2899
|
+
}
|
|
2900
|
+
const runId = ++requestId;
|
|
2901
|
+
options.onTransition?.({
|
|
2902
|
+
currentTheme: current.theme,
|
|
2903
|
+
phase: "preloading",
|
|
2904
|
+
targetTheme: style.theme
|
|
2905
|
+
});
|
|
2906
|
+
let preloaded;
|
|
2907
|
+
try {
|
|
2908
|
+
preloaded = loadFonts(style);
|
|
2909
|
+
} catch (error) {
|
|
2910
|
+
return Promise.resolve(handlePreloadFailure(runId, style, error));
|
|
2911
|
+
}
|
|
2912
|
+
return preloaded.then(
|
|
2913
|
+
() => enqueueTheme(runId, style),
|
|
2914
|
+
(error) => handlePreloadFailure(runId, style, error)
|
|
2915
|
+
);
|
|
2916
|
+
}
|
|
2917
|
+
};
|
|
2918
|
+
function enqueueTheme(runId, style) {
|
|
2919
|
+
const operation = applyQueue.then(
|
|
2920
|
+
() => applyTheme(runId, style),
|
|
2921
|
+
() => applyTheme(runId, style)
|
|
2922
|
+
);
|
|
2923
|
+
applyQueue = operation.then(
|
|
2924
|
+
() => void 0,
|
|
2925
|
+
() => void 0
|
|
2926
|
+
);
|
|
2927
|
+
return operation;
|
|
2928
|
+
}
|
|
2929
|
+
async function applyTheme(runId, style) {
|
|
2930
|
+
if (disposed || runId !== requestId) return { status: "superseded", theme: style.theme };
|
|
2931
|
+
const previous = current;
|
|
2932
|
+
options.onTransition?.({
|
|
2933
|
+
currentTheme: previous.theme,
|
|
2934
|
+
phase: "applying",
|
|
2935
|
+
targetTheme: style.theme
|
|
2936
|
+
});
|
|
2937
|
+
try {
|
|
2938
|
+
await applyMapStyle(options.map, style.style, timeoutMs);
|
|
2939
|
+
if (disposed) return { status: "superseded", theme: style.theme };
|
|
2940
|
+
if (runId !== requestId) {
|
|
2941
|
+
try {
|
|
2942
|
+
await applyMapStyle(options.map, current.style, timeoutMs);
|
|
2943
|
+
} catch {
|
|
2944
|
+
}
|
|
2945
|
+
return { status: "superseded", theme: style.theme };
|
|
2946
|
+
}
|
|
2947
|
+
current = style;
|
|
2948
|
+
options.onTransition?.({
|
|
2949
|
+
currentTheme: style.theme,
|
|
2950
|
+
phase: "ready",
|
|
2951
|
+
targetTheme: style.theme
|
|
2952
|
+
});
|
|
2953
|
+
return { status: "applied", theme: style.theme };
|
|
2954
|
+
} catch (error) {
|
|
2955
|
+
const normalized = normalizeThemeTransitionError(error, "Tileflow theme change failed.");
|
|
2956
|
+
try {
|
|
2957
|
+
await applyMapStyle(options.map, previous.style, timeoutMs);
|
|
2958
|
+
current = previous;
|
|
2959
|
+
} catch {
|
|
2960
|
+
}
|
|
2961
|
+
if (disposed || runId !== requestId) return { status: "superseded", theme: style.theme };
|
|
2962
|
+
options.onTransition?.({
|
|
2963
|
+
currentTheme: current.theme,
|
|
2964
|
+
error: normalized,
|
|
2965
|
+
phase: "error",
|
|
2966
|
+
targetTheme: style.theme
|
|
2967
|
+
});
|
|
2968
|
+
return { error: normalized, status: "failed", theme: style.theme };
|
|
2969
|
+
}
|
|
2970
|
+
}
|
|
2971
|
+
function handlePreloadFailure(runId, style, error) {
|
|
2972
|
+
if (disposed || runId !== requestId) return { status: "superseded", theme: style.theme };
|
|
2973
|
+
const normalized = normalizeThemeTransitionError(error, "Tileflow theme preload failed.");
|
|
2974
|
+
options.onTransition?.({
|
|
2975
|
+
currentTheme: current.theme,
|
|
2976
|
+
error: normalized,
|
|
2977
|
+
phase: "error",
|
|
2978
|
+
targetTheme: style.theme
|
|
2979
|
+
});
|
|
2980
|
+
return { error: normalized, status: "failed", theme: style.theme };
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
function assertConcreteRuntimeTheme(style, role) {
|
|
2984
|
+
const error = validateConcreteRuntimeTheme(style, role);
|
|
2985
|
+
if (error) throw error;
|
|
2986
|
+
}
|
|
2987
|
+
function validateConcreteRuntimeTheme(style, role) {
|
|
2988
|
+
if (isTileflowThemeName(style.theme)) return void 0;
|
|
2989
|
+
return new TypeError(
|
|
2990
|
+
`Tileflow theme controller ${role} style requires a concrete portable theme name; received ${JSON.stringify(style.theme)}.`
|
|
2991
|
+
);
|
|
2992
|
+
}
|
|
2993
|
+
function applyMapStyle(map, style, timeoutMs) {
|
|
2994
|
+
return new Promise((resolve, reject) => {
|
|
2995
|
+
let settled = false;
|
|
2996
|
+
const cleanup = () => {
|
|
2997
|
+
clearTimeout(timeout);
|
|
2998
|
+
map.off("style.load", handleLoad);
|
|
2999
|
+
map.off("error", handleError);
|
|
3000
|
+
};
|
|
3001
|
+
const settle = (error) => {
|
|
3002
|
+
if (settled) return;
|
|
3003
|
+
settled = true;
|
|
3004
|
+
cleanup();
|
|
3005
|
+
if (error) reject(error);
|
|
3006
|
+
else resolve();
|
|
3007
|
+
};
|
|
3008
|
+
const handleLoad = () => settle();
|
|
3009
|
+
const handleError = (event) => settle(
|
|
3010
|
+
normalizeThemeTransitionError(
|
|
3011
|
+
isRecordWithError(event) ? event.error : event,
|
|
3012
|
+
"MapLibre rejected the Tileflow theme."
|
|
3013
|
+
)
|
|
3014
|
+
);
|
|
3015
|
+
const timeout = setTimeout(
|
|
3016
|
+
() => settle(new Error(`Tileflow theme change timed out after ${timeoutMs}ms.`)),
|
|
3017
|
+
timeoutMs
|
|
3018
|
+
);
|
|
3019
|
+
map.on("style.load", handleLoad);
|
|
3020
|
+
map.on("error", handleError);
|
|
3021
|
+
try {
|
|
3022
|
+
if (typeof map.setStyle !== "function") {
|
|
3023
|
+
throw new TypeError("Tileflow theme changes require MapLibre setStyle().");
|
|
3024
|
+
}
|
|
3025
|
+
const setStyle = map.setStyle;
|
|
3026
|
+
setStyle.call(map, style, { diff: true });
|
|
3027
|
+
} catch (error) {
|
|
3028
|
+
settle(normalizeThemeTransitionError(error, "MapLibre rejected the Tileflow theme."));
|
|
3029
|
+
}
|
|
3030
|
+
});
|
|
3031
|
+
}
|
|
3032
|
+
function normalizeThemeTransitionTimeout(value) {
|
|
3033
|
+
const resolved = value ?? 15e3;
|
|
3034
|
+
if (!Number.isSafeInteger(resolved) || resolved < 100 || resolved > 6e4) {
|
|
3035
|
+
throw new TypeError("Tileflow theme transition timeout must be an integer from 100 to 60000.");
|
|
3036
|
+
}
|
|
3037
|
+
return resolved;
|
|
3038
|
+
}
|
|
3039
|
+
function normalizeThemeTransitionError(error, fallback) {
|
|
3040
|
+
return error instanceof Error ? error : new Error(fallback);
|
|
3041
|
+
}
|
|
3042
|
+
function isRecordWithError(value) {
|
|
3043
|
+
return Boolean(value && typeof value === "object" && "error" in value);
|
|
3044
|
+
}
|
|
3045
|
+
var maximumTileflowFontBytes = 1024 * 1024;
|
|
3046
|
+
var maximumTileflowFontStyleBytes = 4 * 1024 * 1024;
|
|
3047
|
+
var loadedTileflowFontFaces = /* @__PURE__ */ new Map();
|
|
3048
|
+
async function loadTileflowStyleFonts(style, options = {}) {
|
|
3049
|
+
const fetcher = options.fetch ?? globalThis.fetch;
|
|
3050
|
+
const styleUrl = typeof style === "string" ? resolveTileflowBrowserResourceUrl(style) : void 0;
|
|
3051
|
+
const fontFaces = options.fontFaces === void 0 ? typeof style === "string" ? await fetchTileflowStyleFontFaces(styleUrl, fetcher) : getTileflowStyleFontFaces(style) : getTileflowStyleFontFaces({
|
|
3052
|
+
metadata: { "tileflow:fontFaces": [...options.fontFaces] }
|
|
3053
|
+
});
|
|
3054
|
+
if (fontFaces.length === 0) return;
|
|
3055
|
+
const browser = globalThis;
|
|
3056
|
+
const FontFaceConstructor = browser.FontFace;
|
|
3057
|
+
const fontSet = browser.document?.fonts;
|
|
3058
|
+
if (!FontFaceConstructor || !fontSet) {
|
|
3059
|
+
throw new Error("Tileflow web fonts require the browser FontFace API.");
|
|
3060
|
+
}
|
|
3061
|
+
await Promise.all(
|
|
3062
|
+
fontFaces.map(async (definition) => {
|
|
3063
|
+
const source = resolveTileflowBrowserResourceUrl(definition.source, styleUrl);
|
|
3064
|
+
const key = `${definition.family}\0${source}\0${definition.style ?? ""}\0${definition.weight ?? ""}`;
|
|
3065
|
+
let loaded = loadedTileflowFontFaces.get(key);
|
|
3066
|
+
if (!loaded) {
|
|
3067
|
+
loaded = loadTileflowFontFace(
|
|
3068
|
+
definition,
|
|
3069
|
+
source,
|
|
3070
|
+
fetcher,
|
|
3071
|
+
FontFaceConstructor,
|
|
3072
|
+
fontSet
|
|
3073
|
+
).catch((error) => {
|
|
3074
|
+
loadedTileflowFontFaces.delete(key);
|
|
3075
|
+
throw error;
|
|
3076
|
+
});
|
|
3077
|
+
loadedTileflowFontFaces.set(key, loaded);
|
|
3078
|
+
}
|
|
3079
|
+
await loaded;
|
|
3080
|
+
})
|
|
3081
|
+
);
|
|
3082
|
+
}
|
|
3083
|
+
async function fetchTileflowStyleFontFaces(styleUrl, fetcher) {
|
|
3084
|
+
const response = await fetcher(styleUrl, {
|
|
3085
|
+
cache: "default",
|
|
3086
|
+
credentials: "same-origin",
|
|
3087
|
+
redirect: "error"
|
|
3088
|
+
});
|
|
3089
|
+
if (!response.ok) throw new Error(`Tileflow style font metadata failed: ${response.status}`);
|
|
3090
|
+
const source = await readBoundedTileflowBrowserResource(
|
|
3091
|
+
response,
|
|
3092
|
+
maximumTileflowFontStyleBytes,
|
|
3093
|
+
"Tileflow style font metadata"
|
|
3094
|
+
);
|
|
3095
|
+
let input;
|
|
3096
|
+
try {
|
|
3097
|
+
input = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(source));
|
|
3098
|
+
} catch {
|
|
3099
|
+
throw new Error("Tileflow style font metadata is not valid JSON.");
|
|
3100
|
+
}
|
|
3101
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
3102
|
+
throw new Error("Tileflow style font metadata is invalid.");
|
|
3103
|
+
}
|
|
3104
|
+
return getTileflowStyleFontFaces(input);
|
|
3105
|
+
}
|
|
3106
|
+
async function loadTileflowFontFace(definition, source, fetcher, FontFaceConstructor, fontSet) {
|
|
3107
|
+
const response = await fetcher(source, {
|
|
3108
|
+
cache: "force-cache",
|
|
3109
|
+
credentials: "same-origin",
|
|
3110
|
+
redirect: "error"
|
|
3111
|
+
});
|
|
3112
|
+
if (!response.ok) throw new Error(`Tileflow font failed: ${response.status}`);
|
|
3113
|
+
const bytes = await readBoundedTileflowBrowserResource(
|
|
3114
|
+
response,
|
|
3115
|
+
maximumTileflowFontBytes,
|
|
3116
|
+
"Tileflow font"
|
|
3117
|
+
);
|
|
3118
|
+
const fontFace = new FontFaceConstructor(definition.family, bytes.buffer, {
|
|
3119
|
+
...definition.style ? { style: definition.style } : {},
|
|
3120
|
+
...definition.weight ? { weight: definition.weight } : {}
|
|
3121
|
+
});
|
|
3122
|
+
await fontFace.load();
|
|
3123
|
+
fontSet.add(fontFace);
|
|
3124
|
+
}
|
|
3125
|
+
async function readBoundedTileflowBrowserResource(response, maximumBytes, label) {
|
|
3126
|
+
const contentLength = response.headers.get("content-length");
|
|
3127
|
+
if (contentLength && /^\d+$/u.test(contentLength) && Number(contentLength) > maximumBytes) {
|
|
3128
|
+
await response.body?.cancel().catch(() => void 0);
|
|
3129
|
+
throw new Error(`${label} exceeds the maximum response size.`);
|
|
3130
|
+
}
|
|
3131
|
+
if (!response.body) return new Uint8Array();
|
|
3132
|
+
const reader = response.body.getReader();
|
|
3133
|
+
const chunks = [];
|
|
3134
|
+
let byteLength = 0;
|
|
3135
|
+
try {
|
|
3136
|
+
while (true) {
|
|
3137
|
+
const { done, value } = await reader.read();
|
|
3138
|
+
if (done) break;
|
|
3139
|
+
if (!value) continue;
|
|
3140
|
+
byteLength += value.byteLength;
|
|
3141
|
+
if (byteLength > maximumBytes) {
|
|
3142
|
+
await reader.cancel().catch(() => void 0);
|
|
3143
|
+
throw new Error(`${label} exceeds the maximum response size.`);
|
|
3144
|
+
}
|
|
3145
|
+
chunks.push(value);
|
|
3146
|
+
}
|
|
3147
|
+
} finally {
|
|
3148
|
+
reader.releaseLock();
|
|
3149
|
+
}
|
|
3150
|
+
const bytes = new Uint8Array(byteLength);
|
|
3151
|
+
let offset = 0;
|
|
3152
|
+
for (const chunk of chunks) {
|
|
3153
|
+
bytes.set(chunk, offset);
|
|
3154
|
+
offset += chunk.byteLength;
|
|
3155
|
+
}
|
|
3156
|
+
return bytes;
|
|
3157
|
+
}
|
|
3158
|
+
function resolveTileflowBrowserResourceUrl(value, baseUrl) {
|
|
3159
|
+
const browser = globalThis;
|
|
3160
|
+
const base = baseUrl ?? browser.document?.baseURI ?? "http://localhost/";
|
|
3161
|
+
let url;
|
|
3162
|
+
try {
|
|
3163
|
+
url = new URL(value, base);
|
|
3164
|
+
} catch {
|
|
3165
|
+
throw new TypeError("Tileflow font resource URL is invalid.");
|
|
3166
|
+
}
|
|
3167
|
+
if (url.protocol !== "http:" && url.protocol !== "https:" || url.username || url.password || url.hash) {
|
|
3168
|
+
throw new TypeError("Tileflow font resource URL is invalid.");
|
|
3169
|
+
}
|
|
3170
|
+
return url.toString();
|
|
3171
|
+
}
|
|
88
3172
|
function createTileflowSessionStarter(options) {
|
|
89
3173
|
const starts = /* @__PURE__ */ new Set();
|
|
90
3174
|
const send = options.startSession ?? startTileflowSession;
|
|
@@ -215,7 +3299,7 @@ function attachTileflowMapLifecycle(options) {
|
|
|
215
3299
|
};
|
|
216
3300
|
}
|
|
217
3301
|
function createTileflowTransformRequest(options) {
|
|
218
|
-
if (!options.always && !options.transformRequest) {
|
|
3302
|
+
if (!options.always && !options.transformRequest && !options.worldRequestBridge) {
|
|
219
3303
|
const analytics = options.getAnalytics();
|
|
220
3304
|
const requiresCommercialSession = Boolean(options.sessionController && analytics?.mapId);
|
|
221
3305
|
if (!requiresCommercialSession && (!analytics || analytics.enabled === false)) {
|
|
@@ -233,7 +3317,8 @@ function createTileflowTransformRequest(options) {
|
|
|
233
3317
|
resolvedRequest,
|
|
234
3318
|
asyncAnalyticsTiming === "resolution" ? options.getAnalytics() : analyticsAtRequest,
|
|
235
3319
|
options.sessionId,
|
|
236
|
-
options.sessionController
|
|
3320
|
+
options.sessionController,
|
|
3321
|
+
options.worldRequestBridge
|
|
237
3322
|
) ?? resolvedRequest
|
|
238
3323
|
);
|
|
239
3324
|
}
|
|
@@ -242,7 +3327,8 @@ function createTileflowTransformRequest(options) {
|
|
|
242
3327
|
request,
|
|
243
3328
|
asyncAnalyticsTiming === "resolution" ? options.getAnalytics() : analyticsAtRequest,
|
|
244
3329
|
options.sessionId,
|
|
245
|
-
options.sessionController
|
|
3330
|
+
options.sessionController,
|
|
3331
|
+
options.worldRequestBridge
|
|
246
3332
|
);
|
|
247
3333
|
};
|
|
248
3334
|
}
|
|
@@ -276,20 +3362,31 @@ function createTileflowMarkerController(options) {
|
|
|
276
3362
|
}
|
|
277
3363
|
};
|
|
278
3364
|
}
|
|
279
|
-
function applyTileflowRequest(url, request, analytics, sessionId, sessionController) {
|
|
3365
|
+
function applyTileflowRequest(url, request, analytics, sessionId, sessionController, worldRequestBridge) {
|
|
280
3366
|
const requestUrl = request?.url ?? url;
|
|
281
3367
|
if (sessionController) {
|
|
282
3368
|
return sessionController.resolveRequestUrl(requestUrl, analytics).then(
|
|
283
|
-
(nextUrl) =>
|
|
3369
|
+
(nextUrl) => applyWorldRequestBridge(
|
|
3370
|
+
composeTileflowRequest(url, request, nextUrl, true) ?? { url },
|
|
3371
|
+
worldRequestBridge
|
|
3372
|
+
) ?? { url }
|
|
284
3373
|
);
|
|
285
3374
|
}
|
|
286
|
-
return
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
3375
|
+
return applyWorldRequestBridge(
|
|
3376
|
+
composeTileflowRequest(
|
|
3377
|
+
url,
|
|
3378
|
+
request,
|
|
3379
|
+
resolveTileflowAnalyticsRequestUrl(requestUrl, analytics, sessionId),
|
|
3380
|
+
Boolean(worldRequestBridge)
|
|
3381
|
+
),
|
|
3382
|
+
worldRequestBridge
|
|
291
3383
|
);
|
|
292
3384
|
}
|
|
3385
|
+
function applyWorldRequestBridge(request, bridge) {
|
|
3386
|
+
if (!request || !bridge) return request;
|
|
3387
|
+
const url = bridge.rewriteUrl(request.url);
|
|
3388
|
+
return url === request.url ? request : { ...request, url };
|
|
3389
|
+
}
|
|
293
3390
|
function composeTileflowRequest(originalUrl, request, nextUrl, ensureRequest) {
|
|
294
3391
|
if (!nextUrl) {
|
|
295
3392
|
return request ?? (ensureRequest ? { url: originalUrl } : void 0);
|
|
@@ -330,8 +3427,35 @@ function removeMarkers(markers, remove) {
|
|
|
330
3427
|
}
|
|
331
3428
|
}
|
|
332
3429
|
export {
|
|
3430
|
+
attachTileflowFairUseNotice,
|
|
333
3431
|
attachTileflowMapLifecycle,
|
|
334
3432
|
createTileflowMarkerController,
|
|
335
3433
|
createTileflowSessionStarter,
|
|
336
|
-
|
|
3434
|
+
createTileflowThemeController,
|
|
3435
|
+
createTileflowTransformRequest,
|
|
3436
|
+
getTileflowSystemColorScheme,
|
|
3437
|
+
loadTileflowStyleFonts,
|
|
3438
|
+
registerTileflowContourProtocol,
|
|
3439
|
+
registerTileflowWorldRequestBridge,
|
|
3440
|
+
subscribeTileflowSystemColorScheme,
|
|
3441
|
+
tileflowFairUseNoticeMessage,
|
|
3442
|
+
tileflowMaplibreContourVersion
|
|
337
3443
|
};
|
|
3444
|
+
/*! Bundled license information:
|
|
3445
|
+
|
|
3446
|
+
maplibre-contour/dist/index.mjs:
|
|
3447
|
+
(*! *****************************************************************************
|
|
3448
|
+
Copyright (c) Microsoft Corporation.
|
|
3449
|
+
|
|
3450
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
3451
|
+
purpose with or without fee is hereby granted.
|
|
3452
|
+
|
|
3453
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
3454
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
3455
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
3456
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
3457
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
3458
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
3459
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
3460
|
+
***************************************************************************** *)
|
|
3461
|
+
*/
|