isard 1.0.0 → 1.2.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.
Files changed (268) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/{basemaps.d.ts → basemap/basemaps.d.ts} +3 -3
  3. package/dist/{basemaps.js → basemap/basemaps.js} +3 -3
  4. package/dist/basemap/basemaps.js.map +1 -0
  5. package/dist/{grid.d.ts → basemap/grid.d.ts} +6 -6
  6. package/dist/{grid.js → basemap/grid.js} +61 -67
  7. package/dist/basemap/grid.js.map +1 -0
  8. package/dist/{mvt.d.ts → basemap/mvt.d.ts} +1 -1
  9. package/dist/{mvt.js → basemap/mvt.js} +6 -6
  10. package/dist/basemap/mvt.js.map +1 -0
  11. package/dist/{pmtiles.d.ts → basemap/pmtiles.d.ts} +16 -10
  12. package/dist/{pmtiles.js → basemap/pmtiles.js} +41 -33
  13. package/dist/basemap/pmtiles.js.map +1 -0
  14. package/dist/{resample.d.ts → basemap/resample.d.ts} +11 -2
  15. package/dist/{resample.js → basemap/resample.js} +18 -16
  16. package/dist/basemap/resample.js.map +1 -0
  17. package/dist/{terrain.d.ts → basemap/terrain.d.ts} +3 -3
  18. package/dist/{terrain.js → basemap/terrain.js} +7 -7
  19. package/dist/basemap/terrain.js.map +1 -0
  20. package/dist/{vectorstyle.d.ts → basemap/vectorstyle.d.ts} +12 -10
  21. package/dist/{vectorstyle.js → basemap/vectorstyle.js} +129 -111
  22. package/dist/basemap/vectorstyle.js.map +1 -0
  23. package/dist/{vectortiles.d.ts → basemap/vectortiles.d.ts} +18 -18
  24. package/dist/{vectortiles.js → basemap/vectortiles.js} +157 -109
  25. package/dist/basemap/vectortiles.js.map +1 -0
  26. package/dist/{wmts.d.ts → basemap/wmts.d.ts} +3 -3
  27. package/dist/{wmts.js → basemap/wmts.js} +19 -14
  28. package/dist/basemap/wmts.js.map +1 -0
  29. package/dist/basemap.worker.js +2 -2
  30. package/dist/basemap.worker.js.map +14 -13
  31. package/dist/bind/layers.d.ts +46 -0
  32. package/dist/bind/layers.js +154 -0
  33. package/dist/bind/layers.js.map +1 -0
  34. package/dist/{crs.d.ts → data/crs.d.ts} +11 -11
  35. package/dist/{crs.js → data/crs.js} +38 -34
  36. package/dist/data/crs.js.map +1 -0
  37. package/dist/{gpx.d.ts → data/gpx.d.ts} +2 -2
  38. package/dist/{gpx.js → data/gpx.js} +20 -20
  39. package/dist/data/gpx.js.map +1 -0
  40. package/dist/{kml.d.ts → data/kml.d.ts} +2 -2
  41. package/dist/{kml.js → data/kml.js} +42 -39
  42. package/dist/data/kml.js.map +1 -0
  43. package/dist/{topojson.d.ts → data/topojson.d.ts} +2 -2
  44. package/dist/{topojson.js → data/topojson.js} +15 -10
  45. package/dist/data/topojson.js.map +1 -0
  46. package/dist/{xml.d.ts → data/xml.d.ts} +5 -5
  47. package/dist/{xml.js → data/xml.js} +19 -18
  48. package/dist/data/xml.js.map +1 -0
  49. package/dist/decoder.worker.js +4 -4
  50. package/dist/decoder.worker.js.map +7 -7
  51. package/dist/{decoders.d.ts → engine/decoders.d.ts} +3 -3
  52. package/dist/{decoders.js → engine/decoders.js} +28 -25
  53. package/dist/engine/decoders.js.map +1 -0
  54. package/dist/{loader.d.ts → engine/loader.d.ts} +1 -1
  55. package/dist/{loader.js → engine/loader.js} +17 -14
  56. package/dist/engine/loader.js.map +1 -0
  57. package/dist/{protocol.d.ts → engine/protocol.d.ts} +1 -1
  58. package/dist/engine/protocol.js +3 -0
  59. package/dist/engine/protocol.js.map +1 -0
  60. package/dist/{requests.d.ts → engine/requests.d.ts} +1 -1
  61. package/dist/{requests.js → engine/requests.js} +19 -16
  62. package/dist/engine/requests.js.map +1 -0
  63. package/dist/engine-loader.d.ts +13 -9
  64. package/dist/engine-loader.js +30 -30
  65. package/dist/engine-loader.js.map +1 -1
  66. package/dist/formats.d.ts +3 -3
  67. package/dist/formats.js +3 -3
  68. package/dist/formats.js.map +1 -1
  69. package/dist/geoplateforme.d.ts +13 -13
  70. package/dist/geoplateforme.js +23 -21
  71. package/dist/geoplateforme.js.map +1 -1
  72. package/dist/index.d.ts +30 -29
  73. package/dist/index.js +18 -18
  74. package/dist/index.js.map +1 -1
  75. package/dist/isard_bg.wasm +0 -0
  76. package/dist/isard_core_bg.wasm +0 -0
  77. package/dist/isard_points_bg.wasm +0 -0
  78. package/dist/{extrusions.d.ts → layers/extrusions.d.ts} +1 -1
  79. package/dist/{extrusions.js → layers/extrusions.js} +10 -5
  80. package/dist/layers/extrusions.js.map +1 -0
  81. package/dist/{features.d.ts → layers/features.d.ts} +10 -10
  82. package/dist/{features.js → layers/features.js} +44 -45
  83. package/dist/layers/features.js.map +1 -0
  84. package/dist/{glyphs.d.ts → layers/glyphs.d.ts} +6 -6
  85. package/dist/{glyphs.js → layers/glyphs.js} +45 -41
  86. package/dist/layers/glyphs.js.map +1 -0
  87. package/dist/{icons.d.ts → layers/icons.d.ts} +10 -10
  88. package/dist/{icons.js → layers/icons.js} +84 -69
  89. package/dist/layers/icons.js.map +1 -0
  90. package/dist/{layers.d.ts → layers/layers.d.ts} +9 -4
  91. package/dist/{layers.js → layers/layers.js} +35 -31
  92. package/dist/layers/layers.js.map +1 -0
  93. package/dist/{panoramas.d.ts → layers/panoramas.d.ts} +3 -3
  94. package/dist/{panoramas.js → layers/panoramas.js} +54 -43
  95. package/dist/layers/panoramas.js.map +1 -0
  96. package/dist/{pointclouds.d.ts → layers/pointclouds.d.ts} +5 -5
  97. package/dist/{pointclouds.js → layers/pointclouds.js} +26 -34
  98. package/dist/layers/pointclouds.js.map +1 -0
  99. package/dist/{symbols.d.ts → layers/symbols.d.ts} +3 -3
  100. package/dist/{symbols.js → layers/symbols.js} +69 -72
  101. package/dist/layers/symbols.js.map +1 -0
  102. package/dist/map/basemap-layers.d.ts +26 -0
  103. package/dist/map/basemap-layers.js +61 -0
  104. package/dist/map/basemap-layers.js.map +1 -0
  105. package/dist/map/canvas.d.ts +17 -0
  106. package/dist/map/canvas.js +56 -0
  107. package/dist/map/canvas.js.map +1 -0
  108. package/dist/map/checks.d.ts +11 -0
  109. package/dist/map/checks.js +39 -0
  110. package/dist/map/checks.js.map +1 -0
  111. package/dist/map/credits.d.ts +17 -0
  112. package/dist/map/credits.js +34 -0
  113. package/dist/map/credits.js.map +1 -0
  114. package/dist/map/engine-settings.d.ts +15 -0
  115. package/dist/map/engine-settings.js +45 -0
  116. package/dist/map/engine-settings.js.map +1 -0
  117. package/dist/map/engines.d.ts +41 -0
  118. package/dist/map/engines.js +77 -0
  119. package/dist/map/engines.js.map +1 -0
  120. package/dist/map/events.d.ts +14 -0
  121. package/dist/map/events.js +46 -0
  122. package/dist/map/events.js.map +1 -0
  123. package/dist/map/frame-loop.d.ts +61 -0
  124. package/dist/map/frame-loop.js +139 -0
  125. package/dist/map/frame-loop.js.map +1 -0
  126. package/dist/map/hover-pick.d.ts +30 -0
  127. package/dist/map/hover-pick.js +56 -0
  128. package/dist/map/hover-pick.js.map +1 -0
  129. package/dist/map/layer-spec.d.ts +42 -0
  130. package/dist/map/layer-spec.js +34 -0
  131. package/dist/map/layer-spec.js.map +1 -0
  132. package/dist/map/layer-stack.d.ts +36 -0
  133. package/dist/map/layer-stack.js +101 -0
  134. package/dist/map/layer-stack.js.map +1 -0
  135. package/dist/map/overlay-host.d.ts +36 -0
  136. package/dist/map/overlay-host.js +101 -0
  137. package/dist/map/overlay-host.js.map +1 -0
  138. package/dist/map/panorama-host.d.ts +5 -0
  139. package/dist/map/panorama-host.js +32 -0
  140. package/dist/map/panorama-host.js.map +1 -0
  141. package/dist/map/raster-source.d.ts +11 -0
  142. package/dist/map/raster-source.js +26 -0
  143. package/dist/map/raster-source.js.map +1 -0
  144. package/dist/map/symbol-atlases.d.ts +26 -0
  145. package/dist/map/symbol-atlases.js +59 -0
  146. package/dist/map/symbol-atlases.js.map +1 -0
  147. package/dist/map/viewshed.d.ts +5 -0
  148. package/dist/map/viewshed.js +28 -0
  149. package/dist/map/viewshed.js.map +1 -0
  150. package/dist/map/workers.d.ts +46 -0
  151. package/dist/map/workers.js +73 -0
  152. package/dist/map/workers.js.map +1 -0
  153. package/dist/map.d.ts +46 -127
  154. package/dist/map.js +183 -698
  155. package/dist/map.js.map +1 -1
  156. package/dist/projections.d.ts +3 -3
  157. package/dist/projections.js +2 -2
  158. package/dist/projections.js.map +1 -1
  159. package/dist/react/Control.d.ts +11 -0
  160. package/dist/react/Control.js +18 -0
  161. package/dist/react/Control.js.map +1 -0
  162. package/dist/react/CustomLayer.d.ts +11 -0
  163. package/dist/react/CustomLayer.js +30 -0
  164. package/dist/react/CustomLayer.js.map +1 -0
  165. package/dist/react/IsardMap.d.ts +43 -0
  166. package/dist/react/IsardMap.js +146 -0
  167. package/dist/react/IsardMap.js.map +1 -0
  168. package/dist/react/Layer.d.ts +42 -0
  169. package/dist/react/Layer.js +74 -0
  170. package/dist/react/Layer.js.map +1 -0
  171. package/dist/react/Marker.d.ts +24 -0
  172. package/dist/react/Marker.js +53 -0
  173. package/dist/react/Marker.js.map +1 -0
  174. package/dist/react/Panel.d.ts +11 -0
  175. package/dist/react/Panel.js +37 -0
  176. package/dist/react/Panel.js.map +1 -0
  177. package/dist/react/Popup.d.ts +18 -0
  178. package/dist/react/Popup.js +60 -0
  179. package/dist/react/Popup.js.map +1 -0
  180. package/dist/react/Swipe.d.ts +9 -0
  181. package/dist/react/Swipe.js +41 -0
  182. package/dist/react/Swipe.js.map +1 -0
  183. package/dist/react/Viewshed.d.ts +5 -0
  184. package/dist/react/Viewshed.js +28 -0
  185. package/dist/react/Viewshed.js.map +1 -0
  186. package/dist/react/context.d.ts +32 -0
  187. package/dist/react/context.js +20 -0
  188. package/dist/react/context.js.map +1 -0
  189. package/dist/react/index.d.ts +26 -0
  190. package/dist/react/index.js +22 -0
  191. package/dist/react/index.js.map +1 -0
  192. package/dist/settings.d.ts +6 -10
  193. package/dist/settings.js +19 -17
  194. package/dist/settings.js.map +1 -1
  195. package/dist/types.d.ts +8 -8
  196. package/dist/types.js +1 -0
  197. package/dist/types.js.map +1 -1
  198. package/dist/{controls.d.ts → ui/controls.d.ts} +1 -1
  199. package/dist/{controls.js → ui/controls.js} +6 -4
  200. package/dist/ui/controls.js.map +1 -0
  201. package/dist/{interaction.d.ts → ui/interaction.d.ts} +9 -5
  202. package/dist/{interaction.js → ui/interaction.js} +9 -8
  203. package/dist/ui/interaction.js.map +1 -0
  204. package/dist/{overlay.d.ts → ui/overlay.d.ts} +2 -2
  205. package/dist/{overlay.js → ui/overlay.js} +18 -20
  206. package/dist/ui/overlay.js.map +1 -0
  207. package/dist/{style.d.ts → ui/style.d.ts} +1 -1
  208. package/dist/{style.js → ui/style.js} +2 -2
  209. package/dist/ui/style.js.map +1 -0
  210. package/dist/{animation.d.ts → util/animation.d.ts} +9 -5
  211. package/dist/{animation.js → util/animation.js} +6 -6
  212. package/dist/util/animation.js.map +1 -0
  213. package/dist/{color.d.ts → util/color.d.ts} +1 -1
  214. package/dist/{color.js → util/color.js} +14 -16
  215. package/dist/util/color.js.map +1 -0
  216. package/dist/{geo.d.ts → util/geo.d.ts} +6 -6
  217. package/dist/{geo.js → util/geo.js} +12 -12
  218. package/dist/util/geo.js.map +1 -0
  219. package/dist/util/guards.d.ts +7 -0
  220. package/dist/util/guards.js +8 -0
  221. package/dist/util/guards.js.map +1 -0
  222. package/dist/util/lru.js.map +1 -0
  223. package/dist/wasm/isard.d.ts +168 -0
  224. package/dist/wasm/isard.js +146 -0
  225. package/dist/wasm/isard_core.d.ts +144 -0
  226. package/dist/wasm/isard_core.js +122 -0
  227. package/dist/{basemap.worker.d.ts → workers/basemap.worker.d.ts} +17 -7
  228. package/dist/workers/basemap.worker.js +658 -0
  229. package/dist/workers/basemap.worker.js.map +1 -0
  230. package/package.json +24 -1
  231. package/vite.js +1 -1
  232. package/dist/animation.js.map +0 -1
  233. package/dist/basemaps.js.map +0 -1
  234. package/dist/color.js.map +0 -1
  235. package/dist/controls.js.map +0 -1
  236. package/dist/crs.js.map +0 -1
  237. package/dist/decoders.js.map +0 -1
  238. package/dist/extrusions.js.map +0 -1
  239. package/dist/features.js.map +0 -1
  240. package/dist/geo.js.map +0 -1
  241. package/dist/glyphs.js.map +0 -1
  242. package/dist/gpx.js.map +0 -1
  243. package/dist/grid.js.map +0 -1
  244. package/dist/icons.js.map +0 -1
  245. package/dist/interaction.js.map +0 -1
  246. package/dist/kml.js.map +0 -1
  247. package/dist/layers.js.map +0 -1
  248. package/dist/loader.js.map +0 -1
  249. package/dist/lru.js.map +0 -1
  250. package/dist/mvt.js.map +0 -1
  251. package/dist/overlay.js.map +0 -1
  252. package/dist/panoramas.js.map +0 -1
  253. package/dist/pmtiles.js.map +0 -1
  254. package/dist/pointclouds.js.map +0 -1
  255. package/dist/protocol.js +0 -2
  256. package/dist/protocol.js.map +0 -1
  257. package/dist/requests.js.map +0 -1
  258. package/dist/resample.js.map +0 -1
  259. package/dist/style.js.map +0 -1
  260. package/dist/symbols.js.map +0 -1
  261. package/dist/terrain.js.map +0 -1
  262. package/dist/topojson.js.map +0 -1
  263. package/dist/vectorstyle.js.map +0 -1
  264. package/dist/vectortiles.js.map +0 -1
  265. package/dist/wmts.js.map +0 -1
  266. package/dist/xml.js.map +0 -1
  267. /package/dist/{lru.d.ts → util/lru.d.ts} +0 -0
  268. /package/dist/{lru.js → util/lru.js} +0 -0
