@fxi/zartigl 0.10.0 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1342 +0,0 @@
1
- const Y = { label: "Thermal", tags: ["sequential", "temperature"], colors: ["#042333", "#2c3395", "#744796", "#b15f82", "#eb7958", "#fbb43d", "#e8fa5b"] }, z = { label: "Haline", tags: ["sequential", "salinity"], colors: ["#2a186c", "#17568b", "#1a7e8f", "#22a785", "#55c666", "#aadc32", "#fde333"] }, K = { label: "Solar", tags: ["sequential", "irradiance"], colors: ["#330f0b", "#6b2313", "#a83c12", "#d6621a", "#f3951e", "#f7c741", "#f9f871"] }, J = { label: "Ice", tags: ["sequential"], colors: ["#040d1a", "#123365", "#1c5f9e", "#2b8ece", "#62bde3", "#aaddf2", "#f2faff"] }, Q = { label: "Deep", tags: ["sequential", "depth"], colors: ["#fdfecc", "#c8e59b", "#74c8a3", "#3194b0", "#2a5b8e", "#281a5e", "#0c0820"] }, Z = { label: "RdYlBu", tags: ["diverging"], colors: ["#3288bd", "#66c2a5", "#abdda4", "#e6f598", "#fee08b", "#fdae61", "#f46d43", "#d53e4f"] }, ee = { label: "Dense", tags: ["sequential"], colors: ["#e6f1f1", "#92c4ca", "#44929a", "#20627a", "#1a3c6a", "#211a50", "#0d0621"] }, te = { label: "Algae", tags: ["sequential", "biology", "log"], colors: ["#d7f9d0", "#a2d595", "#64b463", "#129450", "#126e45", "#1a482f", "#122414"] }, re = { label: "Oxygen", tags: ["sequential", "biology", "hypoxia"], colors: ["#09060f", "#5b1028", "#d43d2f", "#f39b3d", "#f3e7b3", "#79cbd1", "#176b9c"] }, ne = { label: "Matter", tags: ["sequential", "biology"], colors: ["#fdfecc", "#f2c98a", "#e07c4e", "#bc3754", "#8d1a6d", "#51156b", "#1c0c3f"] }, ae = { label: "Viridis", tags: ["sequential", "perceptual"], colors: ["#440154", "#443983", "#31688e", "#21918c", "#35b779", "#90d743", "#fde725"] }, ie = { label: "Plasma", tags: ["sequential", "perceptual"], colors: ["#0d0887", "#5e01a6", "#9c179e", "#cc4778", "#ed7953", "#fdb42f", "#f0f921"] }, oe = { label: "Cyclic", tags: ["cyclic", "direction"], colors: ["#2e22ea", "#b541fb", "#fc93c0", "#f1ee35", "#77c80d", "#458776", "#2c24e9"] }, se = { label: "Tempo", tags: ["sequential"], colors: ["#fff6f4", "#c2d1b9", "#7db390", "#2a937f", "#156d73", "#1c455b", "#151d44"] }, ce = { label: "Turbid", tags: ["sequential", "biology", "log"], colors: ["#e9f5a0", "#c8c86e", "#a09845", "#786031", "#533324", "#341423", "#150d17"] }, de = { label: "Speed", tags: ["sequential", "velocity"], colors: ["#fcfea4", "#d5e429", "#94c63e", "#52a657", "#2d8169", "#1d5b6d", "#0d3361"] }, ue = { label: "Amp", tags: ["sequential"], colors: ["#f2f2f2", "#c0b8db", "#9180b6", "#6c4e9e", "#4e2e83", "#32185d", "#110a35"] }, le = { label: "Heat", tags: ["sequential"], colors: ["#fde725", "#fde725", "#f8961e", "#e63946", "#9d0208", "#3a0007"] }, fe = { label: "Balance", tags: ["diverging"], colors: ["#181c43", "#3066af", "#9bbcdd", "#f2f2f2", "#e07d53", "#b13626", "#2c0b0e"] }, he = { label: "Delta", tags: ["diverging"], colors: ["#0e3f31", "#20877b", "#99d4c1", "#f2f2f2", "#a1b0d4", "#3c5b9e", "#0d1938"] }, me = { label: "Curl", tags: ["diverging"], colors: ["#152237", "#2471b3", "#8dbac4", "#f2f2f2", "#c79f84", "#a63827", "#270b17"] }, Ee = { label: "Gray", tags: ["sequential"], colors: ["#000000", "#252525", "#4d4d4d", "#7a7a7a", "#a8a8a8", "#d4d4d4", "#ffffff"] }, $ = {
2
- thermal: Y,
3
- "thermal-alt": { label: "Thermal Alt", tags: ["sequential", "temperature"], colors: ["#176b9c", "#79cbd1", "#f3e7b3", "#f39b3d", "#d43d2f", "#5b1028", "#09060f"] },
4
- haline: z,
5
- solar: K,
6
- ice: J,
7
- deep: Q,
8
- rdylbu: Z,
9
- dense: ee,
10
- algae: te,
11
- oxygen: re,
12
- matter: ne,
13
- viridis: ae,
14
- plasma: ie,
15
- cyclic: oe,
16
- tempo: se,
17
- turbid: ce,
18
- speed: de,
19
- amp: ue,
20
- heat: le,
21
- "heat-alert": { label: "Heat Alert", tags: ["sequential", "alpha", "deprecated"], colors: ["#fde72500", "#fde725cc", "#f8961e", "#e63946", "#9d0208", "#3a0007"] },
22
- balance: fe,
23
- delta: he,
24
- curl: me,
25
- "mono-black": { label: "Black", tags: ["monochrome", "particles"], colors: ["#000000", "#000000"] },
26
- "mono-white": { label: "White", tags: ["monochrome", "particles"], colors: ["#ffffff", "#ffffff"] },
27
- "mono-pink": { label: "Pink", tags: ["monochrome", "particles"], colors: ["#ff2aa1", "#ff2aa1"] },
28
- gray: Ee
29
- }, I = 64, pe = {
30
- linear: (e) => e,
31
- // Rises fast: values just inside the zone already show.
32
- log: (e) => Math.log10(1 + 9 * e),
33
- // Stays faint longer: codec noise at the end of the range stays hidden.
34
- exp: (e) => (10 ** e - 1) / 9
35
- };
36
- function Te(e, t) {
37
- const r = pe[t.curve ?? "linear"], n = t.low ?? 0, a = t.high ?? 0;
38
- let i = 1;
39
- return n > 0 && e < n && (i = Math.min(i, r(Math.max(e, 0) / n))), a > 0 && e > 1 - a && (i = Math.min(i, r(Math.max(1 - e, 0) / a))), i;
40
- }
41
- function be(e) {
42
- let t = e.replace("#", "");
43
- (t.length === 3 || t.length === 4) && (t = [...t].map((n) => n + n).join(""));
44
- const r = (n) => parseInt(t.slice(n, n + 2), 16);
45
- return [
46
- r(0),
47
- r(2),
48
- r(4),
49
- t.length === 8 ? r(6) : 255
50
- ];
51
- }
52
- function we([e, t, r, n]) {
53
- return `#${[e, t, r, n].map(
54
- (a) => Math.round(Math.min(255, Math.max(0, a))).toString(16).padStart(2, "0")
55
- ).join("")}`;
56
- }
57
- function Re(e, t) {
58
- if (t <= e[0][0])
59
- return e[0][1];
60
- for (let r = 1; r < e.length; r++) {
61
- const [n, a] = e[r];
62
- if (t <= n) {
63
- const [i, s] = e[r - 1], o = n === i ? 1 : (t - i) / (n - i);
64
- return s.map((d, c) => d + (a[c] - d) * o);
65
- }
66
- }
67
- return e[e.length - 1][1];
68
- }
69
- function _e(e, t) {
70
- const r = Object.entries(e).map(
71
- ([a, i]) => [Number(a), be(i)]
72
- ).sort((a, i) => a[0] - i[0]), n = {};
73
- for (let a = 0; a <= I; a++) {
74
- const i = a / I, [s, o, d, c] = Re(r, i);
75
- n[i] = we([s, o, d, c * Te(i, t)]);
76
- }
77
- return n;
78
- }
79
- const Ae = (e) => !!e && ((e.low ?? 0) > 0 || (e.high ?? 0) > 0);
80
- function C(e) {
81
- const t = {}, r = e.length - 1;
82
- return e.forEach((n, a) => {
83
- t[r === 0 ? 0 : a / r] = n;
84
- }), t;
85
- }
86
- function Fe(e, t) {
87
- const r = xe(e, t?.reverse ?? !1);
88
- return Ae(t?.alphaFade) ? _e(r, t.alphaFade) : r;
89
- }
90
- function xe(e, t) {
91
- const r = $;
92
- if (typeof e == "string") {
93
- const n = r[e];
94
- if (!n)
95
- throw new Error(
96
- `Palette "${e}" not found. Available palettes: ${Object.keys(
97
- r
98
- ).join(", ")}`
99
- );
100
- const a = t ? [...n.colors].reverse() : n.colors;
101
- return C(a);
102
- }
103
- if (Array.isArray(e)) {
104
- const n = t ? [...e].reverse() : e;
105
- return C(n);
106
- }
107
- return t ? Object.fromEntries(
108
- Object.entries(e).map(([n, a]) => [1 - Number(n), a])
109
- ) : e;
110
- }
111
- function ut(e = {}) {
112
- return Object.entries($).map(([r, n]) => ({ id: r, ...n })).filter(
113
- (r) => e.includeDeprecated || !r.tags.includes("deprecated")
114
- );
115
- }
116
- function N(e, t, r) {
117
- const n = e.createShader(t);
118
- if (!n)
119
- throw new Error("Failed to create shader");
120
- if (e.shaderSource(n, r), e.compileShader(n), !e.getShaderParameter(n, e.COMPILE_STATUS)) {
121
- const a = e.getShaderInfoLog(n);
122
- throw e.deleteShader(n), new Error(`Shader compile error: ${a}`);
123
- }
124
- return n;
125
- }
126
- function lt(e, t, r) {
127
- const n = e.createProgram();
128
- if (!n)
129
- throw new Error("Failed to create program");
130
- const a = N(e, e.VERTEX_SHADER, t), i = N(e, e.FRAGMENT_SHADER, r);
131
- if (e.attachShader(n, a), e.attachShader(n, i), e.linkProgram(n), !e.getProgramParameter(n, e.LINK_STATUS)) {
132
- const s = e.getProgramInfoLog(n);
133
- throw e.deleteProgram(n), new Error(`Program link error: ${s}`);
134
- }
135
- return e.deleteShader(a), e.deleteShader(i), n;
136
- }
137
- function ft(e, t, r, n, a) {
138
- const i = e.createTexture();
139
- if (!i)
140
- throw new Error("Failed to create texture");
141
- return e.bindTexture(e.TEXTURE_2D, i), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_S, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_T, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, t), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, t), e.texImage2D(
142
- e.TEXTURE_2D,
143
- 0,
144
- e.RGBA,
145
- n,
146
- a,
147
- 0,
148
- e.RGBA,
149
- e.UNSIGNED_BYTE,
150
- r
151
- ), e.bindTexture(e.TEXTURE_2D, null), i;
152
- }
153
- function ye(e, t, r) {
154
- const n = e.getParameter(
155
- e.TEXTURE_BINDING_2D
156
- ), a = e.getParameter(
157
- e.FRAMEBUFFER_BINDING
158
- ), i = e.createTexture(), s = e.createFramebuffer();
159
- if (!i || !s)
160
- return i && e.deleteTexture(i), s && e.deleteFramebuffer(s), e.bindTexture(e.TEXTURE_2D, n), e.bindFramebuffer(e.FRAMEBUFFER, a), !1;
161
- let o = !1;
162
- try {
163
- e.bindTexture(e.TEXTURE_2D, i), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_S, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_T, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, e.NEAREST), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, e.NEAREST), e.texImage2D(
164
- e.TEXTURE_2D,
165
- 0,
166
- t,
167
- 1,
168
- 1,
169
- 0,
170
- e.RGBA,
171
- r,
172
- null
173
- ), e.bindFramebuffer(e.FRAMEBUFFER, s), e.framebufferTexture2D(
174
- e.FRAMEBUFFER,
175
- e.COLOR_ATTACHMENT0,
176
- e.TEXTURE_2D,
177
- i,
178
- 0
179
- ), o = e.checkFramebufferStatus(e.FRAMEBUFFER) === e.FRAMEBUFFER_COMPLETE;
180
- } finally {
181
- e.bindFramebuffer(e.FRAMEBUFFER, a), e.bindTexture(e.TEXTURE_2D, n), e.deleteFramebuffer(s), e.deleteTexture(i);
182
- }
183
- return o;
184
- }
185
- function De(e) {
186
- return {
187
- kind: "rgba8-packed",
188
- internalFormat: e.RGBA,
189
- type: e.UNSIGNED_BYTE
190
- };
191
- }
192
- function ht(e) {
193
- if (typeof WebGL2RenderingContext > "u" || !(e instanceof WebGL2RenderingContext))
194
- throw new Error("zartigl requires WebGL2");
195
- return e;
196
- }
197
- function mt(e) {
198
- const t = [];
199
- e.getExtension("EXT_color_buffer_float") ? t.push(
200
- { kind: "float32", internalFormat: e.RGBA32F, type: e.FLOAT },
201
- { kind: "float16", internalFormat: e.RGBA16F, type: e.HALF_FLOAT }
202
- ) : e.getExtension("EXT_color_buffer_half_float") && t.push({
203
- kind: "float16",
204
- internalFormat: e.RGBA16F,
205
- type: e.HALF_FLOAT
206
- });
207
- for (const r of t)
208
- if (ye(
209
- e,
210
- r.internalFormat,
211
- r.type
212
- ))
213
- return r;
214
- return De(e);
215
- }
216
- function Et(e, t, r, n, a, i, s) {
217
- const o = e.createTexture();
218
- if (!o)
219
- throw new Error("Failed to create texture");
220
- return e.bindTexture(e.TEXTURE_2D, o), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_S, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_T, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, t), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, t), e.texImage2D(
221
- e.TEXTURE_2D,
222
- 0,
223
- i,
224
- n,
225
- a,
226
- 0,
227
- e.RGBA,
228
- s,
229
- r
230
- ), e.bindTexture(e.TEXTURE_2D, null), o;
231
- }
232
- function pt(e, t, r) {
233
- e.activeTexture(e.TEXTURE0 + r), e.bindTexture(e.TEXTURE_2D, t);
234
- }
235
- function Tt(e, t) {
236
- const r = e.createFramebuffer();
237
- if (!r)
238
- throw new Error("Failed to create framebuffer");
239
- return e.bindFramebuffer(e.FRAMEBUFFER, r), e.framebufferTexture2D(
240
- e.FRAMEBUFFER,
241
- e.COLOR_ATTACHMENT0,
242
- e.TEXTURE_2D,
243
- t,
244
- 0
245
- ), e.bindFramebuffer(e.FRAMEBUFFER, null), r;
246
- }
247
- function bt(e) {
248
- const t = e.createBuffer();
249
- if (!t)
250
- throw new Error("Failed to create buffer");
251
- return e.bindBuffer(e.ARRAY_BUFFER, t), e.bufferData(
252
- e.ARRAY_BUFFER,
253
- new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]),
254
- e.STATIC_DRAW
255
- ), t;
256
- }
257
- const Ue = {
258
- 0: "#3288bd",
259
- 0.1: "#66c2a5",
260
- 0.2: "#abdda4",
261
- 0.3: "#e6f598",
262
- 0.4: "#fee08b",
263
- 0.5: "#fdae61",
264
- 0.6: "#f46d43",
265
- 1: "#d53e4f"
266
- };
267
- function wt(e, t, r) {
268
- const n = Fe(t ?? Ue, r), a = document.createElement("canvas");
269
- a.width = 256, a.height = 1;
270
- const i = a.getContext("2d"), s = i.createLinearGradient(0, 0, 256, 0);
271
- for (const [d, c] of Object.entries(n))
272
- s.addColorStop(Number(d), c);
273
- i.fillStyle = s, i.fillRect(0, 0, 256, 1);
274
- const o = e.createTexture();
275
- if (!o)
276
- throw new Error("Failed to create color ramp texture");
277
- return e.bindTexture(e.TEXTURE_2D, o), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_S, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_T, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, e.LINEAR), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, e.LINEAR), e.texImage2D(e.TEXTURE_2D, 0, e.RGBA, e.RGBA, e.UNSIGNED_BYTE, a), e.bindTexture(e.TEXTURE_2D, null), o;
278
- }
279
- function Rt(e) {
280
- const t = e.getExtension("WEBGL_debug_renderer_info");
281
- return {
282
- vendor: String(e.getParameter(e.VENDOR) ?? ""),
283
- renderer: String(e.getParameter(e.RENDERER) ?? ""),
284
- unmaskedVendor: t ? String(e.getParameter(t.UNMASKED_VENDOR_WEBGL) ?? "") : void 0,
285
- unmaskedRenderer: t ? String(e.getParameter(t.UNMASKED_RENDERER_WEBGL) ?? "") : void 0,
286
- version: String(e.getParameter(e.VERSION) ?? "")
287
- };
288
- }
289
- function _t(e) {
290
- return {
291
- program: e.getParameter(e.CURRENT_PROGRAM),
292
- activeTexture: e.getParameter(e.ACTIVE_TEXTURE),
293
- arrayBuffer: e.getParameter(e.ARRAY_BUFFER_BINDING),
294
- elementBuffer: e.getParameter(e.ELEMENT_ARRAY_BUFFER_BINDING),
295
- framebuffer: e.getParameter(e.FRAMEBUFFER_BINDING),
296
- blend: e.isEnabled(e.BLEND),
297
- depthTest: e.isEnabled(e.DEPTH_TEST),
298
- stencilTest: e.isEnabled(e.STENCIL_TEST),
299
- viewport: e.getParameter(e.VIEWPORT),
300
- blendFunc: [
301
- e.getParameter(e.BLEND_SRC_RGB),
302
- e.getParameter(e.BLEND_DST_RGB)
303
- ]
304
- };
305
- }
306
- function At(e, t) {
307
- e.useProgram(t.program), e.activeTexture(t.activeTexture), e.bindBuffer(e.ARRAY_BUFFER, t.arrayBuffer), e.bindBuffer(e.ELEMENT_ARRAY_BUFFER, t.elementBuffer), e.bindFramebuffer(e.FRAMEBUFFER, t.framebuffer), t.blend ? e.enable(e.BLEND) : e.disable(e.BLEND), t.depthTest ? e.enable(e.DEPTH_TEST) : e.disable(e.DEPTH_TEST), t.stencilTest ? e.enable(e.STENCIL_TEST) : e.disable(e.STENCIL_TEST), e.viewport(t.viewport[0], t.viewport[1], t.viewport[2], t.viewport[3]), e.blendFunc(t.blendFunc[0], t.blendFunc[1]);
308
- }
309
- const ve = {
310
- degrees_c: "°C",
311
- degc: "°C",
312
- degrees_celsius: "°C",
313
- degree_celsius: "°C",
314
- celsius: "°C",
315
- // Degree heating weeks accumulate °C over weeks: a product, not a rate.
316
- degree_celsius_weeks: "°C-weeks",
317
- degree: "°",
318
- degrees: "°",
319
- kelvin: "K",
320
- 1: "",
321
- "1e-3": "PSU",
322
- "0.001": "PSU",
323
- psu: "PSU",
324
- stress_level: ""
325
- }, Se = {
326
- meter: "m",
327
- meters: "m",
328
- metre: "m",
329
- metres: "m",
330
- second: "s",
331
- seconds: "s",
332
- day: "d",
333
- days: "d",
334
- hour: "h",
335
- hours: "h",
336
- gram: "g",
337
- grams: "g",
338
- milligram: "mg",
339
- milligrams: "mg",
340
- kilogram: "kg",
341
- kilograms: "kg",
342
- mole: "mol",
343
- millimole: "mmol",
344
- watt: "W",
345
- newton: "N",
346
- pascal: "Pa",
347
- kelvin: "K"
348
- }, Me = "⁰¹²³⁴⁵⁶⁷⁸⁹";
349
- function L(e) {
350
- return e === 1 ? "" : [...String(e)].map((t) => Me[Number(t)]).join("");
351
- }
352
- function Ft(e) {
353
- const t = e?.trim() ?? "", r = ve[t.toLowerCase()];
354
- if (r != null)
355
- return r;
356
- if (t.includes("/"))
357
- return t;
358
- const n = [], a = [];
359
- for (const i of t.split(/\s+/)) {
360
- const s = /^([A-Za-z]+)\^?(-?\d+)?$/.exec(i);
361
- if (!s)
362
- return t.replace(/_/g, " ");
363
- const o = Se[s[1]] ?? s[1], d = Number(s[2] ?? 1);
364
- d < 0 ? a.push(o + L(-d)) : n.push(o + L(d));
365
- }
366
- return [n.join(" ") || "1", ...a].join("/");
367
- }
368
- const V = 20, ge = 600;
369
- function ke(e) {
370
- const t = Math.max(0, Math.min(1, e));
371
- return V * Math.pow(ge / V, t);
372
- }
373
- function xt(e) {
374
- return Math.exp(-1 / ke(e));
375
- }
376
- const Pe = 0.8, Ge = 120, Ie = 300;
377
- class yt {
378
- constructor(t) {
379
- this.base = t, this.moving = !1, this.start = 0, this.duration = 0, this.from = t, this.to = t;
380
- }
381
- /** Configured opacity, applied at once unless the camera moves. */
382
- setBase(t) {
383
- this.base = t, this.moving || (this.from = t, this.to = t, this.duration = 0);
384
- }
385
- setMoving(t, r) {
386
- t !== this.moving && (this.from = this.value(r), this.moving = t, this.to = t ? Pe : this.base, this.start = r, this.duration = t ? Ge : Ie);
387
- }
388
- value(t) {
389
- if (this.duration === 0)
390
- return this.to;
391
- const r = Math.min(1, Math.max(0, (t - this.start) / this.duration));
392
- return r === 1 ? (this.duration = 0, this.from = this.to, this.to) : this.from + (this.to - this.from) * r * r * (3 - 2 * r);
393
- }
394
- }
395
- function Dt(e) {
396
- if (e == null)
397
- return null;
398
- if (!Number.isFinite(e[0]) || !Number.isFinite(e[1]) || e[0] >= e[1])
399
- throw new RangeError(
400
- "colorDomain must contain two finite, increasing values"
401
- );
402
- return [e[0], e[1]];
403
- }
404
- function p(e, t) {
405
- if (typeof e != "number" || !Number.isFinite(e))
406
- throw new Error(`Invalid GeoVideo manifest ${t}`);
407
- return e;
408
- }
409
- function x(e, t) {
410
- if (typeof e != "string")
411
- throw new Error(`Invalid GeoVideo manifest ${t}`);
412
- const r = new Date(e).getTime();
413
- if (!Number.isFinite(r))
414
- throw new Error(`Invalid GeoVideo manifest ${t}`);
415
- return r;
416
- }
417
- function S(e) {
418
- return typeof e == "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(
419
- e
420
- );
421
- }
422
- function B(e) {
423
- if (!e || typeof e != "object")
424
- throw new Error("Invalid GeoVideo manifest");
425
- const t = e;
426
- if (t.schemaVersion !== 3 || t.type !== "geovideo")
427
- throw new Error("Unsupported GeoVideo manifest version or type");
428
- if (t.projection !== "equirectangular")
429
- throw new Error(
430
- `Unsupported GeoVideo projection: ${String(t.projection)}`
431
- );
432
- if (!Array.isArray(t.bounds) || t.bounds.length !== 4)
433
- throw new Error("Invalid GeoVideo manifest bounds");
434
- const [r, n, a, i] = t.bounds.map(
435
- (l, m) => p(l, `bounds[${m}]`)
436
- );
437
- if (n < -90 || i > 90 || n >= i || r === a)
438
- throw new Error("Invalid GeoVideo geographic bounds");
439
- const s = t.media;
440
- if (!s || typeof s.url != "string" || !s.url)
441
- throw new Error("Invalid GeoVideo media");
442
- for (const l of ["width", "height", "fps", "durationSeconds"])
443
- if (p(s[l], `media.${l}`) <= 0)
444
- throw new Error(`Invalid GeoVideo media.${l}`);
445
- const o = t.encoding;
446
- if (!o || o.bits !== 8 || o.colorSpace !== "bt709" || o.colorRange !== "limited" && o.colorRange !== "full")
447
- throw new Error("Invalid GeoVideo encoding");
448
- const d = p(o.codeMin, "encoding.codeMin"), c = p(o.codeMax, "encoding.codeMax");
449
- if (d < 0 || c > 255 || d >= c)
450
- throw new Error("Invalid GeoVideo code range");
451
- let f = s.height;
452
- if (o.kind === "scalar-luma") {
453
- if (o.transfer !== "linear" && o.transfer !== "log10-1p9" || p(o.valueMin, "encoding.valueMin") >= p(o.valueMax, "encoding.valueMax"))
454
- throw new Error("Invalid GeoVideo scalar-luma encoding");
455
- } else if (o.kind === "vector-luma") {
456
- if (o.transfer !== "linear" && o.transfer !== "sqrt" || o.layout !== "stacked-uv" || p(o.valueDomain, "encoding.valueDomain") <= 0 || s.height % 2 !== 0)
457
- throw new Error("Invalid GeoVideo vector-luma encoding");
458
- f = s.height / 2;
459
- } else
460
- throw new Error("Unsupported GeoVideo encoding");
461
- const u = t.mask;
462
- if (!u || u.kind !== "static-validity" || typeof u.url != "string" || !u.url || p(u.width, "mask.width") !== s.width || p(u.height, "mask.height") !== f || p(u.threshold, "mask.threshold") < 0 || u.threshold > 1)
463
- throw new Error("Invalid GeoVideo static mask");
464
- if (t.timeline?.kind === "range") {
465
- const l = x(t.timeline.dateStart, "timeline.dateStart");
466
- if (x(t.timeline.dateEnd, "timeline.dateEnd") <= l)
467
- throw new Error("GeoVideo timeline end must follow start");
468
- if (t.timeline.interpolation !== "linear" && t.timeline.interpolation !== "nearest")
469
- throw new Error("Invalid GeoVideo interpolation");
470
- } else if (t.timeline?.kind === "snapshot-loop")
471
- x(t.timeline.date, "timeline.date");
472
- else if (t.timeline?.kind === "sample-sequence") {
473
- if (!Array.isArray(t.timeline.values) || t.timeline.values.length === 0)
474
- throw new Error("GeoVideo sample sequence must contain values");
475
- const l = t.timeline.values.map(
476
- (m, T) => x(m, `timeline.values[${T}]`)
477
- );
478
- if (l.some((m, T) => T > 0 && m <= l[T - 1]))
479
- throw new Error(
480
- "GeoVideo sample sequence values must be strictly increasing"
481
- );
482
- } else
483
- throw new Error("Invalid GeoVideo timeline");
484
- const h = t.style?.colorDomain;
485
- if (!Array.isArray(h) || h.length !== 2 || !h.every(Number.isFinite) || h[0] >= h[1])
486
- throw new Error("Invalid GeoVideo color domain");
487
- if (!S(t.id) || !t.provenance || !S(t.provenance.catalogEntryId) || !S(t.provenance.inputSourceId) || !Array.isArray(t.provenance.variables) || t.provenance.variables.length === 0)
488
- throw new Error("Invalid GeoVideo provenance");
489
- return { ...t, bounds: [r, n, a, i] };
490
- }
491
- async function Ce(e, t) {
492
- if (typeof e != "string")
493
- return B(e);
494
- const r = await fetch(e, { signal: t });
495
- if (!r.ok)
496
- throw new Error(
497
- `GeoVideo manifest request failed (${r.status}): ${e}`
498
- );
499
- const n = await r.json(), a = B(n), i = typeof document < "u" ? new URL(e, document.baseURI).href : e;
500
- return {
501
- ...a,
502
- media: { ...a.media, url: new URL(a.media.url, i).href },
503
- mask: { ...a.mask, url: new URL(a.mask.url, i).href }
504
- };
505
- }
506
- function A(e) {
507
- if (e.timeline.kind === "snapshot-loop")
508
- return [new Date(e.timeline.date).getTime()];
509
- if (e.timeline.kind === "sample-sequence")
510
- return e.timeline.values.map((a) => new Date(a).getTime());
511
- const t = new Date(e.timeline.dateStart).getTime(), r = new Date(e.timeline.dateEnd).getTime(), n = Math.max(
512
- 2,
513
- Math.round(e.media.durationSeconds * e.media.fps)
514
- );
515
- return Array.from(
516
- { length: n },
517
- (a, i) => t + (r - t) * i / (n - 1)
518
- );
519
- }
520
- function Ne(e) {
521
- return e.timeline.kind === "sample-sequence" ? e.timeline.values.length / e.media.durationSeconds : e.media.fps;
522
- }
523
- function Ut(e, t) {
524
- return t / Ne(e);
525
- }
526
- function Le(e, t) {
527
- if (e.timeline.kind === "snapshot-loop")
528
- return 0;
529
- if (e.timeline.kind === "sample-sequence") {
530
- const i = A(e);
531
- let s = 0;
532
- for (let d = 1; d < i.length; d += 1)
533
- Math.abs(i[d] - t) < Math.abs(i[s] - t) && (s = d);
534
- const o = e.media.durationSeconds / i.length;
535
- return s * o + Math.min(o / 2, 0.5 / e.media.fps);
536
- }
537
- const r = new Date(e.timeline.dateStart).getTime(), n = new Date(e.timeline.dateEnd).getTime();
538
- return Math.max(0, Math.min(1, (t - r) / (n - r))) * W(e);
539
- }
540
- function vt(e, t) {
541
- if (e.timeline.kind === "snapshot-loop")
542
- return new Date(e.timeline.date).getTime();
543
- if (e.timeline.kind === "sample-sequence") {
544
- const s = A(e), o = e.media.durationSeconds / s.length, d = Math.floor((t + 0.25 / e.media.fps) / o);
545
- return s[Math.max(0, Math.min(s.length - 1, d))];
546
- }
547
- const r = new Date(e.timeline.dateStart).getTime(), n = new Date(e.timeline.dateEnd).getTime(), a = W(e), i = a > 0 ? Math.max(0, Math.min(1, t / a)) : 0;
548
- return r + (n - r) * i;
549
- }
550
- function W(e) {
551
- return Math.max(0, e.media.durationSeconds - 1 / e.media.fps);
552
- }
553
- function Ve(e, t) {
554
- const r = new Uint8Array(e.length / 4);
555
- for (let n = 0; n < r.length; n++) {
556
- const a = e[n * 4];
557
- r[n] = t === "limited" ? Math.round(a * 219 / 255 + 16) : a;
558
- }
559
- return r;
560
- }
561
- class Be {
562
- constructor() {
563
- this.gl = null, this.texture = null, this.framebuffer = null;
564
- }
565
- read(t, r, n) {
566
- const a = this.context();
567
- a.bindTexture(a.TEXTURE_2D, this.texture), a.pixelStorei(a.UNPACK_FLIP_Y_WEBGL, !1), a.pixelStorei(a.UNPACK_PREMULTIPLY_ALPHA_WEBGL, !1), a.pixelStorei(a.UNPACK_COLORSPACE_CONVERSION_WEBGL, a.NONE), a.texParameteri(a.TEXTURE_2D, a.TEXTURE_MIN_FILTER, a.NEAREST), a.texParameteri(a.TEXTURE_2D, a.TEXTURE_MAG_FILTER, a.NEAREST), a.texParameteri(a.TEXTURE_2D, a.TEXTURE_WRAP_S, a.CLAMP_TO_EDGE), a.texParameteri(a.TEXTURE_2D, a.TEXTURE_WRAP_T, a.CLAMP_TO_EDGE), a.texImage2D(a.TEXTURE_2D, 0, a.RGBA, a.RGBA, a.UNSIGNED_BYTE, t), a.bindFramebuffer(a.FRAMEBUFFER, this.framebuffer), a.framebufferTexture2D(
568
- a.FRAMEBUFFER,
569
- a.COLOR_ATTACHMENT0,
570
- a.TEXTURE_2D,
571
- this.texture,
572
- 0
573
- );
574
- const i = new Uint8Array(r * n * 4);
575
- return a.readPixels(0, 0, r, n, a.RGBA, a.UNSIGNED_BYTE, i), a.bindFramebuffer(a.FRAMEBUFFER, null), i;
576
- }
577
- release() {
578
- this.gl?.getExtension("WEBGL_lose_context")?.loseContext(), this.gl = null, this.texture = null, this.framebuffer = null;
579
- }
580
- context() {
581
- if (this.gl)
582
- return this.gl;
583
- const t = document.createElement("canvas"), r = {
584
- premultipliedAlpha: !1,
585
- antialias: !1
586
- }, n = t.getContext("webgl2", r);
587
- if (!n)
588
- throw new Error("WebGL2 is required to decode GeoVideo frames");
589
- return this.gl = n, this.texture = n.createTexture(), this.framebuffer = n.createFramebuffer(), n;
590
- }
591
- }
592
- function X(e) {
593
- const t = Math.max(4, Math.floor(e.length / 4 / 997) * 4);
594
- for (let r = 3; r < e.length; r += t)
595
- if (e[r] !== 0)
596
- return !1;
597
- return !0;
598
- }
599
- function E() {
600
- return new DOMException("GeoVideo frame request was cancelled", "AbortError");
601
- }
602
- function R(e, t, r) {
603
- return t ? t.aborted ? (e.catch(() => {
604
- }), r?.(), Promise.reject(E())) : new Promise((n, a) => {
605
- const i = () => {
606
- r?.(), a(E());
607
- };
608
- t.addEventListener("abort", i, { once: !0 }), e.then(n, a).finally(() => {
609
- t.removeEventListener("abort", i);
610
- });
611
- }) : e;
612
- }
613
- function M(e, t) {
614
- return new Promise(
615
- (r) => e.addEventListener(t, () => r(), { once: !0 })
616
- );
617
- }
618
- const Xe = 250;
619
- function Oe(e) {
620
- return "requestVideoFrameCallback" in e ? Promise.race([
621
- new Promise(
622
- (t) => e.requestVideoFrameCallback(() => t())
623
- ),
624
- new Promise((t) => setTimeout(t, Xe))
625
- ]) : Promise.resolve();
626
- }
627
- class H {
628
- constructor(t, r, n = {}) {
629
- this.reader = new Be(), this.video = null, this.maskCodes = null, this.initPromise = null, this.presented = !1, this.primed = !1, this.queue = Promise.resolve(), this.frames = /* @__PURE__ */ new Map(), this.pending = /* @__PURE__ */ new Set(), this.manifest = t, this.planes = r, this.cacheSize = Math.max(1, n.cacheSize ?? 3), this.width = t.media.width, this.height = t.media.height / r, this.times = Float64Array.from(A(t));
630
- }
631
- /** Static validity, one 8-bit value per grid cell; null before init(). */
632
- get mask() {
633
- return this.maskCodes;
634
- }
635
- /** Luma codes of the presented frame, or null when it is blank. */
636
- readCodes(t, r) {
637
- const n = this.reader.read(t, this.width, r);
638
- return X(n) ? null : Ve(n, this.manifest.encoding.colorRange);
639
- }
640
- /** True when the decoder exposed no pixels; reads back one row only. */
641
- isBlank(t) {
642
- return X(this.reader.read(t, this.width, 1));
643
- }
644
- init() {
645
- return this.initPromise ??= this.load().catch((t) => {
646
- throw this.initPromise = null, t;
647
- }), this.initPromise;
648
- }
649
- /** Abort every pending frame decode; frames already decoded stay cached. */
650
- cancelAll() {
651
- for (const t of [...this.pending])
652
- this.drop(t);
653
- }
654
- /** Release the video element and GL context; a later init() reloads them. */
655
- release() {
656
- this.cancelAll(), this.frames.clear(), this.video && (this.video.removeAttribute("src"), this.video.load()), this.video = null, this.maskCodes = null, this.presented = !1, this.primed = !1, this.initPromise = null, this.reader.release();
657
- }
658
- /**
659
- * One decode per time step, cached and shared by concurrent requests.
660
- * Aborting `request.signal` rejects this request with an AbortError; the
661
- * decode goes on while another request waits for it.
662
- */
663
- frame(t, r = {}) {
664
- const { signal: n } = r;
665
- if (n?.aborted)
666
- return Promise.reject(E());
667
- let a = this.frames.get(t);
668
- if (a ? (this.frames.delete(t), this.frames.set(t, a)) : a = this.enqueue(t), a.settled)
669
- return a.promise;
670
- const i = a;
671
- return i.waiters++, R(i.promise, n, () => this.leave(i));
672
- }
673
- enqueue(t) {
674
- const r = new AbortController(), n = this.queue.then(
675
- () => r.signal.aborted ? Promise.reject(E()) : this.decode(t, r.signal)
676
- );
677
- this.queue = n.catch(() => {
678
- });
679
- const a = {
680
- index: t,
681
- controller: r,
682
- promise: R(n, r.signal),
683
- waiters: 0,
684
- settled: !1
685
- };
686
- for (this.pending.add(a), a.promise.then(
687
- () => {
688
- a.settled = !0, this.pending.delete(a);
689
- },
690
- () => {
691
- a.settled = !0, this.pending.delete(a), this.frames.get(t) === a && this.frames.delete(t);
692
- }
693
- ), this.frames.set(t, a); this.frames.size > this.cacheSize; )
694
- this.frames.delete(this.frames.keys().next().value);
695
- return a;
696
- }
697
- /** A request left; drop the decode when it was the last one waiting. */
698
- leave(t) {
699
- t.waiters--, t.waiters <= 0 && !t.settled && this.drop(t);
700
- }
701
- drop(t) {
702
- t.controller.abort(), this.pending.delete(t), this.frames.get(t.index) === t && this.frames.delete(t.index);
703
- }
704
- async load() {
705
- const [t] = await Promise.all([this.loadMask(), this.loadVideo()]);
706
- this.maskCodes = t;
707
- }
708
- async loadMask() {
709
- const { url: t, width: r, height: n } = this.manifest.mask, a = new Image();
710
- a.crossOrigin = "anonymous", a.src = t;
711
- try {
712
- await a.decode();
713
- } catch {
714
- throw new Error(`Failed to load GeoVideo mask: ${t}`);
715
- }
716
- if (a.naturalWidth !== r || a.naturalHeight !== n)
717
- throw new Error(
718
- `GeoVideo mask dimensions ${a.naturalWidth}x${a.naturalHeight} do not match manifest ${r}x${n}`
719
- );
720
- const i = this.reader.read(a, r, n), s = new Uint8Array(r * n);
721
- for (let o = 0; o < s.length; o++)
722
- s[o] = i[o * 4];
723
- return s;
724
- }
725
- async loadVideo() {
726
- const t = document.createElement("video");
727
- t.crossOrigin = "anonymous", t.muted = !0, t.playsInline = !0, t.preload = "metadata", t.src = this.manifest.media.url, this.video = t, await new Promise((r, n) => {
728
- t.addEventListener("loadedmetadata", () => r(), {
729
- once: !0
730
- }), t.addEventListener(
731
- "error",
732
- () => n(
733
- new Error(
734
- `Failed to load GeoVideo media: ${this.manifest.media.url}`
735
- )
736
- ),
737
- { once: !0 }
738
- );
739
- });
740
- }
741
- /** Seek to a frame and wait until it is presented. */
742
- async presentFrame(t, r) {
743
- if (this.presented && Math.abs(t.currentTime - r) <= 1e-3 && !t.seeking)
744
- return;
745
- const n = Oe(t), a = M(t, "seeked");
746
- t.currentTime = r, await a, t.readyState < HTMLMediaElement.HAVE_CURRENT_DATA && await Promise.race([M(t, "loadeddata"), M(t, "canplay")]), await n, this.presented = !0;
747
- }
748
- /**
749
- * Some mobile browsers expose no decoded pixels to WebGL until playback
750
- * started once. A muted play/pause primes the decoder, only when needed:
751
- * playback would otherwise buffer far beyond the requested frame.
752
- */
753
- async primeDecoder(t) {
754
- this.primed = !0;
755
- try {
756
- await t.play();
757
- } catch {
758
- }
759
- t.pause(), this.presented = !1;
760
- }
761
- /**
762
- * Seek and capture one step. `signal` aborts it between steps; a seek
763
- * already started completes first, keeping the queue serial.
764
- */
765
- async decode(t, r) {
766
- if (r.aborted)
767
- throw E();
768
- await this.init();
769
- const n = this.video, a = this.maskCodes;
770
- if (r.aborted || !n || !a)
771
- throw E();
772
- const i = Le(this.manifest, this.times[t]);
773
- if (await this.presentFrame(n, i), r.aborted || n !== this.video)
774
- throw E();
775
- const s = this.height * this.planes;
776
- let o = await this.capture(n, s, a);
777
- if (o === null && !this.primed) {
778
- if (await this.primeDecoder(n), await this.presentFrame(n, i), r.aborted || n !== this.video)
779
- throw E();
780
- o = await this.capture(n, s, a);
781
- }
782
- if (o === null)
783
- throw new Error("GeoVideo frame could not be read back from the decoder");
784
- return o;
785
- }
786
- }
787
- function St(e) {
788
- return {
789
- codeRange: [e.codeMin / 255, e.codeMax / 255],
790
- valueRange: [e.valueMin, e.valueMax],
791
- transfer: e.transfer === "log10-1p9" ? 1 : 0
792
- };
793
- }
794
- class qe extends H {
795
- constructor(t, r = {}) {
796
- if (t.encoding.kind !== "scalar-luma")
797
- throw new Error("GeoVideoScalarSource requires a scalar-luma manifest");
798
- super(t, 1, r);
799
- }
800
- async capture(t) {
801
- return this.isBlank(t) ? null : createImageBitmap(t, {
802
- premultiplyAlpha: "none",
803
- colorSpaceConversion: "none"
804
- });
805
- }
806
- }
807
- function $e(e, t) {
808
- let r = (e - t.codeMin) / (t.codeMax - t.codeMin) * 2 - 1;
809
- return r = Math.max(-1, Math.min(1, r)), t.transfer === "sqrt" && (r = Math.sign(r) * r * r), r * t.valueDomain;
810
- }
811
- function We(e, t, r, n) {
812
- const a = t.length;
813
- if (e.length !== 2 * a)
814
- throw new Error(
815
- `GeoVideo vector frame has ${e.length} codes, expected ${2 * a}`
816
- );
817
- const i = new Float32Array(256);
818
- for (let c = 0; c < 256; c++)
819
- i[c] = $e(c, n);
820
- const s = r * 255, o = new Float32Array(a), d = new Float32Array(a);
821
- for (let c = 0; c < a; c++) {
822
- const f = t[c] >= s;
823
- o[c] = f ? i[e[c]] : NaN, d[c] = f ? i[e[a + c]] : NaN;
824
- }
825
- return { u: o, v: d };
826
- }
827
- class He extends H {
828
- constructor(t, r = {}) {
829
- if (t.encoding.kind !== "vector-luma")
830
- throw new Error("GeoVideoVectorSource requires a vector-luma manifest");
831
- super(t, 2, r), this.encoding = t.encoding;
832
- const [n, a, i, s] = t.bounds, o = (i - n) / this.width, d = (s - a) / this.height;
833
- this.coords = {
834
- time: this.times,
835
- vertical: new Float32Array([0]),
836
- latitude: Float32Array.from(
837
- { length: this.height },
838
- (c, f) => s - (f + 0.5) * d
839
- ),
840
- longitude: Float32Array.from(
841
- { length: this.width },
842
- (c, f) => n + (f + 0.5) * o
843
- )
844
- };
845
- }
846
- getValueDomain() {
847
- return this.encoding.valueDomain;
848
- }
849
- getCoords() {
850
- return this.coords;
851
- }
852
- getDimensions() {
853
- return ["time", "latitude", "longitude"];
854
- }
855
- getChunkShape() {
856
- return [1, this.height, this.width];
857
- }
858
- findDepthIndex() {
859
- return 0;
860
- }
861
- findTimeIndex(t) {
862
- const r = typeof t == "number" ? t : new Date(t).getTime(), n = this.coords.time;
863
- let a = 0;
864
- for (let i = 1; i < n.length; i++)
865
- Math.abs(n[i] - r) < Math.abs(n[a] - r) && (a = i);
866
- return a;
867
- }
868
- getChunksForBounds(t, r, n) {
869
- const { latitude: a, longitude: i } = this.coords;
870
- return [
871
- {
872
- timeIdx: r,
873
- depthIdx: n,
874
- latIdx: 0,
875
- lonIdx: 0,
876
- latRange: [a[0], a[this.height - 1]],
877
- lonRange: [i[0], i[this.width - 1]],
878
- latSize: this.height,
879
- lonSize: this.width
880
- }
881
- ];
882
- }
883
- async fetchSpatialChunkResult(t, r) {
884
- const n = await this.frame(r.timeIndex);
885
- return {
886
- data: t === "v" ? n.v : n.u,
887
- missing: !1,
888
- url: this.manifest.media.url
889
- };
890
- }
891
- /** u/v codes are written into luma: read back, then decoded on the CPU. */
892
- async capture(t, r, n) {
893
- const a = this.readCodes(t, r);
894
- return a ? We(
895
- a,
896
- n,
897
- this.manifest.mask.threshold,
898
- this.encoding
899
- ) : null;
900
- }
901
- }
902
- function je(e, t, r = {}) {
903
- const [n, a] = r.range ?? [-1 / 0, 1 / 0], i = [...e].sort((o, d) => o.start - d.start), s = i.find(
904
- (o) => o.start > t && o.start <= a
905
- ) ?? (r.loop ? i.find(
906
- (o) => o.end >= n && o.start <= a
907
- ) : void 0);
908
- return s ? { chunk: s, time: Math.max(s.start, n) } : null;
909
- }
910
- function Ye(e, t) {
911
- let r = null, n = -1 / 0;
912
- for (const a of t) {
913
- const i = Math.min(e.end, a.end) - Math.max(e.start, a.start);
914
- Number.isFinite(i) && i >= 0 && i > n && (r = a, n = i);
915
- }
916
- return r;
917
- }
918
- function ze(e) {
919
- return {
920
- width: e.mask.width,
921
- height: e.mask.height,
922
- bounds: e.bounds,
923
- rowOrder: "north-to-south"
924
- };
925
- }
926
- function Ke(e, t = {}) {
927
- return e.encoding.kind === "vector-luma" ? new He(e, t) : new qe(e, t);
928
- }
929
- const Je = 3, Qe = 3, Ze = 0.6, et = 1.5;
930
- function tt(e, t) {
931
- const r = e.length - 1;
932
- if (t <= e[0])
933
- return { step: 0, fraction: 0 };
934
- if (t >= e[r])
935
- return { step: r, fraction: 0 };
936
- let n = 0, a = r;
937
- for (; a - n > 1; ) {
938
- const i = n + a >> 1;
939
- e[i] <= t ? n = i : a = i;
940
- }
941
- return { step: n, fraction: (t - e[n]) / (e[a] - e[n]) };
942
- }
943
- function rt(e) {
944
- const t = new AbortController();
945
- if (!e)
946
- return { controller: t, unlink: () => {
947
- } };
948
- const r = () => t.abort();
949
- return e.aborted && r(), e.addEventListener("abort", r, { once: !0 }), {
950
- controller: t,
951
- unlink: () => e.removeEventListener("abort", r)
952
- };
953
- }
954
- class Mt {
955
- constructor(t) {
956
- this.manifests = /* @__PURE__ */ new Map(), this.open = /* @__PURE__ */ new Map(), this.id = t.id, this.chunks = t.chunks.filter(
957
- (r) => Number.isFinite(r.start) && Number.isFinite(r.end) && r.end >= r.start
958
- ).sort((r, n) => r.start - n.start), this.maxOpenChunks = Math.max(2, t.maxOpenChunks ?? Je), this.frameCacheSize = Math.max(
959
- 1,
960
- t.frameCacheSize ?? Qe
961
- ), this.prefetchAt = t.prefetchAt ?? Ze, this.maxGap = t.maxGap, this.loadManifest = t.loadManifest ?? Ce, this.createFrameSource = t.createFrameSource ?? ((r, n) => Ke(
962
- r,
963
- n
964
- ));
965
- }
966
- /** First and last sample of the archive, or null without chunks. */
967
- get range() {
968
- const { chunks: t } = this;
969
- return t.length ? [t[0].start, Math.max(...t.map((r) => r.end))] : null;
970
- }
971
- /** The chunk whose sample range holds `time`, or null. */
972
- chunkAt(t) {
973
- const r = this.chunkIndexAt(t), n = r >= 0 ? this.chunks[r] : null;
974
- return n && t <= n.end ? n : null;
975
- }
976
- /** Every step time of the archive; loads all chunk manifests. */
977
- async steps(t = {}) {
978
- if (t.signal?.aborted)
979
- throw E();
980
- const r = await R(
981
- Promise.all(this.chunks.map((n) => this.manifest(n))),
982
- t.signal
983
- );
984
- return Float64Array.from(r.flatMap(A));
985
- }
986
- /**
987
- * The frames bracketing `time`, decoded; null out of coverage (before the
988
- * first step, after the last, or in a gap wider than `maxGap`).
989
- */
990
- async sample(t, r = {}) {
991
- const { signal: n } = r, a = r.mode ?? "interpolate";
992
- if (n?.aborted)
993
- throw E();
994
- const i = this.chunkIndexAt(t);
995
- if (i < 0)
996
- return null;
997
- const s = [], { controller: o, unlink: d } = rt(n);
998
- try {
999
- const c = this.acquire(this.chunks[i], s), f = await R(c.ready, o.signal), { times: u } = f;
1000
- let h;
1001
- if (t <= u[u.length - 1]) {
1002
- const { step: b, fraction: w } = tt(u, t);
1003
- h = a === "discrete" || w === 0 ? [c, b, c, b, 0] : [c, b, c, b + 1, w];
1004
- } else {
1005
- const b = this.chunks[i + 1];
1006
- if (!b)
1007
- return null;
1008
- const w = this.acquire(b, s), G = await R(w.ready, o.signal), F = u.length - 1, U = u[F], v = G.times[0];
1009
- if (v - U > this.gapLimit(u, G.times))
1010
- return null;
1011
- h = a === "discrete" ? [c, F, c, F, 0] : t >= v ? [w, 0, w, 0, 0] : [c, F, w, 0, (t - U) / (v - U)];
1012
- }
1013
- const [l, m, T, y, _] = h, k = l === T && m === y, P = [this.frame(l, m, o.signal)];
1014
- k || P.push(this.frame(T, y, o.signal));
1015
- let D;
1016
- try {
1017
- D = await Promise.all(P);
1018
- } catch (b) {
1019
- throw o.abort(), b;
1020
- }
1021
- return this.prefetchAfter(i, t), {
1022
- time: t,
1023
- a: D[0],
1024
- b: D[k ? 0 : 1],
1025
- mix: _
1026
- };
1027
- } finally {
1028
- d();
1029
- for (const c of s)
1030
- c.users--;
1031
- this.trim();
1032
- }
1033
- }
1034
- /** Open `chunk` and decode its first frame ahead of a request. */
1035
- prefetch(t) {
1036
- if (this.open.has(t.key))
1037
- return;
1038
- const r = this.touch(t), n = new AbortController();
1039
- r.prefetch = n, r.ready.then(({ source: a }) => a.frame(0, { signal: n.signal })).catch(() => {
1040
- }).finally(() => {
1041
- r.prefetch === n && (r.prefetch = null);
1042
- }), this.trim();
1043
- }
1044
- /** Release every open chunk source; later requests reopen them. */
1045
- release() {
1046
- for (const t of [...this.open.values()])
1047
- this.close(t);
1048
- }
1049
- chunkIndexAt(t) {
1050
- let r = 0, n = this.chunks.length - 1, a = -1;
1051
- for (; r <= n; ) {
1052
- const i = r + n >> 1;
1053
- this.chunks[i].start <= t ? (a = i, r = i + 1) : n = i - 1;
1054
- }
1055
- return a;
1056
- }
1057
- gapLimit(t, r) {
1058
- if (this.maxGap !== void 0)
1059
- return this.maxGap;
1060
- const n = [
1061
- t.length > 1 ? t[t.length - 1] - t[t.length - 2] : 0,
1062
- r.length > 1 ? r[1] - r[0] : 0
1063
- ], a = Math.max(...n);
1064
- return a > 0 ? a * et : -1 / 0;
1065
- }
1066
- prefetchAfter(t, r) {
1067
- const n = this.chunks[t], a = this.chunks[t + 1], i = n.end - n.start, s = i > 0 ? (r - n.start) / i : 1;
1068
- a && s > this.prefetchAt && this.prefetch(a);
1069
- }
1070
- manifest(t) {
1071
- let r = this.manifests.get(t.manifestUrl);
1072
- return r || (r = this.loadManifest(t.manifestUrl), this.manifests.set(t.manifestUrl, r), r.catch(() => {
1073
- this.manifests.get(t.manifestUrl) === r && this.manifests.delete(t.manifestUrl);
1074
- })), r;
1075
- }
1076
- /** The open chunk, pinned for a running sample listed in `used`. */
1077
- acquire(t, r) {
1078
- const n = this.touch(t);
1079
- return n.users++, r.push(n), n;
1080
- }
1081
- /** The open chunk, opened when needed, most recently used; not pinned. */
1082
- touch(t) {
1083
- let r = this.open.get(t.key);
1084
- if (r)
1085
- this.open.delete(t.key);
1086
- else {
1087
- const n = {
1088
- chunk: t,
1089
- ready: null,
1090
- opened: null,
1091
- users: 0,
1092
- prefetch: null,
1093
- released: !1
1094
- };
1095
- n.ready = this.manifest(t).then((a) => {
1096
- if (n.released)
1097
- throw E();
1098
- return n.opened = {
1099
- manifest: a,
1100
- times: Float64Array.from(A(a)),
1101
- grid: ze(a),
1102
- source: this.createFrameSource(a, {
1103
- cacheSize: this.frameCacheSize
1104
- })
1105
- }, n.opened;
1106
- }), n.ready.catch(() => {
1107
- this.open.get(t.key) === n && this.open.delete(t.key);
1108
- }), r = n;
1109
- }
1110
- return this.open.set(t.key, r), r;
1111
- }
1112
- async frame(t, r, n) {
1113
- const { manifest: a, times: i, grid: s, source: o } = await R(
1114
- t.ready,
1115
- n
1116
- );
1117
- if (t.released)
1118
- throw E();
1119
- const d = await o.frame(r, { signal: n });
1120
- return {
1121
- key: `${this.id}/${t.chunk.key}/${r}`,
1122
- chunk: t.chunk,
1123
- step: r,
1124
- time: i[r],
1125
- data: d,
1126
- grid: s,
1127
- manifest: a
1128
- };
1129
- }
1130
- /** Release least recently used chunks beyond the bound, unless in use. */
1131
- trim() {
1132
- let t = this.open.size - this.maxOpenChunks;
1133
- for (const r of [...this.open.values()]) {
1134
- if (t <= 0)
1135
- return;
1136
- r.users === 0 && (this.close(r), t--);
1137
- }
1138
- }
1139
- close(t) {
1140
- t.released = !0, t.prefetch?.abort(), t.prefetch = null, t.opened?.source.release(), t.opened = null, this.open.get(t.chunk.key) === t && this.open.delete(t.chunk.key);
1141
- }
1142
- }
1143
- function g(e) {
1144
- const { start: t, end: r } = e.temporal ?? {};
1145
- return {
1146
- source: e,
1147
- start: Date.parse(t ?? ""),
1148
- end: Date.parse(r ?? t ?? "")
1149
- };
1150
- }
1151
- function gt(e, t, r = {}) {
1152
- const n = e.filter((i) => i.id === t.id && i.temporal?.start != null).map(g), a = je(
1153
- n,
1154
- Date.parse(t.temporal?.end ?? ""),
1155
- r
1156
- );
1157
- return a ? { source: a.chunk.source, time: a.time } : null;
1158
- }
1159
- function kt(e, t) {
1160
- return Ye(g(e), t.map(g))?.source ?? null;
1161
- }
1162
- const nt = /^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$/;
1163
- function at(e) {
1164
- return e instanceof Date ? e.getTime() : typeof e == "number" ? e : new Date(e).getTime();
1165
- }
1166
- function O(e, t) {
1167
- const r = at(e);
1168
- if (!Number.isFinite(r))
1169
- throw new Error(`Invalid ${t}`);
1170
- return r;
1171
- }
1172
- function j(e, t) {
1173
- const r = t.match(nt);
1174
- if (!r)
1175
- throw new Error(`Invalid trailing time duration: ${t}`);
1176
- const n = r.slice(1).map((_) => Number(_ ?? 0));
1177
- if (!n.some((_) => _ > 0))
1178
- throw new Error("Trailing time duration must be positive");
1179
- const [a, i, s, o, d, c, f] = n, u = new Date(e), h = u.getUTCFullYear() * 12 + u.getUTCMonth() - a * 12 - i, l = Math.floor(h / 12), m = (h % 12 + 12) % 12, T = new Date(Date.UTC(l, m + 1, 0)).getUTCDate();
1180
- return Date.UTC(
1181
- l,
1182
- m,
1183
- Math.min(u.getUTCDate(), T),
1184
- u.getUTCHours(),
1185
- u.getUTCMinutes(),
1186
- u.getUTCSeconds(),
1187
- u.getUTCMilliseconds()
1188
- ) - (((s * 7 + o) * 24 + d) * 60 + c) * 6e4 - f * 1e3;
1189
- }
1190
- function Pt(e, [t, r]) {
1191
- let n = t, a = r;
1192
- if (typeof e.trailing == "string" ? n = j(r, e.trailing) : (e.start != null && (n = O(e.start, "time range start")), e.end != null && (a = O(e.end, "time range end"))), n > a)
1193
- throw new Error("Time range start must not follow its end");
1194
- return [Math.max(t, n), Math.min(r, a)];
1195
- }
1196
- const it = (e) => typeof e == "object" && e !== null && !Array.isArray(e);
1197
- function Gt(e, t) {
1198
- if (!it(e))
1199
- throw new Error(`${t} must be an object`);
1200
- for (const i of Object.keys(e))
1201
- if (i !== "start" && i !== "end" && i !== "trailing")
1202
- throw new Error(`${t}.${i} is not a time range key`);
1203
- if (e.trailing !== void 0) {
1204
- if (e.start !== void 0 || e.end !== void 0)
1205
- throw new Error(`${t}.trailing excludes start and end`);
1206
- if (typeof e.trailing != "string")
1207
- throw new Error(`${t}.trailing must be an ISO 8601 duration`);
1208
- return j(0, e.trailing), { trailing: e.trailing };
1209
- }
1210
- const r = (i) => {
1211
- const s = e[i];
1212
- if (s !== void 0) {
1213
- if (typeof s != "string" || !Number.isFinite(Date.parse(s)))
1214
- throw new Error(`${t}.${i} is not a date`);
1215
- return s;
1216
- }
1217
- }, n = r("start"), a = r("end");
1218
- if (n !== void 0 && a !== void 0 && Date.parse(n) > Date.parse(a))
1219
- throw new Error(`${t}.start must not follow its end`);
1220
- return {
1221
- ...n !== void 0 && { start: n },
1222
- ...a !== void 0 && { end: a }
1223
- };
1224
- }
1225
- function It(e) {
1226
- return e.type === "geovideo" && typeof e.indexUrl == "string";
1227
- }
1228
- function Ct(e, t) {
1229
- return e.id === t.id && (e.type !== "geovideo" || t.type !== "geovideo" || e.manifestUrl === t.manifestUrl);
1230
- }
1231
- function q(e) {
1232
- return typeof e == "string" && Number.isFinite(Date.parse(e));
1233
- }
1234
- function ot(e) {
1235
- const t = e;
1236
- if (!t || t.schemaVersion !== 1 || t.type !== "geovideo-index" || !Array.isArray(t.chunks))
1237
- throw new Error("Unsupported GeoVideo index");
1238
- for (const r of t.chunks)
1239
- if (!q(r?.start) || !q(r.end) || Date.parse(r.end) < Date.parse(r.start) || typeof r.manifestUrl != "string")
1240
- throw new Error("Invalid GeoVideo index chunk");
1241
- return t;
1242
- }
1243
- async function Nt(e, t) {
1244
- const r = await fetch(e, { signal: t });
1245
- if (!r.ok)
1246
- throw new Error(
1247
- `GeoVideo index request failed (${r.status}): ${e}`
1248
- );
1249
- return ot(await r.json());
1250
- }
1251
- function st(e) {
1252
- return typeof document < "u" ? new URL(e, document.baseURI).href : e;
1253
- }
1254
- function ct(e, t) {
1255
- const r = st(t);
1256
- return e.chunks.map((n) => ({
1257
- key: n.key,
1258
- manifestUrl: new URL(n.manifestUrl, r).href,
1259
- start: Date.parse(n.start),
1260
- end: Date.parse(n.end),
1261
- samples: n.samples,
1262
- ...n.provisional ? { provisional: !0 } : {}
1263
- }));
1264
- }
1265
- function dt(e, t, r) {
1266
- if (t.sourceId !== e.id || t.catalogEntryId !== r.id)
1267
- throw new Error(
1268
- `GeoVideo index identity does not match catalog entry/source: ${e.id}`
1269
- );
1270
- }
1271
- function Lt(e, t, r) {
1272
- dt(e, t, r);
1273
- const n = ct(t, e.indexUrl);
1274
- return t.chunks.map(
1275
- (a, i) => ({
1276
- id: e.id,
1277
- type: "geovideo",
1278
- title: e.title,
1279
- provenance: e.provenance,
1280
- temporal: {
1281
- mode: "fixed",
1282
- cadence: e.temporal?.cadence,
1283
- start: a.start,
1284
- end: a.end
1285
- },
1286
- manifestUrl: n[i].manifestUrl
1287
- })
1288
- );
1289
- }
1290
- export {
1291
- ut as A,
1292
- It as B,
1293
- gt as C,
1294
- Nt as D,
1295
- Lt as E,
1296
- Pt as F,
1297
- He as G,
1298
- B as H,
1299
- Mt as I,
1300
- H as J,
1301
- qe as K,
1302
- Te as L,
1303
- dt as M,
1304
- Ke as N,
1305
- N as O,
1306
- ke as P,
1307
- ze as Q,
1308
- ct as R,
1309
- je as S,
1310
- yt as T,
1311
- kt as U,
1312
- Ye as V,
1313
- Gt as W,
1314
- j as X,
1315
- ot as Y,
1316
- bt as a,
1317
- wt as b,
1318
- lt as c,
1319
- mt as d,
1320
- Et as e,
1321
- Tt as f,
1322
- Rt as g,
1323
- ft as h,
1324
- pt as i,
1325
- ht as j,
1326
- At as k,
1327
- xt as l,
1328
- Ce as m,
1329
- St as n,
1330
- Le as o,
1331
- Fe as p,
1332
- vt as q,
1333
- De as r,
1334
- _t as s,
1335
- A as t,
1336
- O as u,
1337
- Dt as v,
1338
- Ct as w,
1339
- Ut as x,
1340
- Ne as y,
1341
- Ft as z
1342
- };