isard 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +55 -1
- package/README.md +22 -7
- package/dist/basemap/vectortiles/context.d.ts +43 -0
- package/dist/basemap/vectortiles/context.js +6 -0
- package/dist/basemap/vectortiles/context.js.map +1 -0
- package/dist/basemap/vectortiles/extrusions.d.ts +11 -0
- package/dist/basemap/vectortiles/extrusions.js +46 -0
- package/dist/basemap/vectortiles/extrusions.js.map +1 -0
- package/dist/basemap/vectortiles/labels.d.ts +22 -0
- package/dist/basemap/vectortiles/labels.js +225 -0
- package/dist/basemap/vectortiles/labels.js.map +1 -0
- package/dist/basemap/vectortiles/requests.d.ts +24 -0
- package/dist/basemap/vectortiles/requests.js +61 -0
- package/dist/basemap/vectortiles/requests.js.map +1 -0
- package/dist/basemap/vectortiles/street-wind.d.ts +19 -0
- package/dist/basemap/vectortiles/street-wind.js +133 -0
- package/dist/basemap/vectortiles/street-wind.js.map +1 -0
- package/dist/basemap/vectortiles/style.d.ts +47 -0
- package/dist/basemap/vectortiles/style.js +141 -0
- package/dist/basemap/vectortiles/style.js.map +1 -0
- package/dist/basemap/vectortiles/tiles.d.ts +34 -0
- package/dist/basemap/vectortiles/tiles.js +62 -0
- package/dist/basemap/vectortiles/tiles.js.map +1 -0
- package/dist/basemap/vectortiles/trees.d.ts +19 -0
- package/dist/basemap/vectortiles/trees.js +93 -0
- package/dist/basemap/vectortiles/trees.js.map +1 -0
- package/dist/basemap/vectortiles/vectors.d.ts +20 -0
- package/dist/basemap/vectortiles/vectors.js +167 -0
- package/dist/basemap/vectortiles/vectors.js.map +1 -0
- package/dist/basemap/vectortiles.d.ts +23 -90
- package/dist/basemap/vectortiles.js +57 -765
- package/dist/basemap/vectortiles.js.map +1 -1
- package/dist/basemap/workerpool.js +25 -6
- package/dist/basemap/workerpool.js.map +1 -1
- package/dist/basemap.worker.js +2 -2
- package/dist/basemap.worker.js.map +4 -4
- package/dist/decoder.worker.js +5 -4
- package/dist/decoder.worker.js.map +8 -6
- package/dist/engine/decoders.d.ts +4 -8
- package/dist/engine/decoders.js +29 -2
- package/dist/engine/decoders.js.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/isard_bg.wasm +0 -0
- package/dist/isard_core_bg.wasm +0 -0
- package/dist/layers/flow.d.ts +9 -2
- package/dist/layers/flow.js +51 -10
- package/dist/layers/flow.js.map +1 -1
- package/dist/layers/panoramas.d.ts +2 -0
- package/dist/layers/panoramas.js +27 -6
- package/dist/layers/panoramas.js.map +1 -1
- package/dist/map/workers.js +3 -0
- package/dist/map/workers.js.map +1 -1
- package/dist/util/read.d.ts +4 -0
- package/dist/util/read.js +28 -0
- package/dist/util/read.js.map +1 -0
- package/dist/wasm/isard.d.ts +18 -5
- package/dist/wasm/isard.js +25 -4
- package/dist/wasm/isard_core.d.ts +18 -5
- package/dist/wasm/isard_core.js +25 -4
- package/dist/workers/basemap/street.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Optional decoders of the worker, loaded on first use from configurable URLs (the official builds three.js and
|
|
3
|
-
* Cesium use): Draco geometry (`KHR_draco_mesh_compression`) and KTX2 / Basis Universal textures (`KHR_texture_basisu`),
|
|
4
|
-
* transcoded to the best compressed format the GPU supports.
|
|
5
|
-
*/
|
|
6
1
|
import type { CompressedTexture, DracoGeometry, DracoRequest, TextureFormats } from '../wasm/isard.js';
|
|
7
2
|
/**
|
|
8
3
|
* Base URLs of the decoders (each ending with `/`).
|
|
9
4
|
*
|
|
10
|
-
* The decoders are Emscripten builds published as classic scripts: the worker fetches the script and
|
|
11
|
-
* `
|
|
12
|
-
*
|
|
5
|
+
* The decoders are Emscripten builds published as classic scripts: the worker fetches the script and imports it as a
|
|
6
|
+
* module from a `blob:` URL, so a Content Security Policy needs `blob:` in `script-src` (or `worker-src`) for 3D Tiles
|
|
7
|
+
* that use Draco; it falls back on `new Function` (`'unsafe-eval'`) where `blob:` is refused. The Basis transcoder (KTX2)
|
|
8
|
+
* needs `'unsafe-eval'` anyway: its own bindings (embind) build functions from strings. They are fetched from the default CDNs; to self-host them (offline, locked-down
|
|
13
9
|
* networks, no third-party requests), copy the four files (`draco_wasm_wrapper_gltf.js`, `draco_decoder_gltf.wasm`
|
|
14
10
|
* from the Draco release, `basis_transcoder.js`, `basis_transcoder.wasm` from three.js's `examples/jsm/libs/basis/`)
|
|
15
11
|
* to your server and give their folders in `GeoMapOptions.decoders`.
|
package/dist/engine/decoders.js
CHANGED
|
@@ -1,11 +1,38 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Optional decoders of the worker, loaded on first use from configurable URLs (the official builds three.js and
|
|
11
|
+
* Cesium use): Draco geometry (`KHR_draco_mesh_compression`) and KTX2 / Basis Universal textures (`KHR_texture_basisu`),
|
|
12
|
+
* transcoded to the best compressed format the GPU supports.
|
|
13
|
+
*/
|
|
14
|
+
import { isRecord } from "../util/guards.js";
|
|
1
15
|
export const DEFAULT_DECODERS = {
|
|
2
16
|
draco: 'https://www.gstatic.com/draco/versioned/decoders/1.5.7/',
|
|
3
17
|
basis: 'https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/libs/basis/',
|
|
4
18
|
};
|
|
5
|
-
/** Loads an Emscripten factory published as a classic script (module workers have no importScripts)
|
|
6
|
-
* `
|
|
19
|
+
/** Loads an Emscripten factory published as a classic script (module workers have no importScripts): imported as a
|
|
20
|
+
* module from a `blob:` URL (a Content Security Policy allowing `blob:` scripts is enough), else evaluated (where
|
|
21
|
+
* `blob:` is refused: `'unsafe-eval'`, see `DecoderUrls`) */
|
|
7
22
|
const factory = async (url, name) => {
|
|
8
23
|
const source = await (await fetch(url)).text();
|
|
24
|
+
const blob = URL.createObjectURL(new Blob([`${source}\nexport default ${name};`], { type: 'text/javascript' }));
|
|
25
|
+
try {
|
|
26
|
+
const module = await import(__rewriteRelativeImportExtension(/* @vite-ignore */ blob));
|
|
27
|
+
if (isRecord(module) && typeof module.default === 'function')
|
|
28
|
+
return module.default;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// Refused (`blob:` not allowed): evaluated below
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
URL.revokeObjectURL(blob);
|
|
35
|
+
}
|
|
9
36
|
return new Function(`${source}\nreturn ${name};`)();
|
|
10
37
|
};
|
|
11
38
|
const instantiate = async (base, script, wasm, name) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decoders.js","sourceRoot":"","sources":["../../src/engine/decoders.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Optional decoders of the worker, loaded on first use from configurable URLs (the official builds three.js and\n * Cesium use): Draco geometry (`KHR_draco_mesh_compression`) and KTX2 / Basis Universal textures (`KHR_texture_basisu`),\n * transcoded to the best compressed format the GPU supports.\n */\nimport type { CompressedTexture, DracoGeometry, DracoRequest, TextureFormats } from '../wasm/isard.js';\n\n/**\n * Base URLs of the decoders (each ending with `/`).\n *\n * The decoders are Emscripten builds published as classic scripts: the worker fetches the script and runs it with\n * `new Function`, so a Content Security Policy must allow `'unsafe-eval'` in `script-src` (or `worker-src`) for 3D\n * Tiles that use Draco or KTX2. They are fetched from the default CDNs; to self-host them (offline, locked-down\n * networks, no third-party requests), copy the four files (`draco_wasm_wrapper_gltf.js`, `draco_decoder_gltf.wasm`\n * from the Draco release, `basis_transcoder.js`, `basis_transcoder.wasm` from three.js's `examples/jsm/libs/basis/`)\n * to your server and give their folders in `GeoMapOptions.decoders`.\n */\nexport interface DecoderUrls {\n /** Folder of `draco_wasm_wrapper_gltf.js` and `draco_decoder_gltf.wasm` (and, for Draco point clouds, of the full\n * decoder `draco_wasm_wrapper.js` and `draco_decoder.wasm`) */\n draco: string;\n /** Folder of `basis_transcoder.js` and `basis_transcoder.wasm` */\n basis: string;\n}\n\nexport const DEFAULT_DECODERS: DecoderUrls = {\n draco: 'https://www.gstatic.com/draco/versioned/decoders/1.5.7/',\n basis: 'https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/libs/basis/',\n};\n\n// ── Draco (the subset of its Emscripten API used here) ──\n\ninterface DracoStatus {\n ok(): boolean;\n error_msg(): string;\n}\ninterface DracoMesh {\n num_points(): number;\n num_faces(): number;\n}\ninterface DracoAttribute {\n num_components(): number;\n}\ninterface DracoDecoder {\n DecodeArrayToMesh(data: Int8Array, size: number, mesh: DracoMesh): DracoStatus;\n DecodeArrayToPointCloud(data: Int8Array, size: number, cloud: DracoMesh): DracoStatus;\n GetAttributeByUniqueId(mesh: DracoMesh, id: number): DracoAttribute;\n GetAttributeDataArrayForAllPoints(\n mesh: DracoMesh,\n attribute: DracoAttribute,\n type: number,\n bytes: number,\n pointer: number,\n ): boolean;\n GetTrianglesUInt32Array(mesh: DracoMesh, bytes: number, pointer: number): boolean;\n}\ninterface DracoModule {\n Decoder: new () => DracoDecoder;\n Mesh: new () => DracoMesh;\n PointCloud: new () => DracoMesh;\n DT_FLOAT32: number;\n HEAPF32: Float32Array;\n HEAPU32: Uint32Array;\n _malloc(bytes: number): number;\n _free(pointer: number): void;\n destroy(object: object): void;\n}\n\n// ── Basis Universal transcoder ──\n\ninterface KTX2File {\n isValid(): boolean;\n getLevels(): number;\n getHasAlpha(): boolean;\n startTranscoding(): boolean;\n getImageLevelInfo(level: number, layer: number, face: number): { origWidth: number; origHeight: number };\n getImageTranscodedSizeInBytes(level: number, layer: number, face: number, format: number): number;\n transcodeImage(\n target: Uint8Array,\n level: number,\n layer: number,\n face: number,\n format: number,\n alphaForOpaque: number,\n channel0: number,\n channel1: number,\n ): boolean;\n close(): void;\n delete(): void;\n}\ninterface BasisModule {\n initializeBasis(): void;\n KTX2File: new (data: Uint8Array) => KTX2File;\n}\n\ntype Factory<T> = (options: { wasmBinary: ArrayBuffer }) => Promise<T>;\n\n/** Loads an Emscripten factory published as a classic script (module workers have no importScripts); needs\n * `'unsafe-eval'` under a Content Security Policy (see `DecoderUrls`) */\nconst factory = async <T>(url: string, name: string): Promise<Factory<T>> => {\n const source = await (await fetch(url)).text();\n\n return new Function(`${source}\\nreturn ${name};`)() as Factory<T>;\n};\n\nconst instantiate = async <T>(base: string, script: string, wasm: string, name: string): Promise<T> => {\n const [create, binary] = await Promise.all([\n factory<T>(`${base}${script}`, name),\n fetch(`${base}${wasm}`).then((r) => r.arrayBuffer()),\n ]);\n\n return create({ wasmBinary: binary });\n};\n\nlet draco: Promise<DracoModule> | undefined;\n/** The full Draco decoder: the glTF build decodes meshes only, not the point clouds */\nlet dracoPoints: Promise<DracoModule> | undefined;\nlet basis: Promise<BasisModule> | undefined;\n\n/** Decodes the Draco primitives of a tile (their points alone for point clouds) */\nexport const decodeDraco = async (urls: DecoderUrls, requests: DracoRequest[]): Promise<DracoGeometry[]> => {\n const meshes = requests.some((r) => !r.points);\n\n if (meshes) {\n draco ??= instantiate<DracoModule>(\n urls.draco,\n 'draco_wasm_wrapper_gltf.js',\n 'draco_decoder_gltf.wasm',\n 'DracoDecoderModule',\n );\n }\n if (requests.some((r) => r.points)) {\n dracoPoints ??= instantiate<DracoModule>(\n urls.draco,\n 'draco_wasm_wrapper.js',\n 'draco_decoder.wasm',\n 'DracoDecoderModule',\n );\n }\n\n const [forMeshes, forPoints] = await Promise.all([meshes ? draco : undefined, dracoPoints]);\n\n return requests.map((request) => {\n const module = request.points ? forPoints : forMeshes;\n\n if (!module) throw new Error('isard: the Draco decoder is not loaded');\n\n const decoder = new module.Decoder();\n const mesh = request.points ? new module.PointCloud() : new module.Mesh();\n\n try {\n const data = new Int8Array(request.data.buffer, request.data.byteOffset, request.data.byteLength);\n const status = request.points\n ? decoder.DecodeArrayToPointCloud(data, data.byteLength, mesh)\n : decoder.DecodeArrayToMesh(data, data.byteLength, mesh);\n\n if (!status.ok()) throw new Error(`Draco: ${status.error_msg()}`);\n\n const floats = (id: number): Float32Array => {\n const attribute = decoder.GetAttributeByUniqueId(mesh, id);\n const count = mesh.num_points() * attribute.num_components();\n const pointer = module._malloc(count * 4);\n\n try {\n decoder.GetAttributeDataArrayForAllPoints(mesh, attribute, module.DT_FLOAT32, count * 4, pointer);\n\n return module.HEAPF32.slice(pointer / 4, pointer / 4 + count);\n } finally {\n module._free(pointer);\n }\n };\n\n if (request.points) {\n const geometry: DracoGeometry = {\n mesh: request.mesh,\n primitive: request.primitive,\n positions: floats(request.position),\n };\n\n if (request.color !== undefined) geometry.colors = floats(request.color);\n if (request.normal !== undefined) geometry.normals = floats(request.normal);\n\n return geometry;\n }\n\n const triangles = (): Uint32Array => {\n const count = mesh.num_faces() * 3;\n const pointer = module._malloc(count * 4);\n\n try {\n decoder.GetTrianglesUInt32Array(mesh, count * 4, pointer);\n\n return module.HEAPU32.slice(pointer / 4, pointer / 4 + count);\n } finally {\n module._free(pointer);\n }\n };\n const indices = triangles();\n const geometry: DracoGeometry = {\n mesh: request.mesh,\n primitive: request.primitive,\n positions: floats(request.position),\n indices,\n };\n\n if (request.uv !== undefined) geometry.uvs = floats(request.uv);\n\n return geometry;\n } finally {\n module.destroy(mesh);\n module.destroy(decoder);\n }\n });\n};\n\n/** Basis target format and WebGL internal format, best first */\nconst target = (formats: TextureFormats, alpha: boolean): { basis: number; gl: number } => {\n if (formats.astc) return { basis: 10, gl: 0x93b0 }; // ASTC 4×4\n if (formats.bptc) return { basis: 6, gl: 0x8e8c }; // BC7\n if (formats.etc) return alpha ? { basis: 1, gl: 0x9278 } : { basis: 0, gl: 0x9274 }; // ETC2 RGBA / ETC1 as ETC2 RGB\n if (formats.s3tc) return alpha ? { basis: 3, gl: 0x83f3 } : { basis: 2, gl: 0x83f0 }; // BC3 / BC1\n\n return { basis: 13, gl: 0x8058 }; // RGBA8, uncompressed\n};\n\n/** Transcodes a KTX2 image for the GPU */\nexport const transcodeKtx2 = async (\n urls: DecoderUrls,\n formats: TextureFormats,\n bytes: Uint8Array,\n): Promise<CompressedTexture> => {\n basis ??= instantiate<BasisModule>(urls.basis, 'basis_transcoder.js', 'basis_transcoder.wasm', 'BASIS').then((m) => {\n m.initializeBasis();\n\n return m;\n });\n\n const module = await basis;\n const file = new module.KTX2File(bytes);\n\n try {\n if (!file.isValid() || !file.startTranscoding()) throw new Error('KTX2: invalid file');\n\n const { basis: format, gl } = target(formats, file.getHasAlpha());\n const levels: CompressedTexture['levels'] = Array.from({ length: file.getLevels() }, (_, level) => {\n const { origWidth: width, origHeight: height } = file.getImageLevelInfo(level, 0, 0);\n const data = new Uint8Array(file.getImageTranscodedSizeInBytes(level, 0, 0, format));\n\n if (!file.transcodeImage(data, level, 0, 0, format, 0, -1, -1)) throw new Error('KTX2: transcoding failed');\n\n return { width, height, data };\n });\n\n return { format: gl, levels };\n } finally {\n file.close();\n file.delete();\n }\n};\n"]}
|
|
1
|
+
{"version":3,"file":"decoders.js","sourceRoot":"","sources":["../../src/engine/decoders.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Optional decoders of the worker, loaded on first use from configurable URLs (the official builds three.js and\n * Cesium use): Draco geometry (`KHR_draco_mesh_compression`) and KTX2 / Basis Universal textures (`KHR_texture_basisu`),\n * transcoded to the best compressed format the GPU supports.\n */\nimport { isRecord } from '../util/guards.ts';\nimport type { CompressedTexture, DracoGeometry, DracoRequest, TextureFormats } from '../wasm/isard.js';\n\n/**\n * Base URLs of the decoders (each ending with `/`).\n *\n * The decoders are Emscripten builds published as classic scripts: the worker fetches the script and imports it as a\n * module from a `blob:` URL, so a Content Security Policy needs `blob:` in `script-src` (or `worker-src`) for 3D Tiles\n * that use Draco; it falls back on `new Function` (`'unsafe-eval'`) where `blob:` is refused. The Basis transcoder (KTX2)\n * needs `'unsafe-eval'` anyway: its own bindings (embind) build functions from strings. They are fetched from the default CDNs; to self-host them (offline, locked-down\n * networks, no third-party requests), copy the four files (`draco_wasm_wrapper_gltf.js`, `draco_decoder_gltf.wasm`\n * from the Draco release, `basis_transcoder.js`, `basis_transcoder.wasm` from three.js's `examples/jsm/libs/basis/`)\n * to your server and give their folders in `GeoMapOptions.decoders`.\n */\nexport interface DecoderUrls {\n /** Folder of `draco_wasm_wrapper_gltf.js` and `draco_decoder_gltf.wasm` (and, for Draco point clouds, of the full\n * decoder `draco_wasm_wrapper.js` and `draco_decoder.wasm`) */\n draco: string;\n /** Folder of `basis_transcoder.js` and `basis_transcoder.wasm` */\n basis: string;\n}\n\nexport const DEFAULT_DECODERS: DecoderUrls = {\n draco: 'https://www.gstatic.com/draco/versioned/decoders/1.5.7/',\n basis: 'https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/libs/basis/',\n};\n\n// ── Draco (the subset of its Emscripten API used here) ──\n\ninterface DracoStatus {\n ok(): boolean;\n error_msg(): string;\n}\ninterface DracoMesh {\n num_points(): number;\n num_faces(): number;\n}\ninterface DracoAttribute {\n num_components(): number;\n}\ninterface DracoDecoder {\n DecodeArrayToMesh(data: Int8Array, size: number, mesh: DracoMesh): DracoStatus;\n DecodeArrayToPointCloud(data: Int8Array, size: number, cloud: DracoMesh): DracoStatus;\n GetAttributeByUniqueId(mesh: DracoMesh, id: number): DracoAttribute;\n GetAttributeDataArrayForAllPoints(\n mesh: DracoMesh,\n attribute: DracoAttribute,\n type: number,\n bytes: number,\n pointer: number,\n ): boolean;\n GetTrianglesUInt32Array(mesh: DracoMesh, bytes: number, pointer: number): boolean;\n}\ninterface DracoModule {\n Decoder: new () => DracoDecoder;\n Mesh: new () => DracoMesh;\n PointCloud: new () => DracoMesh;\n DT_FLOAT32: number;\n HEAPF32: Float32Array;\n HEAPU32: Uint32Array;\n _malloc(bytes: number): number;\n _free(pointer: number): void;\n destroy(object: object): void;\n}\n\n// ── Basis Universal transcoder ──\n\ninterface KTX2File {\n isValid(): boolean;\n getLevels(): number;\n getHasAlpha(): boolean;\n startTranscoding(): boolean;\n getImageLevelInfo(level: number, layer: number, face: number): { origWidth: number; origHeight: number };\n getImageTranscodedSizeInBytes(level: number, layer: number, face: number, format: number): number;\n transcodeImage(\n target: Uint8Array,\n level: number,\n layer: number,\n face: number,\n format: number,\n alphaForOpaque: number,\n channel0: number,\n channel1: number,\n ): boolean;\n close(): void;\n delete(): void;\n}\ninterface BasisModule {\n initializeBasis(): void;\n KTX2File: new (data: Uint8Array) => KTX2File;\n}\n\ntype Factory<T> = (options: { wasmBinary: ArrayBuffer }) => Promise<T>;\n\n/** Loads an Emscripten factory published as a classic script (module workers have no importScripts): imported as a\n * module from a `blob:` URL (a Content Security Policy allowing `blob:` scripts is enough), else evaluated (where\n * `blob:` is refused: `'unsafe-eval'`, see `DecoderUrls`) */\nconst factory = async <T>(url: string, name: string): Promise<Factory<T>> => {\n const source = await (await fetch(url)).text();\n const blob = URL.createObjectURL(new Blob([`${source}\\nexport default ${name};`], { type: 'text/javascript' }));\n\n try {\n const module: unknown = await import(/* @vite-ignore */ blob);\n\n if (isRecord(module) && typeof module.default === 'function') return module.default as Factory<T>;\n } catch {\n // Refused (`blob:` not allowed): evaluated below\n } finally {\n URL.revokeObjectURL(blob);\n }\n\n return new Function(`${source}\\nreturn ${name};`)() as Factory<T>;\n};\n\nconst instantiate = async <T>(base: string, script: string, wasm: string, name: string): Promise<T> => {\n const [create, binary] = await Promise.all([\n factory<T>(`${base}${script}`, name),\n fetch(`${base}${wasm}`).then((r) => r.arrayBuffer()),\n ]);\n\n return create({ wasmBinary: binary });\n};\n\nlet draco: Promise<DracoModule> | undefined;\n/** The full Draco decoder: the glTF build decodes meshes only, not the point clouds */\nlet dracoPoints: Promise<DracoModule> | undefined;\nlet basis: Promise<BasisModule> | undefined;\n\n/** Decodes the Draco primitives of a tile (their points alone for point clouds) */\nexport const decodeDraco = async (urls: DecoderUrls, requests: DracoRequest[]): Promise<DracoGeometry[]> => {\n const meshes = requests.some((r) => !r.points);\n\n if (meshes) {\n draco ??= instantiate<DracoModule>(\n urls.draco,\n 'draco_wasm_wrapper_gltf.js',\n 'draco_decoder_gltf.wasm',\n 'DracoDecoderModule',\n );\n }\n if (requests.some((r) => r.points)) {\n dracoPoints ??= instantiate<DracoModule>(\n urls.draco,\n 'draco_wasm_wrapper.js',\n 'draco_decoder.wasm',\n 'DracoDecoderModule',\n );\n }\n\n const [forMeshes, forPoints] = await Promise.all([meshes ? draco : undefined, dracoPoints]);\n\n return requests.map((request) => {\n const module = request.points ? forPoints : forMeshes;\n\n if (!module) throw new Error('isard: the Draco decoder is not loaded');\n\n const decoder = new module.Decoder();\n const mesh = request.points ? new module.PointCloud() : new module.Mesh();\n\n try {\n const data = new Int8Array(request.data.buffer, request.data.byteOffset, request.data.byteLength);\n const status = request.points\n ? decoder.DecodeArrayToPointCloud(data, data.byteLength, mesh)\n : decoder.DecodeArrayToMesh(data, data.byteLength, mesh);\n\n if (!status.ok()) throw new Error(`Draco: ${status.error_msg()}`);\n\n const floats = (id: number): Float32Array => {\n const attribute = decoder.GetAttributeByUniqueId(mesh, id);\n const count = mesh.num_points() * attribute.num_components();\n const pointer = module._malloc(count * 4);\n\n try {\n decoder.GetAttributeDataArrayForAllPoints(mesh, attribute, module.DT_FLOAT32, count * 4, pointer);\n\n return module.HEAPF32.slice(pointer / 4, pointer / 4 + count);\n } finally {\n module._free(pointer);\n }\n };\n\n if (request.points) {\n const geometry: DracoGeometry = {\n mesh: request.mesh,\n primitive: request.primitive,\n positions: floats(request.position),\n };\n\n if (request.color !== undefined) geometry.colors = floats(request.color);\n if (request.normal !== undefined) geometry.normals = floats(request.normal);\n\n return geometry;\n }\n\n const triangles = (): Uint32Array => {\n const count = mesh.num_faces() * 3;\n const pointer = module._malloc(count * 4);\n\n try {\n decoder.GetTrianglesUInt32Array(mesh, count * 4, pointer);\n\n return module.HEAPU32.slice(pointer / 4, pointer / 4 + count);\n } finally {\n module._free(pointer);\n }\n };\n const indices = triangles();\n const geometry: DracoGeometry = {\n mesh: request.mesh,\n primitive: request.primitive,\n positions: floats(request.position),\n indices,\n };\n\n if (request.uv !== undefined) geometry.uvs = floats(request.uv);\n\n return geometry;\n } finally {\n module.destroy(mesh);\n module.destroy(decoder);\n }\n });\n};\n\n/** Basis target format and WebGL internal format, best first */\nconst target = (formats: TextureFormats, alpha: boolean): { basis: number; gl: number } => {\n if (formats.astc) return { basis: 10, gl: 0x93b0 }; // ASTC 4×4\n if (formats.bptc) return { basis: 6, gl: 0x8e8c }; // BC7\n if (formats.etc) return alpha ? { basis: 1, gl: 0x9278 } : { basis: 0, gl: 0x9274 }; // ETC2 RGBA / ETC1 as ETC2 RGB\n if (formats.s3tc) return alpha ? { basis: 3, gl: 0x83f3 } : { basis: 2, gl: 0x83f0 }; // BC3 / BC1\n\n return { basis: 13, gl: 0x8058 }; // RGBA8, uncompressed\n};\n\n/** Transcodes a KTX2 image for the GPU */\nexport const transcodeKtx2 = async (\n urls: DecoderUrls,\n formats: TextureFormats,\n bytes: Uint8Array,\n): Promise<CompressedTexture> => {\n basis ??= instantiate<BasisModule>(urls.basis, 'basis_transcoder.js', 'basis_transcoder.wasm', 'BASIS').then((m) => {\n m.initializeBasis();\n\n return m;\n });\n\n const module = await basis;\n const file = new module.KTX2File(bytes);\n\n try {\n if (!file.isValid() || !file.startTranscoding()) throw new Error('KTX2: invalid file');\n\n const { basis: format, gl } = target(formats, file.getHasAlpha());\n const levels: CompressedTexture['levels'] = Array.from({ length: file.getLevels() }, (_, level) => {\n const { origWidth: width, origHeight: height } = file.getImageLevelInfo(level, 0, 0);\n const data = new Uint8Array(file.getImageTranscodedSizeInBytes(level, 0, 0, format));\n\n if (!file.transcodeImage(data, level, 0, 0, format, 0, -1, -1)) throw new Error('KTX2: transcoding failed');\n\n return { width, height, data };\n });\n\n return { format: gl, levels };\n } finally {\n file.close();\n file.delete();\n }\n};\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,12 @@ export { PMTiles, type PmtilesEntry, type PmtilesHeader, type PmtilesTileType, t
|
|
|
17
17
|
export { basicStyle, type PmtilesOptions } from './basemap/pmtileslayer.ts';
|
|
18
18
|
export { type TreeColors, treeModel } from './basemap/trees.ts';
|
|
19
19
|
export type { CandidateIcon, CandidateOverlap, Json, LabelCandidate, RasterSource, Style, StyleLayer, } from './basemap/vectorstyle.ts';
|
|
20
|
+
export type { VectorExtrusionOptions } from './basemap/vectortiles/extrusions.ts';
|
|
21
|
+
export type { LabelsOptions } from './basemap/vectortiles/labels.ts';
|
|
22
|
+
export type { StreetWindLayer, StreetWindOptions } from './basemap/vectortiles/street-wind.ts';
|
|
23
|
+
export type { LoadedStyle } from './basemap/vectortiles/style.ts';
|
|
24
|
+
export type { TreesOptions } from './basemap/vectortiles/trees.ts';
|
|
25
|
+
export type { VectorsOptions } from './basemap/vectortiles/vectors.ts';
|
|
20
26
|
export type { VectorTilesOptions } from './basemap/vectortiles.ts';
|
|
21
27
|
export { OPENFREEMAP_STYLES, PLAN_STYLES, VectorTiles } from './basemap/vectortiles.ts';
|
|
22
28
|
export { parseWmtsGrid, wmtsGrid } from './basemap/wmts.ts';
|
|
@@ -26,7 +32,7 @@ export { parseKml } from './data/kml.ts';
|
|
|
26
32
|
export { parseTopoJson, type TopoGeometry, type Topology } from './data/topojson.ts';
|
|
27
33
|
export type { DecoderUrls } from './engine/decoders.ts';
|
|
28
34
|
export { setRequestHeaders } from './engine/requests.ts';
|
|
29
|
-
export { BATIMENTS_3D_URL, type BdTopoBuilding, batiments3d, bdtopoBuildings, type GeocodedPlace, geoplateformeGeocode, geoplateformeWfs, geoplateformeWms, geoplateformeWmts, IGN_ATTRIBUTION, IGN_PRESETS, type IgnPreset, } from './geoplateforme.ts';
|
|
35
|
+
export { BATIMENTS_3D_URL, type BdTopoBuilding, batiments3d, bdtopoBuildings, type GeocodedPlace, geoplateformeGeocode, geoplateformeWfs, geoplateformeWms, geoplateformeWmts, IGN_ATTRIBUTION, IGN_PRESETS, type IgnPreset, lambert93Grid, } from './geoplateforme.ts';
|
|
30
36
|
export { type Grid, windAt, windFields } from './grids.ts';
|
|
31
37
|
export type { ExtrusionOptions, ExtrusionStyle, PolygonArrays, TileKey } from './layers/extrusions.ts';
|
|
32
38
|
export { ExtrusionLayer } from './layers/extrusions.ts';
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@ export { parseGpx } from "./data/gpx.js";
|
|
|
22
22
|
export { parseKml } from "./data/kml.js";
|
|
23
23
|
export { parseTopoJson } from "./data/topojson.js";
|
|
24
24
|
export { setRequestHeaders } from "./engine/requests.js";
|
|
25
|
-
export { BATIMENTS_3D_URL, batiments3d, bdtopoBuildings, geoplateformeGeocode, geoplateformeWfs, geoplateformeWms, geoplateformeWmts, IGN_ATTRIBUTION, IGN_PRESETS, } from "./geoplateforme.js";
|
|
25
|
+
export { BATIMENTS_3D_URL, batiments3d, bdtopoBuildings, geoplateformeGeocode, geoplateformeWfs, geoplateformeWms, geoplateformeWmts, IGN_ATTRIBUTION, IGN_PRESETS, lambert93Grid, } from "./geoplateforme.js";
|
|
26
26
|
export { windAt, windFields } from "./grids.js";
|
|
27
27
|
export { ExtrusionLayer } from "./layers/extrusions.js";
|
|
28
28
|
export { CircleLayer, FeatureLayer, FillLayer, interpolate, LineLayer, parseColor } from "./layers/features.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAE3F,OAAO,EACL,OAAO,EAIP,WAAW,EACX,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAuB,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAAmB,SAAS,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAE3F,OAAO,EACL,OAAO,EAIP,WAAW,EACX,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAuB,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAAmB,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAiBhE,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACxF,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAGL,MAAM,EACN,qBAAqB,EACrB,WAAW,EACX,SAAS,EACT,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAoC,MAAM,oBAAoB,CAAC;AAErF,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EACL,gBAAgB,EAEhB,WAAW,EACX,eAAe,EAEf,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,WAAW,EAEX,aAAa,GACd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAa,MAAM,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE3D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAqBxD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEhH,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEtF,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAU9D,OAAO,EACL,WAAW,EACX,WAAW,EACX,KAAK,EACL,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAY,GACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAuC,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvF,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE3F,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAsB,WAAW,EAAuB,MAAM,qBAAqB,CAAC;AAE3F,OAAO,EAAE,MAAM,EAAkB,MAAM,UAAU,CAAC;AAiClD,OAAO,EACL,kBAAkB,EAIlB,iBAAiB,GAElB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAuB,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAEL,MAAM,EAIN,KAAK,EAEL,KAAK,GAGN,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAqB,MAAM,eAAe,CAAC;AAC1F,OAAO,EAAE,aAAa,EAAsB,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC","sourcesContent":["/**\n * isard: a WebGL2 map engine for large, interactive data layers, labels and 3D Tiles.\n *\n * ```ts\n * import { GeoMap } from 'isard';\n * const map = await GeoMap.create(container, { center: [2.4246, 48.8457], zoom: 13 });\n * const network = map.addNetwork({ nodes, edges, max: 1800, contour: 300 });\n * map.on('hover', ({ lonLat }) => lonLat && network.setValues(travelTimes(lonLat)));\n * map.addTiles3d({ url: 'https://…/tileset.json' });\n * map.addControl(new NavigationControl());\n * new Marker().setLonLat([2.4246, 48.8457]).setPopup(new Popup({ offset: [0, -34] }).setText('Here')).addTo(map);\n * ```\n */\nexport { OPENFREEMAP_ATTRIBUTION, TERRAIN_TILES_ATTRIBUTION } from './basemap/basemaps.ts';\nexport type { TileGrid, TileMatrix } from './basemap/grid.ts';\nexport {\n PMTiles,\n type PmtilesEntry,\n type PmtilesHeader,\n type PmtilesTileType,\n tileIdToZxy,\n zxyToTileId,\n} from './basemap/pmtiles.ts';\nexport { basicStyle, type PmtilesOptions } from './basemap/pmtileslayer.ts';\nexport { type TreeColors, treeModel } from './basemap/trees.ts';\nexport type {\n CandidateIcon,\n CandidateOverlap,\n Json,\n LabelCandidate,\n RasterSource,\n Style,\n StyleLayer,\n} from './basemap/vectorstyle.ts';\nexport type { VectorExtrusionOptions } from './basemap/vectortiles/extrusions.ts';\nexport type { LabelsOptions } from './basemap/vectortiles/labels.ts';\nexport type { StreetWindLayer, StreetWindOptions } from './basemap/vectortiles/street-wind.ts';\nexport type { LoadedStyle } from './basemap/vectortiles/style.ts';\nexport type { TreesOptions } from './basemap/vectortiles/trees.ts';\nexport type { VectorsOptions } from './basemap/vectortiles/vectors.ts';\nexport type { VectorTilesOptions } from './basemap/vectortiles.ts';\nexport { OPENFREEMAP_STYLES, PLAN_STYLES, VectorTiles } from './basemap/vectortiles.ts';\nexport { parseWmtsGrid, wmtsGrid } from './basemap/wmts.ts';\nexport {\n type Crs,\n type CrsLike,\n getCrs,\n lambertConformalConic,\n registerCrs,\n reproject,\n transverseMercator,\n} from './data/crs.ts';\nexport { parseGpx } from './data/gpx.ts';\nexport { parseKml } from './data/kml.ts';\nexport { parseTopoJson, type TopoGeometry, type Topology } from './data/topojson.ts';\nexport type { DecoderUrls } from './engine/decoders.ts';\nexport { setRequestHeaders } from './engine/requests.ts';\nexport {\n BATIMENTS_3D_URL,\n type BdTopoBuilding,\n batiments3d,\n bdtopoBuildings,\n type GeocodedPlace,\n geoplateformeGeocode,\n geoplateformeWfs,\n geoplateformeWms,\n geoplateformeWmts,\n IGN_ATTRIBUTION,\n IGN_PRESETS,\n type IgnPreset,\n lambert93Grid,\n} from './geoplateforme.ts';\nexport { type Grid, windAt, windFields } from './grids.ts';\nexport type { ExtrusionOptions, ExtrusionStyle, PolygonArrays, TileKey } from './layers/extrusions.ts';\nexport { ExtrusionLayer } from './layers/extrusions.ts';\nexport type {\n CircleOptions,\n CircleStyle,\n Feature,\n FeatureCollection,\n FeatureData,\n FeatureLayerStyle,\n FillOptions,\n FillStyle,\n Geometry,\n LineOptions,\n LineStyle,\n Placement,\n Position,\n Properties,\n Ramp,\n Size,\n Stops,\n Styled,\n} from './layers/features.ts';\nexport { CircleLayer, FeatureLayer, FillLayer, interpolate, LineLayer, parseColor } from './layers/features.ts';\nexport type { FlowField, FlowOptions, FlowStyle, TimedField } from './layers/flow.ts';\nexport { FlowLayer, flowFieldFromImage, flowFieldsFromImage } from './layers/flow.ts';\nexport type { TextPart } from './layers/glyphs.ts';\nexport { DEFAULT_FONT, GLYPHS_URL } from './layers/glyphs.ts';\nexport type { ImageOptions, Pixels, SpriteIcon } from './layers/icons.ts';\nexport type {\n CustomFrame,\n CustomLayerInterface,\n GroundOptions,\n GroundTexture,\n ModelInstance,\n ModelOptions,\n} from './layers/layers.ts';\nexport {\n CustomLayer,\n GroundLayer,\n Layer,\n ModelLayer,\n NetworkLayer,\n RasterLayer,\n Tiles3dLayer,\n} from './layers/layers.ts';\nexport { type Panorama, type PanoramaOptions, Panoramas } from './layers/panoramas.ts';\nexport type { ClassStyle, PointCloudOptions, PointCloudStyle, PointColor } from './layers/pointclouds.ts';\nexport { CLASSIFICATIONS, ELEVATION_RAMP, PointCloudLayer } from './layers/pointclouds.ts';\nexport type { Overlap, SymbolOptions, SymbolStyle } from './layers/symbols.ts';\nexport { SymbolLayer } from './layers/symbols.ts';\nexport { type VectorFeature, VectorLayer, type VectorSublayer } from './layers/vectors.ts';\nexport type { HoverPicking } from './map/hover-pick.ts';\nexport { GeoMap, type LayerSpec } from './map.ts';\nexport type {\n AnimationOptions,\n AtmosphereOptions,\n Basemap,\n BasemapName,\n BodyOptions,\n CelestialBody,\n FeatureHit,\n FirstPersonView,\n FlyToOptions,\n GeoMapOptions,\n LoadingMode,\n LonLat,\n MapEvents,\n MapHoverFeatureEvent,\n MapPointerEvent,\n NetworkOptions,\n NetworkStyle,\n Point,\n Projection,\n RasterGrid,\n RasterOptions,\n RasterStyle,\n SunOptions,\n SwipeOptions,\n TerrainEncoding,\n TerrainModel,\n TerrainOptions,\n Tiles3dOptions,\n Tiles3dStyle,\n ViewshedOptions,\n} from './types.ts';\nexport {\n AttributionControl,\n type AttributionOptions,\n type Control,\n type ControlPosition,\n NavigationControl,\n type NavigationOptions,\n} from './ui/controls.ts';\nexport { MinimapControl, type MinimapOptions } from './ui/minimap.ts';\nexport {\n type Anchor,\n Marker,\n type MarkerEvent,\n type MarkerEvents,\n type MarkerOptions,\n Panel,\n type PanelOptions,\n Popup,\n type PopupEvents,\n type PopupOptions,\n} from './ui/overlay.ts';\nexport { lengthLabel, roundLength, ScaleControl, type ScaleOptions } from './ui/scale.ts';\nexport { SearchControl, type SearchOptions } from './ui/search.ts';\nexport { sunPosition } from './util/sun.ts';\nexport type {\n Camera,\n NetworkStats,\n PickHit,\n PickResult,\n PointCloudInfo,\n PointCloudPoint,\n PointCloudStats,\n RasterLayerStats,\n Tiles3dStats,\n} from './wasm/isard.js';\n"]}
|
package/dist/isard_bg.wasm
CHANGED
|
Binary file
|
package/dist/isard_core_bg.wasm
CHANGED
|
Binary file
|
package/dist/layers/flow.d.ts
CHANGED
|
@@ -57,6 +57,9 @@ export declare class FlowLayer extends Layer {
|
|
|
57
57
|
/** The fields by time (one at time 0 for a single field), the time shown, the two sent to the engine */
|
|
58
58
|
private fields;
|
|
59
59
|
private time;
|
|
60
|
+
/** Or two fields mixed by weights of any value (the flows of a wind of 1 m/s towards the east and the north: a
|
|
61
|
+
* wind's `u` and `v` as weights), set by `streetWind` */
|
|
62
|
+
private basis;
|
|
60
63
|
private sent;
|
|
61
64
|
private style;
|
|
62
65
|
private readonly particles;
|
|
@@ -72,7 +75,8 @@ export declare class FlowLayer extends Layer {
|
|
|
72
75
|
pause(): void;
|
|
73
76
|
/** Moving or not (`play`, `pause`) */
|
|
74
77
|
setPlaying(playing: boolean): void;
|
|
75
|
-
/** Moves the particles by `seconds` of the page's time, at once (a still image after so many steps; paused)
|
|
78
|
+
/** Moves the particles by `seconds` of the page's time, at once (a still image after so many steps; paused); the map
|
|
79
|
+
* drawn again only if they moved (none in view, or no field yet: the map stays idle) */
|
|
76
80
|
step(seconds?: number): void;
|
|
77
81
|
/** A new field (on another grid, the trails start again) */
|
|
78
82
|
setField(field: FlowField): void;
|
|
@@ -84,8 +88,11 @@ export declare class FlowLayer extends Layer {
|
|
|
84
88
|
setStyle(style: Partial<FlowStyle>): void;
|
|
85
89
|
/** One step an animation frame while it plays, by the time since the last */
|
|
86
90
|
private loop;
|
|
87
|
-
/** The two fields around the time and how far between them, the fields sent only
|
|
91
|
+
/** The two fields around the time and how far between them (or the basis and its weights), the fields sent only
|
|
92
|
+
* when they change: the next hour reached, it becomes the field on the engine, only the one after it sent */
|
|
88
93
|
private sendField;
|
|
94
|
+
/** A field and the second one on the engine, each sent only if it changed */
|
|
95
|
+
private sendPair;
|
|
89
96
|
private sendStyle;
|
|
90
97
|
remove(): void;
|
|
91
98
|
}
|
package/dist/layers/flow.js
CHANGED
|
@@ -20,6 +20,9 @@ export class FlowLayer extends Layer {
|
|
|
20
20
|
/** The fields by time (one at time 0 for a single field), the time shown, the two sent to the engine */
|
|
21
21
|
fields;
|
|
22
22
|
time;
|
|
23
|
+
/** Or two fields mixed by weights of any value (the flows of a wind of 1 m/s towards the east and the north: a
|
|
24
|
+
* wind's `u` and `v` as weights), set by `streetWind` */
|
|
25
|
+
basis;
|
|
23
26
|
sent;
|
|
24
27
|
style;
|
|
25
28
|
particles;
|
|
@@ -72,12 +75,13 @@ export class FlowLayer extends Layer {
|
|
|
72
75
|
else
|
|
73
76
|
this.pause();
|
|
74
77
|
}
|
|
75
|
-
/** Moves the particles by `seconds` of the page's time, at once (a still image after so many steps; paused)
|
|
78
|
+
/** Moves the particles by `seconds` of the page's time, at once (a still image after so many steps; paused); the map
|
|
79
|
+
* drawn again only if they moved (none in view, or no field yet: the map stays idle) */
|
|
76
80
|
step(seconds = 1 / 60) {
|
|
77
81
|
if (this.id < 0)
|
|
78
82
|
return;
|
|
79
|
-
this.map.engine.stepFlow(this.id, seconds)
|
|
80
|
-
|
|
83
|
+
if (this.map.engine.stepFlow(this.id, seconds))
|
|
84
|
+
this.map.requestRender();
|
|
81
85
|
}
|
|
82
86
|
/** A new field (on another grid, the trails start again) */
|
|
83
87
|
setField(field) {
|
|
@@ -86,6 +90,7 @@ export class FlowLayer extends Layer {
|
|
|
86
90
|
/** New fields at their times (a model's hours), mixed at `time` (default the one shown) */
|
|
87
91
|
setFields(fields, time) {
|
|
88
92
|
this.fields = timed({ fields });
|
|
93
|
+
this.basis = undefined;
|
|
89
94
|
if (time !== undefined)
|
|
90
95
|
this.time = Number(time);
|
|
91
96
|
this.sent = undefined;
|
|
@@ -101,6 +106,23 @@ export class FlowLayer extends Layer {
|
|
|
101
106
|
this.sendField(this.map.engine, this.id);
|
|
102
107
|
this.map.requestRender();
|
|
103
108
|
}
|
|
109
|
+
/** @internal Two fields on one grid mixed by `weights` of any value: `weights[0]` times `east` plus `weights[1]`
|
|
110
|
+
* times `north` (the particles go on while the grid stays) */
|
|
111
|
+
setBasis(east, north, weights) {
|
|
112
|
+
this.basis = { east, north, weights };
|
|
113
|
+
if (this.id >= 0)
|
|
114
|
+
this.sendField(this.map.engine, this.id);
|
|
115
|
+
this.map.requestRender();
|
|
116
|
+
}
|
|
117
|
+
/** @internal New weights of the basis: two numbers sent, nothing else */
|
|
118
|
+
setWeights(weights) {
|
|
119
|
+
if (!this.basis)
|
|
120
|
+
return;
|
|
121
|
+
this.basis.weights = weights;
|
|
122
|
+
if (this.id >= 0)
|
|
123
|
+
this.map.engine.setFlowWeights(this.id, weights[0], weights[1]);
|
|
124
|
+
this.map.requestRender();
|
|
125
|
+
}
|
|
104
126
|
setStyle(style) {
|
|
105
127
|
this.style = { ...this.style, ...style };
|
|
106
128
|
if (this.id >= 0)
|
|
@@ -120,20 +142,37 @@ export class FlowLayer extends Layer {
|
|
|
120
142
|
cancelAnimationFrame(this.frame);
|
|
121
143
|
this.frame = requestAnimationFrame(tick);
|
|
122
144
|
}
|
|
123
|
-
/** The two fields around the time and how far between them, the fields sent only
|
|
145
|
+
/** The two fields around the time and how far between them (or the basis and its weights), the fields sent only
|
|
146
|
+
* when they change: the next hour reached, it becomes the field on the engine, only the one after it sent */
|
|
124
147
|
sendField(engine, id) {
|
|
148
|
+
const { basis } = this;
|
|
149
|
+
if (basis) {
|
|
150
|
+
this.sendPair(engine, id, basis.east, basis.north);
|
|
151
|
+
engine.setFlowWeights(id, basis.weights[0], basis.weights[1]);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
125
154
|
const { fields, time } = this;
|
|
126
155
|
const [a, b] = around(fields, time);
|
|
127
156
|
if (!a)
|
|
128
157
|
return;
|
|
129
|
-
|
|
130
|
-
const { width, height, u, v, bounds } = a.field;
|
|
131
|
-
engine.setFlowField(id, width, height, Float32Array.from(u), Float32Array.from(v), Float64Array.from(bounds));
|
|
132
|
-
engine.setFlowNext(id, Float32Array.from(b?.field.u ?? []), Float32Array.from(b?.field.v ?? []));
|
|
133
|
-
this.sent = [a.field, b?.field];
|
|
134
|
-
}
|
|
158
|
+
this.sendPair(engine, id, a.field, b?.field);
|
|
135
159
|
engine.setFlowBlend(id, b ? (time - a.time) / (b.time - a.time) : 0);
|
|
136
160
|
}
|
|
161
|
+
/** A field and the second one on the engine, each sent only if it changed */
|
|
162
|
+
sendPair(engine, id, field, next) {
|
|
163
|
+
const [was, wasNext] = this.sent ?? [];
|
|
164
|
+
if (was === field && wasNext === next)
|
|
165
|
+
return;
|
|
166
|
+
if (wasNext === field) {
|
|
167
|
+
engine.promoteFlowNext(id);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
const { width, height, u, v, bounds } = field;
|
|
171
|
+
engine.setFlowField(id, width, height, floats(u), floats(v), Float64Array.from(bounds));
|
|
172
|
+
}
|
|
173
|
+
engine.setFlowNext(id, floats(next?.u ?? []), floats(next?.v ?? []));
|
|
174
|
+
this.sent = [field, next];
|
|
175
|
+
}
|
|
137
176
|
sendStyle(engine, id) {
|
|
138
177
|
const { colors, width, opacity, height, speed, density } = this.style;
|
|
139
178
|
const stops = colors.slice(0, 8);
|
|
@@ -157,6 +196,8 @@ export class FlowLayer extends Layer {
|
|
|
157
196
|
this.pause();
|
|
158
197
|
}
|
|
159
198
|
}
|
|
199
|
+
/** Components as the engine takes them: a `Float32Array` as it is (copied once, into the engine), else converted */
|
|
200
|
+
const floats = (a) => a instanceof Float32Array ? a : Float32Array.from(a);
|
|
160
201
|
/** The fields around a time: the one before and the one after, or the first or last alone outside them */
|
|
161
202
|
const around = (fields, time) => {
|
|
162
203
|
const after = fields.findIndex((f) => f.time > time);
|
package/dist/layers/flow.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flow.js","sourceRoot":"","sources":["../../src/layers/flow.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Flow layers: particles carried by a field of velocities (a wind's east and north components on a grid of longitudes\n * and latitudes, m/s), their trails drawn on the globe and the relief and animated, colored by speed: wind maps,\n * currents. The engine moves them (`stepFlow`), one step per animation frame while the layer plays.\n */\n\nimport type { LayerHost } from '../types.ts';\nimport type { Engine } from '../wasm/isard.js';\nimport { parseColor, type Ramp } from './features.ts';\nimport { Layer } from './layers.ts';\n\n/**\n * A field of velocities: `width` × `height` points, from west to east and from north to south (row after row), the\n * east (`u`) and north (`v`) components at each (m/s; not a number: none there), the corner points at `bounds` (west,\n * south, east, north, degrees). A last column one step short of 360° goes round the world (a global model's grid)\n */\nexport interface FlowField {\n width: number;\n height: number;\n u: Float32Array | readonly number[];\n v: Float32Array | readonly number[];\n bounds: [west: number, south: number, east: number, north: number];\n}\n\nexport interface FlowStyle {\n /** The colors of the speeds (m/s), linear between them, up to 8 (default from calm blue to storm red) */\n colors: Ramp;\n /** Width of a trail, CSS pixels (default 1.5) */\n width: number;\n /** 0 to 1 (default 0.9) */\n opacity: number;\n /** Metres over the ground (default 0) */\n height: number;\n /** Speed on screen: pixels a second for 10 m/s, whatever the zoom (default 60) */\n speed: number;\n /** Particles moving for each 100 × 100 CSS pixels of the view, the screen as dense at any zoom (default 60; at most\n * `particles`) */\n density: number;\n}\n\n/** A field at a time: one of a model's hours */\nexport interface TimedField {\n time: Date | number;\n field: FlowField;\n}\n\nexport interface FlowOptions extends Partial<FlowStyle> {\n /** The field; or `fields`, at their times, mixed at `time` */\n field?: FlowField;\n /** Fields at their times, on one grid (a model's hours): the layer's field at `time` the mix of the two around it */\n fields?: readonly TimedField[];\n /** The time the fields are mixed at (default the first one's) */\n time?: Date | number;\n /** Particles moving, rounded up to a multiple of 4096 (default 16384) */\n particles?: number;\n /** Positions of a trail, one each 60th of a second (default 24): longer trails, more to draw */\n trail?: number;\n /** Moving from the start (default true); `play`, `pause` and `step` after */\n playing?: boolean;\n before?: Layer;\n}\n\n/** Wind speeds (m/s) from calm to storm */\nconst COLORS: Ramp = [\n [0, '#3a6fb0'],\n [4, '#4fa3c7'],\n [8, '#7fc79a'],\n [12, '#d6e27a'],\n [16, '#f6c14e'],\n [22, '#ef7d3c'],\n [30, '#d2374a'],\n [40, '#8e1f5c'],\n];\n\nexport class FlowLayer extends Layer {\n /** The fields by time (one at time 0 for a single field), the time shown, the two sent to the engine */\n private fields: { time: number; field: FlowField }[];\n private time: number;\n private sent: [FlowField, FlowField | undefined] | undefined;\n private style: FlowStyle;\n private readonly particles: number;\n private readonly trail: number;\n #playing: boolean;\n /** The animation frame asked for, and the time of the last step (ms) */\n private frame = 0;\n private last: number | undefined;\n\n /** @internal */\n constructor(map: LayerHost, options: FlowOptions) {\n super(map);\n this.fields = timed(options);\n this.time = options.time === undefined ? (this.fields[0]?.time ?? 0) : Number(options.time);\n this.particles = options.particles ?? 16384;\n this.trail = options.trail ?? 24;\n this.style = {\n colors: options.colors ?? COLORS,\n width: options.width ?? 1.5,\n opacity: options.opacity ?? 0.9,\n height: options.height ?? 0,\n speed: options.speed ?? 60,\n density: options.density ?? 60,\n };\n this.#playing = options.playing ?? true;\n if (this.#playing) this.loop();\n }\n\n /** Whether the particles move */\n get playing(): boolean {\n return this.#playing;\n }\n\n /** The particles move, a step each animation frame */\n play(): void {\n if (this.#playing) return;\n this.#playing = true;\n this.last = undefined;\n this.loop();\n }\n\n /** The particles stop where they are (the map no longer drawn for them) */\n pause(): void {\n this.#playing = false;\n cancelAnimationFrame(this.frame);\n this.frame = 0;\n }\n\n /** Moving or not (`play`, `pause`) */\n setPlaying(playing: boolean): void {\n if (playing) this.play();\n else this.pause();\n }\n\n /** Moves the particles by `seconds` of the page's time, at once (a still image after so many steps; paused) */\n step(seconds = 1 / 60): void {\n if (this.id < 0) return;\n this.map.engine.stepFlow(this.id, seconds);\n this.map.requestRender();\n }\n\n /** A new field (on another grid, the trails start again) */\n setField(field: FlowField): void {\n this.setFields([{ time: 0, field }], 0);\n }\n\n /** New fields at their times (a model's hours), mixed at `time` (default the one shown) */\n setFields(fields: readonly TimedField[], time?: Date | number): void {\n this.fields = timed({ fields });\n if (time !== undefined) this.time = Number(time);\n this.sent = undefined;\n if (this.id >= 0) this.sendField(this.map.engine, this.id);\n this.map.requestRender();\n }\n\n /** The time the fields are mixed at: between two of the model's hours, the field goes linearly from one to the\n * other (before the first and after the last, theirs); the particles go on */\n setTime(time: Date | number): void {\n this.time = Number(time);\n if (this.id >= 0) this.sendField(this.map.engine, this.id);\n this.map.requestRender();\n }\n\n setStyle(style: Partial<FlowStyle>): void {\n this.style = { ...this.style, ...style };\n if (this.id >= 0) this.sendStyle(this.map.engine, this.id);\n this.map.requestRender();\n }\n\n /** One step an animation frame while it plays, by the time since the last */\n private loop(): void {\n const tick = (now: number) => {\n if (!this.#playing) return;\n\n const seconds = this.last === undefined ? 1 / 60 : (now - this.last) / 1000;\n\n this.last = now;\n this.step(seconds);\n this.frame = requestAnimationFrame(tick);\n };\n\n cancelAnimationFrame(this.frame);\n this.frame = requestAnimationFrame(tick);\n }\n\n /** The two fields around the time and how far between them, the fields sent only when they change */\n private sendField(engine: Engine, id: number): void {\n const { fields, time } = this;\n const [a, b] = around(fields, time);\n\n if (!a) return;\n if (this.sent?.[0] !== a.field || this.sent?.[1] !== b?.field) {\n const { width, height, u, v, bounds } = a.field;\n\n engine.setFlowField(id, width, height, Float32Array.from(u), Float32Array.from(v), Float64Array.from(bounds));\n engine.setFlowNext(id, Float32Array.from(b?.field.u ?? []), Float32Array.from(b?.field.v ?? []));\n this.sent = [a.field, b?.field];\n }\n engine.setFlowBlend(id, b ? (time - a.time) / (b.time - a.time) : 0);\n }\n\n private sendStyle(engine: Engine, id: number): void {\n const { colors, width, opacity, height, speed, density } = this.style;\n const stops = colors.slice(0, 8);\n\n engine.setFlowStyle(\n id,\n Float32Array.from(stops, ([s]) => s),\n Float32Array.from(stops.flatMap(([, c]) => parseColor(c))),\n width,\n opacity,\n height,\n speed,\n density,\n );\n }\n\n /** @internal */\n protected create(engine: Engine): number {\n const id = engine.addFlow(this.particles, this.trail);\n\n // A new engine: everything sent again\n this.sent = undefined;\n this.sendField(engine, id);\n this.sendStyle(engine, id);\n\n return id;\n }\n\n override remove(): void {\n super.remove();\n this.dispose();\n }\n\n /** @internal */\n override dispose(): void {\n this.pause();\n }\n}\n\n/** The fields around a time: the one before and the one after, or the first or last alone outside them */\nconst around = <T extends { time: number }>(fields: readonly T[], time: number): [T | undefined, T | undefined] => {\n const after = fields.findIndex((f) => f.time > time);\n\n if (after < 0) return [fields.at(-1), undefined];\n if (after === 0) return [fields[0], undefined];\n\n return [fields[after - 1], fields[after]];\n};\n\n/** The fields of the options by time: `fields` sorted, or `field` alone (at time 0) */\nconst timed = ({ field, fields }: Pick<FlowOptions, 'field' | 'fields'>): { time: number; field: FlowField }[] => {\n if (fields?.length)\n return fields.map((f) => ({ time: Number(f.time), field: f.field })).sort((a, b) => a.time - b.time);\n if (field) return [{ time: 0, field }];\n throw new Error('isard: a flow layer needs a field or fields');\n};\n\n/**\n * A field from an image (PNG, as wind maps ship them): the east component in red, the north in green, each scaled\n * from 0-255 to its range (`u`, `v`, m/s), none where the image is transparent; its pixels the grid's points over\n * `bounds`\n */\nexport const flowFieldFromImage = async (\n url: string | URL,\n options: { bounds: FlowField['bounds']; u: [min: number, max: number]; v: [min: number, max: number] },\n init?: RequestInit,\n): Promise<FlowField> => {\n const [field] = await flowFieldsFromImage(url, { ...options, count: 1 }, init);\n\n if (!field) throw new Error(`isard: ${String(url)}: no field`);\n\n return field;\n};\n\n/**\n * The fields of an image holding `count` of them one under the other (a model's hours, the first at the top), each\n * read as `flowFieldFromImage` reads one\n */\nexport const flowFieldsFromImage = async (\n url: string | URL,\n options: {\n bounds: FlowField['bounds'];\n u: [min: number, max: number];\n v: [min: number, max: number];\n count: number;\n },\n init?: RequestInit,\n): Promise<FlowField[]> => {\n const response = await fetch(url, init);\n\n if (!response.ok) throw new Error(`isard: ${String(url)}: ${response.status}`);\n\n const bitmap = await createImageBitmap(await response.blob(), { colorSpaceConversion: 'none' });\n const { width, height } = bitmap;\n const canvas = new OffscreenCanvas(width, height);\n const g = canvas.getContext('2d', { willReadFrequently: true });\n\n if (!g) throw new Error('isard: no 2D canvas to read the field');\n g.drawImage(bitmap, 0, 0);\n bitmap.close();\n\n const { data } = g.getImageData(0, 0, width, height);\n const [u0, u1] = options.u;\n const [v0, v1] = options.v;\n const count = Math.max(1, Math.floor(options.count));\n const rows = Math.floor(height / count);\n\n return Array.from({ length: count }, (_, k) => {\n const u = new Float32Array(width * rows);\n const v = new Float32Array(width * rows);\n const first = k * rows * width;\n\n for (let i = 0; i < width * rows; i++) {\n const at = (first + i) * 4;\n const none = (data[at + 3] ?? 0) < 128;\n\n u[i] = none ? Number.NaN : u0 + ((data[at] ?? 0) / 255) * (u1 - u0);\n v[i] = none ? Number.NaN : v0 + ((data[at + 1] ?? 0) / 255) * (v1 - v0);\n }\n\n return { width, height: rows, u, v, bounds: options.bounds };\n });\n};\n"]}
|
|
1
|
+
{"version":3,"file":"flow.js","sourceRoot":"","sources":["../../src/layers/flow.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Flow layers: particles carried by a field of velocities (a wind's east and north components on a grid of longitudes\n * and latitudes, m/s), their trails drawn on the globe and the relief and animated, colored by speed: wind maps,\n * currents. The engine moves them (`stepFlow`), one step per animation frame while the layer plays.\n */\n\nimport type { LayerHost } from '../types.ts';\nimport type { Engine } from '../wasm/isard.js';\nimport { parseColor, type Ramp } from './features.ts';\nimport { Layer } from './layers.ts';\n\n/**\n * A field of velocities: `width` × `height` points, from west to east and from north to south (row after row), the\n * east (`u`) and north (`v`) components at each (m/s; not a number: none there), the corner points at `bounds` (west,\n * south, east, north, degrees). A last column one step short of 360° goes round the world (a global model's grid)\n */\nexport interface FlowField {\n width: number;\n height: number;\n u: Float32Array | readonly number[];\n v: Float32Array | readonly number[];\n bounds: [west: number, south: number, east: number, north: number];\n}\n\nexport interface FlowStyle {\n /** The colors of the speeds (m/s), linear between them, up to 8 (default from calm blue to storm red) */\n colors: Ramp;\n /** Width of a trail, CSS pixels (default 1.5) */\n width: number;\n /** 0 to 1 (default 0.9) */\n opacity: number;\n /** Metres over the ground (default 0) */\n height: number;\n /** Speed on screen: pixels a second for 10 m/s, whatever the zoom (default 60) */\n speed: number;\n /** Particles moving for each 100 × 100 CSS pixels of the view, the screen as dense at any zoom (default 60; at most\n * `particles`) */\n density: number;\n}\n\n/** A field at a time: one of a model's hours */\nexport interface TimedField {\n time: Date | number;\n field: FlowField;\n}\n\nexport interface FlowOptions extends Partial<FlowStyle> {\n /** The field; or `fields`, at their times, mixed at `time` */\n field?: FlowField;\n /** Fields at their times, on one grid (a model's hours): the layer's field at `time` the mix of the two around it */\n fields?: readonly TimedField[];\n /** The time the fields are mixed at (default the first one's) */\n time?: Date | number;\n /** Particles moving, rounded up to a multiple of 4096 (default 16384) */\n particles?: number;\n /** Positions of a trail, one each 60th of a second (default 24): longer trails, more to draw */\n trail?: number;\n /** Moving from the start (default true); `play`, `pause` and `step` after */\n playing?: boolean;\n before?: Layer;\n}\n\n/** Wind speeds (m/s) from calm to storm */\nconst COLORS: Ramp = [\n [0, '#3a6fb0'],\n [4, '#4fa3c7'],\n [8, '#7fc79a'],\n [12, '#d6e27a'],\n [16, '#f6c14e'],\n [22, '#ef7d3c'],\n [30, '#d2374a'],\n [40, '#8e1f5c'],\n];\n\nexport class FlowLayer extends Layer {\n /** The fields by time (one at time 0 for a single field), the time shown, the two sent to the engine */\n private fields: { time: number; field: FlowField }[];\n private time: number;\n /** Or two fields mixed by weights of any value (the flows of a wind of 1 m/s towards the east and the north: a\n * wind's `u` and `v` as weights), set by `streetWind` */\n private basis: { east: FlowField; north: FlowField; weights: [number, number] } | undefined;\n private sent: [FlowField, FlowField | undefined] | undefined;\n private style: FlowStyle;\n private readonly particles: number;\n private readonly trail: number;\n #playing: boolean;\n /** The animation frame asked for, and the time of the last step (ms) */\n private frame = 0;\n private last: number | undefined;\n\n /** @internal */\n constructor(map: LayerHost, options: FlowOptions) {\n super(map);\n this.fields = timed(options);\n this.time = options.time === undefined ? (this.fields[0]?.time ?? 0) : Number(options.time);\n this.particles = options.particles ?? 16384;\n this.trail = options.trail ?? 24;\n this.style = {\n colors: options.colors ?? COLORS,\n width: options.width ?? 1.5,\n opacity: options.opacity ?? 0.9,\n height: options.height ?? 0,\n speed: options.speed ?? 60,\n density: options.density ?? 60,\n };\n this.#playing = options.playing ?? true;\n if (this.#playing) this.loop();\n }\n\n /** Whether the particles move */\n get playing(): boolean {\n return this.#playing;\n }\n\n /** The particles move, a step each animation frame */\n play(): void {\n if (this.#playing) return;\n this.#playing = true;\n this.last = undefined;\n this.loop();\n }\n\n /** The particles stop where they are (the map no longer drawn for them) */\n pause(): void {\n this.#playing = false;\n cancelAnimationFrame(this.frame);\n this.frame = 0;\n }\n\n /** Moving or not (`play`, `pause`) */\n setPlaying(playing: boolean): void {\n if (playing) this.play();\n else this.pause();\n }\n\n /** Moves the particles by `seconds` of the page's time, at once (a still image after so many steps; paused); the map\n * drawn again only if they moved (none in view, or no field yet: the map stays idle) */\n step(seconds = 1 / 60): void {\n if (this.id < 0) return;\n if (this.map.engine.stepFlow(this.id, seconds)) this.map.requestRender();\n }\n\n /** A new field (on another grid, the trails start again) */\n setField(field: FlowField): void {\n this.setFields([{ time: 0, field }], 0);\n }\n\n /** New fields at their times (a model's hours), mixed at `time` (default the one shown) */\n setFields(fields: readonly TimedField[], time?: Date | number): void {\n this.fields = timed({ fields });\n this.basis = undefined;\n if (time !== undefined) this.time = Number(time);\n this.sent = undefined;\n if (this.id >= 0) this.sendField(this.map.engine, this.id);\n this.map.requestRender();\n }\n\n /** The time the fields are mixed at: between two of the model's hours, the field goes linearly from one to the\n * other (before the first and after the last, theirs); the particles go on */\n setTime(time: Date | number): void {\n this.time = Number(time);\n if (this.id >= 0) this.sendField(this.map.engine, this.id);\n this.map.requestRender();\n }\n\n /** @internal Two fields on one grid mixed by `weights` of any value: `weights[0]` times `east` plus `weights[1]`\n * times `north` (the particles go on while the grid stays) */\n setBasis(east: FlowField, north: FlowField, weights: [number, number]): void {\n this.basis = { east, north, weights };\n if (this.id >= 0) this.sendField(this.map.engine, this.id);\n this.map.requestRender();\n }\n\n /** @internal New weights of the basis: two numbers sent, nothing else */\n setWeights(weights: [number, number]): void {\n if (!this.basis) return;\n this.basis.weights = weights;\n if (this.id >= 0) this.map.engine.setFlowWeights(this.id, weights[0], weights[1]);\n this.map.requestRender();\n }\n\n setStyle(style: Partial<FlowStyle>): void {\n this.style = { ...this.style, ...style };\n if (this.id >= 0) this.sendStyle(this.map.engine, this.id);\n this.map.requestRender();\n }\n\n /** One step an animation frame while it plays, by the time since the last */\n private loop(): void {\n const tick = (now: number) => {\n if (!this.#playing) return;\n\n const seconds = this.last === undefined ? 1 / 60 : (now - this.last) / 1000;\n\n this.last = now;\n this.step(seconds);\n this.frame = requestAnimationFrame(tick);\n };\n\n cancelAnimationFrame(this.frame);\n this.frame = requestAnimationFrame(tick);\n }\n\n /** The two fields around the time and how far between them (or the basis and its weights), the fields sent only\n * when they change: the next hour reached, it becomes the field on the engine, only the one after it sent */\n private sendField(engine: Engine, id: number): void {\n const { basis } = this;\n\n if (basis) {\n this.sendPair(engine, id, basis.east, basis.north);\n engine.setFlowWeights(id, basis.weights[0], basis.weights[1]);\n\n return;\n }\n\n const { fields, time } = this;\n const [a, b] = around(fields, time);\n\n if (!a) return;\n this.sendPair(engine, id, a.field, b?.field);\n engine.setFlowBlend(id, b ? (time - a.time) / (b.time - a.time) : 0);\n }\n\n /** A field and the second one on the engine, each sent only if it changed */\n private sendPair(engine: Engine, id: number, field: FlowField, next: FlowField | undefined): void {\n const [was, wasNext] = this.sent ?? [];\n\n if (was === field && wasNext === next) return;\n if (wasNext === field) {\n engine.promoteFlowNext(id);\n } else {\n const { width, height, u, v, bounds } = field;\n\n engine.setFlowField(id, width, height, floats(u), floats(v), Float64Array.from(bounds));\n }\n engine.setFlowNext(id, floats(next?.u ?? []), floats(next?.v ?? []));\n this.sent = [field, next];\n }\n\n private sendStyle(engine: Engine, id: number): void {\n const { colors, width, opacity, height, speed, density } = this.style;\n const stops = colors.slice(0, 8);\n\n engine.setFlowStyle(\n id,\n Float32Array.from(stops, ([s]) => s),\n Float32Array.from(stops.flatMap(([, c]) => parseColor(c))),\n width,\n opacity,\n height,\n speed,\n density,\n );\n }\n\n /** @internal */\n protected create(engine: Engine): number {\n const id = engine.addFlow(this.particles, this.trail);\n\n // A new engine: everything sent again\n this.sent = undefined;\n this.sendField(engine, id);\n this.sendStyle(engine, id);\n\n return id;\n }\n\n override remove(): void {\n super.remove();\n this.dispose();\n }\n\n /** @internal */\n override dispose(): void {\n this.pause();\n }\n}\n\n/** Components as the engine takes them: a `Float32Array` as it is (copied once, into the engine), else converted */\nconst floats = (a: Float32Array | readonly number[]): Float32Array =>\n a instanceof Float32Array ? a : Float32Array.from(a);\n\n/** The fields around a time: the one before and the one after, or the first or last alone outside them */\nconst around = <T extends { time: number }>(fields: readonly T[], time: number): [T | undefined, T | undefined] => {\n const after = fields.findIndex((f) => f.time > time);\n\n if (after < 0) return [fields.at(-1), undefined];\n if (after === 0) return [fields[0], undefined];\n\n return [fields[after - 1], fields[after]];\n};\n\n/** The fields of the options by time: `fields` sorted, or `field` alone (at time 0) */\nconst timed = ({ field, fields }: Pick<FlowOptions, 'field' | 'fields'>): { time: number; field: FlowField }[] => {\n if (fields?.length)\n return fields.map((f) => ({ time: Number(f.time), field: f.field })).sort((a, b) => a.time - b.time);\n if (field) return [{ time: 0, field }];\n throw new Error('isard: a flow layer needs a field or fields');\n};\n\n/**\n * A field from an image (PNG, as wind maps ship them): the east component in red, the north in green, each scaled\n * from 0-255 to its range (`u`, `v`, m/s), none where the image is transparent; its pixels the grid's points over\n * `bounds`\n */\nexport const flowFieldFromImage = async (\n url: string | URL,\n options: { bounds: FlowField['bounds']; u: [min: number, max: number]; v: [min: number, max: number] },\n init?: RequestInit,\n): Promise<FlowField> => {\n const [field] = await flowFieldsFromImage(url, { ...options, count: 1 }, init);\n\n if (!field) throw new Error(`isard: ${String(url)}: no field`);\n\n return field;\n};\n\n/**\n * The fields of an image holding `count` of them one under the other (a model's hours, the first at the top), each\n * read as `flowFieldFromImage` reads one\n */\nexport const flowFieldsFromImage = async (\n url: string | URL,\n options: {\n bounds: FlowField['bounds'];\n u: [min: number, max: number];\n v: [min: number, max: number];\n count: number;\n },\n init?: RequestInit,\n): Promise<FlowField[]> => {\n const response = await fetch(url, init);\n\n if (!response.ok) throw new Error(`isard: ${String(url)}: ${response.status}`);\n\n const bitmap = await createImageBitmap(await response.blob(), { colorSpaceConversion: 'none' });\n const { width, height } = bitmap;\n const canvas = new OffscreenCanvas(width, height);\n const g = canvas.getContext('2d', { willReadFrequently: true });\n\n if (!g) throw new Error('isard: no 2D canvas to read the field');\n g.drawImage(bitmap, 0, 0);\n bitmap.close();\n\n const { data } = g.getImageData(0, 0, width, height);\n const [u0, u1] = options.u;\n const [v0, v1] = options.v;\n const count = Math.max(1, Math.floor(options.count));\n const rows = Math.floor(height / count);\n\n return Array.from({ length: count }, (_, k) => {\n const u = new Float32Array(width * rows);\n const v = new Float32Array(width * rows);\n const first = k * rows * width;\n\n for (let i = 0; i < width * rows; i++) {\n const at = (first + i) * 4;\n const none = (data[at + 3] ?? 0) < 128;\n\n u[i] = none ? Number.NaN : u0 + ((data[at] ?? 0) / 255) * (u1 - u0);\n v[i] = none ? Number.NaN : v0 + ((data[at + 1] ?? 0) / 255) * (v1 - v0);\n }\n\n return { width, height: rows, u, v, bounds: options.bounds };\n });\n};\n"]}
|
|
@@ -66,6 +66,8 @@ export declare class Panoramas {
|
|
|
66
66
|
nearest(lonLat: LonLat): Panorama | undefined;
|
|
67
67
|
/** Shows a panorama (its index in `list`): projected as soon as its first image arrives, the others after */
|
|
68
68
|
show(index: number): Promise<void>;
|
|
69
|
+
/** The downloads of the panorama shown, aborted by the next one shown or by `hide` */
|
|
70
|
+
private loading;
|
|
69
71
|
/** Hides the panorama shown */
|
|
70
72
|
hide(): void;
|
|
71
73
|
/** Stops the walk (`enter`) */
|
package/dist/layers/panoramas.js
CHANGED
|
@@ -109,25 +109,40 @@ export class Panoramas {
|
|
|
109
109
|
if (!pano || !attitude)
|
|
110
110
|
return;
|
|
111
111
|
const shown = ++this.shown;
|
|
112
|
+
// The images of the panorama shown before: no longer downloaded nor decoded
|
|
113
|
+
const controller = new AbortController();
|
|
114
|
+
this.loading?.abort();
|
|
115
|
+
this.loading = controller;
|
|
112
116
|
this.current = pano;
|
|
113
117
|
const rotation = panoramaRotation(attitude, pano.lonLat[0], this.lambert93);
|
|
114
118
|
const { url, backgroundDistance, opacity } = this.options;
|
|
115
119
|
this.host.setPanorama(pano.lonLat[0], pano.lonLat[1], pano.height, Float64Array.from(rotation), Float64Array.from(this.cameras.flatMap(cameraNumbers)), backgroundDistance, opacity);
|
|
116
|
-
|
|
120
|
+
const images = Promise.all(this.cameras.map(async (camera, k) => {
|
|
117
121
|
const src = url.replaceAll('{cameraId}', String(camera.id)).replaceAll('{panoId}', String(pano.id));
|
|
118
|
-
const response = await fetch(src, withHeaders(src));
|
|
122
|
+
const response = await fetch(src, withHeaders(src, { signal: controller.signal }));
|
|
119
123
|
if (!response.ok)
|
|
120
124
|
throw new Error(`isard: panorama image ${src}: ${response.status}`);
|
|
121
|
-
const
|
|
125
|
+
const blob = await response.blob();
|
|
126
|
+
if (controller.signal.aborted)
|
|
127
|
+
return;
|
|
128
|
+
const image = await createImageBitmap(blob, { premultiplyAlpha: 'none' });
|
|
122
129
|
// Another panorama shown since: this image is not its
|
|
123
130
|
if (shown === this.shown)
|
|
124
131
|
this.host.setPanoramaImage(k, image);
|
|
125
132
|
image.close();
|
|
126
133
|
}));
|
|
134
|
+
// Another panorama shown, or this one hidden, meanwhile: not a failure
|
|
135
|
+
await images.catch((error) => {
|
|
136
|
+
if (!controller.signal.aborted)
|
|
137
|
+
throw error;
|
|
138
|
+
});
|
|
127
139
|
}
|
|
140
|
+
/** The downloads of the panorama shown, aborted by the next one shown or by `hide` */
|
|
141
|
+
loading;
|
|
128
142
|
/** Hides the panorama shown */
|
|
129
143
|
hide() {
|
|
130
144
|
this.shown++;
|
|
145
|
+
this.loading?.abort();
|
|
131
146
|
this.current = undefined;
|
|
132
147
|
this.host.clearPanorama();
|
|
133
148
|
}
|
|
@@ -145,13 +160,13 @@ export class Panoramas {
|
|
|
145
160
|
this.stopWalking = this.host.listen((lonLat) => {
|
|
146
161
|
const target = lonLat && this.nearest(lonLat);
|
|
147
162
|
if (target && target !== this.current)
|
|
148
|
-
|
|
163
|
+
this.go(target.index).catch(report);
|
|
149
164
|
}, (e) => {
|
|
150
165
|
const step = { z: 1, Z: 1, PageUp: 1, s: -1, S: -1, PageDown: -1 }[e.key];
|
|
151
166
|
if (!step || !this.current)
|
|
152
167
|
return;
|
|
153
168
|
e.preventDefault();
|
|
154
|
-
|
|
169
|
+
this.go((this.current.index + step + this.list.length) % this.list.length).catch(report);
|
|
155
170
|
}, (e) => {
|
|
156
171
|
// One step per notch, the next ones once it is shown
|
|
157
172
|
if (this.moving || e.deltaY === 0)
|
|
@@ -159,7 +174,9 @@ export class Panoramas {
|
|
|
159
174
|
const target = this.ahead(e.deltaY < 0);
|
|
160
175
|
if (target) {
|
|
161
176
|
this.moving = true;
|
|
162
|
-
|
|
177
|
+
this.go(target.index)
|
|
178
|
+
.catch(report)
|
|
179
|
+
.finally(() => {
|
|
163
180
|
this.moving = false;
|
|
164
181
|
});
|
|
165
182
|
}
|
|
@@ -253,4 +270,8 @@ export const loadPanoramas = async (host, options) => {
|
|
|
253
270
|
opacity: options.opacity ?? 1,
|
|
254
271
|
}, list, attitudes, cameras, lambert93);
|
|
255
272
|
};
|
|
273
|
+
/** A step of the walk that failed (an image not found): told, the walk going on */
|
|
274
|
+
const report = (error) => {
|
|
275
|
+
console.warn('isard: panorama', error);
|
|
276
|
+
};
|
|
256
277
|
//# sourceMappingURL=panoramas.js.map
|