@@ -3,7 +3,7 @@
3
3
  * Cesium use): Draco geometry (`KHR_draco_mesh_compression`) and KTX2 / Basis Universal textures (`KHR_texture_basisu`),
4
4
  * transcoded to the best compressed format the GPU supports.
5
5
  */
6
- import type { CompressedTexture, DracoGeometry, DracoRequest, TextureFormats } from './wasm/isard.js';
6
+ import type { CompressedTexture, DracoGeometry, DracoRequest, TextureFormats } from '../wasm/isard.js';
7
7
  /**
8
8
  * Base URLs of the decoders (each ending with `/`).
9
9
  *
@@ -23,6 +23,6 @@ export interface DecoderUrls {
23
23
  }
24
24
  export declare const DEFAULT_DECODERS: DecoderUrls;
25
25
  /** Decodes the Draco primitives of a tile (their points alone for point clouds) */
26
- export declare function decodeDraco(urls: DecoderUrls, requests: DracoRequest[]): Promise<DracoGeometry[]>;
26
+ export declare const decodeDraco: (urls: DecoderUrls, requests: DracoRequest[]) => Promise<DracoGeometry[]>;
27
27
  /** Transcodes a KTX2 image for the GPU */
28
- export declare function transcodeKtx2(urls: DecoderUrls, formats: TextureFormats, bytes: Uint8Array): Promise<CompressedTexture>;
28
+ export declare const transcodeKtx2: (urls: DecoderUrls, formats: TextureFormats, bytes: Uint8Array) => Promise<CompressedTexture>;
@@ -4,23 +4,23 @@ export const DEFAULT_DECODERS = {
4
4
  };
