isard 0.2.0 → 0.2.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"layers.js","sourceRoot":"","sources":["../src/layers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Handles of the layers added to a map. Each one keeps what it needs to be created again: after a WebGL context loss,\n * the map recreates its engine and every layer in order, with the same handle (its id is updated).\n */\nimport { parseColor, rampTexels, stops } from './features.ts';\nimport type { LayerHost, LonLat, NetworkOptions, NetworkStyle, RasterOptions, Tiles3dStyle } from './types.ts';\nimport type { Engine, NetworkStats, Tiles3dStats } from './wasm/isard.js';\n\nexport abstract class Layer {\n #id = -1;\n\n /** @internal */\n protected readonly map: LayerHost;\n\n /** @internal */\n constructor(map: LayerHost) {\n this.map = map;\n }\n\n /** Id of the layer in the engine */\n get id(): number {\n return this.#id;\n }\n\n /** @internal Creates the layer in an engine (again after a context loss) */\n attach(engine: Engine): void {\n this.#id = this.create(engine);\n }\n\n /** @internal */\n protected abstract create(engine: Engine): number;\n\n remove(): void {\n // Not created yet: a 3D Tiles layer waiting for the engine with 3D Tiles\n if (this.#id >= 0) this.map.engine.removeLayer(this.#id);\n this.map.detach(this);\n this.map.requestRender();\n }\n\n /** Moves the layer under `other`, or on top of every layer (above the labels of a vector basemap too) */\n moveBefore(other: Layer | undefined): void {\n this.map.moveLayer(this, other);\n }\n}\n\n/** Raster tiles (basemaps, overlays) */\nexport class RasterLayer extends Layer {\n /** @internal */\n constructor(\n map: LayerHost,\n private readonly options: Required<Omit<RasterOptions, 'size' | 'loader' | 'grid' | 'attribution'>> & {\n size: number | undefined;\n loader: RasterOptions['loader'] | undefined;\n },\n ) {\n super(map);\n }\n\n setStyle(opacity: number, saturation = 1): void {\n this.options.opacity = opacity;\n this.options.saturation = saturation;\n this.map.engine.setRasterStyle(this.id, opacity, saturation);\n this.map.requestRender();\n }\n\n /** @internal */\n protected create(engine: Engine): number {\n const { url, minZoom, maxZoom, opacity, saturation, size, loader } = this.options;\n return engine.addRaster(url, minZoom, maxZoom, opacity, saturation, size, loader);\n }\n}\n\n/** Line network colored by a value per node (travel time, water depth…) */\nexport class NetworkLayer extends Layer {\n private values: Float32Array | undefined;\n /** Node and line positions in Mercator, kept for a context loss: f32 offsets from an origin (exact to the centimetre\n * across a region, half the memory of f64) */\n private kept: { origin: [number, number]; nodes: Float32Array; lines: Float32Array | undefined } | undefined;\n\n /** @internal */\n constructor(\n map: LayerHost,\n private geometry: { nodes: Float64Array; edges: Uint32Array; lines: NetworkOptions['lines'] | undefined },\n private costs: Float32Array | undefined,\n private style: NetworkStyle,\n private edgeWidths: Float32Array | undefined,\n ) {\n super(map);\n }\n\n /** One value per node, in node order; negative (or 1e30 and above) = unreached. Costs one texture upload, drawn\n * next frame. */\n setValues(values: Float32Array): void {\n this.values = values;\n this.map.engine.setNetworkValues(this.id, values);\n this.map.requestRender();\n }\n\n /** Costs of the edges, A → B then B → A (see `NetworkOptions.costs`), when the way the network is travelled\n * changes; undefined: values interpolated along the edges. The geometry stays on the graphics card. */\n setCosts(costs: Float32Array | undefined): void {\n this.costs = costs;\n this.map.engine.setNetworkCosts(this.id, costs);\n this.map.requestRender();\n }\n\n setStyle(style: Partial<NetworkStyle>): void {\n const ramp = this.style.ramp;\n this.style = { ...this.style, ...style };\n this.map.engine.setNetworkStyle(this.id, networkStyle(this.style));\n if (this.style.ramp !== ramp)\n this.map.engine.setNetworkRamp(this.id, this.style.ramp && rampTexels(this.style.ramp).rgba);\n this.map.requestRender();\n }\n\n /** Width factor of each edge (undefined: 1 for all) */\n setEdgeWidths(widths: Float32Array | undefined): void {\n this.edgeWidths = widths;\n this.map.engine.setNetworkScales(this.id, widths);\n this.map.requestRender();\n }\n\n /** Pieces in all and drawn in the last frame */\n stats(): NetworkStats | undefined {\n return this.map.engine.networkStats(this.id);\n }\n\n /** @internal */\n protected create(engine: Engine): number {\n const { nodes, edges, lines } = this.geometry;\n let mercator: { nodes: Float64Array; lines: Float64Array | undefined };\n if (this.kept) {\n const { origin, nodes: n, lines: l } = this.kept;\n mercator = { nodes: unpack(n, origin), lines: l && unpack(l, origin) };\n } else {\n // Mercator here: Math.tan and Math.log run natively, several times faster than in WebAssembly\n mercator = { nodes: toMercator(nodes), lines: lines && toMercator(lines.points) };\n const origin: [number, number] = [mercator.nodes[0] ?? 0, mercator.nodes[1] ?? 0];\n this.kept = {\n origin,\n nodes: pack(mercator.nodes, origin),\n lines: mercator.lines && pack(mercator.lines, origin),\n };\n // The degrees are not needed again: millions of points for a region\n this.geometry = { nodes: EMPTY, edges, lines: lines && { start: lines.start, points: EMPTY } };\n }\n const id = engine.addNetwork(\n mercator.nodes,\n edges,\n lines?.start,\n mercator.lines,\n this.costs,\n networkStyle(this.style),\n );\n if (this.style.ramp) engine.setNetworkRamp(id, rampTexels(this.style.ramp).rgba);\n if (this.edgeWidths) engine.setNetworkScales(id, this.edgeWidths);\n if (this.values) engine.setNetworkValues(id, this.values);\n return id;\n }\n}\n\n/** The 25 numbers of a network style for the engine */\nfunction networkStyle(style: NetworkStyle): Float32Array {\n const { width, halo, max, contour, opacity, haloOpacity, unreachedColor, fade } = style;\n return Float32Array.from([\n ...stops(width),\n ...stops(halo),\n max,\n contour,\n opacity,\n haloOpacity,\n ...parseColor(unreachedColor),\n fade,\n ]);\n}\n\nconst EMPTY = new Float64Array(0);\n\n/** Interleaved points as f32 offsets from an origin, and back */\nfunction pack(points: Float64Array, [ox, oy]: [number, number]): Float32Array {\n const out = new Float32Array(points.length);\n for (let i = 0; i < points.length; i += 2) {\n out[i] = (points[i] ?? 0) - ox;\n out[i + 1] = (points[i + 1] ?? 0) - oy;\n }\n return out;\n}\n\nfunction unpack(points: Float32Array, [ox, oy]: [number, number]): Float64Array {\n const out = new Float64Array(points.length);\n for (let i = 0; i < points.length; i += 2) {\n out[i] = (points[i] ?? 0) + ox;\n out[i + 1] = (points[i + 1] ?? 0) + oy;\n }\n return out;\n}\n\nconst MAX_LAT = 85.051128779806589;\n\n/** Longitudes and latitudes (degrees, interleaved) to Mercator [0, 1], y towards the south */\nfunction toMercator(lonLat: Float64Array): Float64Array {\n const out = new Float64Array(lonLat.length);\n for (let i = 0; i < lonLat.length; i += 2) {\n const lat = (Math.max(-MAX_LAT, Math.min(MAX_LAT, lonLat[i + 1] ?? 0)) * Math.PI) / 180;\n out[i] = ((lonLat[i] ?? 0) + 180) / 360;\n out[i + 1] = 0.5 - Math.log(Math.tan(Math.PI / 4 + lat / 2)) / (2 * Math.PI);\n }\n return out;\n}\n\n/** Textured meshes in 3D Tiles */\nexport class Tiles3dLayer extends Layer {\n /** @internal */\n constructor(\n map: LayerHost,\n private readonly url: string,\n private style: Tiles3dStyle,\n ) {\n super(map);\n }\n\n setStyle(style: Partial<Tiles3dStyle>): void {\n this.style = { ...this.style, ...style };\n // Kept for its creation while the engine with 3D Tiles loads\n if (this.id < 0) return;\n this.map.engine.setTiles3dStyle(this.id, this.style.maxScreenSpaceError, this.style.opacity);\n this.map.requestRender();\n }\n\n /** Loading counters; undefined once the layer is removed, and while the engine with 3D Tiles loads (see\n * `GeoMapOptions.tiles3d`) */\n stats(): Tiles3dStats | undefined {\n return this.id < 0 ? undefined : this.map.engine.tiles3dStats(this.id);\n }\n\n /** @internal */\n protected create(engine: Engine): number {\n const id = engine.addTiles3d(this.url, this.style.maxScreenSpaceError);\n engine.setTiles3dStyle(id, this.style.maxScreenSpaceError, this.style.opacity);\n return id;\n }\n}\n\n/** A texture of a ground layer (see `GroundLayer`) */\nexport interface GroundTexture {\n /** `r8`, `r8ui`, `r16ui`, `r16i`, `r32ui`, `r32f`, `rg16ui`, `rg32f`, `rgba8`, `rgba8ui`, `rgba16ui`, `rgba32f`:\n * integer formats are read with `usampler2D` / `isampler2D` and `texelFetch` */\n format: string;\n width: number;\n height: number;\n /** Layers of a 2D array (`sampler2DArray`, `usampler2DArray`…); 0 or undefined: a 2D texture */\n depth?: number;\n /** Linear filtering (non-integer formats); default nearest */\n linear?: boolean;\n /** Texels row after row (layer after layer), any typed array; undefined: left empty */\n data?: ArrayBufferView;\n}\n\nexport interface GroundOptions {\n /**\n * GLSL ES 3.0 defining `vec4 ground(vec2 offset)`: the color of the ground (premultiplied alpha, 0 for nothing) at\n * `offset`, the Mercator offset of the pixel from `anchor` (times `ISARD_EARTH`: metres of EPSG:3857), exact to\n * the millimetre at any zoom. The code declares its own uniforms and samplers; also there: `u_zoom`,\n * `u_pixel_ratio`\n */\n code: string;\n /** Where the offsets are taken from */\n anchor: LonLat;\n /** Box it shows in, `[west, south, east, north]` (default the world): only the ground there is drawn again */\n bounds?: [west: number, south: number, east: number, north: number];\n textures?: Record<string, GroundTexture>;\n uniforms?: Record<string, number | readonly number[]>;\n}\n\nconst bytesOf = (data: ArrayBufferView) => new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\n\n/** The application's fragment shader run over the ground, draped on the relief (water depth, heat maps…) */\nexport class GroundLayer extends Layer {\n private readonly textures = new Map<string, GroundTexture>();\n private readonly uniforms = new Map<string, number[]>();\n private visible = true;\n\n /** @internal */\n constructor(\n map: LayerHost,\n private readonly options: GroundOptions,\n ) {\n super(map);\n for (const [name, texture] of Object.entries(options.textures ?? {})) this.textures.set(name, texture);\n for (const [name, value] of Object.entries(options.uniforms ?? {})) this.uniforms.set(name, [value].flat());\n }\n\n /** Creates or replaces a texture of the code's sampler `name` */\n setTexture(name: string, texture: GroundTexture): void {\n this.textures.set(name, texture);\n this.sendTexture(this.map.engine, this.id, name, texture);\n this.map.requestRender();\n }\n\n /**\n * Replaces a region of a texture: `data` holds `width` × `height` texels for (`x`, `y`) of `layer` (2D arrays).\n * Keep the texture's own `data` up to date too if it must survive a WebGL context loss.\n */\n updateTexture(\n name: string,\n data: ArrayBufferView,\n region: { x?: number; y?: number; layer?: number; width: number; height: number },\n ): void {\n const { x = 0, y = 0, layer = 0, width, height } = region;\n this.map.engine.updateGroundTexture(this.id, name, x, y, layer, width, height, bytesOf(data));\n this.map.requestRender();\n }\n\n /** A uniform of the code: a number, or numbers for vectors, arrays and matrices (column major) */\n setUniform(name: string, value: number | readonly number[]): void {\n const values = [value].flat();\n this.uniforms.set(name, values);\n this.map.engine.setGroundUniform(this.id, name, Float64Array.from(values));\n this.map.requestRender();\n }\n\n setBounds(bounds: [west: number, south: number, east: number, north: number]): void {\n this.options.bounds = bounds;\n this.map.engine.setGroundBounds(this.id, ...mercatorBox(bounds));\n this.map.requestRender();\n }\n\n setVisible(visible: boolean): void {\n this.visible = visible;\n this.map.engine.setGroundVisible(this.id, visible);\n this.map.requestRender();\n }\n\n private sendTexture(engine: Engine, id: number, name: string, t: GroundTexture): void {\n const data = t.data && bytesOf(t.data);\n engine.setGroundTexture(id, name, t.format, t.width, t.height, t.depth ?? 0, t.linear ?? false, data);\n }\n\n /** @internal */\n protected create(engine: Engine): number {\n const [ax, ay] = mercatorPoint(this.options.anchor);\n const id = engine.addGround(\n this.options.code,\n ax,\n ay,\n ...mercatorBox(this.options.bounds ?? [-180, -85.06, 180, 85.06]),\n );\n for (const [name, texture] of this.textures) this.sendTexture(engine, id, name, texture);\n for (const [name, values] of this.uniforms) engine.setGroundUniform(id, name, Float64Array.from(values));\n engine.setGroundVisible(id, this.visible);\n return id;\n }\n}\n\nfunction mercatorPoint([lon, lat]: LonLat): [number, number] {\n const out = toMercator(Float64Array.of(lon, lat));\n return [out[0] ?? 0, out[1] ?? 0];\n}\n\n/** A lon/lat box to Mercator min x, min y, max x, max y (y towards the south) */\nfunction mercatorBox([west, south, east, north]: [number, number, number, number]): [number, number, number, number] {\n const [x0, y1] = mercatorPoint([west, south]);\n const [x1, y0] = mercatorPoint([east, north]);\n return [x0, y0, x1, y1];\n}\n"]}
1
+ {"version":3,"file":"layers.js","sourceRoot":"","sources":["../src/layers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Handles of the layers added to a map. Each one keeps what it needs to be created again: after a WebGL context loss,\n * the map recreates its engine and every layer in order, with the same handle (its id is updated).\n */\nimport { parseColor, rampTexels, stops } from './features.ts';\nimport type {\n LayerHost,\n LonLat,\n NetworkOptions,\n NetworkStyle,\n RasterOptions,\n RasterStyle,\n Tiles3dStyle,\n} from './types.ts';\nimport type { Engine, NetworkStats, Tiles3dStats } from './wasm/isard.js';\n\nexport abstract class Layer {\n #id = -1;\n\n /** @internal */\n protected readonly map: LayerHost;\n\n /** @internal */\n constructor(map: LayerHost) {\n this.map = map;\n }\n\n /** Id of the layer in the engine */\n get id(): number {\n return this.#id;\n }\n\n /** @internal Creates the layer in an engine (again after a context loss); its id is -1 if that fails */\n attach(engine: Engine): void {\n this.#id = -1;\n this.#id = this.create(engine);\n }\n\n /** @internal Forgets its id in an engine that is gone (before the layers are created in a new one) */\n forgetEngine(): void {\n this.#id = -1;\n }\n\n /** @internal Sends what refers to other layers, once every layer of a new engine has its id */\n relink(_engine: Engine): void {}\n\n /** @internal */\n protected abstract create(engine: Engine): number;\n\n remove(): void {\n // Not created yet: a 3D Tiles layer waiting for the engine with 3D Tiles\n if (this.#id >= 0) this.map.engine.removeLayer(this.#id);\n this.#id = -1;\n this.map.detach(this);\n this.map.requestRender();\n }\n\n /** Moves the layer under `other`, or on top of every layer (above the labels of a vector basemap too) */\n moveBefore(other: Layer | undefined): void {\n this.map.moveLayer(this, other);\n }\n}\n\n/** Raster tiles (basemaps, overlays) */\nexport class RasterLayer extends Layer {\n /** @internal */\n constructor(\n map: LayerHost,\n private readonly options: Required<Omit<RasterOptions, 'size' | 'loader' | 'grid' | 'attribution'>> & {\n size: number | undefined;\n loader: RasterOptions['loader'] | undefined;\n },\n ) {\n super(map);\n }\n\n /** Changes the opacity or saturation, the other kept */\n setStyle(style: Partial<RasterStyle>): void;\n /** @deprecated Positional form (saturation back to 1 when not given): `setStyle({ opacity, saturation })` */\n setStyle(opacity: number, saturation?: number): void;\n setStyle(style: Partial<RasterStyle> | number, saturation = 1): void {\n const changed = typeof style === 'number' ? { opacity: style, saturation } : style;\n this.options.opacity = changed.opacity ?? this.options.opacity;\n this.options.saturation = changed.saturation ?? this.options.saturation;\n this.map.engine.setRasterStyle(this.id, this.options.opacity, this.options.saturation);\n this.map.requestRender();\n }\n\n /** @internal */\n protected create(engine: Engine): number {\n const { url, minZoom, maxZoom, opacity, saturation, size, loader } = this.options;\n return engine.addRaster(url, minZoom, maxZoom, opacity, saturation, size, loader);\n }\n}\n\n/** Line network colored by a value per node (travel time, water depth…) */\nexport class NetworkLayer extends Layer {\n private values: Float32Array | undefined;\n /** Node and line positions in Mercator, kept for a context loss: f32 offsets from an origin (exact to the centimetre\n * across a region, half the memory of f64) */\n private kept: { origin: [number, number]; nodes: Float32Array; lines: Float32Array | undefined } | undefined;\n\n /** @internal */\n constructor(\n map: LayerHost,\n private geometry: { nodes: Float64Array; edges: Uint32Array; lines: NetworkOptions['lines'] | undefined },\n private costs: Float32Array | undefined,\n private style: NetworkStyle,\n private edgeWidths: Float32Array | undefined,\n ) {\n super(map);\n }\n\n /** One value per node, in node order; negative (or 1e30 and above) = unreached. Costs one texture upload, drawn\n * next frame. */\n setValues(values: Float32Array): void {\n this.values = values;\n this.map.engine.setNetworkValues(this.id, values);\n this.map.requestRender();\n }\n\n /** Costs of the edges, A → B then B → A (see `NetworkOptions.costs`), when the way the network is travelled\n * changes; undefined: values interpolated along the edges. The geometry stays on the graphics card. */\n setCosts(costs: Float32Array | undefined): void {\n this.costs = costs;\n this.map.engine.setNetworkCosts(this.id, costs);\n this.map.requestRender();\n }\n\n setStyle(style: Partial<NetworkStyle>): void {\n const ramp = this.style.ramp;\n this.style = { ...this.style, ...style };\n this.map.engine.setNetworkStyle(this.id, networkStyle(this.style));\n if (this.style.ramp !== ramp)\n this.map.engine.setNetworkRamp(this.id, this.style.ramp && rampTexels(this.style.ramp).rgba);\n this.map.requestRender();\n }\n\n /** Width factor of each edge (undefined: 1 for all) */\n setEdgeWidths(widths: Float32Array | undefined): void {\n this.edgeWidths = widths;\n this.map.engine.setNetworkScales(this.id, widths);\n this.map.requestRender();\n }\n\n /** Pieces in all and drawn in the last frame */\n stats(): NetworkStats | undefined {\n return this.map.engine.networkStats(this.id);\n }\n\n /** @internal */\n protected create(engine: Engine): number {\n const { nodes, edges, lines } = this.geometry;\n let mercator: { nodes: Float64Array; lines: Float64Array | undefined };\n if (this.kept) {\n const { origin, nodes: n, lines: l } = this.kept;\n mercator = { nodes: unpack(n, origin), lines: l && unpack(l, origin) };\n } else {\n // Mercator here: Math.tan and Math.log run natively, several times faster than in WebAssembly\n mercator = { nodes: toMercator(nodes), lines: lines && toMercator(lines.points) };\n const origin: [number, number] = [mercator.nodes[0] ?? 0, mercator.nodes[1] ?? 0];\n this.kept = {\n origin,\n nodes: pack(mercator.nodes, origin),\n lines: mercator.lines && pack(mercator.lines, origin),\n };\n // The degrees are not needed again: millions of points for a region\n this.geometry = { nodes: EMPTY, edges, lines: lines && { start: lines.start, points: EMPTY } };\n }\n const id = engine.addNetwork(\n mercator.nodes,\n edges,\n lines?.start,\n mercator.lines,\n this.costs,\n networkStyle(this.style),\n );\n if (this.style.ramp) engine.setNetworkRamp(id, rampTexels(this.style.ramp).rgba);\n if (this.edgeWidths) engine.setNetworkScales(id, this.edgeWidths);\n if (this.values) engine.setNetworkValues(id, this.values);\n return id;\n }\n}\n\n/** The 25 numbers of a network style for the engine */\nfunction networkStyle(style: NetworkStyle): Float32Array {\n const { width, halo, max, contour, opacity, haloOpacity, unreachedColor, fade } = style;\n return Float32Array.from([\n ...stops(width),\n ...stops(halo),\n max,\n contour,\n opacity,\n haloOpacity,\n ...parseColor(unreachedColor),\n fade,\n ]);\n}\n\nconst EMPTY = new Float64Array(0);\n\n/** Interleaved points as f32 offsets from an origin, and back */\nfunction pack(points: Float64Array, [ox, oy]: [number, number]): Float32Array {\n const out = new Float32Array(points.length);\n for (let i = 0; i < points.length; i += 2) {\n out[i] = (points[i] ?? 0) - ox;\n out[i + 1] = (points[i + 1] ?? 0) - oy;\n }\n return out;\n}\n\nfunction unpack(points: Float32Array, [ox, oy]: [number, number]): Float64Array {\n const out = new Float64Array(points.length);\n for (let i = 0; i < points.length; i += 2) {\n out[i] = (points[i] ?? 0) + ox;\n out[i + 1] = (points[i + 1] ?? 0) + oy;\n }\n return out;\n}\n\nconst MAX_LAT = 85.051128779806589;\n\n/** Longitudes and latitudes (degrees, interleaved) to Mercator [0, 1], y towards the south */\nfunction toMercator(lonLat: Float64Array): Float64Array {\n const out = new Float64Array(lonLat.length);\n for (let i = 0; i < lonLat.length; i += 2) {\n const lat = (Math.max(-MAX_LAT, Math.min(MAX_LAT, lonLat[i + 1] ?? 0)) * Math.PI) / 180;\n out[i] = ((lonLat[i] ?? 0) + 180) / 360;\n out[i + 1] = 0.5 - Math.log(Math.tan(Math.PI / 4 + lat / 2)) / (2 * Math.PI);\n }\n return out;\n}\n\n/** Textured meshes in 3D Tiles */\nexport class Tiles3dLayer extends Layer {\n /** @internal */\n constructor(\n map: LayerHost,\n private readonly url: string,\n private style: Tiles3dStyle,\n ) {\n super(map);\n }\n\n setStyle(style: Partial<Tiles3dStyle>): void {\n this.style = { ...this.style, ...style };\n // Kept for its creation while the engine with 3D Tiles loads\n if (this.id < 0) return;\n this.map.engine.setTiles3dStyle(this.id, this.style.maxScreenSpaceError, this.style.opacity);\n this.map.requestRender();\n }\n\n /** Loading counters; undefined once the layer is removed, and while the engine with 3D Tiles loads (see\n * `GeoMapOptions.tiles3d`) */\n stats(): Tiles3dStats | undefined {\n return this.id < 0 ? undefined : this.map.engine.tiles3dStats(this.id);\n }\n\n /** @internal */\n protected create(engine: Engine): number {\n const id = engine.addTiles3d(this.url, this.style.maxScreenSpaceError);\n engine.setTiles3dStyle(id, this.style.maxScreenSpaceError, this.style.opacity);\n return id;\n }\n}\n\n/** A texture of a ground layer (see `GroundLayer`) */\nexport interface GroundTexture {\n /** `r8`, `r8ui`, `r16ui`, `r16i`, `r32ui`, `r32f`, `rg16ui`, `rg32f`, `rgba8`, `rgba8ui`, `rgba16ui`, `rgba32f`:\n * integer formats are read with `usampler2D` / `isampler2D` and `texelFetch` */\n format: string;\n width: number;\n height: number;\n /** Layers of a 2D array (`sampler2DArray`, `usampler2DArray`…); 0 or undefined: a 2D texture */\n depth?: number;\n /** Linear filtering (non-integer formats); default nearest */\n linear?: boolean;\n /** Texels row after row (layer after layer), any typed array; undefined: left empty */\n data?: ArrayBufferView;\n}\n\nexport interface GroundOptions {\n /**\n * GLSL ES 3.0 defining `vec4 ground(vec2 offset)`: the color of the ground (premultiplied alpha, 0 for nothing) at\n * `offset`, the Mercator offset of the pixel from `anchor` (times `ISARD_EARTH`: metres of EPSG:3857), exact to\n * the millimetre at any zoom. The code declares its own uniforms and samplers; also there: `u_zoom`,\n * `u_pixel_ratio`\n */\n code: string;\n /** Where the offsets are taken from */\n anchor: LonLat;\n /** Box it shows in, `[west, south, east, north]` (default the world): only the ground there is drawn again */\n bounds?: [west: number, south: number, east: number, north: number];\n textures?: Record<string, GroundTexture>;\n uniforms?: Record<string, number | readonly number[]>;\n}\n\nconst bytesOf = (data: ArrayBufferView) => new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\n\n/** The application's fragment shader run over the ground, draped on the relief (water depth, heat maps…) */\nexport class GroundLayer extends Layer {\n private readonly textures = new Map<string, GroundTexture>();\n private readonly uniforms = new Map<string, number[]>();\n private visible = true;\n\n /** @internal */\n constructor(\n map: LayerHost,\n private readonly options: GroundOptions,\n ) {\n super(map);\n for (const [name, texture] of Object.entries(options.textures ?? {})) this.textures.set(name, texture);\n for (const [name, value] of Object.entries(options.uniforms ?? {})) this.uniforms.set(name, [value].flat());\n }\n\n /** Creates or replaces a texture of the code's sampler `name` */\n setTexture(name: string, texture: GroundTexture): void {\n this.textures.set(name, texture);\n this.sendTexture(this.map.engine, this.id, name, texture);\n this.map.requestRender();\n }\n\n /**\n * Replaces a region of a texture: `data` holds `width` × `height` texels for (`x`, `y`) of `layer` (2D arrays).\n * Keep the texture's own `data` up to date too if it must survive a WebGL context loss.\n */\n updateTexture(\n name: string,\n data: ArrayBufferView,\n region: { x?: number; y?: number; layer?: number; width: number; height: number },\n ): void {\n const { x = 0, y = 0, layer = 0, width, height } = region;\n this.map.engine.updateGroundTexture(this.id, name, x, y, layer, width, height, bytesOf(data));\n this.map.requestRender();\n }\n\n /** A uniform of the code: a number, or numbers for vectors, arrays and matrices (column major) */\n setUniform(name: string, value: number | readonly number[]): void {\n const values = [value].flat();\n this.uniforms.set(name, values);\n this.map.engine.setGroundUniform(this.id, name, Float64Array.from(values));\n this.map.requestRender();\n }\n\n setBounds(bounds: [west: number, south: number, east: number, north: number]): void {\n this.options.bounds = bounds;\n this.map.engine.setGroundBounds(this.id, ...mercatorBox(bounds));\n this.map.requestRender();\n }\n\n setVisible(visible: boolean): void {\n this.visible = visible;\n this.map.engine.setGroundVisible(this.id, visible);\n this.map.requestRender();\n }\n\n private sendTexture(engine: Engine, id: number, name: string, t: GroundTexture): void {\n const data = t.data && bytesOf(t.data);\n engine.setGroundTexture(id, name, t.format, t.width, t.height, t.depth ?? 0, t.linear ?? false, data);\n }\n\n /** @internal */\n protected create(engine: Engine): number {\n const [ax, ay] = mercatorPoint(this.options.anchor);\n const id = engine.addGround(\n this.options.code,\n ax,\n ay,\n ...mercatorBox(this.options.bounds ?? [-180, -85.06, 180, 85.06]),\n );\n for (const [name, texture] of this.textures) this.sendTexture(engine, id, name, texture);\n for (const [name, values] of this.uniforms) engine.setGroundUniform(id, name, Float64Array.from(values));\n engine.setGroundVisible(id, this.visible);\n return id;\n }\n}\n\nfunction mercatorPoint([lon, lat]: LonLat): [number, number] {\n const out = toMercator(Float64Array.of(lon, lat));\n return [out[0] ?? 0, out[1] ?? 0];\n}\n\n/** A lon/lat box to Mercator min x, min y, max x, max y (y towards the south) */\nfunction mercatorBox([west, south, east, north]: [number, number, number, number]): [number, number, number, number] {\n const [x0, y1] = mercatorPoint([west, south]);\n const [x1, y0] = mercatorPoint([east, north]);\n return [x0, y0, x1, y1];\n}\n"]}
package/dist/map.d.ts CHANGED
@@ -58,6 +58,8 @@ export declare class GeoMap {
58
58
  private hoverPoint;
59
59
  /** Frame polling the engine for the answer of the hover picking, 0 if none */
60
60
  private hoverPoll;
61
+ /** Polls of the hover picking under way: given up after `MAX_POLLS` (an answer that never comes) */
62
+ private hoverPolls;
61
63
  /** What 'hoverfeature' looks for: within `radius` CSS pixels, in `layers` only if given */
62
64
  hoverPicking: {
63
65
  radius?: number;
@@ -76,6 +78,8 @@ export declare class GeoMap {
76
78
  private basemapPool;
77
79
  /** Stops watching the device pixel ratio */
78
80
  private unwatchRatio;
81
+ /** Stops listening to the canvas's context loss and restoration */
82
+ private readonly unwatchContext;
79
83
  /** Loads the engine (once per page) and creates a map filling `container` */
80
84
  static create(container: HTMLElement, options?: GeoMapOptions): Promise<GeoMap>;
81
85
  private constructor();
@@ -88,6 +92,9 @@ export declare class GeoMap {
88
92
  /** A 3D Tiles layer on the core engine: loads the engine with 3D Tiles, then rebuilds the map on it (camera,
89
93
  * settings and layers kept, as after a context loss); the layer is created then */
90
94
  private upgrade;
95
+ /** Downloads and compiles the engine with 3D Tiles once the map is idle (`tiles3d: 'preload'`), without running
96
+ * it: the first 3D Tiles layer then only instantiates it */
97
+ private preloadTiles3d;
91
98
  /** After a context loss: a new engine with the same camera, settings and layers (same handles, same order) */
92
99
  private restore;
93
100
  /** Takes a layer out of the drawing order (to put it back elsewhere, or for good) */
@@ -132,8 +139,9 @@ export declare class GeoMap {
132
139
  /** Tile counters of the raster layers, for diagnostics */
133
140
  stats(): RasterLayerStats[];
134
141
  /**
135
- * Network edge under a screen point (CSS pixels), undefined if none. Reads one pixel of an offscreen picking pass:
136
- * cheap whatever the number of features, call it on hover.
142
+ * The feature under a screen point (CSS pixels), undefined if none: its layer id and index. Reads one pixel of an
143
+ * offscreen picking pass, whatever the number of features, but waits for the GPU to finish the frame (a stall): for
144
+ * clicks and one-off queries. On hover, listen to 'hoverfeature' instead, which picks without waiting.
137
145
  */
138
146
  pick(point: Point, radius?: number, layers?: readonly Layer[]): PickHit | undefined;
139
147
  /**
package/dist/map.js CHANGED
@@ -44,6 +44,28 @@ function report(error) {
44
44
  * every map; `full` with them, loaded for the first 3D Tiles layer, its module shared with the decoding workers. The
45
45
  * core engine has the same API but the 3D Tiles methods: its class is typed as the full one. */
46
46
  const engines = {};
47
+ /** The modules compiled (downloaded and compiled off the main thread, not instantiated): `tiles3d: 'preload'`
48
+ * compiles the full engine ahead, its first 3D Tiles layer then only instantiates it */
49
+ const modules = {};
50
+ /** @internal Forgets the engines loaded (tests) */
51
+ export function forgetEngines() {
52
+ for (const kind of ['core', 'full']) {
53
+ delete engines[kind];
54
+ delete modules[kind];
55
+ }
56
+ }
57
+ function compileEngine(kind, url) {
58
+ const compiled = modules[kind];
59
+ if (compiled)
60
+ return compiled;
61
+ const compiling = compile(url).catch((error) => {
62
+ // A later call tries again (a network error, a wrong URL fixed)
63
+ delete modules[kind];
64
+ throw error;
65
+ });
66
+ modules[kind] = compiling;
67
+ return compiling;
68
+ }
47
69
  function loadEngine(kind, url) {
48
70
  const loaded = engines[kind];
49
71
  if (loaded)
@@ -51,13 +73,12 @@ function loadEngine(kind, url) {
51
73
  const loading = (async () => {
52
74
  // The bindings by dynamic import: an application bundles the ones it loads only
53
75
  const [module, bindings] = await Promise.all([
54
- compile(url),
76
+ compileEngine(kind, url),
55
77
  kind === 'core' ? import('./wasm/isard_core.js') : import('./wasm/isard.js'),
56
78
  ]);
57
79
  await bindings.default({ module_or_path: module });
58
80
  return { module, Engine: bindings.Engine };
59
81
  })().catch((error) => {
60
- // A later call tries again (a network error, a wrong URL fixed)
61
82
  delete engines[kind];
62
83
  throw error;
63
84
  });
@@ -164,12 +185,19 @@ function terrainSettings(terrain, body, radius) {
164
185
  if (url === undefined)
165
186
  throw new Error('isard: the relief of this body needs a url');
166
187
  const encoding = options.encoding ?? 'float32';
188
+ // PNG encodings are fetched tile by tile: a {bbox} or an image service would be fetched as it is
189
+ if (encoding !== 'float32' &&
190
+ (IMAGE_SERVER.test(url) || !/\{z\}/.test(url) || !/\{x\}/.test(url) || !/\{y\}/.test(url))) {
191
+ throw new Error(`isard: the '${encoding}' terrain encoding takes a tile URL with {z}, {x} and {y} (${url})`);
192
+ }
167
193
  return {
168
194
  url: IMAGE_SERVER.test(url) ? imageServerTerrain(url, earth, radius) : url,
169
195
  exaggeration,
170
196
  maxZoom: options.maxZoom ?? (options.url === undefined && preset ? preset.maxZoom : 15),
171
197
  geoid: options.geoid ?? false,
172
198
  ...(encoding === 'float32' ? {} : { loader: terrainLoader(url, encoding) }),
199
+ // NASA's credits for its models
200
+ ...(options.url === undefined && preset ? { attribution: preset.attribution } : {}),
173
201
  };
174
202
  }
175
203
  /** Sky settings for the engine: colors (RGB 0-1) and blends, MapLibre's defaults */
@@ -217,6 +245,16 @@ function rgb(color) {
217
245
  return [r, g, b];
218
246
  }
219
247
  const CORNERS = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];
248
+ /** Frames the hover picking waits for its answer at most (usually one) */
249
+ const MAX_POLLS = 30;
250
+ /** The name of a basemap, checked: an unknown one throws */
251
+ function checkBasemap(basemap) {
252
+ const name = basemapName(basemap);
253
+ if (name !== 'none' && !(name in VECTOR_BASEMAPS) && !(name in BASEMAPS)) {
254
+ throw new Error(`isard: unknown basemap '${basemap}'`);
255
+ }
256
+ return name;
257
+ }
220
258
  /** A map (see `GeoMap.create`); layers take it as their host */
221
259
  export class GeoMap {
222
260
  canvas;
@@ -279,6 +317,8 @@ export class GeoMap {
279
317
  hoverPoint;
280
318
  /** Frame polling the engine for the answer of the hover picking, 0 if none */
281
319
  hoverPoll = 0;
320
+ /** Polls of the hover picking under way: given up after `MAX_POLLS` (an answer that never comes) */
321
+ hoverPolls = 0;
282
322
  /** What 'hoverfeature' looks for: within `radius` CSS pixels, in `layers` only if given */
283
323
  hoverPicking = {};
284
324
  frameRequest = 0;
@@ -294,14 +334,22 @@ export class GeoMap {
294
334
  basemapPool;
295
335
  /** Stops watching the device pixel ratio */
296
336
  unwatchRatio;
337
+ /** Stops listening to the canvas's context loss and restoration */
338
+ unwatchContext;
297
339
  /** Loads the engine (once per page) and creates a map filling `container` */
298
340
  static async create(container, options = {}) {
299
341
  // With 3D Tiles from the start when asked, or when only that engine's URL is given (as before the core engine)
300
342
  const full = options.tiles3d === true || (options.wasmUrl !== undefined && options.coreWasmUrl === undefined);
343
+ // Before anything is created
344
+ if (options.basemap !== undefined)
345
+ checkBasemap(options.basemap);
301
346
  const bindings = full
302
347
  ? await loadEngine('full', options.wasmUrl ?? new URL('./isard_bg.wasm', import.meta.url))
303
348
  : await loadEngine('core', options.coreWasmUrl ?? new URL('./isard_core_bg.wasm', import.meta.url));
304
- return new GeoMap(container, options, bindings.Engine, full ? bindings.module : undefined);
349
+ const map = new GeoMap(container, options, bindings.Engine, full ? bindings.module : undefined);
350
+ if (options.tiles3d === 'preload' && !full)
351
+ map.preloadTiles3d();
352
+ return map;
305
353
  }
306
354
  constructor(container, options, engineClass, tiles3dModule) {
307
355
  this.engineClass = engineClass;
@@ -348,13 +396,19 @@ export class GeoMap {
348
396
  };
349
397
  this.#engine = this.createEngine();
350
398
  // The browser may take the GPU away (driver reset, background tab on mobile): the map waits, then rebuilds
351
- this.canvas.addEventListener('webglcontextlost', (event) => {
399
+ const lost = (event) => {
352
400
  event.preventDefault();
353
401
  this.lost = true;
354
402
  cancelAnimationFrame(this.frameRequest);
355
403
  this.frameRequest = 0;
356
- });
357
- this.canvas.addEventListener('webglcontextrestored', () => this.restore());
404
+ };
405
+ const restored = () => this.restore();
406
+ this.canvas.addEventListener('webglcontextlost', lost);
407
+ this.canvas.addEventListener('webglcontextrestored', restored);
408
+ this.unwatchContext = () => {
409
+ this.canvas.removeEventListener('webglcontextlost', lost);
410
+ this.canvas.removeEventListener('webglcontextrestored', restored);
411
+ };
358
412
  const start = this.earth
359
413
  ? { center: [2.4246, 48.8457], zoom: 13, pitch: 0, bearing: 0 }
360
414
  : { center: [0, 0], zoom: 2, pitch: 0, bearing: 0 };
@@ -422,7 +476,10 @@ export class GeoMap {
422
476
  * settings and layers kept, as after a context loss); the layer is created then */
423
477
  upgrade() {
424
478
  const url = this.tiles3dOptions.wasmUrl ?? new URL('./isard_bg.wasm', import.meta.url);
425
- this.upgrading ??= loadEngine('full', url).then(({ module, Engine }) => {
479
+ this.upgrading ??= loadEngine('full', url)
480
+ // The map is rebuilt in a task of its own, not in the one that instantiated the engine: two shorter tasks
481
+ .then((bindings) => new Promise((resolve) => setTimeout(() => resolve(bindings), 0)))
482
+ .then(({ module, Engine }) => {
426
483
  this.upgrading = undefined;
427
484
  if (this.gone)
428
485
  return;
@@ -434,12 +491,39 @@ export class GeoMap {
434
491
  }, (error) => {
435
492
  // The 3D Tiles layers stay empty; the next one added tries again
436
493
  this.upgrading = undefined;
494
+ if (this.gone)
495
+ return;
437
496
  report(error);
438
497
  this.requestRender();
439
498
  });
440
499
  }
500
+ /** Downloads and compiles the engine with 3D Tiles once the map is idle (`tiles3d: 'preload'`), without running
501
+ * it: the first 3D Tiles layer then only instantiates it */
502
+ preloadTiles3d() {
503
+ const url = this.tiles3dOptions.wasmUrl ?? new URL('./isard_bg.wasm', import.meta.url);
504
+ const start = () => {
505
+ if (!this.gone && !this.tiles3dModule)
506
+ compileEngine('full', url).catch(() => undefined);
507
+ };
508
+ const later = () => {
509
+ if (typeof requestIdleCallback === 'function')
510
+ requestIdleCallback(start, { timeout: 2000 });
511
+ else
512
+ setTimeout(start, 0);
513
+ };
514
+ if (this.settled)
515
+ later();
516
+ else {
517
+ const off = this.on('idle', () => {
518
+ off();
519
+ later();
520
+ });
521
+ }
522
+ }
441
523
  /** After a context loss: a new engine with the same camera, settings and layers (same handles, same order) */
442
524
  restore() {
525
+ if (this.gone)
526
+ return;
443
527
  this.cancelHoverPick();
444
528
  const camera = this.getCamera();
445
529
  this.#engine.free();
@@ -447,16 +531,46 @@ export class GeoMap {
447
531
  this.lost = false;
448
532
  this.setCamera(camera);
449
533
  this.#glyphs?.attach(this.#engine);
534
+ const engine = this.#engine;
535
+ // No layer refers to an id of the old engine while the others are created
450
536
  for (const layer of this.layers)
451
- layer.attach(this.#engine);
537
+ layer.forgetEngine();
538
+ for (const layer of this.layers) {
539
+ // Still waiting for the engine with 3D Tiles (loading, or failed): created with it
540
+ if (layer instanceof Tiles3dLayer && !this.tiles3dModule)
541
+ continue;
542
+ // A layer that fails is reported and left out; the others are created
543
+ try {
544
+ layer.attach(engine);
545
+ }
546
+ catch (error) {
547
+ report(error);
548
+ }
549
+ }
550
+ // Links between layers, once every layer has its new id (buildings colored by a network above them)
551
+ for (const layer of this.layers) {
552
+ if (layer.id < 0)
553
+ continue;
554
+ try {
555
+ layer.relink(engine);
556
+ }
557
+ catch (error) {
558
+ report(error);
559
+ }
560
+ }
452
561
  this.resize();
453
562
  }
454
563
  /** @internal Forgets a removed layer */
455
564
  detach(layer) {
456
565
  this.unlist(layer);
566
+ this.onTop.delete(layer);
457
567
  if (this.rasterCredits.delete(layer))
458
568
  this.attributionChanged();
459
569
  }
570
+ /** @internal The layer is on the map */
571
+ hasLayer(layer) {
572
+ return !this.gone && this.layers.includes(layer);
573
+ }
460
574
  /** Takes a layer out of the drawing order (to put it back elsewhere, or for good) */
461
575
  unlist(layer) {
462
576
  const index = this.layers.indexOf(layer);
@@ -688,8 +802,9 @@ export class GeoMap {
688
802
  return this.engine.stats();
689
803
  }
690
804
  /**
691
- * Network edge under a screen point (CSS pixels), undefined if none. Reads one pixel of an offscreen picking pass:
692
- * cheap whatever the number of features, call it on hover.
805
+ * The feature under a screen point (CSS pixels), undefined if none: its layer id and index. Reads one pixel of an
806
+ * offscreen picking pass, whatever the number of features, but waits for the GPU to finish the frame (a stall): for
807
+ * clicks and one-off queries. On hover, listen to 'hoverfeature' instead, which picks without waiting.
693
808
  */
694
809
  pick(point, radius = 0, layers) {
695
810
  const only = layers && Uint32Array.from(layers.map((l) => l.id));
@@ -718,10 +833,15 @@ export class GeoMap {
718
833
  requestHoverPick(point) {
719
834
  const { radius = 0, layers } = this.hoverPicking;
720
835
  const only = layers && Uint32Array.from(layers.map((l) => l.id));
721
- // A new request replaces the one in flight (in the engine too): one poll loop at most
722
- if (!this.engine.requestPick(point[0], point[1], radius, only) || this.hoverPoll)
836
+ // The engine cannot pick (no request in flight): the poll under way would wait for nothing
837
+ if (!this.engine.requestPick(point[0], point[1], radius, only)) {
838
+ this.cancelHoverPick();
723
839
  return;
724
- this.hoverPoll = requestAnimationFrame(this.pollHoverPick);
840
+ }
841
+ // A new request replaces the one in flight (in the engine too): one poll loop at most
842
+ this.hoverPolls = 0;
843
+ if (!this.hoverPoll)
844
+ this.hoverPoll = requestAnimationFrame(this.pollHoverPick);
725
845
  }
726
846
  pollHoverPick = () => {
727
847
  this.hoverPoll = 0;
@@ -729,8 +849,10 @@ export class GeoMap {
729
849
  return;
730
850
  const result = this.engine.pollPick();
731
851
  if (!result) {
732
- // The GPU is not done yet (usually a frame): asked again next frame, without drawing
733
- this.hoverPoll = requestAnimationFrame(this.pollHoverPick);
852
+ // The GPU is not done yet (usually a frame): asked again next frame, without drawing; given up at last
853
+ this.hoverPolls += 1;
854
+ if (this.hoverPolls < MAX_POLLS)
855
+ this.hoverPoll = requestAnimationFrame(this.pollHoverPick);
734
856
  return;
735
857
  }
736
858
  this.emit('hoverfeature', {
@@ -795,15 +917,14 @@ export class GeoMap {
795
917
  /** Replaces the basemap and the IGN hillshade, under the other layers (hillshade by default: 0, none). The former
796
918
  * names of the Géoplateforme basemaps (`LegacyBasemap`) are taken under their new ones */
797
919
  setBasemap(basemap, hillshade = 0) {
798
- const name = basemapName(basemap);
799
- this.basemap?.remove();
800
- this.hillshade?.remove();
801
- if (this.vector) {
802
- this.onTop.delete(this.vector.labels);
803
- this.vector.labels.remove();
804
- this.vector.tiles.destroy();
805
- this.vector = undefined;
806
- }
920
+ const name = checkBasemap(basemap);
921
+ if (this.basemap && this.hasLayer(this.basemap))
922
+ this.basemap.remove();
923
+ if (this.hillshade && this.hasLayer(this.hillshade))
924
+ this.hillshade.remove();
925
+ // Its raster and labels go with it
926
+ this.vector?.tiles.destroy();
927
+ this.vector = undefined;
807
928
  const vector = VECTOR_BASEMAPS[name];
808
929
  if (vector) {
809
930
  const tiles = new VectorTiles(this, {
@@ -834,8 +955,9 @@ export class GeoMap {
834
955
  let layer;
835
956
  if (grid === 'equirectangular' && !options.loader) {
836
957
  // The source's level n has the pixel size of Mercator level n + 1 at the equator
837
- const loader = equirectangularLoader(url, maxZoom, size ?? 256);
838
- layer = new RasterLayer(this, { url, minZoom, maxZoom: maxZoom + 1, opacity, saturation, size, loader });
958
+ const loader = equirectangularLoader(url, maxZoom, size ?? 256, minZoom);
959
+ const levels = { minZoom: minZoom + 1, maxZoom: maxZoom + 1 };
960
+ layer = new RasterLayer(this, { url, ...levels, opacity, saturation, size, loader });
839
961
  }
840
962
  else {
841
963
  layer = new RasterLayer(this, { url, minZoom, maxZoom, opacity, saturation, size, loader: options.loader });
@@ -904,6 +1026,10 @@ export class GeoMap {
904
1026
  this.vectorSets.add(tiles);
905
1027
  return tiles;
906
1028
  }
1029
+ /** @internal Forgets a destroyed `VectorTiles` */
1030
+ dropVectorTiles(tiles) {
1031
+ this.vectorSets.delete(tiles);
1032
+ }
907
1033
  /**
908
1034
  * @internal The workers for a `VectorTiles`: the map's shared pool, or a pool of its own (`own`, to stop with it)
909
1035
  * when it asks for another count or URL
@@ -947,13 +1073,18 @@ export class GeoMap {
947
1073
  this.animation = step;
948
1074
  this.requestRender();
949
1075
  }
950
- /** @internal */
1076
+ /** @internal The pointer moved over the map (undefined: it left). Without 'hover' and 'hoverfeature' listeners,
1077
+ * nothing is drawn: a still map stays idle under a moving mouse */
951
1078
  hover(point) {
952
- this.hoverPoint = point;
953
- if (point)
954
- this.requestRender();
955
- else
1079
+ if (!point) {
1080
+ this.hoverPoint = undefined;
956
1081
  this.cancelHoverPick();
1082
+ return;
1083
+ }
1084
+ if (this.listeners.hover.size === 0 && this.listeners.hoverfeature.size === 0)
1085
+ return;
1086
+ this.hoverPoint = point;
1087
+ this.requestRender();
957
1088
  }
958
1089
  frame(now) {
959
1090
  this.frameRequest = 0;
@@ -991,7 +1122,9 @@ export class GeoMap {
991
1122
  const point = this.hoverPoint;
992
1123
  hovered = point;
993
1124
  this.hoverPoint = undefined;
994
- this.emit('hover', { point, lonLat: this.unproject(point) });
1125
+ // The position under the pointer for its listeners only (a 'hoverfeature' alone does not need it)
1126
+ if (this.listeners.hover.size > 0)
1127
+ this.emit('hover', { point, lonLat: this.unproject(point) });
995
1128
  }
996
1129
  const t0 = performance.now();
997
1130
  // The engine asks for the next frame while it draws (uploads past the frame budget, fades): not ignored
@@ -1048,12 +1181,16 @@ export class GeoMap {
1048
1181
  this.frame(performance.now());
1049
1182
  }
1050
1183
  destroy() {
1184
+ if (this.gone)
1185
+ return;
1051
1186
  this.gone = true;
1187
+ // A context restored later rebuilds nothing
1188
+ this.unwatchContext();
1052
1189
  const camera = this.getCamera();
1053
1190
  cancelAnimationFrame(this.frameRequest);
1054
1191
  this.cancelHoverPick();
1055
1192
  this.vector?.tiles.destroy();
1056
- for (const tiles of this.vectorSets)
1193
+ for (const tiles of [...this.vectorSets])
1057
1194
  tiles.destroy();
1058
1195
  this.vectorSets.clear();
1059
1196
  this.basemapPool?.terminate();
@@ -1067,6 +1204,8 @@ export class GeoMap {
1067
1204
  // Work still under way (labels being shaped, tiles arriving, timers) may call the engine after this: it finds one
1068
1205
  // that does nothing, and nothing is drawn again
1069
1206
  this.#engine = destroyed(camera);
1207
+ // Glyph ranges still arriving upload to it, not to the freed engine
1208
+ this.#glyphs?.attach(this.#engine);
1070
1209
  this.lost = true;
1071
1210
  for (const control of [...this.controls.keys()])
1072
1211
  this.removeControl(control);