isard 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +121 -0
- package/README.md +44 -39
- package/dist/basemap/basemaps.d.ts +1 -1
- package/dist/basemap/basemaps.js +2 -2
- package/dist/basemap/basemaps.js.map +1 -1
- package/dist/basemap/grid.d.ts +5 -5
- package/dist/basemap/grid.js +59 -65
- package/dist/basemap/grid.js.map +1 -1
- package/dist/basemap/mvt.d.ts +1 -1
- package/dist/basemap/mvt.js +6 -6
- package/dist/basemap/mvt.js.map +1 -1
- package/dist/basemap/pmtiles.d.ts +10 -10
- package/dist/basemap/pmtiles.js +39 -31
- package/dist/basemap/pmtiles.js.map +1 -1
- package/dist/basemap/pmtileslayer.d.ts +33 -0
- package/dist/basemap/pmtileslayer.js +97 -0
- package/dist/basemap/pmtileslayer.js.map +1 -0
- package/dist/basemap/resample.d.ts +2 -2
- package/dist/basemap/resample.js +16 -14
- package/dist/basemap/resample.js.map +1 -1
- package/dist/basemap/terrain.d.ts +3 -3
- package/dist/basemap/terrain.js +6 -6
- package/dist/basemap/terrain.js.map +1 -1
- package/dist/basemap/trees.d.ts +26 -0
- package/dist/basemap/trees.js +141 -0
- package/dist/basemap/trees.js.map +1 -0
- package/dist/basemap/vectorstyle.d.ts +22 -10
- package/dist/basemap/vectorstyle.js +163 -110
- package/dist/basemap/vectorstyle.js.map +1 -1
- package/dist/basemap/vectortiles.d.ts +70 -47
- package/dist/basemap/vectortiles.js +480 -358
- package/dist/basemap/vectortiles.js.map +1 -1
- package/dist/basemap/wmts.d.ts +3 -3
- package/dist/basemap/wmts.js +16 -11
- package/dist/basemap/wmts.js.map +1 -1
- package/dist/basemap/workerpool.d.ts +17 -0
- package/dist/basemap/workerpool.js +194 -0
- package/dist/basemap/workerpool.js.map +1 -0
- package/dist/basemap.worker.js +2 -2
- package/dist/basemap.worker.js.map +21 -13
- package/dist/bind/layers.d.ts +13 -4
- package/dist/bind/layers.js +64 -40
- package/dist/bind/layers.js.map +1 -1
- package/dist/data/crs.d.ts +10 -10
- package/dist/data/crs.js +38 -34
- package/dist/data/crs.js.map +1 -1
- package/dist/data/gpx.d.ts +1 -1
- package/dist/data/gpx.js +20 -20
- package/dist/data/gpx.js.map +1 -1
- package/dist/data/kml.d.ts +1 -1
- package/dist/data/kml.js +42 -39
- package/dist/data/kml.js.map +1 -1
- package/dist/data/topojson.d.ts +1 -1
- package/dist/data/topojson.js +15 -10
- package/dist/data/topojson.js.map +1 -1
- package/dist/data/xml.d.ts +5 -5
- package/dist/data/xml.js +19 -18
- package/dist/data/xml.js.map +1 -1
- package/dist/decoder.worker.js +4 -4
- package/dist/decoder.worker.js.map +6 -6
- package/dist/engine/decoders.d.ts +2 -2
- package/dist/engine/decoders.js +28 -25
- package/dist/engine/decoders.js.map +1 -1
- package/dist/engine/loader.js +13 -14
- package/dist/engine/loader.js.map +1 -1
- package/dist/engine/requests.d.ts +1 -1
- package/dist/engine/requests.js +19 -16
- package/dist/engine/requests.js.map +1 -1
- package/dist/engine-loader.d.ts +13 -9
- package/dist/engine-loader.js +38 -28
- package/dist/engine-loader.js.map +1 -1
- package/dist/geoplateforme.d.ts +26 -10
- package/dist/geoplateforme.js +45 -20
- package/dist/geoplateforme.js.map +1 -1
- package/dist/index.d.ts +12 -4
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -1
- package/dist/isard_bg.wasm +0 -0
- package/dist/isard_core_bg.wasm +0 -0
- package/dist/isard_points_bg.wasm +0 -0
- package/dist/isard_tess_bg.wasm +0 -0
- package/dist/layers/extrusions.d.ts +1 -1
- package/dist/layers/extrusions.js +10 -5
- package/dist/layers/extrusions.js.map +1 -1
- package/dist/layers/features.d.ts +10 -10
- package/dist/layers/features.js +41 -42
- package/dist/layers/features.js.map +1 -1
- package/dist/layers/glyphs.d.ts +3 -3
- package/dist/layers/glyphs.js +34 -40
- package/dist/layers/glyphs.js.map +1 -1
- package/dist/layers/icons.d.ts +8 -8
- package/dist/layers/icons.js +76 -68
- package/dist/layers/icons.js.map +1 -1
- package/dist/layers/layers.d.ts +1 -1
- package/dist/layers/layers.js +42 -29
- package/dist/layers/layers.js.map +1 -1
- package/dist/layers/panoramas.d.ts +2 -2
- package/dist/layers/panoramas.js +52 -41
- package/dist/layers/panoramas.js.map +1 -1
- package/dist/layers/pointclouds.d.ts +3 -3
- package/dist/layers/pointclouds.js +25 -33
- package/dist/layers/pointclouds.js.map +1 -1
- package/dist/layers/symbols.d.ts +1 -1
- package/dist/layers/symbols.js +68 -71
- package/dist/layers/symbols.js.map +1 -1
- package/dist/layers/vectors.d.ts +60 -0
- package/dist/layers/vectors.js +130 -0
- package/dist/layers/vectors.js.map +1 -0
- package/dist/map/basemap-layers.d.ts +26 -0
- package/dist/map/basemap-layers.js +61 -0
- package/dist/map/basemap-layers.js.map +1 -0
- package/dist/map/canvas.d.ts +17 -0
- package/dist/map/canvas.js +56 -0
- package/dist/map/canvas.js.map +1 -0
- package/dist/map/checks.d.ts +11 -0
- package/dist/map/checks.js +39 -0
- package/dist/map/checks.js.map +1 -0
- package/dist/map/credits.d.ts +17 -0
- package/dist/map/credits.js +34 -0
- package/dist/map/credits.js.map +1 -0
- package/dist/map/engine-settings.d.ts +15 -0
- package/dist/map/engine-settings.js +45 -0
- package/dist/map/engine-settings.js.map +1 -0
- package/dist/map/engines.d.ts +41 -0
- package/dist/map/engines.js +77 -0
- package/dist/map/engines.js.map +1 -0
- package/dist/map/events.d.ts +14 -0
- package/dist/map/events.js +46 -0
- package/dist/map/events.js.map +1 -0
- package/dist/map/frame-loop.d.ts +64 -0
- package/dist/map/frame-loop.js +145 -0
- package/dist/map/frame-loop.js.map +1 -0
- package/dist/map/hover-pick.d.ts +30 -0
- package/dist/map/hover-pick.js +56 -0
- package/dist/map/hover-pick.js.map +1 -0
- package/dist/map/layer-spec.d.ts +42 -0
- package/dist/map/layer-spec.js +34 -0
- package/dist/map/layer-spec.js.map +1 -0
- package/dist/map/layer-stack.d.ts +36 -0
- package/dist/map/layer-stack.js +101 -0
- package/dist/map/layer-stack.js.map +1 -0
- package/dist/map/overlay-host.d.ts +36 -0
- package/dist/map/overlay-host.js +101 -0
- package/dist/map/overlay-host.js.map +1 -0
- package/dist/map/panorama-host.d.ts +5 -0
- package/dist/map/panorama-host.js +32 -0
- package/dist/map/panorama-host.js.map +1 -0
- package/dist/map/raster-source.d.ts +11 -0
- package/dist/map/raster-source.js +26 -0
- package/dist/map/raster-source.js.map +1 -0
- package/dist/map/symbol-atlases.d.ts +26 -0
- package/dist/map/symbol-atlases.js +59 -0
- package/dist/map/symbol-atlases.js.map +1 -0
- package/dist/map/viewshed.d.ts +5 -0
- package/dist/map/viewshed.js +28 -0
- package/dist/map/viewshed.js.map +1 -0
- package/dist/map/workers.d.ts +46 -0
- package/dist/map/workers.js +73 -0
- package/dist/map/workers.js.map +1 -0
- package/dist/map.d.ts +54 -126
- package/dist/map.js +227 -698
- package/dist/map.js.map +1 -1
- package/dist/react/Control.d.ts +11 -0
- package/dist/react/Control.js +18 -0
- package/dist/react/Control.js.map +1 -0
- package/dist/react/CustomLayer.d.ts +11 -0
- package/dist/react/CustomLayer.js +30 -0
- package/dist/react/CustomLayer.js.map +1 -0
- package/dist/react/IsardMap.d.ts +43 -0
- package/dist/react/IsardMap.js +147 -0
- package/dist/react/IsardMap.js.map +1 -0
- package/dist/react/Layer.d.ts +42 -0
- package/dist/react/Layer.js +74 -0
- package/dist/react/Layer.js.map +1 -0
- package/dist/react/Marker.d.ts +24 -0
- package/dist/react/Marker.js +53 -0
- package/dist/react/Marker.js.map +1 -0
- package/dist/react/Panel.d.ts +11 -0
- package/dist/react/Panel.js +37 -0
- package/dist/react/Panel.js.map +1 -0
- package/dist/react/Popup.d.ts +18 -0
- package/dist/react/Popup.js +60 -0
- package/dist/react/Popup.js.map +1 -0
- package/dist/react/Swipe.d.ts +16 -0
- package/dist/react/Swipe.js +52 -0
- package/dist/react/Swipe.js.map +1 -0
- package/dist/react/VectorGeometry.d.ts +35 -0
- package/dist/react/VectorGeometry.js +82 -0
- package/dist/react/VectorGeometry.js.map +1 -0
- package/dist/react/Viewshed.d.ts +5 -0
- package/dist/react/Viewshed.js +28 -0
- package/dist/react/Viewshed.js.map +1 -0
- package/dist/react/context.d.ts +33 -0
- package/dist/react/context.js +20 -0
- package/dist/react/context.js.map +1 -0
- package/dist/react/index.d.ts +16 -108
- package/dist/react/index.js +11 -397
- package/dist/react/index.js.map +1 -1
- package/dist/settings.d.ts +5 -9
- package/dist/settings.js +17 -15
- package/dist/settings.js.map +1 -1
- package/dist/types.d.ts +27 -4
- package/dist/types.js.map +1 -1
- package/dist/ui/controls.js +6 -4
- package/dist/ui/controls.js.map +1 -1
- package/dist/ui/interaction.d.ts +2 -2
- package/dist/ui/interaction.js +8 -7
- package/dist/ui/interaction.js.map +1 -1
- package/dist/ui/minimap.d.ts +25 -0
- package/dist/ui/minimap.js +90 -0
- package/dist/ui/minimap.js.map +1 -0
- package/dist/ui/overlay.js +18 -20
- package/dist/ui/overlay.js.map +1 -1
- package/dist/ui/scale.d.ts +19 -0
- package/dist/ui/scale.js +44 -0
- package/dist/ui/scale.js.map +1 -0
- package/dist/ui/search.d.ts +25 -0
- package/dist/ui/search.js +119 -0
- package/dist/ui/search.js.map +1 -0
- package/dist/ui/style.d.ts +1 -1
- package/dist/ui/style.js +19 -2
- package/dist/ui/style.js.map +1 -1
- package/dist/util/animation.d.ts +3 -3
- package/dist/util/animation.js +6 -6
- package/dist/util/animation.js.map +1 -1
- package/dist/util/color.d.ts +1 -1
- package/dist/util/color.js +14 -16
- package/dist/util/color.js.map +1 -1
- package/dist/util/geo.d.ts +6 -6
- package/dist/util/geo.js +12 -12
- package/dist/util/geo.js.map +1 -1
- package/dist/util/guards.d.ts +7 -0
- package/dist/util/guards.js +8 -0
- package/dist/util/guards.js.map +1 -0
- package/dist/util/lru.js.map +1 -1
- package/dist/util/sun.d.ts +11 -0
- package/dist/util/sun.js +26 -0
- package/dist/util/sun.js.map +1 -0
- package/dist/wasm/isard.d.ts +250 -7
- package/dist/wasm/isard.js +375 -8
- package/dist/wasm/isard_core.d.ts +226 -7
- package/dist/wasm/isard_core.js +351 -8
- package/dist/wasm/isard_tess.d.ts +109 -0
- package/dist/wasm/isard_tess.js +398 -0
- package/dist/workers/basemap/geometry.d.ts +72 -0
- package/dist/workers/basemap/labels.d.ts +8 -0
- package/dist/workers/basemap/raster.d.ts +10 -0
- package/dist/workers/basemap/tiles.d.ts +65 -0
- package/dist/workers/basemap/trees.d.ts +19 -0
- package/dist/workers/basemap.worker.d.ts +126 -22
- package/dist/workers/basemap.worker.js +76 -544
- package/dist/workers/basemap.worker.js.map +1 -1
- package/package.json +5 -4
- package/vite.js +10 -2
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which engine a map runs: the core one, or the one with 3D Tiles, from the start or loaded once a layer needs it
|
|
3
|
+
* (the map is rebuilt on it then); and the workers decoding its 3D Tiles, started with the first engine that has them.
|
|
4
|
+
*/
|
|
5
|
+
import { engineUrl, loadFullEngineLater, preloadFullEngine, startTileLoader, } from "../engine-loader.js";
|
|
6
|
+
import { applySettings } from "./engine-settings.js";
|
|
7
|
+
/** The engine class of a map, and the engine with 3D Tiles loaded when needed */
|
|
8
|
+
export class MapEngines {
|
|
9
|
+
/** The class of the engine: without 3D Tiles until a 3D Tiles layer is added, unless asked for from the start */
|
|
10
|
+
engineClass;
|
|
11
|
+
/** The module of the engine with 3D Tiles once it runs the map (the decoding workers run it too) */
|
|
12
|
+
module;
|
|
13
|
+
#upgrading;
|
|
14
|
+
loader;
|
|
15
|
+
options;
|
|
16
|
+
/** The map is destroyed: a loaded engine is not used */
|
|
17
|
+
gone;
|
|
18
|
+
/** `module`: the module of the engine with 3D Tiles if `engineClass` is that engine */
|
|
19
|
+
constructor(engineClass, module, options, gone) {
|
|
20
|
+
this.engineClass = engineClass;
|
|
21
|
+
this.module = module;
|
|
22
|
+
this.options = { ...options };
|
|
23
|
+
this.gone = gone;
|
|
24
|
+
}
|
|
25
|
+
/** The engine with 3D Tiles runs the map */
|
|
26
|
+
get tiles3d() {
|
|
27
|
+
return this.module !== undefined;
|
|
28
|
+
}
|
|
29
|
+
/** The engine with 3D Tiles is loading, for the 3D Tiles layers added on the core engine */
|
|
30
|
+
get upgrading() {
|
|
31
|
+
return this.#upgrading;
|
|
32
|
+
}
|
|
33
|
+
/** A new engine drawing on `canvas`, with the settings and the decoding workers of 3D Tiles if it has them */
|
|
34
|
+
create(canvas, redraw, settings) {
|
|
35
|
+
const engine = new this.engineClass(canvas, redraw);
|
|
36
|
+
applySettings(engine, settings);
|
|
37
|
+
// The decoding workers of 3D Tiles, with the engine that has them (they run its module) and unless turned off
|
|
38
|
+
this.loader ??= this.module && startTileLoader(this.module, this.options, engine);
|
|
39
|
+
if (this.loader)
|
|
40
|
+
engine.setTileLoader(this.loader);
|
|
41
|
+
return engine;
|
|
42
|
+
}
|
|
43
|
+
/** Height of the geoid above the ellipsoid at a position, in metres */
|
|
44
|
+
geoidHeight(lon, lat) {
|
|
45
|
+
return this.engineClass.geoidHeight(lon, lat);
|
|
46
|
+
}
|
|
47
|
+
/** The matrix of a custom layer's model at a position */
|
|
48
|
+
customMatrix(lon, lat, altitude) {
|
|
49
|
+
return this.engineClass.customMatrix(lon, lat, altitude);
|
|
50
|
+
}
|
|
51
|
+
/** Loads the engine with 3D Tiles, once at a time: `loaded` once it is the map's class, `failed` with the error;
|
|
52
|
+
* neither if the map is gone by then */
|
|
53
|
+
upgrade(loaded, failed) {
|
|
54
|
+
this.#upgrading ??= loadFullEngineLater(engineUrl('full', this.options)).then(({ module, Engine }) => {
|
|
55
|
+
this.#upgrading = undefined;
|
|
56
|
+
if (this.gone())
|
|
57
|
+
return;
|
|
58
|
+
this.engineClass = Engine;
|
|
59
|
+
this.module = module;
|
|
60
|
+
loaded();
|
|
61
|
+
}, (error) => {
|
|
62
|
+
this.#upgrading = undefined;
|
|
63
|
+
if (this.gone())
|
|
64
|
+
return;
|
|
65
|
+
failed(error);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/** Downloads and compiles the engine with 3D Tiles without running it, unless the map is gone or has it by then */
|
|
69
|
+
preload() {
|
|
70
|
+
preloadFullEngine(engineUrl('full', this.options), () => !this.gone() && !this.module);
|
|
71
|
+
}
|
|
72
|
+
/** Stops the decoding workers */
|
|
73
|
+
destroy() {
|
|
74
|
+
this.loader?.destroy();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=engines.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engines.js","sourceRoot":"","sources":["../../src/map/engines.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Which engine a map runs: the core one, or the one with 3D Tiles, from the start or loaded once a layer needs it\n * (the map is rebuilt on it then); and the workers decoding its 3D Tiles, started with the first engine that has them.\n */\n\nimport type { TileLoader } from '../engine/loader.ts';\nimport {\n type EngineClass,\n engineUrl,\n loadFullEngineLater,\n preloadFullEngine,\n startTileLoader,\n} from '../engine-loader.ts';\nimport type { Settings } from '../settings.ts';\nimport type { GeoMapOptions } from '../types.ts';\nimport type { Engine } from '../wasm/isard.js';\nimport { applySettings } from './engine-settings.ts';\n\n/** What loading the engine with 3D Tiles and its workers needs */\nexport type Tiles3dEngineOptions = Pick<\n GeoMapOptions,\n 'wasmUrl' | 'workers' | 'workerUrl' | 'decoders' | 'pointsWasmUrl' | 'assetsUrl'\n>;\n\n/** The engine class of a map, and the engine with 3D Tiles loaded when needed */\nexport class MapEngines {\n /** The class of the engine: without 3D Tiles until a 3D Tiles layer is added, unless asked for from the start */\n private engineClass: EngineClass;\n /** The module of the engine with 3D Tiles once it runs the map (the decoding workers run it too) */\n private module: WebAssembly.Module | undefined;\n #upgrading: Promise<void> | undefined;\n private loader: TileLoader | undefined;\n private readonly options: Tiles3dEngineOptions;\n /** The map is destroyed: a loaded engine is not used */\n private readonly gone: () => boolean;\n\n /** `module`: the module of the engine with 3D Tiles if `engineClass` is that engine */\n constructor(\n engineClass: EngineClass,\n module: WebAssembly.Module | undefined,\n options: Tiles3dEngineOptions,\n gone: () => boolean,\n ) {\n this.engineClass = engineClass;\n this.module = module;\n this.options = { ...options };\n this.gone = gone;\n }\n\n /** The engine with 3D Tiles runs the map */\n get tiles3d(): boolean {\n return this.module !== undefined;\n }\n\n /** The engine with 3D Tiles is loading, for the 3D Tiles layers added on the core engine */\n get upgrading(): Promise<void> | undefined {\n return this.#upgrading;\n }\n\n /** A new engine drawing on `canvas`, with the settings and the decoding workers of 3D Tiles if it has them */\n create(canvas: HTMLCanvasElement, redraw: () => void, settings: Settings): Engine {\n const engine = new this.engineClass(canvas, redraw);\n\n applySettings(engine, settings);\n // The decoding workers of 3D Tiles, with the engine that has them (they run its module) and unless turned off\n this.loader ??= this.module && startTileLoader(this.module, this.options, engine);\n if (this.loader) engine.setTileLoader(this.loader);\n\n return engine;\n }\n\n /** Height of the geoid above the ellipsoid at a position, in metres */\n geoidHeight(lon: number, lat: number): number {\n return this.engineClass.geoidHeight(lon, lat);\n }\n\n /** The matrix of a custom layer's model at a position */\n customMatrix(lon: number, lat: number, altitude: number): Float32Array | undefined {\n return this.engineClass.customMatrix(lon, lat, altitude);\n }\n\n /** Loads the engine with 3D Tiles, once at a time: `loaded` once it is the map's class, `failed` with the error;\n * neither if the map is gone by then */\n upgrade(loaded: () => void, failed: (error: unknown) => void): void {\n this.#upgrading ??= loadFullEngineLater(engineUrl('full', this.options)).then(\n ({ module, Engine }) => {\n this.#upgrading = undefined;\n if (this.gone()) return;\n this.engineClass = Engine;\n this.module = module;\n loaded();\n },\n (error: unknown) => {\n this.#upgrading = undefined;\n if (this.gone()) return;\n failed(error);\n },\n );\n }\n\n /** Downloads and compiles the engine with 3D Tiles without running it, unless the map is gone or has it by then */\n preload(): void {\n preloadFullEngine(engineUrl('full', this.options), () => !this.gone() && !this.module);\n }\n\n /** Stops the decoding workers */\n destroy(): void {\n this.loader?.destroy();\n }\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** The listeners of the map's events: added, called, cleared with the map. */
|
|
2
|
+
import type { MapEvents } from '../types.ts';
|
|
3
|
+
/** The listeners of the map's events, by type */
|
|
4
|
+
export declare class MapListeners {
|
|
5
|
+
private readonly listeners;
|
|
6
|
+
/** Listens to an event; returns the function that stops listening */
|
|
7
|
+
on<K extends keyof MapEvents>(type: K, listener: (event: MapEvents[K]) => void): () => void;
|
|
8
|
+
/** Calls the listeners; one that throws is reported and does not stop the others nor the frame */
|
|
9
|
+
emit<K extends keyof MapEvents>(type: K, event: MapEvents[K]): void;
|
|
10
|
+
/** Something listens to `type` */
|
|
11
|
+
has(type: keyof MapEvents): boolean;
|
|
12
|
+
/** Forgets every listener */
|
|
13
|
+
clear(): void;
|
|
14
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** The listeners of the map's events: added, called, cleared with the map. */
|
|
2
|
+
import { report } from "./checks.js";
|
|
3
|
+
/** The listeners of the map's events, by type */
|
|
4
|
+
export class MapListeners {
|
|
5
|
+
listeners = {
|
|
6
|
+
movestart: new Set(),
|
|
7
|
+
move: new Set(),
|
|
8
|
+
moveend: new Set(),
|
|
9
|
+
resize: new Set(),
|
|
10
|
+
hover: new Set(),
|
|
11
|
+
hoverfeature: new Set(),
|
|
12
|
+
click: new Set(),
|
|
13
|
+
render: new Set(),
|
|
14
|
+
idle: new Set(),
|
|
15
|
+
leave: new Set(),
|
|
16
|
+
};
|
|
17
|
+
/** Listens to an event; returns the function that stops listening */
|
|
18
|
+
on(type, listener) {
|
|
19
|
+
const listeners = this.listeners[type];
|
|
20
|
+
listeners.add(listener);
|
|
21
|
+
return () => listeners.delete(listener);
|
|
22
|
+
}
|
|
23
|
+
/** Calls the listeners; one that throws is reported and does not stop the others nor the frame */
|
|
24
|
+
emit(type, event) {
|
|
25
|
+
const listeners = this.listeners[type];
|
|
26
|
+
listeners.forEach((listener) => {
|
|
27
|
+
try {
|
|
28
|
+
listener(event);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
report(error);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/** Something listens to `type` */
|
|
36
|
+
has(type) {
|
|
37
|
+
return this.listeners[type].size > 0;
|
|
38
|
+
}
|
|
39
|
+
/** Forgets every listener */
|
|
40
|
+
clear() {
|
|
41
|
+
Object.values(this.listeners).forEach((listeners) => {
|
|
42
|
+
listeners.clear();
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/map/events.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAG9E,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAIrC,iDAAiD;AACjD,MAAM,OAAO,YAAY;IACN,SAAS,GAAc;QACtC,SAAS,EAAE,IAAI,GAAG,EAAE;QACpB,IAAI,EAAE,IAAI,GAAG,EAAE;QACf,OAAO,EAAE,IAAI,GAAG,EAAE;QAClB,MAAM,EAAE,IAAI,GAAG,EAAE;QACjB,KAAK,EAAE,IAAI,GAAG,EAAE;QAChB,YAAY,EAAE,IAAI,GAAG,EAAE;QACvB,KAAK,EAAE,IAAI,GAAG,EAAE;QAChB,MAAM,EAAE,IAAI,GAAG,EAAE;QACjB,IAAI,EAAE,IAAI,GAAG,EAAE;QACf,KAAK,EAAE,IAAI,GAAG,EAAE;KACjB,CAAC;IAEF,qEAAqE;IACrE,EAAE,CAA4B,IAAO,EAAE,QAAuC;QAC5E,MAAM,SAAS,GAAuC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAE3E,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAExB,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC;IAED,kGAAkG;IAClG,IAAI,CAA4B,IAAO,EAAE,KAAmB;QAC1D,MAAM,SAAS,GAAuC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAE3E,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;YAC7B,IAAI,CAAC;gBACH,QAAQ,CAAC,KAAK,CAAC,CAAC;YAClB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,KAAK,CAAC,CAAC;YAChB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,kCAAkC;IAClC,GAAG,CAAC,IAAqB;QACvB,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;IACvC,CAAC;IAED,6BAA6B;IAC7B,KAAK;QACH,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE;YAClD,SAAS,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC,CAAC,CAAC;IACL,CAAC;CACF","sourcesContent":["/** The listeners of the map's events: added, called, cleared with the map. */\n\nimport type { MapEvents } from '../types.ts';\nimport { report } from './checks.ts';\n\ntype Listeners = { [K in keyof MapEvents]: Set<(event: MapEvents[K]) => void> };\n\n/** The listeners of the map's events, by type */\nexport class MapListeners {\n private readonly listeners: Listeners = {\n movestart: new Set(),\n move: new Set(),\n moveend: new Set(),\n resize: new Set(),\n hover: new Set(),\n hoverfeature: new Set(),\n click: new Set(),\n render: new Set(),\n idle: new Set(),\n leave: new Set(),\n };\n\n /** Listens to an event; returns the function that stops listening */\n on<K extends keyof MapEvents>(type: K, listener: (event: MapEvents[K]) => void): () => void {\n const listeners: Set<(event: MapEvents[K]) => void> = this.listeners[type];\n\n listeners.add(listener);\n\n return () => listeners.delete(listener);\n }\n\n /** Calls the listeners; one that throws is reported and does not stop the others nor the frame */\n emit<K extends keyof MapEvents>(type: K, event: MapEvents[K]): void {\n const listeners: Set<(event: MapEvents[K]) => void> = this.listeners[type];\n\n listeners.forEach((listener) => {\n try {\n listener(event);\n } catch (error) {\n report(error);\n }\n });\n }\n\n /** Something listens to `type` */\n has(type: keyof MapEvents): boolean {\n return this.listeners[type].size > 0;\n }\n\n /** Forgets every listener */\n clear(): void {\n Object.values(this.listeners).forEach((listeners) => {\n listeners.clear();\n });\n }\n}\n"]}
|
|
@@ -0,0 +1,64 @@
|
|
|
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
|
+
import type { Point } from '../types.ts';
|
|
7
|
+
import type { Step } from '../util/animation.ts';
|
|
8
|
+
import type { Camera, Engine } from '../wasm/isard.js';
|
|
9
|
+
import type { MapListeners } from './events.ts';
|
|
10
|
+
/** What the frame loop needs of its map */
|
|
11
|
+
export interface FrameHost {
|
|
12
|
+
/** The map's engine of the moment */
|
|
13
|
+
engine(): Engine;
|
|
14
|
+
/** The map's camera */
|
|
15
|
+
camera(): Camera;
|
|
16
|
+
/** The WebGL context is lost: nothing is drawn */
|
|
17
|
+
lost(): boolean;
|
|
18
|
+
/** The pointer or the keys are moving the camera: no 'moveend' yet */
|
|
19
|
+
interacting(): boolean;
|
|
20
|
+
/** Custom layers are drawn: they read the camera of the frame */
|
|
21
|
+
customLayers(): boolean;
|
|
22
|
+
/** The engine with 3D Tiles is loading: not idle */
|
|
23
|
+
upgrading(): boolean;
|
|
24
|
+
/** The frame is drawn: what follows it (the overlays placed, the hover picking asked for at `hovered`) */
|
|
25
|
+
drawn(hovered: Point | undefined): void;
|
|
26
|
+
}
|
|
27
|
+
/** The frames of a map, asked for and drawn */
|
|
28
|
+
export declare class FrameLoop {
|
|
29
|
+
#private;
|
|
30
|
+
private readonly host;
|
|
31
|
+
private readonly listeners;
|
|
32
|
+
/** Frame asked for, 0 if none */
|
|
33
|
+
private requested;
|
|
34
|
+
private inFrame;
|
|
35
|
+
private animation;
|
|
36
|
+
/** The pointer's position for the next frame */
|
|
37
|
+
private hoverPoint;
|
|
38
|
+
private lastCamera;
|
|
39
|
+
/** The camera moved since the last 'moveend' */
|
|
40
|
+
private moving;
|
|
41
|
+
/** `listeners`: the map's, told of the frame's events */
|
|
42
|
+
constructor(host: FrameHost, listeners: MapListeners);
|
|
43
|
+
/** The last frame found everything loaded ('idle' sent) */
|
|
44
|
+
get settled(): boolean;
|
|
45
|
+
/** The camera of the frame being drawn: what `getCamera` gives the custom layers while the engine is busy */
|
|
46
|
+
get camera(): Camera | undefined;
|
|
47
|
+
/** Asks for a frame; several calls before the next frame draw it once */
|
|
48
|
+
request(): void;
|
|
49
|
+
/** Asks for a frame that sends 'idle' once everything is loaded, even if the last one already did: the waiters of
|
|
50
|
+
* `whenIdle` on a map already idle (else no frame would change from loading to loaded, and none would send it) */
|
|
51
|
+
requestIdle(): void;
|
|
52
|
+
/** Runs `step` every frame until it returns false; replaces the running animation */
|
|
53
|
+
animate(step: Step | undefined): void;
|
|
54
|
+
/** The pointer's position for the next frame (undefined: none) */
|
|
55
|
+
hover(point: Point | undefined): void;
|
|
56
|
+
/** Draws a frame now, in place of the one asked for (a resized canvas is cleared: waiting one frame would flash) */
|
|
57
|
+
drawNow(): void;
|
|
58
|
+
/** Cancels the frame asked for (the context is lost); a new one can be asked for */
|
|
59
|
+
cancel(): void;
|
|
60
|
+
/** Cancels the frame asked for, for good (the map is destroyed): it stays marked as asked for */
|
|
61
|
+
stop(): void;
|
|
62
|
+
private frame;
|
|
63
|
+
private draw;
|
|
64
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
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
|
+
/** Asks for a frame that sends 'idle' once everything is loaded, even if the last one already did: the waiters of
|
|
42
|
+
* `whenIdle` on a map already idle (else no frame would change from loading to loaded, and none would send it) */
|
|
43
|
+
requestIdle() {
|
|
44
|
+
this.#settled = false;
|
|
45
|
+
this.request();
|
|
46
|
+
}
|
|
47
|
+
/** Runs `step` every frame until it returns false; replaces the running animation */
|
|
48
|
+
animate(step) {
|
|
49
|
+
// A flight cut short no longer needs its destination
|
|
50
|
+
if (this.animation)
|
|
51
|
+
this.host.engine().clearPreload();
|
|
52
|
+
this.animation = step;
|
|
53
|
+
this.request();
|
|
54
|
+
}
|
|
55
|
+
/** The pointer's position for the next frame (undefined: none) */
|
|
56
|
+
hover(point) {
|
|
57
|
+
this.hoverPoint = point;
|
|
58
|
+
}
|
|
59
|
+
/** Draws a frame now, in place of the one asked for (a resized canvas is cleared: waiting one frame would flash) */
|
|
60
|
+
drawNow() {
|
|
61
|
+
cancelAnimationFrame(this.requested);
|
|
62
|
+
this.frame(performance.now());
|
|
63
|
+
}
|
|
64
|
+
/** Cancels the frame asked for (the context is lost); a new one can be asked for */
|
|
65
|
+
cancel() {
|
|
66
|
+
cancelAnimationFrame(this.requested);
|
|
67
|
+
this.requested = 0;
|
|
68
|
+
}
|
|
69
|
+
/** Cancels the frame asked for, for good (the map is destroyed): it stays marked as asked for */
|
|
70
|
+
stop() {
|
|
71
|
+
cancelAnimationFrame(this.requested);
|
|
72
|
+
}
|
|
73
|
+
frame(now) {
|
|
74
|
+
this.requested = 0;
|
|
75
|
+
try {
|
|
76
|
+
this.inFrame = true;
|
|
77
|
+
this.draw(now);
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
// Whatever throws in a frame, the next ones are still drawn
|
|
81
|
+
this.inFrame = false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
draw(now) {
|
|
85
|
+
if (this.animation && !this.animation(now))
|
|
86
|
+
this.animation = undefined;
|
|
87
|
+
const { host, listeners } = this;
|
|
88
|
+
const camera = host.camera();
|
|
89
|
+
const key = `${camera.center}|${camera.zoom}|${camera.pitch}|${camera.bearing}`;
|
|
90
|
+
const moved = key !== this.lastCamera;
|
|
91
|
+
if (moved) {
|
|
92
|
+
// The first frame is no move
|
|
93
|
+
if (!this.moving && this.lastCamera !== '') {
|
|
94
|
+
this.moving = true;
|
|
95
|
+
listeners.emit('movestart', camera);
|
|
96
|
+
}
|
|
97
|
+
this.lastCamera = key;
|
|
98
|
+
listeners.emit('move', camera);
|
|
99
|
+
}
|
|
100
|
+
else if (this.moving && !this.animation && !host.interacting()) {
|
|
101
|
+
this.moving = false;
|
|
102
|
+
listeners.emit('moveend', camera);
|
|
103
|
+
}
|
|
104
|
+
// Values for the pointer position are computed before drawing, in the same frame
|
|
105
|
+
const hovered = this.hoverPoint;
|
|
106
|
+
if (hovered) {
|
|
107
|
+
this.hoverPoint = undefined;
|
|
108
|
+
// The position under the pointer for its listeners only (a 'hoverfeature' alone does not need it)
|
|
109
|
+
if (listeners.has('hover')) {
|
|
110
|
+
listeners.emit('hover', { point: hovered, lonLat: host.engine().ground(hovered[0], hovered[1]) });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const t0 = performance.now();
|
|
114
|
+
// The engine asks for the next frame while it draws (uploads past the frame budget, fades): not ignored
|
|
115
|
+
this.inFrame = false;
|
|
116
|
+
// As the engine has it now (a listener may have moved it), for the custom layers drawn in the frame
|
|
117
|
+
this.#camera = host.customLayers() ? host.engine().camera() : undefined;
|
|
118
|
+
const render = () => {
|
|
119
|
+
try {
|
|
120
|
+
return host.engine().render();
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
this.#camera = undefined;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const loading = render();
|
|
127
|
+
this.inFrame = true;
|
|
128
|
+
host.drawn(hovered);
|
|
129
|
+
listeners.emit('render', { ms: performance.now() - t0 });
|
|
130
|
+
this.inFrame = false;
|
|
131
|
+
// A move goes on until a frame finds the camera still: that frame sends 'moveend'
|
|
132
|
+
if (this.animation || (moved && this.moving))
|
|
133
|
+
this.request();
|
|
134
|
+
// Idle: nothing loading (the engine with 3D Tiles neither), no animation, no frame asked for (uploads waiting,
|
|
135
|
+
// fades, listeners)
|
|
136
|
+
if (loading || host.upgrading() || this.animation || this.requested !== 0) {
|
|
137
|
+
this.#settled = false;
|
|
138
|
+
}
|
|
139
|
+
else if (!this.#settled) {
|
|
140
|
+
this.#settled = true;
|
|
141
|
+
listeners.emit('idle', {});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
//# 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 /** Asks for a frame that sends 'idle' once everything is loaded, even if the last one already did: the waiters of\n * `whenIdle` on a map already idle (else no frame would change from loading to loaded, and none would send it) */\n requestIdle(): void {\n this.#settled = false;\n this.request();\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
|
+
}
|