isard 1.7.0 → 1.9.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 (229) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/dist/basemap/grid.js +2 -5
  3. package/dist/basemap/grid.js.map +1 -1
  4. package/dist/basemap/models/furniture.d.ts +12 -0
  5. package/dist/basemap/{furniture.js → models/furniture.js} +6 -8
  6. package/dist/basemap/models/furniture.js.map +1 -0
  7. package/dist/basemap/{meshes.js → models/meshes.js} +1 -1
  8. package/dist/basemap/models/meshes.js.map +1 -0
  9. package/dist/basemap/models/trees.d.ts +21 -0
  10. package/dist/basemap/{trees.js → models/trees.js} +4 -36
  11. package/dist/basemap/models/trees.js.map +1 -0
  12. package/dist/basemap/placed.d.ts +2 -0
  13. package/dist/basemap/placed.js +2 -0
  14. package/dist/basemap/placed.js.map +1 -1
  15. package/dist/basemap/pmtiles.js +4 -3
  16. package/dist/basemap/pmtiles.js.map +1 -1
  17. package/dist/basemap/pmtileslayer.d.ts +4 -4
  18. package/dist/basemap/pmtileslayer.js +2 -1
  19. package/dist/basemap/pmtileslayer.js.map +1 -1
  20. package/dist/basemap/resample.js +3 -2
  21. package/dist/basemap/resample.js.map +1 -1
  22. package/dist/basemap/terrain.d.ts +5 -0
  23. package/dist/basemap/terrain.js +6 -4
  24. package/dist/basemap/terrain.js.map +1 -1
  25. package/dist/basemap/vectortiles/context.d.ts +3 -2
  26. package/dist/basemap/vectortiles/context.js.map +1 -1
  27. package/dist/basemap/vectortiles/extrusions.js.map +1 -1
  28. package/dist/basemap/vectortiles/furniture.d.ts +3 -3
  29. package/dist/basemap/vectortiles/furniture.js +2 -1
  30. package/dist/basemap/vectortiles/furniture.js.map +1 -1
  31. package/dist/basemap/vectortiles/labels.js +2 -1
  32. package/dist/basemap/vectortiles/labels.js.map +1 -1
  33. package/dist/basemap/vectortiles/lamps.d.ts +3 -3
  34. package/dist/basemap/vectortiles/lamps.js +1 -1
  35. package/dist/basemap/vectortiles/lamps.js.map +1 -1
  36. package/dist/basemap/vectortiles/placed.d.ts +3 -2
  37. package/dist/basemap/vectortiles/placed.js +5 -10
  38. package/dist/basemap/vectortiles/placed.js.map +1 -1
  39. package/dist/basemap/vectortiles/street-wind.js +2 -2
  40. package/dist/basemap/vectortiles/street-wind.js.map +1 -1
  41. package/dist/basemap/vectortiles/style.js +7 -8
  42. package/dist/basemap/vectortiles/style.js.map +1 -1
  43. package/dist/basemap/vectortiles/tiles.d.ts +1 -3
  44. package/dist/basemap/vectortiles/tiles.js +1 -1
  45. package/dist/basemap/vectortiles/tiles.js.map +1 -1
  46. package/dist/basemap/vectortiles/trees.d.ts +4 -4
  47. package/dist/basemap/vectortiles/trees.js +2 -1
  48. package/dist/basemap/vectortiles/trees.js.map +1 -1
  49. package/dist/basemap/vectortiles/vectors.d.ts +2 -3
  50. package/dist/basemap/vectortiles/vectors.js.map +1 -1
  51. package/dist/basemap/vectortiles.d.ts +6 -5
  52. package/dist/basemap/vectortiles.js +4 -3
  53. package/dist/basemap/vectortiles.js.map +1 -1
  54. package/dist/basemap/wmts.js +3 -4
  55. package/dist/basemap/wmts.js.map +1 -1
  56. package/dist/basemap/{trees.d.ts → woods.d.ts} +2 -19
  57. package/dist/basemap/woods.js +38 -0
  58. package/dist/basemap/woods.js.map +1 -0
  59. package/dist/basemap/workerpool.d.ts +1 -1
  60. package/dist/basemap/workerpool.js +3 -3
  61. package/dist/basemap/workerpool.js.map +1 -1
  62. package/dist/basemap.worker.js +2 -2
  63. package/dist/basemap.worker.js.map +23 -22
  64. package/dist/bind/layers.d.ts +10 -3
  65. package/dist/bind/layers.js +11 -4
  66. package/dist/bind/layers.js.map +1 -1
  67. package/dist/data/collada.js +4 -4
  68. package/dist/data/collada.js.map +1 -1
  69. package/dist/data/ifc.js +6 -11
  70. package/dist/data/ifc.js.map +1 -1
  71. package/dist/decoder.worker.js +5 -5
  72. package/dist/decoder.worker.js.map +7 -6
  73. package/dist/decoding/decoders.js.map +1 -0
  74. package/dist/{engine → decoding}/loader.js +2 -2
  75. package/dist/decoding/loader.js.map +1 -0
  76. package/dist/{engine → decoding}/protocol.d.ts +1 -1
  77. package/dist/decoding/protocol.js.map +1 -0
  78. package/dist/engine-loader.d.ts +1 -1
  79. package/dist/engine-loader.js +3 -2
  80. package/dist/engine-loader.js.map +1 -1
  81. package/dist/geoplateforme.d.ts +4 -3
  82. package/dist/geoplateforme.js +8 -10
  83. package/dist/geoplateforme.js.map +1 -1
  84. package/dist/index.d.ts +16 -8
  85. package/dist/index.js +9 -3
  86. package/dist/index.js.map +1 -1
  87. package/dist/isard_bg.wasm +0 -0
  88. package/dist/isard_core_bg.wasm +0 -0
  89. package/dist/isard_grid_bg.wasm +0 -0
  90. package/dist/isard_tess_bg.wasm +0 -0
  91. package/dist/layers/custom.d.ts +56 -0
  92. package/dist/layers/custom.js +93 -0
  93. package/dist/layers/custom.js.map +1 -0
  94. package/dist/layers/extrusions.d.ts +4 -2
  95. package/dist/layers/extrusions.js +2 -1
  96. package/dist/layers/extrusions.js.map +1 -1
  97. package/dist/layers/features.d.ts +3 -14
  98. package/dist/layers/features.js +4 -25
  99. package/dist/layers/features.js.map +1 -1
  100. package/dist/layers/flow.d.ts +3 -3
  101. package/dist/layers/flow.js +3 -4
  102. package/dist/layers/flow.js.map +1 -1
  103. package/dist/layers/glyphs.js +5 -3
  104. package/dist/layers/glyphs.js.map +1 -1
  105. package/dist/layers/ground.d.ts +57 -0
  106. package/dist/layers/ground.js +78 -0
  107. package/dist/layers/ground.js.map +1 -0
  108. package/dist/layers/icons.js +8 -6
  109. package/dist/layers/icons.js.map +1 -1
  110. package/dist/layers/layers.d.ts +2 -199
  111. package/dist/layers/layers.js +2 -469
  112. package/dist/layers/layers.js.map +1 -1
  113. package/dist/layers/models.d.ts +48 -0
  114. package/dist/layers/models.js +111 -0
  115. package/dist/layers/models.js.map +1 -0
  116. package/dist/layers/network.d.ts +26 -0
  117. package/dist/layers/network.js +127 -0
  118. package/dist/layers/network.js.map +1 -0
  119. package/dist/layers/panoramas.d.ts +2 -11
  120. package/dist/layers/panoramas.js +19 -9
  121. package/dist/layers/panoramas.js.map +1 -1
  122. package/dist/layers/photos.d.ts +4 -7
  123. package/dist/layers/photos.js +3 -4
  124. package/dist/layers/photos.js.map +1 -1
  125. package/dist/layers/pointclouds.d.ts +3 -2
  126. package/dist/layers/pointclouds.js +3 -3
  127. package/dist/layers/pointclouds.js.map +1 -1
  128. package/dist/layers/raster.d.ts +9 -0
  129. package/dist/layers/raster.js +24 -0
  130. package/dist/layers/raster.js.map +1 -0
  131. package/dist/layers/symbols.d.ts +2 -2
  132. package/dist/layers/symbols.js +2 -1
  133. package/dist/layers/symbols.js.map +1 -1
  134. package/dist/layers/tiles3d.d.ts +15 -0
  135. package/dist/layers/tiles3d.js +55 -0
  136. package/dist/layers/tiles3d.js.map +1 -0
  137. package/dist/layers/trees.d.ts +5 -7
  138. package/dist/layers/trees.js +2 -1
  139. package/dist/layers/trees.js.map +1 -1
  140. package/dist/layers/vectors.js.map +1 -1
  141. package/dist/map/basemap-layers.js +1 -1
  142. package/dist/map/basemap-layers.js.map +1 -1
  143. package/dist/map/engine-settings.d.ts +1 -1
  144. package/dist/map/engine-settings.js +1 -1
  145. package/dist/map/engine-settings.js.map +1 -1
  146. package/dist/map/engines.js.map +1 -1
  147. package/dist/map/layer-spec.d.ts +7 -13
  148. package/dist/map/layer-spec.js.map +1 -1
  149. package/dist/map/workers.js +3 -4
  150. package/dist/map/workers.js.map +1 -1
  151. package/dist/map.d.ts +15 -58
  152. package/dist/map.js +39 -52
  153. package/dist/map.js.map +1 -1
  154. package/dist/panoramax.d.ts +15 -2
  155. package/dist/panoramax.js +38 -21
  156. package/dist/panoramax.js.map +1 -1
  157. package/dist/react/CustomLayer.d.ts +1 -1
  158. package/dist/react/CustomLayer.js +5 -4
  159. package/dist/react/CustomLayer.js.map +1 -1
  160. package/dist/react/Layer.d.ts +6 -2
  161. package/dist/react/Layer.js +6 -5
  162. package/dist/react/Layer.js.map +1 -1
  163. package/dist/react/VectorGeometry.js +5 -4
  164. package/dist/react/VectorGeometry.js.map +1 -1
  165. package/dist/react/VectorTiles.d.ts +2 -2
  166. package/dist/react/VectorTiles.js +1 -1
  167. package/dist/react/VectorTiles.js.map +1 -1
  168. package/dist/react/context.d.ts +3 -0
  169. package/dist/react/context.js +8 -1
  170. package/dist/react/context.js.map +1 -1
  171. package/dist/types.d.ts +14 -4
  172. package/dist/types.js.map +1 -1
  173. package/dist/ui/controls.js +2 -1
  174. package/dist/ui/controls.js.map +1 -1
  175. package/dist/ui/interaction.js +6 -5
  176. package/dist/ui/interaction.js.map +1 -1
  177. package/dist/ui/minimap.js +1 -1
  178. package/dist/ui/minimap.js.map +1 -1
  179. package/dist/ui/overlay.js +3 -3
  180. package/dist/ui/overlay.js.map +1 -1
  181. package/dist/ui/search.js +1 -1
  182. package/dist/ui/search.js.map +1 -1
  183. package/dist/util/animation.js +3 -2
  184. package/dist/util/animation.js.map +1 -1
  185. package/dist/util/color.d.ts +10 -0
  186. package/dist/util/color.js +29 -9
  187. package/dist/util/color.js.map +1 -1
  188. package/dist/util/fetch.d.ts +5 -0
  189. package/dist/util/fetch.js +11 -0
  190. package/dist/util/fetch.js.map +1 -0
  191. package/dist/util/geo.d.ts +5 -0
  192. package/dist/util/geo.js +8 -2
  193. package/dist/util/geo.js.map +1 -1
  194. package/dist/util/math.d.ts +3 -0
  195. package/dist/util/math.js +4 -0
  196. package/dist/util/math.js.map +1 -0
  197. package/dist/util/requests.js.map +1 -0
  198. package/dist/util/roofs.d.ts +0 -2
  199. package/dist/util/roofs.js +0 -3
  200. package/dist/util/roofs.js.map +1 -1
  201. package/dist/wasm/isard.js +1 -1
  202. package/dist/wasm/isard_core.js +1 -1
  203. package/dist/workers/basemap/geometry.d.ts +9 -19
  204. package/dist/workers/{basemap.worker.d.ts → basemap/protocol.d.ts} +29 -23
  205. package/dist/workers/basemap/street.d.ts +4 -2
  206. package/dist/workers/basemap/tiles.d.ts +1 -3
  207. package/dist/workers/basemap/trees.d.ts +2 -2
  208. package/package.json +1 -1
  209. package/dist/basemap/furniture.d.ts +0 -26
  210. package/dist/basemap/furniture.js.map +0 -1
  211. package/dist/basemap/meshes.js.map +0 -1
  212. package/dist/basemap/trees.js.map +0 -1
  213. package/dist/engine/decoders.js.map +0 -1
  214. package/dist/engine/loader.js.map +0 -1
  215. package/dist/engine/protocol.js.map +0 -1
  216. package/dist/engine/requests.js.map +0 -1
  217. package/dist/workers/basemap/furniture.d.ts +0 -13
  218. package/dist/workers/basemap/labels.d.ts +0 -24
  219. package/dist/workers/basemap/lamps.d.ts +0 -10
  220. package/dist/workers/basemap/raster.d.ts +0 -10
  221. package/dist/workers/basemap.worker.js +0 -221
  222. package/dist/workers/basemap.worker.js.map +0 -1
  223. /package/dist/basemap/{meshes.d.ts → models/meshes.d.ts} +0 -0
  224. /package/dist/{engine → decoding}/decoders.d.ts +0 -0
  225. /package/dist/{engine → decoding}/decoders.js +0 -0
  226. /package/dist/{engine → decoding}/loader.d.ts +0 -0
  227. /package/dist/{engine → decoding}/protocol.js +0 -0
  228. /package/dist/{engine → util}/requests.d.ts +0 -0
  229. /package/dist/{engine → util}/requests.js +0 -0
