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
@@ -0,0 +1,139 @@
1
+ /**
2
+ * The frame loop of a map: frames drawn on demand only (an idle map costs nothing), the running animation stepped in
3
+ * each, and the events of a frame sent with it: the camera's moves, the pointer's position (coalesced to one per
4
+ * frame, so the values computed for it are drawn in the same frame), 'render', and 'idle' once everything is loaded.
5
+ */
6
+ /** The frames of a map, asked for and drawn */
7
+ export class FrameLoop {
8
+ host;
9
+ listeners;
10
+ /** Frame asked for, 0 if none */
11
+ requested = 0;
12
+ inFrame = false;
13
+ animation;
14
+ /** The pointer's position for the next frame */
15
+ hoverPoint;
16
+ lastCamera = '';
17
+ /** The camera moved since the last 'moveend' */
18
+ moving = false;
19
+ #settled = false;
20
+ #camera;
21
+ /** `listeners`: the map's, told of the frame's events */
22
+ constructor(host, listeners) {
23
+ this.host = host;
24
+ this.listeners = listeners;
25
+ }
26
+ /** The last frame found everything loaded ('idle' sent) */
27
+ get settled() {
28
+ return this.#settled;
29
+ }
30
+ /** The camera of the frame being drawn: what `getCamera` gives the custom layers while the engine is busy */
31
+ get camera() {
32
+ return this.#camera;
33
+ }
34
+ /** Asks for a frame; several calls before the next frame draw it once */
35
+ request() {
36
+ // Changes made by listeners during a frame are drawn by that frame; nothing is drawn without a context
37
+ if (this.inFrame || this.host.lost())
38
+ return;
39
+ this.requested ||= requestAnimationFrame((now) => this.frame(now));
40
+ }
41
+ /** Runs `step` every frame until it returns false; replaces the running animation */
42
+ animate(step) {
43
+ // A flight cut short no longer needs its destination
44
+ if (this.animation)
45
+ this.host.engine().clearPreload();
46
+ this.animation = step;
47
+ this.request();
48
+ }
49
+ /** The pointer's position for the next frame (undefined: none) */
50
+ hover(point) {
51
+ this.hoverPoint = point;
52
+ }
53
+ /** Draws a frame now, in place of the one asked for (a resized canvas is cleared: waiting one frame would flash) */
54
+ drawNow() {
55
+ cancelAnimationFrame(this.requested);
56
+ this.frame(performance.now());
57
+ }
58
+ /** Cancels the frame asked for (the context is lost); a new one can be asked for */
59
+ cancel() {
60
+ cancelAnimationFrame(this.requested);
61
+ this.requested = 0;
62
+ }
63
+ /** Cancels the frame asked for, for good (the map is destroyed): it stays marked as asked for */
64
+ stop() {
65
+ cancelAnimationFrame(this.requested);
66
+ }
67
+ frame(now) {
68
+ this.requested = 0;
69
+ try {
70
+ this.inFrame = true;
71
+ this.draw(now);
72
+ }
73
+ finally {
74
+ // Whatever throws in a frame, the next ones are still drawn
75
+ this.inFrame = false;
76
+ }
77
+ }
78
+ draw(now) {
79
+ if (this.animation && !this.animation(now))
80
+ this.animation = undefined;
81
+ const { host, listeners } = this;
82
+ const camera = host.camera();
83
+ const key = `${camera.center}|${camera.zoom}|${camera.pitch}|${camera.bearing}`;
84
+ const moved = key !== this.lastCamera;
85
+ if (moved) {
86
+ // The first frame is no move
87
+ if (!this.moving && this.lastCamera !== '') {
88
+ this.moving = true;
89
+ listeners.emit('movestart', camera);
90
+ }
91
+ this.lastCamera = key;
92
+ listeners.emit('move', camera);
93
+ }
94
+ else if (this.moving && !this.animation && !host.interacting()) {
95
+ this.moving = false;
96
+ listeners.emit('moveend', camera);
97
+ }
98
+ // Values for the pointer position are computed before drawing, in the same frame
99
+ const hovered = this.hoverPoint;
100
+ if (hovered) {
101
+ this.hoverPoint = undefined;
102
+ // The position under the pointer for its listeners only (a 'hoverfeature' alone does not need it)
103
+ if (listeners.has('hover')) {
104
+ listeners.emit('hover', { point: hovered, lonLat: host.engine().ground(hovered[0], hovered[1]) });
105
+ }
106
+ }
107
+ const t0 = performance.now();
108
+ // The engine asks for the next frame while it draws (uploads past the frame budget, fades): not ignored
109
+ this.inFrame = false;
110
+ // As the engine has it now (a listener may have moved it), for the custom layers drawn in the frame
111
+ this.#camera = host.customLayers() ? host.engine().camera() : undefined;
112
+ const render = () => {
113
+ try {
114
+ return host.engine().render();
115
+ }
116
+ finally {
117
+ this.#camera = undefined;
118
+ }
119
+ };
120
+ const loading = render();
121
+ this.inFrame = true;
122
+ host.drawn(hovered);
123
+ listeners.emit('render', { ms: performance.now() - t0 });
124
+ this.inFrame = false;
125
+ // A move goes on until a frame finds the camera still: that frame sends 'moveend'
126
+ if (this.animation || (moved && this.moving))
127
+ this.request();
128
+ // Idle: nothing loading (the engine with 3D Tiles neither), no animation, no frame asked for (uploads waiting,
129
+ // fades, listeners)
130
+ if (loading || host.upgrading() || this.animation || this.requested !== 0) {
131
+ this.#settled = false;
132
+ }
133
+ else if (!this.#settled) {
134
+ this.#settled = true;
135
+ listeners.emit('idle', {});
136
+ }
137
+ }
138
+ }
139
+ //# sourceMappingURL=frame-loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-loop.js","sourceRoot":"","sources":["../../src/map/frame-loop.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The frame loop of a map: frames drawn on demand only (an idle map costs nothing), the running animation stepped in\n * each, and the events of a frame sent with it: the camera's moves, the pointer's position (coalesced to one per\n * frame, so the values computed for it are drawn in the same frame), 'render', and 'idle' once everything is loaded.\n */\n\nimport type { Point } from '../types.ts';\nimport type { Step } from '../util/animation.ts';\nimport type { Camera, Engine } from '../wasm/isard.js';\nimport type { MapListeners } from './events.ts';\n\n/** What the frame loop needs of its map */\nexport interface FrameHost {\n /** The map's engine of the moment */\n engine(): Engine;\n /** The map's camera */\n camera(): Camera;\n /** The WebGL context is lost: nothing is drawn */\n lost(): boolean;\n /** The pointer or the keys are moving the camera: no 'moveend' yet */\n interacting(): boolean;\n /** Custom layers are drawn: they read the camera of the frame */\n customLayers(): boolean;\n /** The engine with 3D Tiles is loading: not idle */\n upgrading(): boolean;\n /** The frame is drawn: what follows it (the overlays placed, the hover picking asked for at `hovered`) */\n drawn(hovered: Point | undefined): void;\n}\n\n/** The frames of a map, asked for and drawn */\nexport class FrameLoop {\n private readonly host: FrameHost;\n private readonly listeners: MapListeners;\n /** Frame asked for, 0 if none */\n private requested = 0;\n private inFrame = false;\n private animation: Step | undefined;\n /** The pointer's position for the next frame */\n private hoverPoint: Point | undefined;\n private lastCamera = '';\n /** The camera moved since the last 'moveend' */\n private moving = false;\n #settled = false;\n #camera: Camera | undefined;\n\n /** `listeners`: the map's, told of the frame's events */\n constructor(host: FrameHost, listeners: MapListeners) {\n this.host = host;\n this.listeners = listeners;\n }\n\n /** The last frame found everything loaded ('idle' sent) */\n get settled(): boolean {\n return this.#settled;\n }\n\n /** The camera of the frame being drawn: what `getCamera` gives the custom layers while the engine is busy */\n get camera(): Camera | undefined {\n return this.#camera;\n }\n\n /** Asks for a frame; several calls before the next frame draw it once */\n request(): void {\n // Changes made by listeners during a frame are drawn by that frame; nothing is drawn without a context\n if (this.inFrame || this.host.lost()) return;\n this.requested ||= requestAnimationFrame((now) => this.frame(now));\n }\n\n /** Runs `step` every frame until it returns false; replaces the running animation */\n animate(step: Step | undefined): void {\n // A flight cut short no longer needs its destination\n if (this.animation) this.host.engine().clearPreload();\n this.animation = step;\n this.request();\n }\n\n /** The pointer's position for the next frame (undefined: none) */\n hover(point: Point | undefined): void {\n this.hoverPoint = point;\n }\n\n /** Draws a frame now, in place of the one asked for (a resized canvas is cleared: waiting one frame would flash) */\n drawNow(): void {\n cancelAnimationFrame(this.requested);\n this.frame(performance.now());\n }\n\n /** Cancels the frame asked for (the context is lost); a new one can be asked for */\n cancel(): void {\n cancelAnimationFrame(this.requested);\n this.requested = 0;\n }\n\n /** Cancels the frame asked for, for good (the map is destroyed): it stays marked as asked for */\n stop(): void {\n cancelAnimationFrame(this.requested);\n }\n\n private frame(now: number): void {\n this.requested = 0;\n try {\n this.inFrame = true;\n this.draw(now);\n } finally {\n // Whatever throws in a frame, the next ones are still drawn\n this.inFrame = false;\n }\n }\n\n private draw(now: number): void {\n if (this.animation && !this.animation(now)) this.animation = undefined;\n\n const { host, listeners } = this;\n const camera = host.camera();\n const key = `${camera.center}|${camera.zoom}|${camera.pitch}|${camera.bearing}`;\n const moved = key !== this.lastCamera;\n\n if (moved) {\n // The first frame is no move\n if (!this.moving && this.lastCamera !== '') {\n this.moving = true;\n listeners.emit('movestart', camera);\n }\n this.lastCamera = key;\n listeners.emit('move', camera);\n } else if (this.moving && !this.animation && !host.interacting()) {\n this.moving = false;\n listeners.emit('moveend', camera);\n }\n\n // Values for the pointer position are computed before drawing, in the same frame\n const hovered = this.hoverPoint;\n\n if (hovered) {\n this.hoverPoint = undefined;\n // The position under the pointer for its listeners only (a 'hoverfeature' alone does not need it)\n if (listeners.has('hover')) {\n listeners.emit('hover', { point: hovered, lonLat: host.engine().ground(hovered[0], hovered[1]) });\n }\n }\n\n const t0 = performance.now();\n\n // The engine asks for the next frame while it draws (uploads past the frame budget, fades): not ignored\n this.inFrame = false;\n // As the engine has it now (a listener may have moved it), for the custom layers drawn in the frame\n this.#camera = host.customLayers() ? host.engine().camera() : undefined;\n\n const render = (): boolean => {\n try {\n return host.engine().render();\n } finally {\n this.#camera = undefined;\n }\n };\n const loading = render();\n\n this.inFrame = true;\n host.drawn(hovered);\n listeners.emit('render', { ms: performance.now() - t0 });\n this.inFrame = false;\n // A move goes on until a frame finds the camera still: that frame sends 'moveend'\n if (this.animation || (moved && this.moving)) this.request();\n // Idle: nothing loading (the engine with 3D Tiles neither), no animation, no frame asked for (uploads waiting,\n // fades, listeners)\n if (loading || host.upgrading() || this.animation || this.requested !== 0) {\n this.#settled = false;\n } else if (!this.#settled) {\n this.#settled = true;\n listeners.emit('idle', {});\n }\n }\n}\n"]}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The picking of what is under the pointer for 'hoverfeature', without stalling the GPU: the engine is asked once the
3
+ * frame is drawn, its answer read on a later frame, when the GPU is done.
4
+ */
5
+ import type { Layer } from '../layers/layers.ts';
6
+ import type { Point } from '../types.ts';
7
+ import type { Engine, PickResult } from '../wasm/isard.js';
8
+ /** What 'hoverfeature' looks for: within `radius` CSS pixels, in `layers` only if given */
9
+ export interface HoverPicking {
10
+ radius?: number;
11
+ layers?: readonly Layer[];
12
+ }
13
+ /** The hover picking of a map: one request in flight at most, its answer polled frame after frame */
14
+ export declare class HoverPick {
15
+ private readonly engine;
16
+ /** The WebGL context is lost: no answer will come */
17
+ private readonly lost;
18
+ private readonly answer;
19
+ /** Frame polling the engine for the answer, 0 if none */
20
+ private poll;
21
+ /** Polls under way: given up after `MAX_POLLS` (an answer that never comes) */
22
+ private polls;
23
+ /** `engine`: the map's engine of the moment; `answer`: called with what the engine found */
24
+ constructor(engine: () => Engine, lost: () => boolean, answer: (result: PickResult) => void);
25
+ /** Asks the engine what is under the pointer; its answer, read without waiting for the GPU, comes on a later frame */
26
+ request(point: Point, { radius, layers }: HoverPicking): void;
27
+ /** Stops waiting for the answer */
28
+ cancel(): void;
29
+ private readonly next;
30
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * The picking of what is under the pointer for 'hoverfeature', without stalling the GPU: the engine is asked once the
3
+ * frame is drawn, its answer read on a later frame, when the GPU is done.
4
+ */
5
+ /** Frames the hover picking waits for its answer at most (usually one) */
6
+ const MAX_POLLS = 30;
7
+ /** The hover picking of a map: one request in flight at most, its answer polled frame after frame */
8
+ export class HoverPick {
9
+ engine;
10
+ /** The WebGL context is lost: no answer will come */
11
+ lost;
12
+ answer;
13
+ /** Frame polling the engine for the answer, 0 if none */
14
+ poll = 0;
15
+ /** Polls under way: given up after `MAX_POLLS` (an answer that never comes) */
16
+ polls = 0;
17
+ /** `engine`: the map's engine of the moment; `answer`: called with what the engine found */
18
+ constructor(engine, lost, answer) {
19
+ this.engine = engine;
20
+ this.lost = lost;
21
+ this.answer = answer;
22
+ }
23
+ /** Asks the engine what is under the pointer; its answer, read without waiting for the GPU, comes on a later frame */
24
+ request(point, { radius = 0, layers }) {
25
+ const only = layers && Uint32Array.from(layers.map((l) => l.id));
26
+ // The engine cannot pick (no request in flight): the poll under way would wait for nothing
27
+ if (!this.engine().requestPick(point[0], point[1], radius, only)) {
28
+ this.cancel();
29
+ return;
30
+ }
31
+ // A new request replaces the one in flight (in the engine too): one poll loop at most
32
+ this.polls = 0;
33
+ if (!this.poll)
34
+ this.poll = requestAnimationFrame(this.next);
35
+ }
36
+ /** Stops waiting for the answer */
37
+ cancel() {
38
+ cancelAnimationFrame(this.poll);
39
+ this.poll = 0;
40
+ }
41
+ next = () => {
42
+ this.poll = 0;
43
+ if (this.lost())
44
+ return;
45
+ const result = this.engine().pollPick();
46
+ if (!result) {
47
+ // The GPU is not done yet (usually a frame): asked again next frame, without drawing; given up at last
48
+ this.polls += 1;
49
+ if (this.polls < MAX_POLLS)
50
+ this.poll = requestAnimationFrame(this.next);
51
+ return;
52
+ }
53
+ this.answer(result);
54
+ };
55
+ }
56
+ //# sourceMappingURL=hover-pick.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hover-pick.js","sourceRoot":"","sources":["../../src/map/hover-pick.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,0EAA0E;AAC1E,MAAM,SAAS,GAAG,EAAE,CAAC;AAQrB,qGAAqG;AACrG,MAAM,OAAO,SAAS;IACH,MAAM,CAAe;IACtC,qDAAqD;IACpC,IAAI,CAAgB;IACpB,MAAM,CAA+B;IACtD,yDAAyD;IACjD,IAAI,GAAG,CAAC,CAAC;IACjB,+EAA+E;IACvE,KAAK,GAAG,CAAC,CAAC;IAElB,4FAA4F;IAC5F,YAAY,MAAoB,EAAE,IAAmB,EAAE,MAAoC;QACzF,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,sHAAsH;IACtH,OAAO,CAAC,KAAY,EAAE,EAAE,MAAM,GAAG,CAAC,EAAE,MAAM,EAAgB;QACxD,MAAM,IAAI,GAAG,MAAM,IAAI,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAEjE,2FAA2F;QAC3F,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC;YACjE,IAAI,CAAC,MAAM,EAAE,CAAC;YAEd,OAAO;QACT,CAAC;QACD,sFAAsF;QACtF,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/D,CAAC;IAED,mCAAmC;IACnC,MAAM;QACJ,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;IAChB,CAAC;IAEgB,IAAI,GAAG,GAAS,EAAE;QACjC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;QACd,IAAI,IAAI,CAAC,IAAI,EAAE;YAAE,OAAO;QAExB,MAAM,MAAM,GAA2B,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC;QAEhE,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,uGAAuG;YACvG,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;YAChB,IAAI,IAAI,CAAC,KAAK,GAAG,SAAS;gBAAE,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEzE,OAAO;QACT,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACtB,CAAC,CAAC;CACH","sourcesContent":["/**\n * The picking of what is under the pointer for 'hoverfeature', without stalling the GPU: the engine is asked once the\n * frame is drawn, its answer read on a later frame, when the GPU is done.\n */\n\nimport type { Layer } from '../layers/layers.ts';\nimport type { Point } from '../types.ts';\nimport type { Engine, PickResult } from '../wasm/isard.js';\n\n/** Frames the hover picking waits for its answer at most (usually one) */\nconst MAX_POLLS = 30;\n\n/** What 'hoverfeature' looks for: within `radius` CSS pixels, in `layers` only if given */\nexport interface HoverPicking {\n radius?: number;\n layers?: readonly Layer[];\n}\n\n/** The hover picking of a map: one request in flight at most, its answer polled frame after frame */\nexport class HoverPick {\n private readonly engine: () => Engine;\n /** The WebGL context is lost: no answer will come */\n private readonly lost: () => boolean;\n private readonly answer: (result: PickResult) => void;\n /** Frame polling the engine for the answer, 0 if none */\n private poll = 0;\n /** Polls under way: given up after `MAX_POLLS` (an answer that never comes) */\n private polls = 0;\n\n /** `engine`: the map's engine of the moment; `answer`: called with what the engine found */\n constructor(engine: () => Engine, lost: () => boolean, answer: (result: PickResult) => void) {\n this.engine = engine;\n this.lost = lost;\n this.answer = answer;\n }\n\n /** Asks the engine what is under the pointer; its answer, read without waiting for the GPU, comes on a later frame */\n request(point: Point, { radius = 0, layers }: HoverPicking): void {\n const only = layers && Uint32Array.from(layers.map((l) => l.id));\n\n // The engine cannot pick (no request in flight): the poll under way would wait for nothing\n if (!this.engine().requestPick(point[0], point[1], radius, only)) {\n this.cancel();\n\n return;\n }\n // A new request replaces the one in flight (in the engine too): one poll loop at most\n this.polls = 0;\n if (!this.poll) this.poll = requestAnimationFrame(this.next);\n }\n\n /** Stops waiting for the answer */\n cancel(): void {\n cancelAnimationFrame(this.poll);\n this.poll = 0;\n }\n\n private readonly next = (): void => {\n this.poll = 0;\n if (this.lost()) return;\n\n const result: PickResult | undefined = this.engine().pollPick();\n\n if (!result) {\n // The GPU is not done yet (usually a frame): asked again next frame, without drawing; given up at last\n this.polls += 1;\n if (this.polls < MAX_POLLS) this.poll = requestAnimationFrame(this.next);\n\n return;\n }\n this.answer(result);\n };\n}\n"]}
@@ -0,0 +1,42 @@
1
+ /** A layer described by its type and options, as an application's configuration gives it, and the map adding it. */
2
+ import type { ExtrusionOptions } from '../layers/extrusions.ts';
3
+ import type { CircleOptions, FillOptions, LineOptions } from '../layers/features.ts';
4
+ import type { GroundOptions, Layer, ModelOptions } from '../layers/layers.ts';
5
+ import type { PointCloudOptions } from '../layers/pointclouds.ts';
6
+ import type { SymbolOptions } from '../layers/symbols.ts';
7
+ import type { GeoMap } from '../map.ts';
8
+ import type { NetworkOptions, RasterOptions, Tiles3dOptions } from '../types.ts';
9
+ /** A layer by its type and the options of its `add…` method (`GeoMap.add`) */
10
+ export type LayerSpec<P = Record<string, unknown>> = ({
11
+ type: 'lines';
12
+ } & LineOptions<P>) | ({
13
+ type: 'circles';
14
+ } & CircleOptions<P>) | ({
15
+ type: 'fills';
16
+ } & FillOptions<P>) | ({
17
+ type: 'symbols';
18
+ } & SymbolOptions<P>) | ({
19
+ type: 'extrusions';
20
+ } & ExtrusionOptions<P>) | ({
21
+ type: 'raster';
22
+ } & RasterOptions & {
23
+ before?: Layer;
24
+ }) | ({
25
+ type: 'ground';
26
+ } & GroundOptions & {
27
+ before?: Layer;
28
+ }) | ({
29
+ type: 'network';
30
+ } & NetworkOptions) | ({
31
+ type: 'tiles3d';
32
+ } & Tiles3dOptions) | ({
33
+ type: 'pointcloud';
34
+ } & PointCloudOptions & {
35
+ before?: Layer;
36
+ }) | ({
37
+ type: 'models';
38
+ } & ModelOptions & {
39
+ before?: Layer;
40
+ });
41
+ /** Adds the layer a description gives with the `add…` method of its type; an unknown type throws */
42
+ export declare const addSpec: <P = Record<string, unknown>>(map: GeoMap, spec: LayerSpec<P>) => Layer;
@@ -0,0 +1,34 @@
1
+ /** A layer described by its type and options, as an application's configuration gives it, and the map adding it. */
2
+ /** Adds the layer a description gives with the `add…` method of its type; an unknown type throws */
3
+ export const addSpec = (map, spec) => {
4
+ switch (spec.type) {
5
+ case 'lines':
6
+ return map.addLines(spec);
7
+ case 'circles':
8
+ return map.addCircles(spec);
9
+ case 'fills':
10
+ return map.addFills(spec);
11
+ case 'symbols':
12
+ return map.addSymbols(spec);
13
+ case 'extrusions':
14
+ return map.addExtrusions(spec);
15
+ case 'raster':
16
+ return map.addRaster(spec);
17
+ case 'ground':
18
+ return map.addGround(spec);
19
+ case 'network':
20
+ return map.addNetwork(spec);
21
+ case 'tiles3d':
22
+ return map.addTiles3d(spec);
23
+ case 'pointcloud':
24
+ return map.addPointCloud(spec);
25
+ case 'models':
26
+ return map.addModels(spec);
27
+ default: {
28
+ // Only from an application's configuration, untyped: the cases above cover every type
29
+ const { type } = spec;
30
+ throw new Error(`isard: no layer of type ${String(type)}`);
31
+ }
32
+ }
33
+ };
34
+ //# sourceMappingURL=layer-spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layer-spec.js","sourceRoot":"","sources":["../../src/map/layer-spec.ts"],"names":[],"mappings":"AAAA,oHAAoH;AAwBpH,oGAAoG;AACpG,MAAM,CAAC,MAAM,OAAO,GAAG,CAA8B,GAAW,EAAE,IAAkB,EAAS,EAAE;IAC7F,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,OAAO;YACV,OAAO,GAAG,CAAC,QAAQ,CAAI,IAAI,CAAC,CAAC;QAC/B,KAAK,SAAS;YACZ,OAAO,GAAG,CAAC,UAAU,CAAI,IAAI,CAAC,CAAC;QACjC,KAAK,OAAO;YACV,OAAO,GAAG,CAAC,QAAQ,CAAI,IAAI,CAAC,CAAC;QAC/B,KAAK,SAAS;YACZ,OAAO,GAAG,CAAC,UAAU,CAAI,IAAI,CAAC,CAAC;QACjC,KAAK,YAAY;YACf,OAAO,GAAG,CAAC,aAAa,CAAI,IAAI,CAAC,CAAC;QACpC,KAAK,QAAQ;YACX,OAAO,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC7B,KAAK,QAAQ;YACX,OAAO,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC7B,KAAK,SAAS;YACZ,OAAO,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAC9B,KAAK,SAAS;YACZ,OAAO,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAC9B,KAAK,YAAY;YACf,OAAO,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QACjC,KAAK,QAAQ;YACX,OAAO,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC7B,OAAO,CAAC,CAAC,CAAC;YACR,sFAAsF;YACtF,MAAM,EAAE,IAAI,EAAE,GAAuB,IAAI,CAAC;YAE1C,MAAM,IAAI,KAAK,CAAC,2BAA2B,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;AACH,CAAC,CAAC","sourcesContent":["/** A layer described by its type and options, as an application's configuration gives it, and the map adding it. */\n\nimport type { ExtrusionOptions } from '../layers/extrusions.ts';\nimport type { CircleOptions, FillOptions, LineOptions } from '../layers/features.ts';\nimport type { GroundOptions, Layer, ModelOptions } from '../layers/layers.ts';\nimport type { PointCloudOptions } from '../layers/pointclouds.ts';\nimport type { SymbolOptions } from '../layers/symbols.ts';\nimport type { GeoMap } from '../map.ts';\nimport type { NetworkOptions, RasterOptions, Tiles3dOptions } from '../types.ts';\n\n/** A layer by its type and the options of its `add…` method (`GeoMap.add`) */\nexport type LayerSpec<P = Record<string, unknown>> =\n | ({ type: 'lines' } & LineOptions<P>)\n | ({ type: 'circles' } & CircleOptions<P>)\n | ({ type: 'fills' } & FillOptions<P>)\n | ({ type: 'symbols' } & SymbolOptions<P>)\n | ({ type: 'extrusions' } & ExtrusionOptions<P>)\n | ({ type: 'raster' } & RasterOptions & { before?: Layer })\n | ({ type: 'ground' } & GroundOptions & { before?: Layer })\n | ({ type: 'network' } & NetworkOptions)\n | ({ type: 'tiles3d' } & Tiles3dOptions)\n | ({ type: 'pointcloud' } & PointCloudOptions & { before?: Layer })\n | ({ type: 'models' } & ModelOptions & { before?: Layer });\n\n/** Adds the layer a description gives with the `add…` method of its type; an unknown type throws */\nexport const addSpec = <P = Record<string, unknown>>(map: GeoMap, spec: LayerSpec<P>): Layer => {\n switch (spec.type) {\n case 'lines':\n return map.addLines<P>(spec);\n case 'circles':\n return map.addCircles<P>(spec);\n case 'fills':\n return map.addFills<P>(spec);\n case 'symbols':\n return map.addSymbols<P>(spec);\n case 'extrusions':\n return map.addExtrusions<P>(spec);\n case 'raster':\n return map.addRaster(spec);\n case 'ground':\n return map.addGround(spec);\n case 'network':\n return map.addNetwork(spec);\n case 'tiles3d':\n return map.addTiles3d(spec);\n case 'pointcloud':\n return map.addPointCloud(spec);\n case 'models':\n return map.addModels(spec);\n default: {\n // Only from an application's configuration, untyped: the cases above cover every type\n const { type }: { type?: unknown } = spec;\n\n throw new Error(`isard: no layer of type ${String(type)}`);\n }\n }\n};\n"]}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * The drawing order of a map's layers, kept beside the engine's: the layers waiting for the engine with 3D Tiles are
3
+ * in the order but not in the engine yet, and the order recreates the layers in a new engine after a context loss.
4
+ */
5
+ import type { Layer } from '../layers/layers.ts';
6
+ import type { Engine } from '../wasm/isard.js';
7
+ /** A map's layers in drawing order, bottom first, and those kept on top */
8
+ export declare class LayerStack {
9
+ /** Layers in drawing order (bottom first), to recreate them after a context loss */
10
+ readonly layers: Layer[];
11
+ /** Layers new layers go under */
12
+ readonly onTop: Set<Layer>;
13
+ private readonly engine;
14
+ /** `engine`: the map's engine of the moment */
15
+ constructor(engine: () => Engine);
16
+ has(layer: Layer): boolean;
17
+ /** Puts a new layer on top, under the layers kept on top (the basemap's labels) */
18
+ add(layer: Layer): void;
19
+ /** Forgets a removed layer */
20
+ forget(layer: Layer): void;
21
+ /** Moves a layer under `before`, or on top of all */
22
+ move(layer: Layer, before: Layer | undefined): void;
23
+ /** A layer made again in the engine under a new id: `old` removed, the new one moved to the layer's place */
24
+ replace(layer: Layer, old: number): void;
25
+ /** Moves a layer under all the others */
26
+ toBottom(layer: Layer): void;
27
+ /** Creates the layers in a new engine, in order, but those still `waiting` (for the engine with 3D Tiles); a layer
28
+ * that fails is reported and left out */
29
+ reattach(engine: Engine, waiting: (layer: Layer) => boolean): void;
30
+ /** Frees what the layers hold beside the engine (custom layers' WebGL objects, models' data) */
31
+ dispose(): void;
32
+ /** Takes a layer out of the drawing order (to put it back elsewhere, or for good) */
33
+ private unlist;
34
+ /** Index in the engine of the layer at `index`: the layers waiting for the engine with 3D Tiles are not in it yet */
35
+ private engineIndex;
36
+ }
@@ -0,0 +1,101 @@
1
+ /**
2
+ * The drawing order of a map's layers, kept beside the engine's: the layers waiting for the engine with 3D Tiles are
3
+ * in the order but not in the engine yet, and the order recreates the layers in a new engine after a context loss.
4
+ */
5
+ import { report } from "./checks.js";
6
+ /** A map's layers in drawing order, bottom first, and those kept on top */
7
+ export class LayerStack {
8
+ /** Layers in drawing order (bottom first), to recreate them after a context loss */
9
+ layers = [];
10
+ /** Layers new layers go under */
11
+ onTop = new Set();
12
+ engine;
13
+ /** `engine`: the map's engine of the moment */
14
+ constructor(engine) {
15
+ this.engine = engine;
16
+ }
17
+ has(layer) {
18
+ return this.layers.includes(layer);
19
+ }
20
+ /** Puts a new layer on top, under the layers kept on top (the basemap's labels) */
21
+ add(layer) {
22
+ this.layers.push(layer);
23
+ const top = this.layers.find((l) => this.onTop.has(l) && l !== layer);
24
+ if (top)
25
+ this.move(layer, top);
26
+ }
27
+ /** Forgets a removed layer */
28
+ forget(layer) {
29
+ this.unlist(layer);
30
+ this.onTop.delete(layer);
31
+ }
32
+ /** Moves a layer under `before`, or on top of all */
33
+ move(layer, before) {
34
+ this.unlist(layer);
35
+ const index = before ? this.layers.indexOf(before) : -1;
36
+ const at = index < 0 ? this.layers.length : index;
37
+ this.layers.splice(at, 0, layer);
38
+ if (layer.id >= 0)
39
+ this.engine().moveLayer(layer.id, this.engineIndex(at));
40
+ }
41
+ /** A layer made again in the engine under a new id: `old` removed, the new one moved to the layer's place */
42
+ replace(layer, old) {
43
+ const engine = this.engine();
44
+ engine.removeLayer(old);
45
+ const index = this.layers.indexOf(layer);
46
+ if (index >= 0)
47
+ engine.moveLayer(layer.id, this.engineIndex(index));
48
+ }
49
+ /** Moves a layer under all the others */
50
+ toBottom(layer) {
51
+ this.engine().moveLayer(layer.id, 0);
52
+ this.unlist(layer);
53
+ this.layers.unshift(layer);
54
+ }
55
+ /** Creates the layers in a new engine, in order, but those still `waiting` (for the engine with 3D Tiles); a layer
56
+ * that fails is reported and left out */
57
+ reattach(engine, waiting) {
58
+ // No layer refers to an id of the old engine while the others are created
59
+ this.layers.forEach((layer) => {
60
+ layer.forgetEngine();
61
+ });
62
+ this.layers.forEach((layer) => {
63
+ if (waiting(layer))
64
+ return;
65
+ try {
66
+ layer.attach(engine);
67
+ }
68
+ catch (error) {
69
+ report(error);
70
+ }
71
+ });
72
+ // Links between layers, once every layer has its new id (buildings colored by a network above them)
73
+ this.layers.forEach((layer) => {
74
+ if (layer.id < 0)
75
+ return;
76
+ try {
77
+ layer.relink(engine);
78
+ }
79
+ catch (error) {
80
+ report(error);
81
+ }
82
+ });
83
+ }
84
+ /** Frees what the layers hold beside the engine (custom layers' WebGL objects, models' data) */
85
+ dispose() {
86
+ this.layers.forEach((layer) => {
87
+ layer.dispose();
88
+ });
89
+ }
90
+ /** Takes a layer out of the drawing order (to put it back elsewhere, or for good) */
91
+ unlist(layer) {
92
+ const index = this.layers.indexOf(layer);
93
+ if (index >= 0)
94
+ this.layers.splice(index, 1);
95
+ }
96
+ /** Index in the engine of the layer at `index`: the layers waiting for the engine with 3D Tiles are not in it yet */
97
+ engineIndex(index) {
98
+ return this.layers.slice(0, index).filter((layer) => layer.id >= 0).length;
99
+ }
100
+ }
101
+ //# sourceMappingURL=layer-stack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layer-stack.js","sourceRoot":"","sources":["../../src/map/layer-stack.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The drawing order of a map's layers, kept beside the engine's: the layers waiting for the engine with 3D Tiles are\n * in the order but not in the engine yet, and the order recreates the layers in a new engine after a context loss.\n */\n\nimport type { Layer } from '../layers/layers.ts';\nimport type { Engine } from '../wasm/isard.js';\nimport { report } from './checks.ts';\n\n/** A map's layers in drawing order, bottom first, and those kept on top */\nexport class LayerStack {\n /** Layers in drawing order (bottom first), to recreate them after a context loss */\n readonly layers: Layer[] = [];\n /** Layers new layers go under */\n readonly onTop = new Set<Layer>();\n private readonly engine: () => Engine;\n\n /** `engine`: the map's engine of the moment */\n constructor(engine: () => Engine) {\n this.engine = engine;\n }\n\n has(layer: Layer): boolean {\n return this.layers.includes(layer);\n }\n\n /** Puts a new layer on top, under the layers kept on top (the basemap's labels) */\n add(layer: Layer): void {\n this.layers.push(layer);\n\n const top = this.layers.find((l) => this.onTop.has(l) && l !== layer);\n\n if (top) this.move(layer, top);\n }\n\n /** Forgets a removed layer */\n forget(layer: Layer): void {\n this.unlist(layer);\n this.onTop.delete(layer);\n }\n\n /** Moves a layer under `before`, or on top of all */\n move(layer: Layer, before: Layer | undefined): void {\n this.unlist(layer);\n\n const index = before ? this.layers.indexOf(before) : -1;\n const at = index < 0 ? this.layers.length : index;\n\n this.layers.splice(at, 0, layer);\n if (layer.id >= 0) this.engine().moveLayer(layer.id, this.engineIndex(at));\n }\n\n /** A layer made again in the engine under a new id: `old` removed, the new one moved to the layer's place */\n replace(layer: Layer, old: number): void {\n const engine = this.engine();\n\n engine.removeLayer(old);\n\n const index = this.layers.indexOf(layer);\n\n if (index >= 0) engine.moveLayer(layer.id, this.engineIndex(index));\n }\n\n /** Moves a layer under all the others */\n toBottom(layer: Layer): void {\n this.engine().moveLayer(layer.id, 0);\n this.unlist(layer);\n this.layers.unshift(layer);\n }\n\n /** Creates the layers in a new engine, in order, but those still `waiting` (for the engine with 3D Tiles); a layer\n * that fails is reported and left out */\n reattach(engine: Engine, waiting: (layer: Layer) => boolean): void {\n // No layer refers to an id of the old engine while the others are created\n this.layers.forEach((layer) => {\n layer.forgetEngine();\n });\n this.layers.forEach((layer) => {\n if (waiting(layer)) return;\n try {\n layer.attach(engine);\n } catch (error) {\n report(error);\n }\n });\n // Links between layers, once every layer has its new id (buildings colored by a network above them)\n this.layers.forEach((layer) => {\n if (layer.id < 0) return;\n try {\n layer.relink(engine);\n } catch (error) {\n report(error);\n }\n });\n }\n\n /** Frees what the layers hold beside the engine (custom layers' WebGL objects, models' data) */\n dispose(): void {\n this.layers.forEach((layer) => {\n layer.dispose();\n });\n }\n\n /** Takes a layer out of the drawing order (to put it back elsewhere, or for good) */\n private unlist(layer: Layer): void {\n const index = this.layers.indexOf(layer);\n\n if (index >= 0) this.layers.splice(index, 1);\n }\n\n /** Index in the engine of the layer at `index`: the layers waiting for the engine with 3D Tiles are not in it yet */\n private engineIndex(index: number): number {\n return this.layers.slice(0, index).filter((layer) => layer.id >= 0).length;\n }\n}\n"]}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * What the map shows over its canvas, in its container: the markers and popups (placed after every frame) and the
3
+ * controls in the four corners.
4
+ */
5
+ import type { GeoMap } from '../map.ts';
6
+ import type { Point } from '../types.ts';
7
+ import type { Control, ControlPosition } from '../ui/controls.ts';
8
+ import type { Positioned } from '../ui/overlay.ts';
9
+ /** The map's container: its canvas, the element of the markers and popups over it, the corners of the controls */
10
+ export declare class OverlayHost {
11
+ /** Canvas size in CSS pixels, kept on resize so placing overlays never reads the layout */
12
+ size: Point;
13
+ private readonly container;
14
+ private readonly canvas;
15
+ /** The map the controls are added to */
16
+ private readonly map;
17
+ /** Markers and popups, over the canvas */
18
+ private readonly overlay;
19
+ private readonly corners;
20
+ private readonly controls;
21
+ private readonly positioned;
22
+ /** Puts the canvas, the overlay and the corners in `container` */
23
+ constructor(container: HTMLElement, canvas: HTMLCanvasElement, map: GeoMap);
24
+ /** Adds a control in a corner; controls stack from the corner inward */
25
+ addControl(control: Control, position: ControlPosition): void;
26
+ removeControl(control: Control): void;
27
+ /** Shows a marker or popup, placed after every frame from now on */
28
+ attach(item: Positioned, element: HTMLElement): void;
29
+ detach(item: Positioned, element: HTMLElement): void;
30
+ /** Places one overlay now (it moved) */
31
+ position(item: Positioned): void;
32
+ /** Places every overlay for the frame just drawn (camera, relief altitudes): all in one pass, transforms only */
33
+ positionAll(): void;
34
+ /** Removes the controls, then the canvas, the overlay and the corners from the container */
35
+ destroy(): void;
36
+ }
@@ -0,0 +1,101 @@
1
+ /**
2
+ * What the map shows over its canvas, in its container: the markers and popups (placed after every frame) and the
3
+ * controls in the four corners.
4
+ */
5
+ import { injectStyle } from "../ui/style.js";
6
+ const CORNERS = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];
7
+ /** The map's container: its canvas, the element of the markers and popups over it, the corners of the controls */
8
+ export class OverlayHost {
9
+ /** Canvas size in CSS pixels, kept on resize so placing overlays never reads the layout */
10
+ size = [0, 0];
11
+ container;
12
+ canvas;
13
+ /** The map the controls are added to */
14
+ map;
15
+ /** Markers and popups, over the canvas */
16
+ overlay;
17
+ corners;
18
+ controls = new Map();
19
+ positioned = new Set();
20
+ /** Puts the canvas, the overlay and the corners in `container` */
21
+ constructor(container, canvas, map) {
22
+ this.container = container;
23
+ this.canvas = canvas;
24
+ this.map = map;
25
+ // Overlays and controls are positioned against the container
26
+ injectStyle(container.ownerDocument);
27
+ if (getComputedStyle(container).position === 'static')
28
+ container.style.position = 'relative';
29
+ container.classList.add('isard-map');
30
+ this.overlay = document.createElement('div');
31
+ this.overlay.className = 'isard-overlay';
32
+ const corner = (position) => {
33
+ const element = document.createElement('div');
34
+ element.className = `isard-ctrl-${position}`;
35
+ return element;
36
+ };
37
+ this.corners = {
38
+ 'top-left': corner('top-left'),
39
+ 'top-right': corner('top-right'),
40
+ 'bottom-left': corner('bottom-left'),
41
+ 'bottom-right': corner('bottom-right'),
42
+ };
43
+ container.append(canvas, this.overlay, ...CORNERS.map((position) => this.corners[position]));
44
+ }
45
+ /** Adds a control in a corner; controls stack from the corner inward */
46
+ addControl(control, position) {
47
+ if (this.controls.has(control))
48
+ return;
49
+ const element = control.onAdd(this.map);
50
+ element.classList.add('isard-ctrl');
51
+ // In the bottom corners the first control added stays lowest, as in MapLibre
52
+ if (position.startsWith('bottom'))
53
+ this.corners[position].prepend(element);
54
+ else
55
+ this.corners[position].append(element);
56
+ this.controls.set(control, element);
57
+ }
58
+ removeControl(control) {
59
+ const element = this.controls.get(control);
60
+ if (!element)
61
+ return;
62
+ this.controls.delete(control);
63
+ control.onRemove(this.map);
64
+ element.remove();
65
+ }
66
+ /** Shows a marker or popup, placed after every frame from now on */
67
+ attach(item, element) {
68
+ this.overlay.append(element);
69
+ this.positioned.add(item);
70
+ item.position(this.size);
71
+ }
72
+ detach(item, element) {
73
+ this.positioned.delete(item);
74
+ element.remove();
75
+ }
76
+ /** Places one overlay now (it moved) */
77
+ position(item) {
78
+ if (this.positioned.has(item))
79
+ item.position(this.size);
80
+ }
81
+ /** Places every overlay for the frame just drawn (camera, relief altitudes): all in one pass, transforms only */
82
+ positionAll() {
83
+ this.positioned.forEach((item) => {
84
+ item.position(this.size);
85
+ });
86
+ }
87
+ /** Removes the controls, then the canvas, the overlay and the corners from the container */
88
+ destroy() {
89
+ [...this.controls.keys()].forEach((control) => {
90
+ this.removeControl(control);
91
+ });
92
+ this.positioned.clear();
93
+ this.canvas.remove();
94
+ this.overlay.remove();
95
+ CORNERS.forEach((position) => {
96
+ this.corners[position].remove();
97
+ });
98
+ this.container.classList.remove('isard-map');
99
+ }
100
+ }
101
+ //# sourceMappingURL=overlay-host.js.map