5
5
  /** Loads an Emscripten factory published as a classic script (module workers have no importScripts); needs
6
6
  * `'unsafe-eval'` under a Content Security Policy (see `DecoderUrls`) */
7
- async function factory(url, name) {
7
+ const factory = async (url, name) => {
8
8
  const source = await (await fetch(url)).text();
9
9
  return new Function(`${source}\nreturn ${name};`)();
10
- }
11
- async function instantiate(base, script, wasm, name) {
10
+ };
11
+ const instantiate = async (base, script, wasm, name) => {
12
12
  const [create, binary] = await Promise.all([
13
13
  factory(`${base}${script}`, name),
14
14
  fetch(`${base}${wasm}`).then((r) => r.arrayBuffer()),
15
15
  ]);
16
16
  return create({ wasmBinary: binary });
17
- }
17
+ };
18
18
  let draco;
19
19
  /** The full Draco decoder: the glTF build decodes meshes only, not the point clouds */
20
20
  let dracoPoints;
21
21
  let basis;
22
22
  /** Decodes the Draco primitives of a tile (their points alone for point clouds) */
23
- export async function decodeDraco(urls, requests) {
23
+ export const decodeDraco = async (urls, requests) => {
24
24
  const meshes = requests.some((r) => !r.points);
25
25
  if (meshes) {
26
26
  draco ??= instantiate(urls.draco, 'draco_wasm_wrapper_gltf.js', 'draco_decoder_gltf.wasm', 'DracoDecoderModule');
@@ -30,7 +30,9 @@ export async function decodeDraco(urls, requests) {
30
30
  }
31
31
  const [forMeshes, forPoints] = await Promise.all([meshes ? draco : undefined, dracoPoints]);
32
32
  return requests.map((request) => {
33
- const module = (request.points ? forPoints : forMeshes);
33
+ const module = request.points ? forPoints : forMeshes;
34
+ if (!module)
35
+ throw new Error('isard: the Draco decoder is not loaded');
34
36
  const decoder = new module.Decoder();
35
37
  const mesh = request.points ? new module.PointCloud() : new module.Mesh();
36
38
  try {
@@ -64,16 +66,18 @@ export async function decodeDraco(urls, requests) {
64
66
  geometry.normals = floats(request.normal);
65
67
  return geometry;
66
68
  }
67
- const count = mesh.num_faces() * 3;
68
- const pointer = module._malloc(count * 4);
69
- let indices;
70
- try {
71
- decoder.GetTrianglesUInt32Array(mesh, count * 4, pointer);
72
- indices = module.HEAPU32.slice(pointer / 4, pointer / 4 + count);
73
- }
74
- finally {
75
- module._free(pointer);
76
- }
69
+ const triangles = () => {
70
+ const count = mesh.num_faces() * 3;
71
+ const pointer = module._malloc(count * 4);
72
+ try {
73
+ decoder.GetTrianglesUInt32Array(mesh, count * 4, pointer);
74
+ return module.HEAPU32.slice(pointer / 4, pointer / 4 + count);
75
+ }
76
+ finally {
77
+ module._free(pointer);
78
+ }
79
+ };
80
+ const indices = triangles();
77
81
  const geometry = {
78
82
  mesh: request.mesh,
79
83
  primitive: request.primitive,
@@ -89,9 +93,9 @@ export async function decodeDraco(urls, requests) {
89
93
  module.destroy(decoder);
90
94
  }
91
95
  });
92
- }
96
+ };
93
97
  /** Basis target format and WebGL internal format, best first */
94
- function target(formats, alpha) {
98
+ const target = (formats, alpha) => {
95
99
  if (formats.astc)
96
100
  return { basis: 10, gl: 0x93b0 }; // ASTC 4×4
97
101
  if (formats.bptc)
@@ -101,9 +105,9 @@ function target(formats, alpha) {
101
105
  if (formats.s3tc)
102
106
  return alpha ? { basis: 3, gl: 0x83f3 } : { basis: 2, gl: 0x83f0 }; // BC3 / BC1
103
107
  return { basis: 13, gl: 0x8058 }; // RGBA8, uncompressed
104
- }
108
+ };
105
109
  /** Transcodes a KTX2 image for the GPU */
106
- export async function transcodeKtx2(urls, formats, bytes) {
110
+ export const transcodeKtx2 = async (urls, formats, bytes) => {
107
111
  basis ??= instantiate(urls.basis, 'basis_transcoder.js', 'basis_transcoder.wasm', 'BASIS').then((m) => {
108
112
  m.initializeBasis();
109
113
  return m;
@@ -114,19 +118,18 @@ export async function transcodeKtx2(urls, formats, bytes) {
114
118
  if (!file.isValid() || !file.startTranscoding())
115
119
  throw new Error('KTX2: invalid file');
116
120
  const { basis: format, gl } = target(formats, file.getHasAlpha());
117
- const levels = [];
118
- for (let level = 0; level < file.getLevels(); level++) {
121
+ const levels = Array.from({ length: file.getLevels() }, (_, level) => {
119
122
  const { origWidth: width, origHeight: height } = file.getImageLevelInfo(level, 0, 0);
120
123
  const data = new Uint8Array(file.getImageTranscodedSizeInBytes(level, 0, 0, format));
121
124
  if (!file.transcodeImage(data, level, 0, 0, format, 0, -1, -1))
122
125
  throw new Error('KTX2: transcoding failed');
123
- levels.push({ width, height, data });
124
- }
126
+ return { width, height, data };
127
+ });
125
128
  return { format: gl, levels };
126
129
  }
127
130
  finally {
128
131
  file.close();
129
132
  file.delete();
130
133
  }
131
- }
134
+ };
132
135
  //# sourceMappingURL=decoders.js.map
@@ -0,0 +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"]}
@@ -2,8 +2,8 @@
2
2
  * Pool of decoding workers for 3D Tiles content and point clouds. The engine calls `load`, `loadPoints` and `abort`
3
3
  * (`TileLoaderLike`); the main thread then only uploads the decoded arrays to the GPU.
4
4
  */
5
+ import type { DecodedTile, TextureFormats, TileLoaderLike } from '../wasm/isard.js';
5
6
  import type { DecoderUrls } from './decoders.ts';
6
- import type { DecodedTile, TextureFormats, TileLoaderLike } from './wasm/isard.js';
7
7
  export declare class TileLoader implements TileLoaderLike {
8
8
  private readonly module;
9
9
  private readonly workerUrl;
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Pool of decoding workers for 3D Tiles content and point clouds. The engine calls `load`, `loadPoints` and `abort`
3
+ * (`TileLoaderLike`); the main thread then only uploads the decoded arrays to the GPU.
4
+ */
1
5
  import { headerRules, onHeaderRules } from "./requests.js";
2
6
  export class TileLoader {
3
7
  module;
@@ -14,8 +18,9 @@ export class TileLoader {
14
18
  failed;
15
19
  /** The page's request headers, sent to the workers as they change */
16
20
  unfollow = onHeaderRules((rules) => {
17
- for (const worker of this.workers)
21
+ this.workers.forEach((worker) => {
18
22
  this.send(worker, { type: 'headers', rules });
23
+ });
19
24
  });
20
25
  constructor(module, workerUrl, size, decoders, formats,
21
26
  /** URL of the point cloud module, for the workers */
@@ -57,18 +62,20 @@ export class TileLoader {
57
62
  }
58
63
  destroy() {
59
64
  this.unfollow();
60
- for (const worker of this.workers)
65
+ this.workers.forEach((worker) => {
61
66
  worker.terminate();
67
+ });
62
68
  this.workers = [];
63
69
  this.busy.clear();
64
- for (const { reject } of this.pending.values())
70
+ this.pending.forEach(({ reject }) => {
65
71
  reject(new Error('loader destroyed'));
72
+ });
66
73
  this.pending.clear();
67
74
  }
68
75
  /** Workers start with the first tile: a map without 3D Tiles costs nothing */
69
76
  leastBusy() {
70
77
  if (this.workers.length === 0) {
71
- for (let i = 0; i < this.size; i++) {
78
+ Array.from({ length: this.size }).forEach(() => {
72
79
  const worker = new Worker(this.workerUrl, { type: 'module' });
73
80
  worker.onmessage = (event) => this.receive(worker, event.data);
74
81
  // A worker that fails to load (a bundler serving it from elsewhere) or to read a message fails its requests
@@ -84,14 +91,10 @@ export class TileLoader {
84
91
  this.send(worker, { type: 'headers', rules });
85
92
  this.workers.push(worker);
86
93
  this.busy.set(worker, 0);
87
- }
94
+ });
88
95
  }
89
- let best = this.workers[0];
90
- for (const worker of this.workers) {
91
- if ((this.busy.get(worker) ?? 0) < (this.busy.get(best) ?? 0))
92
- best = worker;
93
- }
94
- return best;
96
+ const load = (worker) => this.busy.get(worker) ?? 0;
97
+ return this.workers.reduce((best, worker) => (load(worker) < load(best) ? worker : best));
95
98
  }
96
99
  send(worker, message) {
97
100
  worker.postMessage(message);
@@ -114,12 +117,12 @@ export class TileLoader {
114
117
  /** Rejects the requests of a failed worker */
115
118
  fail(worker, message) {
116
119
  const error = new Error(`isard: ${message}. If a bundler moves the worker, give its URL in the \`workerUrl\` option (see "With a bundler" in the guide)`);
117
- for (const [id, pending] of this.pending) {
120
+ this.pending.forEach((pending, id) => {
118
121
  if (pending.worker !== worker)
119
- continue;
122
+ return;
120
123
  this.pending.delete(id);
121
124
  pending.reject(error);
122
- }
125
+ });
123
126
  // Out of the pool: when none is left, the next requests fail at once
124
127
  worker.terminate();
125
128
  this.workers = this.workers.filter((w) => w !== worker);
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/engine/loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pool of decoding workers for 3D Tiles content and point clouds. The engine calls `load`, `loadPoints` and `abort`\n * (`TileLoaderLike`); the main thread then only uploads the decoded arrays to the GPU.\n */\n\nimport type { DecodedTile, TextureFormats, TileLoaderLike } from '../wasm/isard.js';\nimport type { DecoderUrls } from './decoders.ts';\nimport type { WorkerReply, WorkerRequest } from './protocol.ts';\nimport { headerRules, onHeaderRules } from './requests.ts';\n\ninterface Pending {\n resolve: (result: DecodedTile | Uint8Array<ArrayBuffer>) => void;\n reject: (error: Error) => void;\n worker: Worker;\n}\n\nexport class TileLoader implements TileLoaderLike {\n private workers: Worker[] = [];\n /** Requests in flight per worker */\n private readonly busy = new Map<Worker, number>();\n private readonly pending = new Map<number, Pending>();\n /** Every worker failed: why */\n private failed: Error | undefined;\n /** The page's request headers, sent to the workers as they change */\n private readonly unfollow = onHeaderRules((rules) => {\n this.workers.forEach((worker) => {\n this.send(worker, { type: 'headers', rules });\n });\n });\n\n constructor(\n private readonly module: WebAssembly.Module,\n private readonly workerUrl: string | URL,\n private readonly size: number,\n private readonly decoders: DecoderUrls,\n private readonly formats: TextureFormats,\n /** URL of the point cloud module, for the workers */\n private readonly points: string = '',\n ) {}\n\n /** Called by the engine: fetch and decode off the main thread, on the least busy worker */\n load(\n id: number,\n url: string,\n transform: Float64Array,\n yUp: boolean,\n reload: boolean,\n priority?: 'high' | 'low',\n ): Promise<DecodedTile> {\n if (this.failed) return Promise.reject(this.failed);\n\n const worker = this.leastBusy();\n\n this.busy.set(worker, (this.busy.get(worker) ?? 0) + 1);\n\n return new Promise((resolve, reject) => {\n this.pending.set(id, { resolve: resolve as Pending['resolve'], reject, worker });\n this.send(worker, { type: 'load', id, url, transform, yUp, reload, ...(priority ? { priority } : {}) });\n });\n }\n\n /** Called by the engine: the points of a COPC node, fetched (a range request) and decoded off the main thread */\n loadPoints(\n id: number,\n url: string,\n offset: number,\n size: number,\n laz: Uint8Array,\n layout: Float64Array,\n grid: Float64Array,\n count: number,\n priority?: 'high' | 'low',\n ): Promise<Uint8Array<ArrayBuffer>> {\n if (this.failed) return Promise.reject(this.failed);\n\n const worker = this.leastBusy();\n\n this.busy.set(worker, (this.busy.get(worker) ?? 0) + 1);\n\n return new Promise((resolve, reject) => {\n this.pending.set(id, { resolve: resolve as Pending['resolve'], reject, worker });\n\n const message = { type: 'points', id, url, offset, size, laz, layout, grid, count } as const;\n\n this.send(worker, { ...message, ...(priority ? { priority } : {}) });\n });\n }\n\n abort(id: number): void {\n const pending = this.pending.get(id);\n\n if (pending) this.send(pending.worker, { type: 'abort', id });\n }\n\n destroy(): void {\n this.unfollow();\n this.workers.forEach((worker) => {\n worker.terminate();\n });\n this.workers = [];\n this.busy.clear();\n this.pending.forEach(({ reject }) => {\n reject(new Error('loader destroyed'));\n });\n this.pending.clear();\n }\n\n /** Workers start with the first tile: a map without 3D Tiles costs nothing */\n private leastBusy(): Worker {\n if (this.workers.length === 0) {\n Array.from({ length: this.size }).forEach(() => {\n const worker = new Worker(this.workerUrl, { type: 'module' });\n\n worker.onmessage = (event: MessageEvent<WorkerReply>) => this.receive(worker, event.data);\n // A worker that fails to load (a bundler serving it from elsewhere) or to read a message fails its requests\n worker.onerror = (event) => {\n event.preventDefault();\n this.fail(worker, `the decoding worker ${this.workerUrl} failed${event.message ? `: ${event.message}` : ''}`);\n };\n worker.onmessageerror = () =>\n this.fail(worker, `the decoding worker ${this.workerUrl} sent an unreadable message`);\n\n const { module, decoders, formats, points } = this;\n\n this.send(worker, { type: 'init', module, decoders, formats, points });\n\n const rules = headerRules();\n\n if (rules.length > 0) this.send(worker, { type: 'headers', rules });\n this.workers.push(worker);\n this.busy.set(worker, 0);\n });\n }\n\n const load = (worker: Worker) => this.busy.get(worker) ?? 0;\n\n return this.workers.reduce((best, worker) => (load(worker) < load(best) ? worker : best));\n }\n\n private send(worker: Worker, message: WorkerRequest): void {\n worker.postMessage(message);\n }\n\n private receive(worker: Worker, reply: WorkerReply): void {\n this.busy.set(worker, Math.max(0, (this.busy.get(worker) ?? 1) - 1));\n\n const pending = this.pending.get(reply.id);\n\n if (!pending) return;\n this.pending.delete(reply.id);\n if (reply.type === 'tile') pending.resolve(reply.tile);\n else if (reply.type === 'points') pending.resolve(reply.vertices);\n else if (reply.aborted) pending.reject(new DOMException(`tile ${reply.id} aborted`, 'AbortError'));\n else pending.reject(new Error(reply.error));\n }\n\n /** Rejects the requests of a failed worker */\n private fail(worker: Worker, message: string): void {\n const error = new Error(\n `isard: ${message}. If a bundler moves the worker, give its URL in the \\`workerUrl\\` option (see \"With a bundler\" in the guide)`,\n );\n\n this.pending.forEach((pending, id) => {\n if (pending.worker !== worker) return;\n this.pending.delete(id);\n pending.reject(error);\n });\n // Out of the pool: when none is left, the next requests fail at once\n worker.terminate();\n this.workers = this.workers.filter((w) => w !== worker);\n this.busy.delete(worker);\n if (this.workers.length === 0) this.failed = error;\n }\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  /** Messages between the main thread and the decoding workers */
2
+ import type { DecodedTile, TextureFormats } from '../wasm/isard.js';
2
3
  import type { DecoderUrls } from './decoders.ts';
3
4
  import type { HeaderRules } from './requests.ts';
4
- import type { DecodedTile, TextureFormats } from './wasm/isard.js';
5
5
  export type WorkerRequest =
6
6
  /** The page's request headers (`setRequestHeaders`) */
7
7
  {
@@ -0,0 +1,3 @@
1
+ /** Messages between the main thread and the decoding workers */
2
+ export {};
3
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/engine/protocol.ts"],"names":[],"mappings":"AAAA,gEAAgE","sourcesContent":["/** Messages between the main thread and the decoding workers */\n\nimport type { DecodedTile, TextureFormats } from '../wasm/isard.js';\nimport type { DecoderUrls } from './decoders.ts';\nimport type { HeaderRules } from './requests.ts';\n\nexport type WorkerRequest =\n /** The page's request headers (`setRequestHeaders`) */\n | { type: 'headers'; rules: HeaderRules }\n | {\n type: 'init';\n module: WebAssembly.Module;\n decoders: DecoderUrls;\n formats: TextureFormats;\n /** URL of the point cloud module (`isard_points_bg.wasm`), loaded with the first COPC chunk */\n points: string;\n }\n | {\n type: 'load';\n id: number;\n url: string;\n transform: Float64Array;\n yUp: boolean;\n reload: boolean;\n priority?: 'high' | 'low';\n }\n | {\n type: 'points';\n id: number;\n url: string;\n offset: number;\n size: number;\n laz: Uint8Array;\n layout: Float64Array;\n grid: Float64Array;\n count: number;\n priority?: 'high' | 'low';\n }\n | { type: 'abort'; id: number };\n\nexport type WorkerReply =\n | { type: 'tile'; id: number; tile: DecodedTile }\n | { type: 'points'; id: number; vertices: Uint8Array<ArrayBuffer> }\n | { type: 'error'; id: number; error: string; aborted: boolean };\n"]}
@@ -11,4 +11,4 @@ export type HeaderRules = [prefix: string, headers: Record<string, string>][];
11
11
  * no headers, stops: `setRequestHeaders('https://data.geopf.fr/private/', { Authorization: 'Bearer …' })`. The
12
12
  * server must allow these headers (CORS). For the whole page: every map, the ones to come too
13
13
  */
14
- export declare function setRequestHeaders(prefix: string, headers?: Record<string, string>): void;
14
+ export declare const setRequestHeaders: (prefix: string, headers?: Record<string, string>) => void;
@@ -11,38 +11,41 @@ const listeners = new Set();
11
11
  * no headers, stops: `setRequestHeaders('https://data.geopf.fr/private/', { Authorization: 'Bearer …' })`. The
12
12
  * server must allow these headers (CORS). For the whole page: every map, the ones to come too
13
13
  */
14
- export function setRequestHeaders(prefix, headers) {
14
+ export const setRequestHeaders = (prefix, headers) => {
15
15
  const kept = rules.filter(([p]) => p !== prefix);
16
16
  if (headers && Object.keys(headers).length > 0)
17
17
  kept.push([prefix, { ...headers }]);
18
18
  kept.sort(([p], [q]) => p.length - q.length);
19
19
  setHeaderRules(kept);
20
- for (const listener of listeners)
20
+ listeners.forEach((listener) => {
21
21
  listener(rules);
22
- }
22
+ });
23
+ };
23
24
  /** @internal The rules now */
24
- export function headerRules() {
25
+ export const headerRules = () => {
25
26
  return rules;
26
- }
27
+ };
27
28
  /** @internal The rules, from the page (a worker's copy) */
28
- export function setHeaderRules(next) {
29
+ export const setHeaderRules = (next) => {
29
30
  rules = next;
30
- }
31
+ };
31
32
  /** @internal Follows the rules (the workers and engines of a map); returns the function that stops */
32
- export function onHeaderRules(listener) {
33
+ export const onHeaderRules = (listener) => {
33
34
  listeners.add(listener);
34
35
  return () => listeners.delete(listener);
35
- }
36
+ };
36
37
  /** @internal `init` with the headers of the rules matching `url` (unchanged when none does) */
37
- export function withHeaders(url, init) {
38
+ export const withHeaders = (url, init = {}) => {
38
39
  const href = String(url);
39
40
  const matching = rules.filter(([prefix]) => href.startsWith(prefix));
40
41
  if (matching.length === 0)
41
- return init ?? {};
42
- const headers = new Headers(init?.headers);
43
- for (const [, set] of matching)
44
- for (const [name, value] of Object.entries(set))
42
+ return init;
43
+ const headers = new Headers(init.headers);
44
+ matching.forEach(([, set]) => {
45
+ Object.entries(set).forEach(([name, value]) => {
45
46
  headers.set(name, value);
46
- return { ...(init ?? {}), headers };
47
- }
47
+ });
48
+ });
49
+ return { ...init, headers };
50
+ };
48
51
  //# sourceMappingURL=requests.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requests.js","sourceRoot":"","sources":["../../src/engine/requests.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,IAAI,KAAK,GAAgB,EAAE,CAAC;AAC5B,MAAM,SAAS,GAAG,IAAI,GAAG,EAAgC,CAAC;AAE1D;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAAc,EAAE,OAAgC,EAAQ,EAAE;IAC1F,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC;IAEjD,IAAI,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC;IACpF,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;IAC7C,cAAc,CAAC,IAAI,CAAC,CAAC;IACrB,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;QAC7B,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,8BAA8B;AAC9B,MAAM,CAAC,MAAM,WAAW,GAAG,GAAgB,EAAE;IAC3C,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,2DAA2D;AAC3D,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,IAAiB,EAAQ,EAAE;IACxD,KAAK,GAAG,IAAI,CAAC;AACf,CAAC,CAAC;AAEF,sGAAsG;AACtG,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,QAAsC,EAAgB,EAAE;IACpF,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAExB,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC1C,CAAC,CAAC;AAEF,+FAA+F;AAC/F,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,GAAiB,EAAE,OAAoB,EAAE,EAAe,EAAE;IACpF,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;IAErE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAE1C,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE;QAC3B,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE;YAC5C,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC3B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC,CAAC","sourcesContent":["/**\n * Headers added to the requests of the page by URL prefix: an access token for private sources (a Géoplateforme\n * private stream, a server behind single sign-on), on every request isard makes, from the page, its workers (vector\n * tiles, 3D Tiles and point clouds) and its engine (raster tiles, tilesets): `setRequestHeaders(prefix, headers)`,\n * again with a new token when it is renewed. The rules of a URL are merged, the longest prefix last (it wins).\n */\n\n/** Rules: a URL prefix and its headers, the shortest prefix first */\nexport type HeaderRules = [prefix: string, headers: Record<string, string>][];\n\nlet rules: HeaderRules = [];\nconst listeners = new Set<(rules: HeaderRules) => void>();\n\n/**\n * Adds `headers` to every request isard makes to a URL starting with `prefix` (in the page and its workers), or with\n * no headers, stops: `setRequestHeaders('https://data.geopf.fr/private/', { Authorization: 'Bearer …' })`. The\n * server must allow these headers (CORS). For the whole page: every map, the ones to come too\n */\nexport const setRequestHeaders = (prefix: string, headers?: Record<string, string>): void => {\n const kept = rules.filter(([p]) => p !== prefix);\n\n if (headers && Object.keys(headers).length > 0) kept.push([prefix, { ...headers }]);\n kept.sort(([p], [q]) => p.length - q.length);\n setHeaderRules(kept);\n listeners.forEach((listener) => {\n listener(rules);\n });\n};\n\n/** @internal The rules now */\nexport const headerRules = (): HeaderRules => {\n return rules;\n};\n\n/** @internal The rules, from the page (a worker's copy) */\nexport const setHeaderRules = (next: HeaderRules): void => {\n rules = next;\n};\n\n/** @internal Follows the rules (the workers and engines of a map); returns the function that stops */\nexport const onHeaderRules = (listener: (rules: HeaderRules) => void): (() => void) => {\n listeners.add(listener);\n\n return () => listeners.delete(listener);\n};\n\n/** @internal `init` with the headers of the rules matching `url` (unchanged when none does) */\nexport const withHeaders = (url: string | URL, init: RequestInit = {}): RequestInit => {\n const href = String(url);\n const matching = rules.filter(([prefix]) => href.startsWith(prefix));\n\n if (matching.length === 0) return init;\n\n const headers = new Headers(init.headers);\n\n matching.forEach(([, set]) => {\n Object.entries(set).forEach(([name, value]) => {\n headers.set(name, value);\n });\n });\n\n return { ...init, headers };\n};\n"]}
@@ -1,4 +1,8 @@
1
- import { TileLoader } from './loader.ts';
1
+ /**
2
+ * The two builds of the engine, downloaded, compiled and instantiated once per page; the decoding workers of 3D Tiles
3
+ * that run the full one; the engine of a destroyed map.
4
+ */
5
+ import { TileLoader } from './engine/loader.ts';
2
6
  import type { GeoMapOptions } from './types.ts';
3
7
  import type { Camera, Engine } from './wasm/isard.js';
4
8
  /** The class of an engine build: its constructor and its static `customMatrix` (custom layers) */
@@ -16,23 +20,23 @@ export type AssetFile = 'isard_bg.wasm' | 'isard_core_bg.wasm' | 'isard_points_b
16
20
  * Where a file of isard is loaded from: its own option, else in the folder `assetsUrl` (the option, or the page's
17
21
  * as `isard/vite` sets it), else next to the module (`import.meta.url`)
18
22
  */
19
- export declare function assetUrl(file: AssetFile, explicit: string | URL | undefined, assetsUrl?: string | URL): string | URL;
23
+ export declare const assetUrl: (file: AssetFile, explicit: string | URL | undefined, assetsUrl?: string | URL) => string | URL;
20
24
  /** Where a build of the engine is loaded from: the option, the assets' folder, or next to the module */
21
- export declare function engineUrl(kind: EngineKind, options: Pick<GeoMapOptions, 'wasmUrl' | 'coreWasmUrl' | 'assetsUrl'>): string | URL;
25
+ export declare const engineUrl: (kind: EngineKind, options: Pick<GeoMapOptions, "wasmUrl" | "coreWasmUrl" | "assetsUrl">) => string | URL;
22
26
  /** A build compiled and instantiated with its bindings (once per page, unless it failed) */
23
- export declare function loadEngine(kind: EngineKind, url: string | URL): Promise<Bindings>;
27
+ export declare const loadEngine: (kind: EngineKind, url: string | URL) => Promise<Bindings>;
24
28
  /** The full engine for a map on the core one, resolved in a task of its own, not in the one that instantiated it:
25
29
  * the map rebuilt on it there, two shorter tasks */
26
- export declare function loadFullEngineLater(url: string | URL): Promise<Bindings>;
30
+ export declare const loadFullEngineLater: (url: string | URL) => Promise<Bindings>;
27
31
  /** Downloads and compiles the full engine when the page is idle, without running it; a failure is left to the first
28
32
  * 3D Tiles layer, which tries again */
29
- export declare function preloadFullEngine(url: string | URL, wanted: () => boolean): void;
33
+ export declare const preloadFullEngine: (url: string | URL, wanted: () => boolean) => void;
30
34
  /** Where the workers load the point cloud module from (`isard_points_bg.wasm`, the LAZ decoder): the option, or next
31
35
  * to the module; absolute, the workers being elsewhere */
32
- export declare function pointsUrl(options: Pick<GeoMapOptions, 'pointsWasmUrl' | 'assetsUrl'>): string;
36
+ export declare const pointsUrl: (options: Pick<GeoMapOptions, "pointsWasmUrl" | "assetsUrl">) => string;
33
37
  /** The decoding workers of 3D Tiles and point clouds, running the full engine's module, unless turned off (`workers:
34
38
  * false` or 0, or no workers in this environment) */
35
- export declare function startTileLoader(module: WebAssembly.Module, options: Pick<GeoMapOptions, 'workers' | 'workerUrl' | 'decoders' | 'pointsWasmUrl' | 'assetsUrl'>, engine: Engine): TileLoader | undefined;
39
+ export declare const startTileLoader: (module: WebAssembly.Module, options: Pick<GeoMapOptions, "workers" | "workerUrl" | "decoders" | "pointsWasmUrl" | "assetsUrl">, engine: Engine) => TileLoader | undefined;
36
40
  /** The engine of a destroyed map: every method a no-op returning undefined, but the camera (the last one) and the
37
41
  * bounds, which late callers read */
38
- export declare function destroyedEngine(camera: Camera): Engine;
42
+ export declare const destroyedEngine: (camera: Camera) => Engine;
@@ -2,9 +2,9 @@
2
2
  * The two builds of the engine, downloaded, compiled and instantiated once per page; the decoding workers of 3D Tiles
3
3
  * that run the full one; the engine of a destroyed map.
4
4
  */
5
- import { DEFAULT_DECODERS } from "./decoders.js";
6
- import { TileLoader } from "./loader.js";
7
- import { defaultWorkerCount } from "./vectortiles.js";
5
+ import { defaultWorkerCount } from "./basemap/vectortiles.js";
6
+ import { DEFAULT_DECODERS } from "./engine/decoders.js";
7
+ import { TileLoader } from "./engine/loader.js";
8
8
  /** The two builds of the engine, each compiled once per page: `core` without 3D Tiles (a third smaller), loaded by
9
9
  * every map; `full` with them, loaded for the first 3D Tiles layer, its module shared with the decoding workers. The
10
10
  * core engine has the same API but the 3D Tiles methods: its class is typed as the full one. */
@@ -13,22 +13,22 @@ const engines = {};
13
13
  * compiles the full engine ahead, its first 3D Tiles layer then only instantiates it */
14
14
  const modules = {};
15
15
  /** @internal Forgets the engines loaded (tests) */
16
- export function forgetEngines() {
17
- for (const kind of ['core', 'full']) {
16
+ export const forgetEngines = () => {
17
+ ['core', 'full'].forEach((kind) => {
18
18
  delete engines[kind];
19
19
  delete modules[kind];
20
- }
21
- }
20
+ });
21
+ };
22
22
  /** The folder the assets are served from for the whole page, as `isard/vite` sets it; undefined: next to the module */
23
- function pageAssets() {
24
- const url = globalThis.isardAssetsUrl;
23
+ const pageAssets = () => {
24
+ const url = Reflect.get(globalThis, 'isardAssetsUrl');
25
25
  return typeof url === 'string' ? url : undefined;
26
- }
26
+ };
27
27
  /**
28
28
  * Where a file of isard is loaded from: its own option, else in the folder `assetsUrl` (the option, or the page's
29
29
  * as `isard/vite` sets it), else next to the module (`import.meta.url`)
30
30
  */
31
- export function assetUrl(file, explicit, assetsUrl) {
31
+ export const assetUrl = (file, explicit, assetsUrl) => {
32
32
  if (explicit)
33
33
  return explicit;
34
34
  const folder = assetsUrl ?? pageAssets();
@@ -49,15 +49,15 @@ export function assetUrl(file, explicit, assetsUrl) {
49
49
  default:
50
50
  return new URL('./basemap.worker.js', import.meta.url);
51
51
  }
52
- }
52
+ };
53
53
  /** Where a build of the engine is loaded from: the option, the assets' folder, or next to the module */
54
- export function engineUrl(kind, options) {
54
+ export const engineUrl = (kind, options) => {
55
55
  return kind === 'full'
56
56
  ? assetUrl('isard_bg.wasm', options.wasmUrl, options.assetsUrl)
57
57
  : assetUrl('isard_core_bg.wasm', options.coreWasmUrl, options.assetsUrl);
58
- }
58
+ };
59
59
  /** Downloads and compiles a build (once per page, unless it failed: a later call tries again) */
60
- function compileEngine(kind, url) {
60
+ const compileEngine = (kind, url) => {
61
61
  const compiled = modules[kind];
62
62
  if (compiled)
63
63
  return compiled;
@@ -68,9 +68,9 @@ function compileEngine(kind, url) {
68
68
  });
69
69
  modules[kind] = compiling;
70
70
  return compiling;
71
- }
71
+ };
72
72
  /** A build compiled and instantiated with its bindings (once per page, unless it failed) */
73
- export function loadEngine(kind, url) {
73
+ export const loadEngine = (kind, url) => {
74
74
  const loaded = engines[kind];
75
75
  if (loaded)
76
76
  return loaded;
@@ -88,15 +88,15 @@ export function loadEngine(kind, url) {
88
88
  });
89
89
  engines[kind] = loading;
90
90
  return loading;
91
- }
91
+ };
92
92
  /** The full engine for a map on the core one, resolved in a task of its own, not in the one that instantiated it:
93
93
  * the map rebuilt on it there, two shorter tasks */
94
- export function loadFullEngineLater(url) {
94
+ export const loadFullEngineLater = (url) => {
95
95
  return loadEngine('full', url).then((bindings) => new Promise((resolve) => setTimeout(() => resolve(bindings), 0)));
96
- }
96
+ };
97
97
  /** Downloads and compiles the full engine when the page is idle, without running it; a failure is left to the first
98
98
  * 3D Tiles layer, which tries again */
99
- export function preloadFullEngine(url, wanted) {
99
+ export const preloadFullEngine = (url, wanted) => {
100
100
  const start = () => {
101
101
  if (wanted())
102
102
  compileEngine('full', url).catch(() => undefined);
@@ -105,8 +105,8 @@ export function preloadFullEngine(url, wanted) {
105
105
  requestIdleCallback(start, { timeout: 2000 });
106
106
  else
107
107
  setTimeout(start, 0);
108
- }
109
- async function compile(url) {
108
+ };
109
+ const compile = async (url) => {
110
110
  const response = await fetch(url);
111
111
  if (!response.ok)
112
112
  throw new Error(`isard: failed to load the engine from ${url}: ${response.status}`);
@@ -117,26 +117,26 @@ async function compile(url) {
117
117
  // Servers that do not send application/wasm
118
118
  return WebAssembly.compile(await response.arrayBuffer());
119
119
  }
120
- }
120
+ };
121
121
  /** Where the workers load the point cloud module from (`isard_points_bg.wasm`, the LAZ decoder): the option, or next
122
122
  * to the module; absolute, the workers being elsewhere */
123
- export function pointsUrl(options) {
123
+ export const pointsUrl = (options) => {
124
124
  const url = assetUrl('isard_points_bg.wasm', options.pointsWasmUrl, options.assetsUrl);
125
125
  const base = typeof document === 'undefined' ? undefined : document.baseURI;
126
126
  return base ? new URL(url, base).href : String(url);
127
- }
127
+ };
128
128
  /** The decoding workers of 3D Tiles and point clouds, running the full engine's module, unless turned off (`workers:
129
129
  * false` or 0, or no workers in this environment) */
130
- export function startTileLoader(module, options, engine) {
130
+ export const startTileLoader = (module, options, engine) => {
131
131
  const { workers: count, workerUrl, decoders } = options;
132
132
  const workers = count ?? defaultWorkerCount();
133
133
  if (workers === false || workers <= 0 || typeof Worker === 'undefined')
134
134
  return undefined;
135
135
  return new TileLoader(module, assetUrl('decoder.worker.js', workerUrl, options.assetsUrl), workers, { ...DEFAULT_DECODERS, ...decoders }, engine.textureFormats(), pointsUrl(options));
136
- }
136
+ };
137
137
  /** The engine of a destroyed map: every method a no-op returning undefined, but the camera (the last one) and the
138
138
  * bounds, which late callers read */
139
- export function destroyedEngine(camera) {
139
+ export const destroyedEngine = (camera) => {
140
140
  return new Proxy({}, {
141
141
  get: (_, name) => {
142
142
  if (name === 'camera')
@@ -146,5 +146,5 @@ export function destroyedEngine(camera) {
146
146
  return () => undefined;
147
147
  },
148
148
  });
149
- }
149
+ };
150
150
  //# sourceMappingURL=engine-loader.js.map