@@ -3,7 +3,8 @@
3
3
  * and latitudes, m/s), their trails drawn on the globe and the relief and animated, colored by speed: wind maps,
4
4
  * currents. The engine moves them (`stepFlow`), one step per animation frame while the layer plays.
5
5
  */
6
- import { parseColor } from "./features.js";
6
+ import { parseColor } from "../util/color.js";
7
+ import { fetchOk } from "../util/fetch.js";
7
8
  import { Layer } from "./layers.js";
8
9
  /** Wind speeds (m/s) from calm to storm */
9
10
  const COLORS = [
@@ -231,9 +232,7 @@ export const flowFieldFromImage = async (url, options, init) => {
231
232
  * read as `flowFieldFromImage` reads one
232
233
  */
233
234
  export const flowFieldsFromImage = async (url, options, init) => {
234
- const response = await fetch(url, init);
235
- if (!response.ok)
236
- throw new Error(`isard: ${String(url)}: ${response.status}`);
235
+ const response = await fetchOk(url, init);
237
236
  const bitmap = await createImageBitmap(await response.blob(), { colorSpaceConversion: 'none' });
238
237
  const { width, height } = bitmap;
239
238
  const canvas = new OffscreenCanvas(width, height);
@@ -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 /** 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"]}
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, Placement } from '../types.ts';\nimport { parseColor, type Ramp } from '../util/color.ts';\nimport { fetchOk } from '../util/fetch.ts';\nimport type { Engine } from '../wasm/isard.js';\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>, Placement {\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}\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 fetchOk(url, init);\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"]}
@@ -8,7 +8,9 @@
8
8
  * runs out. A glyph's atlas row counts the rows of the pages before its own (`y + page × size`, the pages stacked):
9
9
  * the coordinates of the glyphs placed so far stay valid as the atlas grows.
10
10
  */
11
- import { withHeaders } from "../engine/requests.js";
11
+ import { httpError } from "../util/fetch.js";
12
+ import { clamp } from "../util/math.js";
13
+ import { withHeaders } from "../util/requests.js";
12
14
  /** OpenFreeMap's fonts, those of its styles (Noto Sans Regular, Bold, Italic) */
13
15
  export const GLYPHS_URL = 'https://tiles.openfreemap.org/fonts/{fontstack}/{range}.pbf';
14
16
  /** The font of labels that name none */
@@ -143,7 +145,7 @@ export class Glyphs {
143
145
  /** `maxSize`: the GPU's texture size limit if known (the pages are at most 2048 × 2048) */
144
146
  constructor(url = GLYPHS_URL, maxSize = 4096) {
145
147
  this.url = url;
146
- this.maxSize = Math.max(512, Math.min(PAGE_MAX, maxSize));
148
+ this.maxSize = clamp(maxSize, 512, PAGE_MAX);
147
149
  }
148
150
  /** Sends the whole atlas to an engine (a new one after a context loss) */
149
151
  attach(engine) {
@@ -182,7 +184,7 @@ export class Glyphs {
182
184
  .replace('{fontstack}', encodeURIComponent(font))
183
185
  .replace('{range}', `${start}-${start + 255}`);
184
186
  const pending = fetch(url, withHeaders(url))
185
- .then((r) => (r.ok ? r.arrayBuffer() : Promise.reject(new Error(`${url}: ${r.status}`))))
187
+ .then((r) => (r.ok ? r.arrayBuffer() : Promise.reject(httpError(url, r.status))))
186
188
  .then((buffer) => {
187
189
  parse(buffer).forEach(({ glyph, bitmap }, id) => {
188
190
  if (glyph.width > 0 && bitmap.length >= (glyph.width + 2 * BUFFER) * (glyph.height + 2 * BUFFER)) {
@@ -1 +1 @@
1
- {"version":3,"file":"glyphs.js","sourceRoot":"","sources":["../../src/layers/glyphs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Glyphs for the symbol layers: signed distance fields in MapLibre's glyph format (ranges of 256 code points per\n * protobuf file, 24 px glyphs with a 3 px buffer), loaded on first use (from OpenFreeMap's fonts by default, a vector\n * basemap's labels from the glyphs of its style), packed into an atlas the engine samples; and the shaping of a label:\n * its lines (explicit and wrapped), their glyphs placed around the anchor.\n *\n * The atlas has pages of one size: the first one grows up to the page size limit, then pages are added, so it never\n * runs out. A glyph's atlas row counts the rows of the pages before its own (`y + page × size`, the pages stacked):\n * the coordinates of the glyphs placed so far stay valid as the atlas grows.\n */\n\nimport { withHeaders } from '../engine/requests.ts';\nimport type { Anchor } from '../ui/overlay.ts';\nimport type { Engine } from '../wasm/isard.js';\n\n/** OpenFreeMap's fonts, those of its styles (Noto Sans Regular, Bold, Italic) */\nexport const GLYPHS_URL = 'https://tiles.openfreemap.org/fonts/{fontstack}/{range}.pbf';\n\n/** The font of labels that name none */\nexport const DEFAULT_FONT = 'Noto Sans Regular';\n\n/** Size the glyphs are drawn at in the files, and their buffer */\nconst EM = 24;\nconst BUFFER = 3;\n\nexport interface Glyph {\n width: number;\n height: number;\n left: number;\n top: number;\n advance: number;\n /**\n * Place of its bitmap ((width + 6) × (height + 6)) in the atlas, `y` counting the rows of the pages before its\n * own; undefined for an empty one (a space)\n */\n x?: number;\n y?: number;\n /** Its page of the atlas */\n page?: number;\n}\n\n/** Largest side of a page of the atlas, and most pages (WebGL2 guarantees 256 layers of a texture array) */\nconst PAGE_MAX = 2048;\nconst MAX_PAGES = 256;\n\n/** A protobuf reader, enough for the glyph files */\nclass Reader {\n pos = 0;\n constructor(private readonly buf: Uint8Array) {}\n get done(): boolean {\n return this.pos >= this.buf.length;\n }\n varint(): number {\n let value = 0;\n let shift = 0;\n\n for (;;) {\n const b = this.buf[this.pos++] ?? 0;\n\n value += (b & 0x7f) * 2 ** shift;\n if (b < 0x80) return value;\n shift += 7;\n }\n }\n sint(): number {\n const v = this.varint();\n\n return v % 2 === 1 ? -(v + 1) / 2 : v / 2;\n }\n bytes(): Uint8Array {\n const n = this.varint();\n const out = this.buf.subarray(this.pos, this.pos + n);\n\n this.pos += n;\n\n return out;\n }\n skip(wire: number): void {\n if (wire === 0) this.varint();\n else if (wire === 2) this.pos += this.varint();\n else if (wire === 5) this.pos += 4;\n else if (wire === 1) this.pos += 8;\n }\n}\n\n/** Glyphs of a range file: id → metrics and bitmap */\nconst parse = (buffer: ArrayBuffer): Map<number, { glyph: Glyph; bitmap: Uint8Array }> => {\n const out = new Map<number, { glyph: Glyph; bitmap: Uint8Array }>();\n const root = new Reader(new Uint8Array(buffer));\n\n while (!root.done) {\n const tag = root.varint();\n\n if (tag >> 3 !== 1) {\n root.skip(tag & 7);\n continue;\n }\n\n // A fontstack\n const stack = new Reader(root.bytes());\n\n while (!stack.done) {\n const t = stack.varint();\n\n if (t >> 3 !== 3) {\n stack.skip(t & 7);\n continue;\n }\n\n const g = new Reader(stack.bytes());\n let id = 0;\n let bitmap: Uint8Array = new Uint8Array(0);\n const glyph: Glyph = { width: 0, height: 0, left: 0, top: 0, advance: 0 };\n\n while (!g.done) {\n const f = g.varint();\n\n switch (f >> 3) {\n case 1:\n id = g.varint();\n break;\n case 2:\n bitmap = g.bytes();\n break;\n case 3:\n glyph.width = g.varint();\n break;\n case 4:\n glyph.height = g.varint();\n break;\n case 5:\n glyph.left = g.sint();\n break;\n case 6:\n glyph.top = g.sint();\n break;\n case 7:\n glyph.advance = g.varint();\n break;\n default:\n g.skip(f & 7);\n }\n }\n out.set(id, { glyph, bitmap });\n }\n }\n\n return out;\n};\n\n/** A shelf of the packer: its page, y, height, and the x of the next free place */\ninterface Shelf {\n page: number;\n y: number;\n height: number;\n x: number;\n}\n\n/** The glyphs of a map and their atlas */\nexport class Glyphs {\n /** Side of the pages */\n private size = 512;\n private pages: Uint8Array[] = [new Uint8Array(512 * 512)];\n /** Pages allocated in the engine (doubled when more are needed: fewer reallocations) */\n private capacity = 1;\n private shelves: Shelf[] = [];\n /** Rows of each page holding glyphs (from its top): the rest is blank, never sent */\n private readonly used: number[] = [0];\n private readonly fonts = new Map<string, Map<number, Glyph>>();\n private readonly ranges = new Map<string, Promise<void>>();\n /** Glyph URLs of fonts other than the map's (those of a vector basemap's style) */\n private readonly sources = new Map<string, string>();\n private engine: Engine | undefined;\n /** Rows of each page changed since the last upload: first, end */\n private readonly dirty = new Map<number, [number, number]>();\n /** The atlas has its most pages: new glyphs stay blank */\n private full = false;\n /** Largest side of a page */\n private readonly maxSize: number;\n /** Bumped each time glyphs are added: labels shaped while some of theirs were missing are shaped again */\n version = 0;\n\n /** `maxSize`: the GPU's texture size limit if known (the pages are at most 2048 × 2048) */\n constructor(\n private readonly url = GLYPHS_URL,\n maxSize = 4096,\n ) {\n this.maxSize = Math.max(512, Math.min(PAGE_MAX, maxSize));\n }\n\n /** Sends the whole atlas to an engine (a new one after a context loss) */\n attach(engine: Engine): void {\n this.engine = engine;\n this.dirty.clear();\n this.upload();\n }\n\n /** Side of the pages of the atlas */\n get atlasSize(): number {\n return this.size;\n }\n\n get pageCount(): number {\n return this.pages.length;\n }\n\n /** Loads these fonts from another glyph URL (a style's `glyphs`); a font keeps the first URL given for it */\n register(url: string, fonts: Iterable<string>): void {\n [...fonts].forEach((font) => {\n if (!this.sources.has(font)) this.sources.set(font, url);\n });\n }\n\n /** Loads the glyphs of these code points in a font */\n async load(font: string, codes: Iterable<number>): Promise<Map<number, Glyph>> {\n const glyphs = this.fonts.get(font) ?? new Map<number, Glyph>();\n\n this.fonts.set(font, glyphs);\n\n const starts = new Set([...codes].filter((code) => !glyphs.has(code)).map((code) => Math.floor(code / 256) * 256));\n\n await Promise.all([...starts].map((start) => this.range(font, start, glyphs)));\n\n return glyphs;\n }\n\n private range(font: string, start: number, glyphs: Map<number, Glyph>): Promise<void> {\n const key = `${font}/${start}`;\n const cached = this.ranges.get(key);\n\n if (cached) return cached;\n\n const url = (this.sources.get(font) ?? this.url)\n .replace('{fontstack}', encodeURIComponent(font))\n .replace('{range}', `${start}-${start + 255}`);\n const pending = fetch(url, withHeaders(url))\n .then((r) => (r.ok ? r.arrayBuffer() : Promise.reject(new Error(`${url}: ${r.status}`))))\n .then((buffer) => {\n parse(buffer).forEach(({ glyph, bitmap }, id) => {\n if (glyph.width > 0 && bitmap.length >= (glyph.width + 2 * BUFFER) * (glyph.height + 2 * BUFFER)) {\n this.pack(glyph, bitmap);\n }\n glyphs.set(id, glyph);\n });\n this.version += 1;\n // One upload for the range\n this.flush();\n })\n .catch((error: unknown) => {\n // A missing range is not retried this session; its characters stay blank\n console.warn('isard: glyphs', error);\n });\n\n this.ranges.set(key, pending);\n\n return pending;\n }\n\n /**\n * Allocates the pages in the engine and sends what they hold (their rows with glyphs). The engine allocates its\n * pages again empty: everything is sent each time, the pages doubled to make it rare\n */\n private upload(): void {\n const engine = this.engine;\n\n if (!engine) return;\n engine.setGlyphPages(this.size, this.size, this.capacity);\n this.pages.forEach((page, i) => {\n const rows = this.used[i] ?? 0;\n\n if (rows > 0) engine.updateGlyphPage(i, 0, 0, this.size, rows, page.subarray(0, rows * this.size));\n });\n }\n\n /** Sends the rows changed since the last upload to the engine */\n private flush(): void {\n this.dirty.forEach(([y0, y1], page) => {\n const data = this.pages[page];\n\n if (data)\n this.engine?.updateGlyphPage(page, 0, y0, this.size, y1 - y0, data.subarray(y0 * this.size, y1 * this.size));\n });\n this.dirty.clear();\n }\n\n /**\n * Places a bitmap in the atlas (growing the first page, then adding pages when full); `flush` sends it to the\n * engine\n */\n private pack(glyph: Glyph, bitmap: Uint8Array): void {\n const w = glyph.width + 2 * BUFFER;\n const h = glyph.height + 2 * BUFFER;\n // One texel of padding between bitmaps: linear filtering never reads a neighbour\n let shelf = this.shelves.find((s) => s.height >= h && s.height <= h + 4 && s.x + w + 1 <= this.size);\n\n if (!shelf) {\n const page = this.pages.length - 1;\n // New shelves go on the last page only: the last shelf is on it, unless the page is new\n const last = this.shelves.at(-1);\n const y = last && last.page === page ? last.y + last.height + 1 : 0;\n\n if (y + h > this.size) {\n if (this.pages.length === 1 && this.size * 2 <= this.maxSize) this.grow();\n else if (this.pages.length < MAX_PAGES) this.addPage();\n else {\n // Full: the glyph takes its room in the text but is not drawn\n if (!this.full) console.warn(`isard: the glyph atlas is full (${MAX_PAGES} pages)`);\n this.full = true;\n\n return;\n }\n this.pack(glyph, bitmap);\n\n return;\n }\n shelf = { page, y, height: h, x: 0 };\n this.shelves.push(shelf);\n }\n\n const data = this.pages[shelf.page];\n\n if (!data) return;\n glyph.x = shelf.x;\n glyph.y = shelf.page * this.size + shelf.y;\n glyph.page = shelf.page;\n shelf.x += w + 1;\n for (let row = 0; row < h; row += 1) {\n data.set(bitmap.subarray(row * w, row * w + w), (shelf.y + row) * this.size + glyph.x);\n }\n this.used[shelf.page] = Math.max(this.used[shelf.page] ?? 0, shelf.y + h);\n\n const dirty = this.dirty.get(shelf.page);\n\n this.dirty.set(shelf.page, [Math.min(dirty?.[0] ?? shelf.y, shelf.y), Math.max(dirty?.[1] ?? 0, shelf.y + h)]);\n }\n\n /** Doubles the only page; the glyphs keep their places (texel coordinates) */\n private grow(): void {\n const size = this.size * 2;\n const old = this.pages[0] ?? new Uint8Array(this.size * this.size);\n const page = new Uint8Array(size * size);\n\n for (let row = 0; row < this.size; row += 1) {\n page.set(old.subarray(row * this.size, (row + 1) * this.size), row * size);\n }\n this.size = size;\n this.pages = [page];\n // The whole atlas is sent with what it holds so far\n this.dirty.clear();\n this.upload();\n }\n\n /** A new empty page, after the others; the engine's pages are allocated again only past its capacity */\n private addPage(): void {\n this.pages.push(new Uint8Array(this.size * this.size));\n this.used.push(0);\n if (this.pages.length > this.capacity) {\n this.capacity = Math.min(MAX_PAGES, this.capacity * 2);\n // The pages are allocated again: everything is sent, pending changes included\n this.dirty.clear();\n this.upload();\n }\n }\n}\n\n/** A run of text with its own scale (MapLibre's `format` with `font-scale`) and font */\nexport interface TextPart {\n text: string;\n scale?: number;\n font?: string;\n}\n\nexport type { Anchor } from '../ui/overlay.ts';\n\nexport interface Shaping {\n /** Glyph quads: x, y, width, height (CSS pixels from the anchor), atlas u0, v0, u1, v1, font scale */\n quads: number[][];\n /** Ink box from the anchor: min x, min y, max x, max y */\n box: [number, number, number, number];\n /** Layout box from the anchor, what an icon fitted to the text frames: the advances of its widest line across, its\n * lines' height (`lineHeight` each) down, centered on the ink */\n layout: [number, number, number, number];\n}\n\n/** Code points of a text, for loading */\nexport const codes = (parts: readonly TextPart[]): Set<number> => {\n return new Set(parts.flatMap((p) => [...p.text].map((ch) => ch.codePointAt(0) ?? 32)));\n};\n\n/**\n * Lays out a label: lines split at `\\n` and wrapped at `maxWidth` ems, centered, the block placed by `anchor` around\n * the anchor point and moved by `offset` (ems); `size` in CSS pixels. Glyphs not loaded take no room.\n */\nexport const shape = (\n parts: readonly TextPart[],\n glyphsOf: (font: string) => Map<number, Glyph> | undefined,\n options: {\n font: string;\n size: number;\n maxWidth: number;\n lineHeight: number;\n anchor: Anchor;\n offset: [number, number];\n },\n): Shaping => {\n const { size, maxWidth, lineHeight, anchor, offset } = options;\n const k = size / EM;\n\n // Characters with their glyph and scale, split into lines\n type Char = { glyph: Glyph | undefined; scale: number; space: boolean };\n\n const lines: Char[][] = [[]];\n\n for (const part of parts) {\n const glyphs = glyphsOf(part.font ?? options.font);\n\n for (const ch of part.text) {\n if (ch === '\\n') {\n lines.push([]);\n continue;\n }\n\n const code = ch.codePointAt(0) ?? 32;\n\n lines.at(-1)?.push({ glyph: glyphs?.get(code), scale: part.scale ?? 1, space: /\\s/.test(ch) });\n }\n }\n\n const advance = (c: Char) => (c.glyph?.advance ?? (c.space ? EM / 4 : 0)) * c.scale;\n // Wrapping at spaces, greedy\n const limit = maxWidth * EM;\n const wrapped: Char[][] = [];\n\n for (const line of lines) {\n let current: Char[] = [];\n let width = 0;\n let lastSpace = -1;\n\n for (const c of line) {\n current.push(c);\n width += advance(c);\n if (c.space) lastSpace = current.length - 1;\n if (width > limit && lastSpace > 0) {\n wrapped.push(current.slice(0, lastSpace));\n current = current.slice(lastSpace + 1);\n width = current.reduce((s, x) => s + advance(x), 0);\n lastSpace = -1;\n }\n }\n wrapped.push(current);\n }\n\n // Glyphs on their lines, each line centered on x = 0, in units of the 24 px font\n const quads: number[][] = [];\n let [x0, y0, x1, y1] = [\n Number.POSITIVE_INFINITY,\n Number.POSITIVE_INFINITY,\n Number.NEGATIVE_INFINITY,\n Number.NEGATIVE_INFINITY,\n ];\n let baseline = 0;\n let widest = 0;\n let height = 0;\n\n wrapped.forEach((line, i) => {\n const scale = Math.max(1, ...line.map((c) => c.scale));\n\n if (i > 0) baseline += lineHeight * EM * scale;\n height += lineHeight * EM * scale;\n\n const width = line.reduce((s, c) => s + advance(c), 0);\n\n widest = Math.max(widest, width);\n\n let pen = -width / 2;\n\n for (const c of line) {\n const g = c.glyph;\n\n if (g && g.x !== undefined && g.y !== undefined && g.width > 0) {\n const qx = pen + (g.left - BUFFER) * c.scale;\n const qy = baseline - (g.top + BUFFER) * c.scale;\n const qw = (g.width + 2 * BUFFER) * c.scale;\n const qh = (g.height + 2 * BUFFER) * c.scale;\n\n quads.push([qx, qy, qw, qh, g.x, g.y, g.x + g.width + 2 * BUFFER, g.y + g.height + 2 * BUFFER, c.scale]);\n x0 = Math.min(x0, qx + BUFFER * c.scale);\n y0 = Math.min(y0, qy + BUFFER * c.scale);\n x1 = Math.max(x1, qx + qw - BUFFER * c.scale);\n y1 = Math.max(y1, qy + qh - BUFFER * c.scale);\n }\n pen += advance(c);\n }\n });\n if (!quads.length) return { quads, box: [0, 0, 0, 0], layout: [0, 0, 0, 0] };\n\n // The block placed around the anchor by its ink box\n // The side of the box at the anchor: its start, its end, or its middle\n const side = (start: boolean, end: boolean, lo: number, hi: number) => {\n if (start) return -lo;\n if (end) return -hi;\n\n return -(lo + hi) / 2;\n };\n const horizontal = side(anchor.includes('left'), anchor.includes('right'), x0, x1);\n const vertical = side(anchor.startsWith('top'), anchor.startsWith('bottom'), y0, y1);\n const dx = horizontal + offset[0] * EM;\n const dy = vertical + offset[1] * EM;\n\n for (const q of quads) {\n q[0] = ((q[0] ?? 0) + dx) * k;\n q[1] = ((q[1] ?? 0) + dy) * k;\n q[2] = (q[2] ?? 0) * k;\n q[3] = (q[3] ?? 0) * k;\n q[8] = (q[8] ?? 1) * k;\n }\n\n const middle = (y0 + y1) / 2 + dy;\n\n height = Math.max(height, y1 - y0);\n\n return {\n quads,\n box: [(x0 + dx) * k, (y0 + dy) * k, (x1 + dx) * k, (y1 + dy) * k],\n layout: [(dx - widest / 2) * k, (middle - height / 2) * k, (dx + widest / 2) * k, (middle + height / 2) * k],\n };\n};\n"]}
1
+ {"version":3,"file":"glyphs.js","sourceRoot":"","sources":["../../src/layers/glyphs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Glyphs for the symbol layers: signed distance fields in MapLibre's glyph format (ranges of 256 code points per\n * protobuf file, 24 px glyphs with a 3 px buffer), loaded on first use (from OpenFreeMap's fonts by default, a vector\n * basemap's labels from the glyphs of its style), packed into an atlas the engine samples; and the shaping of a label:\n * its lines (explicit and wrapped), their glyphs placed around the anchor.\n *\n * The atlas has pages of one size: the first one grows up to the page size limit, then pages are added, so it never\n * runs out. A glyph's atlas row counts the rows of the pages before its own (`y + page × size`, the pages stacked):\n * the coordinates of the glyphs placed so far stay valid as the atlas grows.\n */\n\nimport type { Anchor } from '../ui/overlay.ts';\nimport { httpError } from '../util/fetch.ts';\nimport { clamp } from '../util/math.ts';\nimport { withHeaders } from '../util/requests.ts';\nimport type { Engine } from '../wasm/isard.js';\n\n/** OpenFreeMap's fonts, those of its styles (Noto Sans Regular, Bold, Italic) */\nexport const GLYPHS_URL = 'https://tiles.openfreemap.org/fonts/{fontstack}/{range}.pbf';\n\n/** The font of labels that name none */\nexport const DEFAULT_FONT = 'Noto Sans Regular';\n\n/** Size the glyphs are drawn at in the files, and their buffer */\nconst EM = 24;\nconst BUFFER = 3;\n\nexport interface Glyph {\n width: number;\n height: number;\n left: number;\n top: number;\n advance: number;\n /**\n * Place of its bitmap ((width + 6) × (height + 6)) in the atlas, `y` counting the rows of the pages before its\n * own; undefined for an empty one (a space)\n */\n x?: number;\n y?: number;\n /** Its page of the atlas */\n page?: number;\n}\n\n/** Largest side of a page of the atlas, and most pages (WebGL2 guarantees 256 layers of a texture array) */\nconst PAGE_MAX = 2048;\nconst MAX_PAGES = 256;\n\n/** A protobuf reader, enough for the glyph files */\nclass Reader {\n pos = 0;\n constructor(private readonly buf: Uint8Array) {}\n get done(): boolean {\n return this.pos >= this.buf.length;\n }\n varint(): number {\n let value = 0;\n let shift = 0;\n\n for (;;) {\n const b = this.buf[this.pos++] ?? 0;\n\n value += (b & 0x7f) * 2 ** shift;\n if (b < 0x80) return value;\n shift += 7;\n }\n }\n sint(): number {\n const v = this.varint();\n\n return v % 2 === 1 ? -(v + 1) / 2 : v / 2;\n }\n bytes(): Uint8Array {\n const n = this.varint();\n const out = this.buf.subarray(this.pos, this.pos + n);\n\n this.pos += n;\n\n return out;\n }\n skip(wire: number): void {\n if (wire === 0) this.varint();\n else if (wire === 2) this.pos += this.varint();\n else if (wire === 5) this.pos += 4;\n else if (wire === 1) this.pos += 8;\n }\n}\n\n/** Glyphs of a range file: id → metrics and bitmap */\nconst parse = (buffer: ArrayBuffer): Map<number, { glyph: Glyph; bitmap: Uint8Array }> => {\n const out = new Map<number, { glyph: Glyph; bitmap: Uint8Array }>();\n const root = new Reader(new Uint8Array(buffer));\n\n while (!root.done) {\n const tag = root.varint();\n\n if (tag >> 3 !== 1) {\n root.skip(tag & 7);\n continue;\n }\n\n // A fontstack\n const stack = new Reader(root.bytes());\n\n while (!stack.done) {\n const t = stack.varint();\n\n if (t >> 3 !== 3) {\n stack.skip(t & 7);\n continue;\n }\n\n const g = new Reader(stack.bytes());\n let id = 0;\n let bitmap: Uint8Array = new Uint8Array(0);\n const glyph: Glyph = { width: 0, height: 0, left: 0, top: 0, advance: 0 };\n\n while (!g.done) {\n const f = g.varint();\n\n switch (f >> 3) {\n case 1:\n id = g.varint();\n break;\n case 2:\n bitmap = g.bytes();\n break;\n case 3:\n glyph.width = g.varint();\n break;\n case 4:\n glyph.height = g.varint();\n break;\n case 5:\n glyph.left = g.sint();\n break;\n case 6:\n glyph.top = g.sint();\n break;\n case 7:\n glyph.advance = g.varint();\n break;\n default:\n g.skip(f & 7);\n }\n }\n out.set(id, { glyph, bitmap });\n }\n }\n\n return out;\n};\n\n/** A shelf of the packer: its page, y, height, and the x of the next free place */\ninterface Shelf {\n page: number;\n y: number;\n height: number;\n x: number;\n}\n\n/** The glyphs of a map and their atlas */\nexport class Glyphs {\n /** Side of the pages */\n private size = 512;\n private pages: Uint8Array[] = [new Uint8Array(512 * 512)];\n /** Pages allocated in the engine (doubled when more are needed: fewer reallocations) */\n private capacity = 1;\n private shelves: Shelf[] = [];\n /** Rows of each page holding glyphs (from its top): the rest is blank, never sent */\n private readonly used: number[] = [0];\n private readonly fonts = new Map<string, Map<number, Glyph>>();\n private readonly ranges = new Map<string, Promise<void>>();\n /** Glyph URLs of fonts other than the map's (those of a vector basemap's style) */\n private readonly sources = new Map<string, string>();\n private engine: Engine | undefined;\n /** Rows of each page changed since the last upload: first, end */\n private readonly dirty = new Map<number, [number, number]>();\n /** The atlas has its most pages: new glyphs stay blank */\n private full = false;\n /** Largest side of a page */\n private readonly maxSize: number;\n /** Bumped each time glyphs are added: labels shaped while some of theirs were missing are shaped again */\n version = 0;\n\n /** `maxSize`: the GPU's texture size limit if known (the pages are at most 2048 × 2048) */\n constructor(\n private readonly url = GLYPHS_URL,\n maxSize = 4096,\n ) {\n this.maxSize = clamp(maxSize, 512, PAGE_MAX);\n }\n\n /** Sends the whole atlas to an engine (a new one after a context loss) */\n attach(engine: Engine): void {\n this.engine = engine;\n this.dirty.clear();\n this.upload();\n }\n\n /** Side of the pages of the atlas */\n get atlasSize(): number {\n return this.size;\n }\n\n get pageCount(): number {\n return this.pages.length;\n }\n\n /** Loads these fonts from another glyph URL (a style's `glyphs`); a font keeps the first URL given for it */\n register(url: string, fonts: Iterable<string>): void {\n [...fonts].forEach((font) => {\n if (!this.sources.has(font)) this.sources.set(font, url);\n });\n }\n\n /** Loads the glyphs of these code points in a font */\n async load(font: string, codes: Iterable<number>): Promise<Map<number, Glyph>> {\n const glyphs = this.fonts.get(font) ?? new Map<number, Glyph>();\n\n this.fonts.set(font, glyphs);\n\n const starts = new Set([...codes].filter((code) => !glyphs.has(code)).map((code) => Math.floor(code / 256) * 256));\n\n await Promise.all([...starts].map((start) => this.range(font, start, glyphs)));\n\n return glyphs;\n }\n\n private range(font: string, start: number, glyphs: Map<number, Glyph>): Promise<void> {\n const key = `${font}/${start}`;\n const cached = this.ranges.get(key);\n\n if (cached) return cached;\n\n const url = (this.sources.get(font) ?? this.url)\n .replace('{fontstack}', encodeURIComponent(font))\n .replace('{range}', `${start}-${start + 255}`);\n const pending = fetch(url, withHeaders(url))\n .then((r) => (r.ok ? r.arrayBuffer() : Promise.reject(httpError(url, r.status))))\n .then((buffer) => {\n parse(buffer).forEach(({ glyph, bitmap }, id) => {\n if (glyph.width > 0 && bitmap.length >= (glyph.width + 2 * BUFFER) * (glyph.height + 2 * BUFFER)) {\n this.pack(glyph, bitmap);\n }\n glyphs.set(id, glyph);\n });\n this.version += 1;\n // One upload for the range\n this.flush();\n })\n .catch((error: unknown) => {\n // A missing range is not retried this session; its characters stay blank\n console.warn('isard: glyphs', error);\n });\n\n this.ranges.set(key, pending);\n\n return pending;\n }\n\n /**\n * Allocates the pages in the engine and sends what they hold (their rows with glyphs). The engine allocates its\n * pages again empty: everything is sent each time, the pages doubled to make it rare\n */\n private upload(): void {\n const engine = this.engine;\n\n if (!engine) return;\n engine.setGlyphPages(this.size, this.size, this.capacity);\n this.pages.forEach((page, i) => {\n const rows = this.used[i] ?? 0;\n\n if (rows > 0) engine.updateGlyphPage(i, 0, 0, this.size, rows, page.subarray(0, rows * this.size));\n });\n }\n\n /** Sends the rows changed since the last upload to the engine */\n private flush(): void {\n this.dirty.forEach(([y0, y1], page) => {\n const data = this.pages[page];\n\n if (data)\n this.engine?.updateGlyphPage(page, 0, y0, this.size, y1 - y0, data.subarray(y0 * this.size, y1 * this.size));\n });\n this.dirty.clear();\n }\n\n /**\n * Places a bitmap in the atlas (growing the first page, then adding pages when full); `flush` sends it to the\n * engine\n */\n private pack(glyph: Glyph, bitmap: Uint8Array): void {\n const w = glyph.width + 2 * BUFFER;\n const h = glyph.height + 2 * BUFFER;\n // One texel of padding between bitmaps: linear filtering never reads a neighbour\n let shelf = this.shelves.find((s) => s.height >= h && s.height <= h + 4 && s.x + w + 1 <= this.size);\n\n if (!shelf) {\n const page = this.pages.length - 1;\n // New shelves go on the last page only: the last shelf is on it, unless the page is new\n const last = this.shelves.at(-1);\n const y = last && last.page === page ? last.y + last.height + 1 : 0;\n\n if (y + h > this.size) {\n if (this.pages.length === 1 && this.size * 2 <= this.maxSize) this.grow();\n else if (this.pages.length < MAX_PAGES) this.addPage();\n else {\n // Full: the glyph takes its room in the text but is not drawn\n if (!this.full) console.warn(`isard: the glyph atlas is full (${MAX_PAGES} pages)`);\n this.full = true;\n\n return;\n }\n this.pack(glyph, bitmap);\n\n return;\n }\n shelf = { page, y, height: h, x: 0 };\n this.shelves.push(shelf);\n }\n\n const data = this.pages[shelf.page];\n\n if (!data) return;\n glyph.x = shelf.x;\n glyph.y = shelf.page * this.size + shelf.y;\n glyph.page = shelf.page;\n shelf.x += w + 1;\n for (let row = 0; row < h; row += 1) {\n data.set(bitmap.subarray(row * w, row * w + w), (shelf.y + row) * this.size + glyph.x);\n }\n this.used[shelf.page] = Math.max(this.used[shelf.page] ?? 0, shelf.y + h);\n\n const dirty = this.dirty.get(shelf.page);\n\n this.dirty.set(shelf.page, [Math.min(dirty?.[0] ?? shelf.y, shelf.y), Math.max(dirty?.[1] ?? 0, shelf.y + h)]);\n }\n\n /** Doubles the only page; the glyphs keep their places (texel coordinates) */\n private grow(): void {\n const size = this.size * 2;\n const old = this.pages[0] ?? new Uint8Array(this.size * this.size);\n const page = new Uint8Array(size * size);\n\n for (let row = 0; row < this.size; row += 1) {\n page.set(old.subarray(row * this.size, (row + 1) * this.size), row * size);\n }\n this.size = size;\n this.pages = [page];\n // The whole atlas is sent with what it holds so far\n this.dirty.clear();\n this.upload();\n }\n\n /** A new empty page, after the others; the engine's pages are allocated again only past its capacity */\n private addPage(): void {\n this.pages.push(new Uint8Array(this.size * this.size));\n this.used.push(0);\n if (this.pages.length > this.capacity) {\n this.capacity = Math.min(MAX_PAGES, this.capacity * 2);\n // The pages are allocated again: everything is sent, pending changes included\n this.dirty.clear();\n this.upload();\n }\n }\n}\n\n/** A run of text with its own scale (MapLibre's `format` with `font-scale`) and font */\nexport interface TextPart {\n text: string;\n scale?: number;\n font?: string;\n}\n\nexport type { Anchor } from '../ui/overlay.ts';\n\nexport interface Shaping {\n /** Glyph quads: x, y, width, height (CSS pixels from the anchor), atlas u0, v0, u1, v1, font scale */\n quads: number[][];\n /** Ink box from the anchor: min x, min y, max x, max y */\n box: [number, number, number, number];\n /** Layout box from the anchor, what an icon fitted to the text frames: the advances of its widest line across, its\n * lines' height (`lineHeight` each) down, centered on the ink */\n layout: [number, number, number, number];\n}\n\n/** Code points of a text, for loading */\nexport const codes = (parts: readonly TextPart[]): Set<number> => {\n return new Set(parts.flatMap((p) => [...p.text].map((ch) => ch.codePointAt(0) ?? 32)));\n};\n\n/**\n * Lays out a label: lines split at `\\n` and wrapped at `maxWidth` ems, centered, the block placed by `anchor` around\n * the anchor point and moved by `offset` (ems); `size` in CSS pixels. Glyphs not loaded take no room.\n */\nexport const shape = (\n parts: readonly TextPart[],\n glyphsOf: (font: string) => Map<number, Glyph> | undefined,\n options: {\n font: string;\n size: number;\n maxWidth: number;\n lineHeight: number;\n anchor: Anchor;\n offset: [number, number];\n },\n): Shaping => {\n const { size, maxWidth, lineHeight, anchor, offset } = options;\n const k = size / EM;\n\n // Characters with their glyph and scale, split into lines\n type Char = { glyph: Glyph | undefined; scale: number; space: boolean };\n\n const lines: Char[][] = [[]];\n\n for (const part of parts) {\n const glyphs = glyphsOf(part.font ?? options.font);\n\n for (const ch of part.text) {\n if (ch === '\\n') {\n lines.push([]);\n continue;\n }\n\n const code = ch.codePointAt(0) ?? 32;\n\n lines.at(-1)?.push({ glyph: glyphs?.get(code), scale: part.scale ?? 1, space: /\\s/.test(ch) });\n }\n }\n\n const advance = (c: Char) => (c.glyph?.advance ?? (c.space ? EM / 4 : 0)) * c.scale;\n // Wrapping at spaces, greedy\n const limit = maxWidth * EM;\n const wrapped: Char[][] = [];\n\n for (const line of lines) {\n let current: Char[] = [];\n let width = 0;\n let lastSpace = -1;\n\n for (const c of line) {\n current.push(c);\n width += advance(c);\n if (c.space) lastSpace = current.length - 1;\n if (width > limit && lastSpace > 0) {\n wrapped.push(current.slice(0, lastSpace));\n current = current.slice(lastSpace + 1);\n width = current.reduce((s, x) => s + advance(x), 0);\n lastSpace = -1;\n }\n }\n wrapped.push(current);\n }\n\n // Glyphs on their lines, each line centered on x = 0, in units of the 24 px font\n const quads: number[][] = [];\n let [x0, y0, x1, y1] = [\n Number.POSITIVE_INFINITY,\n Number.POSITIVE_INFINITY,\n Number.NEGATIVE_INFINITY,\n Number.NEGATIVE_INFINITY,\n ];\n let baseline = 0;\n let widest = 0;\n let height = 0;\n\n wrapped.forEach((line, i) => {\n const scale = Math.max(1, ...line.map((c) => c.scale));\n\n if (i > 0) baseline += lineHeight * EM * scale;\n height += lineHeight * EM * scale;\n\n const width = line.reduce((s, c) => s + advance(c), 0);\n\n widest = Math.max(widest, width);\n\n let pen = -width / 2;\n\n for (const c of line) {\n const g = c.glyph;\n\n if (g && g.x !== undefined && g.y !== undefined && g.width > 0) {\n const qx = pen + (g.left - BUFFER) * c.scale;\n const qy = baseline - (g.top + BUFFER) * c.scale;\n const qw = (g.width + 2 * BUFFER) * c.scale;\n const qh = (g.height + 2 * BUFFER) * c.scale;\n\n quads.push([qx, qy, qw, qh, g.x, g.y, g.x + g.width + 2 * BUFFER, g.y + g.height + 2 * BUFFER, c.scale]);\n x0 = Math.min(x0, qx + BUFFER * c.scale);\n y0 = Math.min(y0, qy + BUFFER * c.scale);\n x1 = Math.max(x1, qx + qw - BUFFER * c.scale);\n y1 = Math.max(y1, qy + qh - BUFFER * c.scale);\n }\n pen += advance(c);\n }\n });\n if (!quads.length) return { quads, box: [0, 0, 0, 0], layout: [0, 0, 0, 0] };\n\n // The block placed around the anchor by its ink box\n // The side of the box at the anchor: its start, its end, or its middle\n const side = (start: boolean, end: boolean, lo: number, hi: number) => {\n if (start) return -lo;\n if (end) return -hi;\n\n return -(lo + hi) / 2;\n };\n const horizontal = side(anchor.includes('left'), anchor.includes('right'), x0, x1);\n const vertical = side(anchor.startsWith('top'), anchor.startsWith('bottom'), y0, y1);\n const dx = horizontal + offset[0] * EM;\n const dy = vertical + offset[1] * EM;\n\n for (const q of quads) {\n q[0] = ((q[0] ?? 0) + dx) * k;\n q[1] = ((q[1] ?? 0) + dy) * k;\n q[2] = (q[2] ?? 0) * k;\n q[3] = (q[3] ?? 0) * k;\n q[8] = (q[8] ?? 1) * k;\n }\n\n const middle = (y0 + y1) / 2 + dy;\n\n height = Math.max(height, y1 - y0);\n\n return {\n quads,\n box: [(x0 + dx) * k, (y0 + dy) * k, (x1 + dx) * k, (y1 + dy) * k],\n layout: [(dx - widest / 2) * k, (middle - height / 2) * k, (dx + widest / 2) * k, (middle + height / 2) * k],\n };\n};\n"]}
@@ -0,0 +1,57 @@
1
+ /** A ground shader as a layer: the page's fragment shader over the ground, its uniforms and textures */
2
+ import type { LonLat, Placement } from '../types.ts';
3
+ import { Layer } from './layers.ts';
4
+ /** A texture of a ground layer (see `GroundLayer`) */
5
+ export interface GroundTexture {
6
+ /** `r8`, `r8ui`, `r16ui`, `r16i`, `r32ui`, `r32f`, `rg16ui`, `rg32f`, `rgba8`, `rgba8ui`, `rgba16ui`, `rgba32f`:
7
+ * integer formats are read with `usampler2D` / `isampler2D` and `texelFetch` */
8
+ format: string;
9
+ width: number;
10
+ height: number;
11
+ /** Layers of a 2D array (`sampler2DArray`, `usampler2DArray`…); 0 or undefined: a 2D texture */
12
+ depth?: number;
13
+ /** Linear filtering (non-integer formats); default nearest */
14
+ linear?: boolean;
15
+ /** Texels row after row (layer after layer), any typed array; undefined: left empty */
16
+ data?: ArrayBufferView;
17
+ }
18
+ export interface GroundOptions extends Placement {
19
+ /**
20
+ * GLSL ES 3.0 defining `vec4 ground(vec2 offset)`: the color of the ground (premultiplied alpha, 0 for nothing) at
21
+ * `offset`, the Mercator offset of the pixel from `anchor` (times `ISARD_CIRCUMFERENCE`: metres of EPSG:3857), exact to
22
+ * the millimetre at any zoom. The code declares its own uniforms and samplers; also there: `u_zoom`,
23
+ * `u_pixel_ratio`
24
+ */
25
+ code: string;
26
+ /** Where the offsets are taken from */
27
+ anchor: LonLat;
28
+ /** Box it shows in, `[west, south, east, north]` (default the world): only the ground there is drawn again */
29
+ bounds?: [west: number, south: number, east: number, north: number];
30
+ textures?: Record<string, GroundTexture>;
31
+ uniforms?: Record<string, number | readonly number[]>;
32
+ }
33
+ /** The application's fragment shader run over the ground, draped on the relief (water depth, heat maps…) */
34
+ export declare class GroundLayer extends Layer {
35
+ private readonly options;
36
+ private readonly textures;
37
+ private readonly uniforms;
38
+ private visible;
39
+ /** Creates or replaces a texture of the code's sampler `name` */
40
+ setTexture(name: string, texture: GroundTexture): void;
41
+ /**
42
+ * Replaces a region of a texture: `data` holds `width` × `height` texels for (`x`, `y`) of `layer` (2D arrays).
43
+ * Keep the texture's own `data` up to date too if it must survive a WebGL context loss.
44
+ */
45
+ updateTexture(name: string, data: ArrayBufferView, region: {
46
+ x?: number;
47
+ y?: number;
48
+ layer?: number;
49
+ width: number;
50
+ height: number;
51
+ }): void;
52
+ /** A uniform of the code: a number, or numbers for vectors, arrays and matrices (column major) */
53
+ setUniform(name: string, value: number | readonly number[]): void;
54
+ setBounds(bounds: [west: number, south: number, east: number, north: number]): void;
55
+ setVisible(visible: boolean): void;
56
+ private sendTexture;
57
+ }
@@ -0,0 +1,78 @@
1
+ /** A ground shader as a layer: the page's fragment shader over the ground, its uniforms and textures */
2
+ import { toMercator } from "../util/geo.js";
3
+ import { Layer } from "./layers.js";
4
+ const bytesOf = (data) => new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
5
+ /** The application's fragment shader run over the ground, draped on the relief (water depth, heat maps…) */
6
+ export class GroundLayer extends Layer {
7
+ options;
8
+ textures = new Map();
9
+ uniforms = new Map();
10
+ visible = true;
11
+ /** @internal */
12
+ constructor(map, options) {
13
+ super(map);
14
+ this.options = options;
15
+ Object.entries(options.textures ?? {}).forEach(([name, texture]) => {
16
+ this.textures.set(name, texture);
17
+ });
18
+ Object.entries(options.uniforms ?? {}).forEach(([name, value]) => {
19
+ this.uniforms.set(name, [value].flat());
20
+ });
21
+ }
22
+ /** Creates or replaces a texture of the code's sampler `name` */
23
+ setTexture(name, texture) {
24
+ this.textures.set(name, texture);
25
+ this.sendTexture(this.map.engine, this.id, name, texture);
26
+ this.map.requestRender();
27
+ }
28
+ /**
29
+ * Replaces a region of a texture: `data` holds `width` × `height` texels for (`x`, `y`) of `layer` (2D arrays).
30
+ * Keep the texture's own `data` up to date too if it must survive a WebGL context loss.
31
+ */
32
+ updateTexture(name, data, region) {
33
+ const { x = 0, y = 0, layer = 0, width, height } = region;
34
+ this.map.engine.updateGroundTexture(this.id, name, x, y, layer, width, height, bytesOf(data));
35
+ this.map.requestRender();
36
+ }
37
+ /** A uniform of the code: a number, or numbers for vectors, arrays and matrices (column major) */
38
+ setUniform(name, value) {
39
+ const values = [value].flat();
40
+ this.uniforms.set(name, values);
41
+ this.map.engine.setGroundUniform(this.id, name, Float64Array.from(values));
42
+ this.map.requestRender();
43
+ }
44
+ setBounds(bounds) {
45
+ this.options.bounds = bounds;
46
+ this.map.engine.setGroundBounds(this.id, ...mercatorBox(bounds));
47
+ this.map.requestRender();
48
+ }
49
+ setVisible(visible) {
50
+ this.visible = visible;
51
+ this.map.engine.setGroundVisible(this.id, visible);
52
+ this.map.requestRender();
53
+ }
54
+ sendTexture(engine, id, name, t) {
55
+ const data = t.data && bytesOf(t.data);
56
+ engine.setGroundTexture(id, name, t.format, t.width, t.height, t.depth ?? 0, t.linear ?? false, data);
57
+ }
58
+ /** @internal */
59
+ create(engine) {
60
+ const [ax, ay] = toMercator(this.options.anchor);
61
+ const id = engine.addGround(this.options.code, ax, ay, ...mercatorBox(this.options.bounds ?? [-180, -85.06, 180, 85.06]));
62
+ this.textures.forEach((texture, name) => {
63
+ this.sendTexture(engine, id, name, texture);
64
+ });
65
+ this.uniforms.forEach((values, name) => {
66
+ engine.setGroundUniform(id, name, Float64Array.from(values));
67
+ });
68
+ engine.setGroundVisible(id, this.visible);
69
+ return id;
70
+ }
71
+ }
72
+ /** A lon/lat box to Mercator min x, min y, max x, max y (y towards the south) */
73
+ const mercatorBox = ([west, south, east, north]) => {
74
+ const [x0, y1] = toMercator([west, south]);
75
+ const [x1, y0] = toMercator([east, north]);
76
+ return [x0, y0, x1, y1];
77
+ };
78
+ //# sourceMappingURL=ground.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ground.js","sourceRoot":"","sources":["../../src/layers/ground.ts"],"names":[],"mappings":"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","sourcesContent":["/** A ground shader as a layer: the page's fragment shader over the ground, its uniforms and textures */\n\nimport type { LayerHost, LonLat, Placement } from '../types.ts';\nimport { toMercator } from '../util/geo.ts';\nimport type { Engine } from '../wasm/isard.js';\nimport { Layer } from './layers.ts';\n\n/** A texture of a ground layer (see `GroundLayer`) */\nexport interface GroundTexture {\n /** `r8`, `r8ui`, `r16ui`, `r16i`, `r32ui`, `r32f`, `rg16ui`, `rg32f`, `rgba8`, `rgba8ui`, `rgba16ui`, `rgba32f`:\n * integer formats are read with `usampler2D` / `isampler2D` and `texelFetch` */\n format: string;\n width: number;\n height: number;\n /** Layers of a 2D array (`sampler2DArray`, `usampler2DArray`…); 0 or undefined: a 2D texture */\n depth?: number;\n /** Linear filtering (non-integer formats); default nearest */\n linear?: boolean;\n /** Texels row after row (layer after layer), any typed array; undefined: left empty */\n data?: ArrayBufferView;\n}\n\nexport interface GroundOptions extends Placement {\n /**\n * GLSL ES 3.0 defining `vec4 ground(vec2 offset)`: the color of the ground (premultiplied alpha, 0 for nothing) at\n * `offset`, the Mercator offset of the pixel from `anchor` (times `ISARD_CIRCUMFERENCE`: metres of EPSG:3857), exact to\n * the millimetre at any zoom. The code declares its own uniforms and samplers; also there: `u_zoom`,\n * `u_pixel_ratio`\n */\n code: string;\n /** Where the offsets are taken from */\n anchor: LonLat;\n /** Box it shows in, `[west, south, east, north]` (default the world): only the ground there is drawn again */\n bounds?: [west: number, south: number, east: number, north: number];\n textures?: Record<string, GroundTexture>;\n uniforms?: Record<string, number | readonly number[]>;\n}\n\nconst bytesOf = (data: ArrayBufferView) => new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\n\n/** The application's fragment shader run over the ground, draped on the relief (water depth, heat maps…) */\nexport class GroundLayer extends Layer {\n private readonly textures = new Map<string, GroundTexture>();\n private readonly uniforms = new Map<string, number[]>();\n private visible = true;\n\n /** @internal */\n constructor(\n map: LayerHost,\n private readonly options: GroundOptions,\n ) {\n super(map);\n Object.entries(options.textures ?? {}).forEach(([name, texture]) => {\n this.textures.set(name, texture);\n });\n Object.entries(options.uniforms ?? {}).forEach(([name, value]) => {\n this.uniforms.set(name, [value].flat());\n });\n }\n\n /** Creates or replaces a texture of the code's sampler `name` */\n setTexture(name: string, texture: GroundTexture): void {\n this.textures.set(name, texture);\n this.sendTexture(this.map.engine, this.id, name, texture);\n this.map.requestRender();\n }\n\n /**\n * Replaces a region of a texture: `data` holds `width` × `height` texels for (`x`, `y`) of `layer` (2D arrays).\n * Keep the texture's own `data` up to date too if it must survive a WebGL context loss.\n */\n updateTexture(\n name: string,\n data: ArrayBufferView,\n region: { x?: number; y?: number; layer?: number; width: number; height: number },\n ): void {\n const { x = 0, y = 0, layer = 0, width, height } = region;\n\n this.map.engine.updateGroundTexture(this.id, name, x, y, layer, width, height, bytesOf(data));\n this.map.requestRender();\n }\n\n /** A uniform of the code: a number, or numbers for vectors, arrays and matrices (column major) */\n setUniform(name: string, value: number | readonly number[]): void {\n const values = [value].flat();\n\n this.uniforms.set(name, values);\n this.map.engine.setGroundUniform(this.id, name, Float64Array.from(values));\n this.map.requestRender();\n }\n\n setBounds(bounds: [west: number, south: number, east: number, north: number]): void {\n this.options.bounds = bounds;\n this.map.engine.setGroundBounds(this.id, ...mercatorBox(bounds));\n this.map.requestRender();\n }\n\n setVisible(visible: boolean): void {\n this.visible = visible;\n this.map.engine.setGroundVisible(this.id, visible);\n this.map.requestRender();\n }\n\n private sendTexture(engine: Engine, id: number, name: string, t: GroundTexture): void {\n const data = t.data && bytesOf(t.data);\n\n engine.setGroundTexture(id, name, t.format, t.width, t.height, t.depth ?? 0, t.linear ?? false, data);\n }\n\n /** @internal */\n protected create(engine: Engine): number {\n const [ax, ay] = toMercator(this.options.anchor);\n const id = engine.addGround(\n this.options.code,\n ax,\n ay,\n ...mercatorBox(this.options.bounds ?? [-180, -85.06, 180, 85.06]),\n );\n\n this.textures.forEach((texture, name) => {\n this.sendTexture(engine, id, name, texture);\n });\n this.uniforms.forEach((values, name) => {\n engine.setGroundUniform(id, name, Float64Array.from(values));\n });\n engine.setGroundVisible(id, this.visible);\n\n return id;\n }\n}\n\n/** A lon/lat box to Mercator min x, min y, max x, max y (y towards the south) */\nconst mercatorBox = ([west, south, east, north]: [number, number, number, number]): [\n number,\n number,\n number,\n number,\n] => {\n const [x0, y1] = toMercator([west, south]);\n const [x1, y0] = toMercator([east, north]);\n\n return [x0, y0, x1, y1];\n};\n"]}
@@ -5,8 +5,10 @@
5
5
  * layout of an icon around its anchor: by its anchor and offset, or stretched around its text (`icon-text-fit`), by
6
6
  * the stretchable zones and the content box of its image when it has them (`stretchX`, `stretchY`, `content`).
7
7
  */
8
- import { withHeaders } from "../engine/requests.js";
8
+ import { RAD } from "../util/geo.js";
9
9
  import { isNumbers, isRecord } from "../util/guards.js";
10
+ import { clamp } from "../util/math.js";
11
+ import { withHeaders } from "../util/requests.js";
10
12
  const isPairs = (value) => Array.isArray(value) && value.every((pair) => isNumbers(pair) && pair.length === 2);
11
13
  /** An icon of a sprite index: its place, and what is drawn from the rest */
12
14
  const isSpriteIcon = (value) => isRecord(value) &&
@@ -82,7 +84,7 @@ export class Icons {
82
84
  version = 0;
83
85
  /** `maxSize`: the GPU's texture size limit if known (the atlas is at most 4096 × 4096) */
84
86
  constructor(maxSize = 4096) {
85
- this.maxSize = Math.max(256, Math.min(4096, maxSize));
87
+ this.maxSize = clamp(maxSize, 256, 4096);
86
88
  }
87
89
  /** Sends the whole atlas to an engine (a new one after a context loss) */
88
90
  attach(engine) {
@@ -247,17 +249,17 @@ export class Icons {
247
249
  * pixel) leave
248
250
  */
249
251
  export const stretch = (length, zones, content, lo, hi, scale) => {
250
- const clamp = (v) => Math.max(0, Math.min(length, Number(v) || 0));
252
+ const within = (v) => clamp(Number(v) || 0, 0, length);
251
253
  const whole = [[0, length]];
252
254
  const spans = (zones?.length ? zones : whole)
253
- .map(([a, b]) => [clamp(Math.min(a, b)), clamp(Math.max(a, b))])
255
+ .map(([a, b]) => [within(Math.min(a, b)), within(Math.max(a, b))])
254
256
  .filter(([a, b]) => b > a);
255
257
  const cuts = [...new Set([0, length, ...spans.flat()])].sort((a, b) => a - b);
256
258
  const pieces = cuts.slice(1).map((b, i) => {
257
259
  const a = cuts[i] ?? 0;
258
260
  return [a, b, spans.some(([s, e]) => s <= a && b <= e)];
259
261
  });
260
- const [c0, c1] = content ? [clamp(content[0]), clamp(content[1])] : [0, length];
262
+ const [c0, c1] = content ? [within(content[0]), within(content[1])] : [0, length];
261
263
  const overlap = (a, b) => Math.max(0, Math.min(b, c1) - Math.max(a, c0));
262
264
  const stretchable = pieces.reduce((n, [a, b, s]) => n + (s ? overlap(a, b) : 0), 0);
263
265
  const fixed = c1 - c0 - stretchable;
@@ -305,7 +307,7 @@ export const layoutIcon = (icon, options) => {
305
307
  const [left, top] = [offset[0] * size - dw * ax, offset[1] * size - dh * ay];
306
308
  return [[[0, w, left, left + dw]], [[0, h, top, top + dh]]];
307
309
  })();
308
- const angle = ((Number(rotate) || 0) * Math.PI) / 180;
310
+ const angle = (Number(rotate) || 0) * RAD;
309
311
  const kind = icon.sdf ? -2 : -1;
310
312
  const quads = [];
311
313
  const [cs, sn] = [Math.cos(angle), Math.sin(angle)];