isard 1.10.0 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +1 -1
  3. package/dist/basemap/vectortiles/vectors.js +2 -1
  4. package/dist/basemap/vectortiles/vectors.js.map +1 -1
  5. package/dist/basemap/vectortiles.d.ts +13 -8
  6. package/dist/basemap/vectortiles.js.map +1 -1
  7. package/dist/bind/layers.js +7 -2
  8. package/dist/bind/layers.js.map +1 -1
  9. package/dist/decoder.worker.js +3 -3
  10. package/dist/decoder.worker.js.map +3 -3
  11. package/dist/index.d.ts +3 -3
  12. package/dist/index.js +1 -0
  13. package/dist/index.js.map +1 -1
  14. package/dist/isard_bg.wasm +0 -0
  15. package/dist/isard_core_bg.wasm +0 -0
  16. package/dist/isard_grid_bg.wasm +0 -0
  17. package/dist/isard_tess_bg.wasm +0 -0
  18. package/dist/layers/features.d.ts +7 -0
  19. package/dist/layers/features.js +21 -5
  20. package/dist/layers/features.js.map +1 -1
  21. package/dist/layers/layers.js +2 -0
  22. package/dist/layers/layers.js.map +1 -1
  23. package/dist/layers/tiles3d.d.ts +1 -0
  24. package/dist/layers/tiles3d.js +42 -2
  25. package/dist/layers/tiles3d.js.map +1 -1
  26. package/dist/layers/vectors.js +6 -0
  27. package/dist/layers/vectors.js.map +1 -1
  28. package/dist/map/events.js +1 -0
  29. package/dist/map/events.js.map +1 -1
  30. package/dist/map/quality.d.ts +37 -0
  31. package/dist/map/quality.js +63 -0
  32. package/dist/map/quality.js.map +1 -0
  33. package/dist/map.d.ts +12 -1
  34. package/dist/map.js +64 -6
  35. package/dist/map.js.map +1 -1
  36. package/dist/react/IsardMap.d.ts +1 -0
  37. package/dist/react/IsardMap.js +2 -0
  38. package/dist/react/IsardMap.js.map +1 -1
  39. package/dist/react/VectorTiles.d.ts +5 -1
  40. package/dist/react/VectorTiles.js +8 -0
  41. package/dist/react/VectorTiles.js.map +1 -1
  42. package/dist/react/index.d.ts +1 -1
  43. package/dist/react/index.js +1 -1
  44. package/dist/react/index.js.map +1 -1
  45. package/dist/types.d.ts +20 -0
  46. package/dist/types.js.map +1 -1
  47. package/dist/wasm/isard.d.ts +16 -8
  48. package/dist/wasm/isard.js +38 -8
  49. package/dist/wasm/isard_core.d.ts +11 -8
  50. package/dist/wasm/isard_core.js +26 -8
  51. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"vectors.js","sourceRoot":"","sources":["../../src/layers/vectors.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The fills and lines of a MapLibre style drawn as geometry, tile by tile (`VectorTiles.vectors`), instead of into the\n * images of a raster layer: sharp at any zoom and pitch, on the relief, picked by feature, restyled without cutting the\n * tiles again. The workers cut each vector tile into polygons and lines and style its features; the engine draws the\n * style's layers in their order, each over its zoom range.\n */\n\nimport type { LayerHost } from '../types.ts';\nimport { FLOATS } from '../util/style-floats.ts';\nimport type { Engine } from '../wasm/isard.js';\nimport type { TileVectors } from '../workers/basemap/protocol.ts';\nimport { type Feature, type Size, stops } from './features.ts';\nimport { Layer } from './layers.ts';\nimport type { Tiles3dLayer } from './tiles3d.ts';\n\n/** A style layer as the engine draws it: its kind, zoom range, visibility and dashes (dash, gap, dash, gap, in line\n * widths; zeros: solid) */\nexport interface VectorSublayer {\n /** The style layer's id */\n id: string;\n /** Its source layer, if any (not for a background) */\n sourceLayer: string | undefined;\n kind: 'fill' | 'line' | 'extrusion' | 'circle';\n minZoom: number;\n maxZoom: number;\n visible: boolean;\n /** Its opacity when it depends on the zoom only, evaluated at the camera's zoom (else 1: the features' colors hold\n * it) */\n opacity: Size;\n dash: [number, number, number, number];\n /** The caps of its lines' ends (`line-cap`) */\n cap: 'butt' | 'round' | 'square';\n /** The joins of its lines' pieces (`line-join`), a miter longer than `miterLimit` line widths bevelled\n * (`line-miter-limit`); round and 2 if left out */\n join?: 'miter' | 'bevel' | 'round';\n miterLimit?: number;\n /** How far its fills or lines move on screen (`fill-translate`, `line-translate`: CSS pixels, x right, y down),\n * turning with the map or staying on the screen (`*-translate-anchor`); none and `map` if left out */\n translate?: [number, number];\n translateAnchor?: 'map' | 'viewport';\n /** Its fills have patterns (`fill-pattern`, `background-pattern`): over the relief, the engine finds the ground under\n * them */\n patterned?: boolean;\n /** Its lines glow at night (the streets: its id names a road, not its casing; `setSun`) */\n lit: boolean;\n}\n\n/** The properties of a picked feature, with the style layer that drew it */\nexport type VectorFeature = Feature<Record<string, unknown>> & { layer: string; sourceLayer: string | undefined };\n\n/** The main thread's time a frame gives to uploading tiles (ms): tiles arriving together are uploaded over several\n * frames, not all in the one (copying a tile's buffers to the GPU takes milliseconds) */\nconst UPLOAD_MS = 4;\n\ninterface Tile {\n /** Its number in the engine: tiles are numbered for picking in this order */\n key: number;\n /** What picking needs (its geometry and styles are the engine's only: an engine made anew asks the tiles again) */\n vectors: Pick<TileVectors, 'properties' | 'sublayer'>;\n}\n\nexport class VectorLayer extends Layer {\n private readonly tiles = new Map<string, Tile>();\n /** The tiles waiting for their upload (`UPLOAD_MS` a frame), each with what resolves its `setTile`; `sent`: in the\n * engine already, its blocks still uploading */\n private readonly queue = new Map<string, { vectors: TileVectors; uploaded: () => void; sent?: number }>();\n private flushing = false;\n private sublayers: VectorSublayer[] = [];\n private nextKey = 0;\n /** The whole layer shown (`setVisible`), over each style layer's visibility */\n private shown = true;\n /** Its buildings' walls show their windows (`setFacades`) */\n private facades = false;\n /** @internal Resolved once the style is loaded and its layers drawn known (set by its `VectorTiles`) */\n styled: Promise<void> = Promise.resolve();\n /** @internal Changes a property of a style layer drawn (set by its `VectorTiles`) */\n restyle: ((layer: string, group: 'paint' | 'layout', name: string, value: unknown) => void) | undefined;\n /** @internal Asks the workers for the tiles in view again (set by its `VectorTiles`): an engine made anew has none */\n recut: (() => void) | undefined;\n /** The 3D buildings drawn in place of its raised ones (`vectors({ buildings3d })`), for `map.pickFeature` */\n buildings3d: Tiles3dLayer | undefined;\n\n /** @internal */\n constructor(map: LayerHost) {\n super(map);\n }\n\n /** Resolves once the style is loaded, its layers drawn known (`layers`), and the map has drawn the layer; rejected\n * if the style fails */\n override get ready(): Promise<void> {\n return this.styled.then(() => super.ready);\n }\n\n /** The style layers drawn, in order */\n get layers(): readonly VectorSublayer[] {\n return this.sublayers;\n }\n\n /** Keys of the tiles held (`z/x/y`) */\n get tileKeys(): string[] {\n return [...this.tiles.keys()];\n }\n\n /** @internal Sets the style layers drawn, in order (the tiles' sublayers) */\n setSublayers(sublayers: VectorSublayer[]): void {\n this.sublayers = sublayers;\n this.sendSublayers(this.map.engine, this.id);\n this.map.requestRender();\n }\n\n /** @internal Adds or replaces a tile, cut by the workers (and made ready for the GPU there, with its mesh): uploaded\n * on a coming frame, within its share of the frame (`UPLOAD_MS`); resolves once it is (or once dropped meanwhile) */\n setTile(tile: string, vectors: TileVectors): Promise<void> {\n if (this.removed) return Promise.resolve();\n // The map not idle until it is uploaded\n return this.map.track(\n new Promise((uploaded) => {\n // A newer cut of a tile still waiting takes its place\n this.queue.get(tile)?.uploaded();\n this.queue.set(tile, { vectors, uploaded });\n this.flushSoon();\n }),\n );\n }\n\n /** Uploads the waiting tiles on the next frame */\n private flushSoon(): void {\n if (this.flushing) return;\n this.flushing = true;\n requestAnimationFrame(() => {\n this.flushing = false;\n this.flush();\n });\n }\n\n /** Uploads waiting tiles for `UPLOAD_MS` at most (one at least, or a part of its blocks), the rest on the next\n * frames; a tile's `setTile` resolves once its blocks are all there */\n private flush(): void {\n // Removed meanwhile, or between two engines (the new one asks for the tiles again)\n if (this.id < 0) return;\n\n const start = performance.now();\n const within = () => performance.now() - start <= UPLOAD_MS;\n\n for (const [tile, waiting] of this.queue) {\n waiting.sent ??= this.upload(tile, waiting.vectors);\n\n // A large tile's blocks (a pitched view's far tiles of a city: 10 MB and more), a part at a time\n let left = this.map.engine.uploadVectorTile(this.id, waiting.sent);\n\n while (left && within()) left = this.map.engine.uploadVectorTile(this.id, waiting.sent);\n if (left) break;\n this.queue.delete(tile);\n waiting.uploaded();\n if (!within()) break;\n }\n if (this.queue.size > 0) this.flushSoon();\n this.map.requestRender();\n }\n\n /** Sends a tile to the engine (its blocks' first part); its key */\n private upload(tile: string, vectors: TileVectors): number {\n const key = this.tiles.get(tile)?.key ?? this.nextKey++;\n const { properties, sublayer } = vectors;\n\n this.tiles.set(tile, { key, vectors: { properties, sublayer } });\n this.sendTile(this.map.engine, this.id, key, vectors);\n\n return key;\n }\n\n /** @internal New styles of a tile's features, as the workers evaluated them (the same features) */\n setTileStyles(tile: string, styles: Float32Array): void {\n const waiting = this.queue.get(tile);\n\n // Not uploaded yet: uploaded with them\n if (waiting && waiting.sent === undefined) {\n if (styles.length === waiting.vectors.properties.length * FLOATS) waiting.vectors.styles = styles;\n\n return;\n }\n\n const t = this.tiles.get(tile);\n\n if (!t || styles.length !== t.vectors.properties.length * FLOATS) return;\n this.map.engine.setFeatureStyle(this.id, styles, t.key);\n this.map.requestRender();\n }\n\n override remove(): void {\n super.remove();\n this.dispose();\n }\n\n /** @internal The tiles waiting resolved (dropped), none held */\n override dispose(): void {\n this.queue.forEach((waiting) => {\n waiting.uploaded();\n });\n this.queue.clear();\n this.tiles.clear();\n }\n\n /** @internal */\n removeTile(tile: string): void {\n this.queue.get(tile)?.uploaded();\n this.queue.delete(tile);\n\n const t = this.tiles.get(tile);\n\n if (!t) return;\n this.tiles.delete(tile);\n this.map.engine.removeVectorTile(this.id, t.key);\n this.map.requestRender();\n }\n\n /** The feature of a picked index (no geometry: the tiles hold it cut), its properties and style layer. Tiles are\n * numbered one after the other, in the order they were first added */\n featureAt(index: number): VectorFeature | undefined {\n const tiles = [...this.tiles.values()].sort((a, b) => a.key - b.key);\n // The tile holding the index, and the index among its features (one pass, the features of the tiles before\n // taken off)\n const { tile, rest } = tiles.reduce<{ tile?: Tile; rest: number }>(\n (found, t) => {\n if (found.tile) return found;\n\n const count = t.vectors.properties.length;\n\n return found.rest < count ? { tile: t, rest: found.rest } : { rest: found.rest - count };\n },\n { rest: index },\n );\n\n if (!tile) return undefined;\n\n const properties = tile.vectors.properties[rest];\n const sublayer = this.sublayers[tile.vectors.sublayer[rest] ?? -1];\n\n if (properties === undefined || !sublayer) return undefined;\n\n return { type: 'Feature', properties, geometry: null, layer: sublayer.id, sourceLayer: sublayer.sourceLayer };\n }\n\n /** Changes a paint property of a style layer drawn, as MapLibre's `setPaintProperty`: the tiles are restyled, not cut\n * again */\n setPaintProperty(layer: string, name: string, value: unknown): void {\n this.restyle?.(layer, 'paint', name, value);\n }\n\n /** Changes a layout property of a style layer drawn (`visibility`: shown or hidden at once), as MapLibre's\n * `setLayoutProperty` */\n setLayoutProperty(layer: string, name: string, value: unknown): void {\n this.restyle?.(layer, 'layout', name, value);\n }\n\n /** Whether its buildings' walls show their windows: glass by day, some lit at night (only the lit ones without) */\n setFacades(facades: boolean): void {\n this.facades = facades;\n this.map.engine.setFacades(this.id, facades);\n // Its 3D buildings' walls too\n this.buildings3d?.setFacades(facades);\n this.map.requestRender();\n }\n\n setVisible(visible: boolean): void {\n this.shown = visible;\n this.sendSublayers(this.map.engine, this.id);\n this.map.requestRender();\n }\n\n private sendSublayers(engine: Engine, id: number): void {\n const s = this.sublayers;\n\n engine.setVectorSublayers(\n id,\n Uint8Array.from(s, (l) => ({ fill: 0, line: 1, extrusion: 2, circle: 3 })[l.kind]),\n Float64Array.from(s.flatMap((l) => [l.minZoom, l.maxZoom])),\n Uint8Array.from(s, (l) => (l.visible && this.shown ? 1 : 0)),\n Float32Array.from(s.flatMap((l) => l.dash)),\n Float32Array.from(s.flatMap((l) => stops(l.opacity))),\n Uint8Array.from(s, (l) => ({ butt: 0, round: 1, square: 2 })[l.cap]),\n Uint8Array.from(s, (l) => (l.lit ? 1 : 0)),\n Float32Array.from(s.flatMap((l) => [{ round: 0, miter: 1, bevel: 2 }[l.join ?? 'round'], l.miterLimit ?? 2])),\n Float32Array.from(s.flatMap((l) => [...(l.translate ?? [0, 0]), l.translateAnchor === 'viewport' ? 1 : 0])),\n Uint8Array.from(s, (l) => (l.patterned ? 1 : 0)),\n );\n }\n\n /** A tile to the engine: its mesh uploaded as it is, or without one its geometry, which the engine makes ready */\n private sendTile(engine: Engine, id: number, key: number, vectors: TileVectors): void {\n const { fills, lines, circles, styles, properties, mesh } = vectors;\n\n if (mesh) {\n engine.setVectorTileMesh(\n id,\n key,\n fills.points,\n fills.ringStart,\n fills.polygonStart,\n fills.feature,\n fills.fillStart,\n mesh.vertices,\n mesh.indices,\n mesh.fillRanges,\n mesh.prism,\n mesh.pieces,\n mesh.lineTable,\n mesh.lineRanges,\n mesh.blocks,\n mesh.blockIndices,\n mesh.blockRanges,\n mesh.bounds,\n properties.length,\n );\n } else {\n engine.setVectorTile(\n id,\n key,\n fills.points,\n fills.ringStart,\n fills.polygonStart,\n fills.feature,\n fills.fillStart,\n lines.points,\n lines.start,\n lines.feature,\n lines.lineStart,\n properties.length,\n vectors.tile ?? new Float64Array(),\n fills.roofs ?? new Uint8Array(),\n fills.roofHeights ?? new Float32Array(),\n fills.roofOutlines ?? new Float64Array(),\n fills.roofOutlineStart ?? new Uint32Array(),\n fills.roofMetres ?? 0,\n );\n }\n // The circles' points, once the tile is there\n if (circles) engine.setVectorTilePoints(id, key, circles.points, circles.feature, circles.circleStart);\n engine.setFeatureStyle(id, styles, key);\n }\n\n /** @internal */\n protected create(engine: Engine): number {\n const id = engine.addVectorTiles();\n\n this.sendSublayers(engine, id);\n engine.setFacades(id, this.facades);\n // An engine made anew (after a context loss, or the one with 3D Tiles): its tiles cut again by the workers, once\n // the layer has its id there. Keeping their geometry here would double the memory they take\n this.dispose();\n queueMicrotask(() => this.recut?.());\n\n return id;\n }\n}\n"]}
1
+ {"version":3,"file":"vectors.js","sourceRoot":"","sources":["../../src/layers/vectors.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The fills and lines of a MapLibre style drawn as geometry, tile by tile (`VectorTiles.vectors`), instead of into the\n * images of a raster layer: sharp at any zoom and pitch, on the relief, picked by feature, restyled without cutting the\n * tiles again. The workers cut each vector tile into polygons and lines and style its features; the engine draws the\n * style's layers in their order, each over its zoom range.\n */\n\nimport type { LayerHost } from '../types.ts';\nimport { FLOATS } from '../util/style-floats.ts';\nimport type { Engine } from '../wasm/isard.js';\nimport type { TileVectors } from '../workers/basemap/protocol.ts';\nimport { type Feature, type Size, stops } from './features.ts';\nimport { Layer } from './layers.ts';\nimport type { Tiles3dLayer } from './tiles3d.ts';\n\n/** A style layer as the engine draws it: its kind, zoom range, visibility and dashes (dash, gap, dash, gap, in line\n * widths; zeros: solid) */\nexport interface VectorSublayer {\n /** The style layer's id */\n id: string;\n /** Its source layer, if any (not for a background) */\n sourceLayer: string | undefined;\n kind: 'fill' | 'line' | 'extrusion' | 'circle';\n minZoom: number;\n maxZoom: number;\n visible: boolean;\n /** Its opacity when it depends on the zoom only, evaluated at the camera's zoom (else 1: the features' colors hold\n * it) */\n opacity: Size;\n dash: [number, number, number, number];\n /** The caps of its lines' ends (`line-cap`) */\n cap: 'butt' | 'round' | 'square';\n /** The joins of its lines' pieces (`line-join`), a miter longer than `miterLimit` line widths bevelled\n * (`line-miter-limit`); round and 2 if left out */\n join?: 'miter' | 'bevel' | 'round';\n miterLimit?: number;\n /** How far its fills or lines move on screen (`fill-translate`, `line-translate`: CSS pixels, x right, y down),\n * turning with the map or staying on the screen (`*-translate-anchor`); none and `map` if left out */\n translate?: [number, number];\n translateAnchor?: 'map' | 'viewport';\n /** Its fills have patterns (`fill-pattern`, `background-pattern`): over the relief, the engine finds the ground under\n * them */\n patterned?: boolean;\n /** Its lines glow at night (the streets: its id names a road, not its casing; `setSun`) */\n lit: boolean;\n}\n\n/** The properties of a picked feature, with the style layer that drew it */\nexport type VectorFeature = Feature<Record<string, unknown>> & { layer: string; sourceLayer: string | undefined };\n\n/** The main thread's time a frame gives to uploading tiles (ms): tiles arriving together are uploaded over several\n * frames, not all in the one (copying a tile's buffers to the GPU takes milliseconds) */\nconst UPLOAD_MS = 4;\n\ninterface Tile {\n /** Its number in the engine: tiles are numbered for picking in this order */\n key: number;\n /** What picking needs (its geometry and styles are the engine's only: an engine made anew asks the tiles again) */\n vectors: Pick<TileVectors, 'properties' | 'sublayer'>;\n}\n\nexport class VectorLayer extends Layer {\n private readonly tiles = new Map<string, Tile>();\n /** The tiles waiting for their upload (`UPLOAD_MS` a frame), each with what resolves its `setTile`; `sent`: in the\n * engine already, its blocks still uploading */\n private readonly queue = new Map<string, { vectors: TileVectors; uploaded: () => void; sent?: number }>();\n private flushing = false;\n private sublayers: VectorSublayer[] = [];\n private nextKey = 0;\n /** The whole layer shown (`setVisible`), over each style layer's visibility */\n private shown = true;\n /** Its buildings' walls show their windows (`setFacades`) */\n private facades = false;\n /** @internal Resolved once the style is loaded and its layers drawn known (set by its `VectorTiles`) */\n styled: Promise<void> = Promise.resolve();\n /** @internal Changes a property of a style layer drawn (set by its `VectorTiles`) */\n restyle: ((layer: string, group: 'paint' | 'layout', name: string, value: unknown) => void) | undefined;\n /** @internal Asks the workers for the tiles in view again (set by its `VectorTiles`): an engine made anew has none */\n recut: (() => void) | undefined;\n /** @internal Asks for the tiles in view (set by its `VectorTiles`): those of a new quality */\n refresh: (() => void) | undefined;\n /** The 3D buildings drawn in place of its raised ones (`vectors({ buildings3d })`), for `map.pickFeature` */\n buildings3d: Tiles3dLayer | undefined;\n\n /** @internal */\n constructor(map: LayerHost) {\n super(map);\n }\n\n /** @internal Its tiles as far as the map's quality reaches */\n override qualityChanged(): void {\n this.refresh?.();\n }\n\n /** Resolves once the style is loaded, its layers drawn known (`layers`), and the map has drawn the layer; rejected\n * if the style fails */\n override get ready(): Promise<void> {\n return this.styled.then(() => super.ready);\n }\n\n /** The style layers drawn, in order */\n get layers(): readonly VectorSublayer[] {\n return this.sublayers;\n }\n\n /** Keys of the tiles held (`z/x/y`) */\n get tileKeys(): string[] {\n return [...this.tiles.keys()];\n }\n\n /** @internal Sets the style layers drawn, in order (the tiles' sublayers) */\n setSublayers(sublayers: VectorSublayer[]): void {\n this.sublayers = sublayers;\n this.sendSublayers(this.map.engine, this.id);\n this.map.requestRender();\n }\n\n /** @internal Adds or replaces a tile, cut by the workers (and made ready for the GPU there, with its mesh): uploaded\n * on a coming frame, within its share of the frame (`UPLOAD_MS`); resolves once it is (or once dropped meanwhile) */\n setTile(tile: string, vectors: TileVectors): Promise<void> {\n if (this.removed) return Promise.resolve();\n // The map not idle until it is uploaded\n return this.map.track(\n new Promise((uploaded) => {\n // A newer cut of a tile still waiting takes its place\n this.queue.get(tile)?.uploaded();\n this.queue.set(tile, { vectors, uploaded });\n this.flushSoon();\n }),\n );\n }\n\n /** Uploads the waiting tiles on the next frame */\n private flushSoon(): void {\n if (this.flushing) return;\n this.flushing = true;\n requestAnimationFrame(() => {\n this.flushing = false;\n this.flush();\n });\n }\n\n /** Uploads waiting tiles for `UPLOAD_MS` at most (one at least, or a part of its blocks), the rest on the next\n * frames; a tile's `setTile` resolves once its blocks are all there */\n private flush(): void {\n // Removed meanwhile, or between two engines (the new one asks for the tiles again)\n if (this.id < 0) return;\n\n const start = performance.now();\n const within = () => performance.now() - start <= UPLOAD_MS;\n\n for (const [tile, waiting] of this.queue) {\n waiting.sent ??= this.upload(tile, waiting.vectors);\n\n // A large tile's blocks (a pitched view's far tiles of a city: 10 MB and more), a part at a time\n let left = this.map.engine.uploadVectorTile(this.id, waiting.sent);\n\n while (left && within()) left = this.map.engine.uploadVectorTile(this.id, waiting.sent);\n if (left) break;\n this.queue.delete(tile);\n waiting.uploaded();\n if (!within()) break;\n }\n if (this.queue.size > 0) this.flushSoon();\n this.map.requestRender();\n }\n\n /** Sends a tile to the engine (its blocks' first part); its key */\n private upload(tile: string, vectors: TileVectors): number {\n const key = this.tiles.get(tile)?.key ?? this.nextKey++;\n const { properties, sublayer } = vectors;\n\n this.tiles.set(tile, { key, vectors: { properties, sublayer } });\n this.sendTile(this.map.engine, this.id, key, vectors);\n\n return key;\n }\n\n /** @internal New styles of a tile's features, as the workers evaluated them (the same features) */\n setTileStyles(tile: string, styles: Float32Array): void {\n const waiting = this.queue.get(tile);\n\n // Not uploaded yet: uploaded with them\n if (waiting && waiting.sent === undefined) {\n if (styles.length === waiting.vectors.properties.length * FLOATS) waiting.vectors.styles = styles;\n\n return;\n }\n\n const t = this.tiles.get(tile);\n\n if (!t || styles.length !== t.vectors.properties.length * FLOATS) return;\n this.map.engine.setFeatureStyle(this.id, styles, t.key);\n this.map.requestRender();\n }\n\n override remove(): void {\n super.remove();\n this.dispose();\n }\n\n /** @internal The tiles waiting resolved (dropped), none held */\n override dispose(): void {\n this.queue.forEach((waiting) => {\n waiting.uploaded();\n });\n this.queue.clear();\n this.tiles.clear();\n }\n\n /** @internal */\n removeTile(tile: string): void {\n this.queue.get(tile)?.uploaded();\n this.queue.delete(tile);\n\n const t = this.tiles.get(tile);\n\n if (!t) return;\n this.tiles.delete(tile);\n this.map.engine.removeVectorTile(this.id, t.key);\n this.map.requestRender();\n }\n\n /** The feature of a picked index (no geometry: the tiles hold it cut), its properties and style layer. Tiles are\n * numbered one after the other, in the order they were first added */\n featureAt(index: number): VectorFeature | undefined {\n const tiles = [...this.tiles.values()].sort((a, b) => a.key - b.key);\n // The tile holding the index, and the index among its features (one pass, the features of the tiles before\n // taken off)\n const { tile, rest } = tiles.reduce<{ tile?: Tile; rest: number }>(\n (found, t) => {\n if (found.tile) return found;\n\n const count = t.vectors.properties.length;\n\n return found.rest < count ? { tile: t, rest: found.rest } : { rest: found.rest - count };\n },\n { rest: index },\n );\n\n if (!tile) return undefined;\n\n const properties = tile.vectors.properties[rest];\n const sublayer = this.sublayers[tile.vectors.sublayer[rest] ?? -1];\n\n if (properties === undefined || !sublayer) return undefined;\n\n return { type: 'Feature', properties, geometry: null, layer: sublayer.id, sourceLayer: sublayer.sourceLayer };\n }\n\n /** Changes a paint property of a style layer drawn, as MapLibre's `setPaintProperty`: the tiles are restyled, not cut\n * again */\n setPaintProperty(layer: string, name: string, value: unknown): void {\n this.restyle?.(layer, 'paint', name, value);\n }\n\n /** Changes a layout property of a style layer drawn (`visibility`: shown or hidden at once), as MapLibre's\n * `setLayoutProperty` */\n setLayoutProperty(layer: string, name: string, value: unknown): void {\n this.restyle?.(layer, 'layout', name, value);\n }\n\n /** Whether its buildings' walls show their windows: glass by day, some lit at night (only the lit ones without) */\n setFacades(facades: boolean): void {\n this.facades = facades;\n this.map.engine.setFacades(this.id, facades);\n // Its 3D buildings' walls too\n this.buildings3d?.setFacades(facades);\n this.map.requestRender();\n }\n\n setVisible(visible: boolean): void {\n this.shown = visible;\n this.sendSublayers(this.map.engine, this.id);\n this.map.requestRender();\n }\n\n private sendSublayers(engine: Engine, id: number): void {\n const s = this.sublayers;\n\n engine.setVectorSublayers(\n id,\n Uint8Array.from(s, (l) => ({ fill: 0, line: 1, extrusion: 2, circle: 3 })[l.kind]),\n Float64Array.from(s.flatMap((l) => [l.minZoom, l.maxZoom])),\n Uint8Array.from(s, (l) => (l.visible && this.shown ? 1 : 0)),\n Float32Array.from(s.flatMap((l) => l.dash)),\n Float32Array.from(s.flatMap((l) => stops(l.opacity))),\n Uint8Array.from(s, (l) => ({ butt: 0, round: 1, square: 2 })[l.cap]),\n Uint8Array.from(s, (l) => (l.lit ? 1 : 0)),\n Float32Array.from(s.flatMap((l) => [{ round: 0, miter: 1, bevel: 2 }[l.join ?? 'round'], l.miterLimit ?? 2])),\n Float32Array.from(s.flatMap((l) => [...(l.translate ?? [0, 0]), l.translateAnchor === 'viewport' ? 1 : 0])),\n Uint8Array.from(s, (l) => (l.patterned ? 1 : 0)),\n );\n }\n\n /** A tile to the engine: its mesh uploaded as it is, or without one its geometry, which the engine makes ready */\n private sendTile(engine: Engine, id: number, key: number, vectors: TileVectors): void {\n const { fills, lines, circles, styles, properties, mesh } = vectors;\n\n if (mesh) {\n engine.setVectorTileMesh(\n id,\n key,\n fills.points,\n fills.ringStart,\n fills.polygonStart,\n fills.feature,\n fills.fillStart,\n mesh.vertices,\n mesh.indices,\n mesh.fillRanges,\n mesh.prism,\n mesh.pieces,\n mesh.lineTable,\n mesh.lineRanges,\n mesh.blocks,\n mesh.blockIndices,\n mesh.blockRanges,\n mesh.bounds,\n properties.length,\n );\n } else {\n engine.setVectorTile(\n id,\n key,\n fills.points,\n fills.ringStart,\n fills.polygonStart,\n fills.feature,\n fills.fillStart,\n lines.points,\n lines.start,\n lines.feature,\n lines.lineStart,\n properties.length,\n vectors.tile ?? new Float64Array(),\n fills.roofs ?? new Uint8Array(),\n fills.roofHeights ?? new Float32Array(),\n fills.roofOutlines ?? new Float64Array(),\n fills.roofOutlineStart ?? new Uint32Array(),\n fills.roofMetres ?? 0,\n );\n }\n // The circles' points, once the tile is there\n if (circles) engine.setVectorTilePoints(id, key, circles.points, circles.feature, circles.circleStart);\n engine.setFeatureStyle(id, styles, key);\n }\n\n /** @internal */\n protected create(engine: Engine): number {\n const id = engine.addVectorTiles();\n\n this.sendSublayers(engine, id);\n engine.setFacades(id, this.facades);\n // An engine made anew (after a context loss, or the one with 3D Tiles): its tiles cut again by the workers, once\n // the layer has its id there. Keeping their geometry here would double the memory they take\n this.dispose();\n queueMicrotask(() => this.recut?.());\n\n return id;\n }\n}\n"]}
@@ -11,6 +11,7 @@ export class MapListeners {
11
11
  hoverfeature: new Set(),
12
12
  click: new Set(),
13
13
  render: new Set(),
14
+ quality: new Set(),
14
15
  idle: new Set(),
15
16
  leave: new Set(),
16
17
  };
@@ -1 +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"]}
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,OAAO,EAAE,IAAI,GAAG,EAAE;QAClB,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 quality: 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,37 @@
1
+ /**
2
+ * The map's quality: what it draws less of on a device that cannot keep up. Each level a ceiling on the pixels drawn
3
+ * (the device's pixel ratio capped: a high-density screen draws four times the pixels of its CSS size), the sun's
4
+ * shadows (the solid scene drawn twice more for them: the sun's map, the camera's depth), how far the 3D Tiles are
5
+ * refined (their screen-space error multiplied: fewer, coarser tiles far away) and how far toward the horizon the
6
+ * vector tiles go (a city's tiles there carry its whole detail over square kilometres, mostly above the screen's top
7
+ * edge: Paris tilted 65° on a phone, 940 MB of a page against 720 without them, the view the same). 'auto' starts high
8
+ * and steps down when the frames stay slow while the map moves.
9
+ */
10
+ import type { Quality } from '../types.ts';
11
+ /** What a level draws */
12
+ export interface QualitySettings {
13
+ /** The highest pixel ratio drawn */
14
+ pixelRatio: number;
15
+ /** The sun casts its shadows (its light and the night stay without) */
16
+ shadows: boolean;
17
+ /** Multiplies the 3D Tiles' screen-space error */
18
+ errorScale: number;
19
+ /** How far toward the horizon the vector tiles go, in distances of the screen center */
20
+ reach: number;
21
+ }
22
+ export declare const QUALITY: Readonly<Record<Quality, QualitySettings>>;
23
+ /**
24
+ * 'auto': the intervals between the frames drawn while the map moves; once a window of them (`WINDOW`) has a median
25
+ * past `SLOW_MS`, `step` is called with the level under the current one. It never steps up: at the display's rate a fast
26
+ * frame tells nothing of what a finer level would cost
27
+ */
28
+ export declare class QualityWatch {
29
+ private level;
30
+ private readonly step;
31
+ private readonly intervals;
32
+ private last;
33
+ private settled;
34
+ constructor(level: Quality, step: (level: Quality) => void);
35
+ /** A frame drawn at `now` (ms), the map moving or not */
36
+ frame(now: number, moving: boolean): void;
37
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * The map's quality: what it draws less of on a device that cannot keep up. Each level a ceiling on the pixels drawn
3
+ * (the device's pixel ratio capped: a high-density screen draws four times the pixels of its CSS size), the sun's
4
+ * shadows (the solid scene drawn twice more for them: the sun's map, the camera's depth), how far the 3D Tiles are
5
+ * refined (their screen-space error multiplied: fewer, coarser tiles far away) and how far toward the horizon the
6
+ * vector tiles go (a city's tiles there carry its whole detail over square kilometres, mostly above the screen's top
7
+ * edge: Paris tilted 65° on a phone, 940 MB of a page against 720 without them, the view the same). 'auto' starts high
8
+ * and steps down when the frames stay slow while the map moves.
9
+ */
10
+ export const QUALITY = {
11
+ high: { pixelRatio: Number.POSITIVE_INFINITY, shadows: true, errorScale: 1, reach: Number.POSITIVE_INFINITY },
12
+ medium: { pixelRatio: 1.5, shadows: true, errorScale: 1.5, reach: 3 },
13
+ low: { pixelRatio: 1, shadows: false, errorScale: 2.5, reach: 3 },
14
+ };
15
+ /** The level under each, for 'auto' */
16
+ const LOWER = { high: 'medium', medium: 'low', low: undefined };
17
+ /** A move measured before it is judged: `WINDOW` frames, or `WINDOW_MS` of them on a slow device (at least
18
+ * `MIN_FRAMES`); a gap past `GAP_MS` between two frames is no move (the map was still) */
19
+ const WINDOW = 60;
20
+ const WINDOW_MS = 2000;
21
+ const MIN_FRAMES = 10;
22
+ const GAP_MS = 500;
23
+ /** The median interval between the frames of a move past which the map steps down (some 40 frames a second) */
24
+ const SLOW_MS = 25;
25
+ /** After a step down, the time the new level is given before it is judged */
26
+ const SETTLE_MS = 3000;
27
+ /**
28
+ * 'auto': the intervals between the frames drawn while the map moves; once a window of them (`WINDOW`) has a median
29
+ * past `SLOW_MS`, `step` is called with the level under the current one. It never steps up: at the display's rate a fast
30
+ * frame tells nothing of what a finer level would cost
31
+ */
32
+ export class QualityWatch {
33
+ level;
34
+ step;
35
+ intervals = [];
36
+ last = 0;
37
+ settled = 0;
38
+ constructor(level, step) {
39
+ this.level = level;
40
+ this.step = step;
41
+ }
42
+ /** A frame drawn at `now` (ms), the map moving or not */
43
+ frame(now, moving) {
44
+ const gap = now - this.last;
45
+ this.last = now;
46
+ if (!moving || gap > GAP_MS || now < this.settled)
47
+ return;
48
+ this.intervals.push(gap);
49
+ const spent = this.intervals.reduce((sum, i) => sum + i, 0);
50
+ if (this.intervals.length < WINDOW && (spent < WINDOW_MS || this.intervals.length < MIN_FRAMES))
51
+ return;
52
+ const sorted = [...this.intervals].sort((a, b) => a - b);
53
+ const median = sorted[Math.floor(sorted.length / 2)] ?? 0;
54
+ const lower = LOWER[this.level];
55
+ this.intervals.length = 0;
56
+ if (median <= SLOW_MS || !lower)
57
+ return;
58
+ this.level = lower;
59
+ this.settled = now + SETTLE_MS;
60
+ this.step(lower);
61
+ }
62
+ }
63
+ //# sourceMappingURL=quality.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality.js","sourceRoot":"","sources":["../../src/map/quality.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAgBH,MAAM,CAAC,MAAM,OAAO,GAA+C;IACjE,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,iBAAiB,EAAE;IAC7G,MAAM,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE;IACrE,GAAG,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE;CAClE,CAAC;AAEF,uCAAuC;AACvC,MAAM,KAAK,GAAmD,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;AAEhH;0FAC0F;AAC1F,MAAM,MAAM,GAAG,EAAE,CAAC;AAClB,MAAM,SAAS,GAAG,IAAI,CAAC;AACvB,MAAM,UAAU,GAAG,EAAE,CAAC;AACtB,MAAM,MAAM,GAAG,GAAG,CAAC;AAEnB,+GAA+G;AAC/G,MAAM,OAAO,GAAG,EAAE,CAAC;AAEnB,6EAA6E;AAC7E,MAAM,SAAS,GAAG,IAAI,CAAC;AAEvB;;;;GAIG;AACH,MAAM,OAAO,YAAY;IAMb;IACS;IANF,SAAS,GAAa,EAAE,CAAC;IAClC,IAAI,GAAG,CAAC,CAAC;IACT,OAAO,GAAG,CAAC,CAAC;IAEpB,YACU,KAAc,EACL,IAA8B;QADvC,UAAK,GAAL,KAAK,CAAS;QACL,SAAI,GAAJ,IAAI,CAA0B;IAC9C,CAAC;IAEJ,yDAAyD;IACzD,KAAK,CAAC,GAAW,EAAE,MAAe;QAChC,MAAM,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC;QAE5B,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;QAChB,IAAI,CAAC,MAAM,IAAI,GAAG,GAAG,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO;YAAE,OAAO;QAC1D,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEzB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QAE5D,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,GAAG,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,UAAU,CAAC;YAAE,OAAO;QAExG,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC1D,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEhC,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;QAC1B,IAAI,MAAM,IAAI,OAAO,IAAI,CAAC,KAAK;YAAE,OAAO;QACxC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,OAAO,GAAG,GAAG,GAAG,SAAS,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC;CACF","sourcesContent":["/**\n * The map's quality: what it draws less of on a device that cannot keep up. Each level a ceiling on the pixels drawn\n * (the device's pixel ratio capped: a high-density screen draws four times the pixels of its CSS size), the sun's\n * shadows (the solid scene drawn twice more for them: the sun's map, the camera's depth), how far the 3D Tiles are\n * refined (their screen-space error multiplied: fewer, coarser tiles far away) and how far toward the horizon the\n * vector tiles go (a city's tiles there carry its whole detail over square kilometres, mostly above the screen's top\n * edge: Paris tilted 65° on a phone, 940 MB of a page against 720 without them, the view the same). 'auto' starts high\n * and steps down when the frames stay slow while the map moves.\n */\n\nimport type { Quality } from '../types.ts';\n\n/** What a level draws */\nexport interface QualitySettings {\n /** The highest pixel ratio drawn */\n pixelRatio: number;\n /** The sun casts its shadows (its light and the night stay without) */\n shadows: boolean;\n /** Multiplies the 3D Tiles' screen-space error */\n errorScale: number;\n /** How far toward the horizon the vector tiles go, in distances of the screen center */\n reach: number;\n}\n\nexport const QUALITY: Readonly<Record<Quality, QualitySettings>> = {\n high: { pixelRatio: Number.POSITIVE_INFINITY, shadows: true, errorScale: 1, reach: Number.POSITIVE_INFINITY },\n medium: { pixelRatio: 1.5, shadows: true, errorScale: 1.5, reach: 3 },\n low: { pixelRatio: 1, shadows: false, errorScale: 2.5, reach: 3 },\n};\n\n/** The level under each, for 'auto' */\nconst LOWER: Readonly<Record<Quality, Quality | undefined>> = { high: 'medium', medium: 'low', low: undefined };\n\n/** A move measured before it is judged: `WINDOW` frames, or `WINDOW_MS` of them on a slow device (at least\n * `MIN_FRAMES`); a gap past `GAP_MS` between two frames is no move (the map was still) */\nconst WINDOW = 60;\nconst WINDOW_MS = 2000;\nconst MIN_FRAMES = 10;\nconst GAP_MS = 500;\n\n/** The median interval between the frames of a move past which the map steps down (some 40 frames a second) */\nconst SLOW_MS = 25;\n\n/** After a step down, the time the new level is given before it is judged */\nconst SETTLE_MS = 3000;\n\n/**\n * 'auto': the intervals between the frames drawn while the map moves; once a window of them (`WINDOW`) has a median\n * past `SLOW_MS`, `step` is called with the level under the current one. It never steps up: at the display's rate a fast\n * frame tells nothing of what a finer level would cost\n */\nexport class QualityWatch {\n private readonly intervals: number[] = [];\n private last = 0;\n private settled = 0;\n\n constructor(\n private level: Quality,\n private readonly step: (level: Quality) => void,\n ) {}\n\n /** A frame drawn at `now` (ms), the map moving or not */\n frame(now: number, moving: boolean): void {\n const gap = now - this.last;\n\n this.last = now;\n if (!moving || gap > GAP_MS || now < this.settled) return;\n this.intervals.push(gap);\n\n const spent = this.intervals.reduce((sum, i) => sum + i, 0);\n\n if (this.intervals.length < WINDOW && (spent < WINDOW_MS || this.intervals.length < MIN_FRAMES)) return;\n\n const sorted = [...this.intervals].sort((a, b) => a - b);\n const median = sorted[Math.floor(sorted.length / 2)] ?? 0;\n const lower = LOWER[this.level];\n\n this.intervals.length = 0;\n if (median <= SLOW_MS || !lower) return;\n this.level = lower;\n this.settled = now + SETTLE_MS;\n this.step(lower);\n }\n}\n"]}
package/dist/map.d.ts CHANGED
@@ -26,7 +26,7 @@ import { Tiles3dLayer } from './layers/tiles3d.ts';
26
26
  import { type TreeOptions } from './layers/trees.ts';
27
27
  import { type HoverPicking } from './map/hover-pick.ts';
28
28
  import { type LayerSpec } from './map/layer-spec.ts';
29
- import type { AnimationOptions, AtmosphereOptions, Basemap, FeatureHit, FirstPersonView, FlyToOptions, GeoMapOptions, LoadingMode, LonLat, MapEvents, NetworkOptions, PickOptions, Point, Projection, RasterOptions, SunOptions, SwipeOptions, TerrainModel, TerrainOptions, Tiles3dOptions, ViewshedOptions } from './types.ts';
29
+ import type { AnimationOptions, AtmosphereOptions, Basemap, FeatureHit, FirstPersonView, FlyToOptions, GeoMapOptions, LoadingMode, LonLat, MapEvents, NetworkOptions, PickOptions, Point, Projection, Quality, RasterOptions, SunOptions, SwipeOptions, TerrainModel, TerrainOptions, Tiles3dOptions, ViewshedOptions } from './types.ts';
30
30
  import { type Control, type ControlPosition } from './ui/controls.ts';
31
31
  import type { Camera, PickHit, RasterLayerStats } from './wasm/isard.js';
32
32
  export type { LayerSpec } from './map/layer-spec.ts';
@@ -119,8 +119,19 @@ export declare class GeoMap {
119
119
  setSwipe(options: SwipeOptions | undefined): void;
120
120
  private applySwipe;
121
121
  private addLayer;
122
+ /** Whether the canvas's WebGL context is lost, its event come or not */
123
+ private contextLost;
122
124
  /** Listens to an event; returns the function that stops listening */
123
125
  on<K extends keyof MapEvents>(type: K, listener: (event: MapEvents[K]) => void): () => void;
126
+ /** 'auto': the frames watched, the map stepped down while they stay slow */
127
+ private qualityWatch;
128
+ private movingNow;
129
+ /** The map's quality: `'high'`, `'medium'` or `'low'` (as `GeoMapOptions.quality` says; `'auto'` the level it
130
+ * stepped down to) */
131
+ getQuality(): Quality;
132
+ /** Sets the map's quality (`GeoMapOptions.quality`); `'auto'` starts again from `'high'` */
133
+ setQuality(quality: Quality | 'auto'): void;
134
+ private applyQuality;
124
135
  getCamera(): Camera;
125
136
  setCamera(camera: Partial<Camera>): void;
126
137
  /** Animated move to a camera: over `duration` milliseconds (or the options), ease-out by default */
package/dist/map.js CHANGED
@@ -39,6 +39,7 @@ import { addSpec } from "./map/layer-spec.js";
39
39
  import { LayerStack } from "./map/layer-stack.js";
40
40
  import { OverlayHost } from "./map/overlay-host.js";
41
41
  import { panoramaHost } from "./map/panorama-host.js";
42
+ import { QUALITY, QualityWatch } from "./map/quality.js";
42
43
  import { rasterSource } from "./map/raster-source.js";
43
44
  import { SymbolAtlases } from "./map/symbol-atlases.js";
44
45
  import { applyViewshed } from "./map/viewshed.js";
@@ -158,6 +159,7 @@ export class GeoMap {
158
159
  upgrading: () => this.engines.upgrading !== undefined,
159
160
  working: () => this.#working > 0,
160
161
  drawn: (hovered) => {
162
+ this.qualityWatch?.frame(performance.now(), this.movingNow);
161
163
  // The picking pass sees the frame just drawn; its answer comes on a later frame
162
164
  if (hovered && this.listeners.has('hoverfeature'))
163
165
  this.hoverPick.request(hovered, this.hoverPicking);
@@ -181,6 +183,17 @@ export class GeoMap {
181
183
  this.setSun(options.sun);
182
184
  this.resizeObserver = new ResizeObserver(() => this.resize());
183
185
  this.resizeObserver.observe(container);
186
+ this.#quality = options.quality === 'auto' || options.quality === undefined ? 'high' : options.quality;
187
+ if (options.quality === 'auto') {
188
+ this.qualityWatch = new QualityWatch('high', (level) => this.applyQuality(level));
189
+ // The frames measured are those of a move
190
+ this.on('movestart', () => {
191
+ this.movingNow = true;
192
+ });
193
+ this.on('moveend', () => {
194
+ this.movingNow = false;
195
+ });
196
+ }
184
197
  this.unwatchRatio = watchPixelRatio(() => this.resize());
185
198
  this.resize();
186
199
  const interactive = options.interactive ?? true;
@@ -345,13 +358,26 @@ export class GeoMap {
345
358
  // others on it
346
359
  if (layer.needsFullEngine && !this.engines.tiles3d)
347
360
  this.upgrade();
348
- else
349
- layer.attach(this.engine);
361
+ else {
362
+ try {
363
+ layer.attach(this.engine);
364
+ }
365
+ catch (error) {
366
+ // A context lost before the browser says so (its event comes later): nothing could be made on it, the layer is
367
+ // made with the others on the next engine (`restore`). Any other failure is the caller's
368
+ if (!this.contextLost())
369
+ throw error;
370
+ }
371
+ }
350
372
  // Under the layers kept on top (the basemap's labels)
351
373
  this.stack.add(layer);
352
374
  this.requestRender();
353
375
  return layer;
354
376
  }
377
+ /** Whether the canvas's WebGL context is lost, its event come or not */
378
+ contextLost() {
379
+ return this.lost || this.canvas.getContext('webgl2')?.isContextLost() === true;
380
+ }
355
381
  /** @internal Keeps a layer above the layers added after it (they go under it), as the labels of a basemap */
356
382
  keepOnTop(layer) {
357
383
  this.onTop.add(layer);
@@ -375,6 +401,38 @@ export class GeoMap {
375
401
  this.listeners.emit(type, event);
376
402
  }
377
403
  // ── Camera ──
404
+ #quality = 'high';
405
+ /** 'auto': the frames watched, the map stepped down while they stay slow */
406
+ qualityWatch;
407
+ movingNow = false;
408
+ /** The map's quality: `'high'`, `'medium'` or `'low'` (as `GeoMapOptions.quality` says; `'auto'` the level it
409
+ * stepped down to) */
410
+ getQuality() {
411
+ return this.#quality;
412
+ }
413
+ /** @internal What its quality draws */
414
+ get quality() {
415
+ return QUALITY[this.#quality];
416
+ }
417
+ /** Sets the map's quality (`GeoMapOptions.quality`); `'auto'` starts again from `'high'` */
418
+ setQuality(quality) {
419
+ this.qualityWatch = quality === 'auto' ? new QualityWatch('high', (level) => this.applyQuality(level)) : undefined;
420
+ this.applyQuality(quality === 'auto' ? 'high' : quality);
421
+ }
422
+ applyQuality(quality) {
423
+ if (quality === this.#quality)
424
+ return;
425
+ this.#quality = quality;
426
+ // The canvas at its pixel ratio, the sun's shadows, the layers' detail
427
+ this.resize();
428
+ if (this.sun)
429
+ this.setSun(this.sun);
430
+ this.layers.forEach((layer) => {
431
+ layer.qualityChanged();
432
+ });
433
+ this.emit('quality', { quality });
434
+ this.requestRender();
435
+ }
378
436
  getCamera() {
379
437
  return this.frames.camera ?? this.engine.camera();
380
438
  }
@@ -473,8 +531,8 @@ export class GeoMap {
473
531
  // The twilight: from 6° above the horizon to 6° under it, smoothly
474
532
  const dusk = Math.min(1, Math.max(0, (6 - altitude) / 12));
475
533
  const night = Math.min(1, Math.max(0, options.night ?? dusk * dusk * (3 - 2 * dusk)));
476
- // The shadows fade with the sun's light
477
- const opacity = Math.min(1, Math.max(0, options.opacity ?? 0.35)) * (1 - night);
534
+ // The shadows fade with the sun's light; none at a low quality (its light and the night stay)
535
+ const opacity = this.quality.shadows ? Math.min(1, Math.max(0, options.opacity ?? 0.35)) * (1 - night) : 0;
478
536
  this.engine.setSun(azimuth, altitude, opacity, night);
479
537
  this.requestRender();
480
538
  }
@@ -728,7 +786,7 @@ export class GeoMap {
728
786
  }
729
787
  /** Lines from GeoJSON (line strings, and polygon outlines), styled per feature */
730
788
  addLines(options) {
731
- return this.place(new LineLayer(this, options.data, lineStyle(options)), options.before);
789
+ return this.place(new LineLayer(this, options.data, lineStyle(options), options.altitudeReference), options.before);
732
790
  }
733
791
  /** Discs from GeoJSON points, styled per feature */
734
792
  addCircles(options) {
@@ -888,7 +946,7 @@ export class GeoMap {
888
946
  if (this.lost)
889
947
  return;
890
948
  const { clientWidth: width, clientHeight: height } = this.canvas;
891
- const ratio = window.devicePixelRatio || 1;
949
+ const ratio = Math.min(window.devicePixelRatio || 1, this.quality.pixelRatio);
892
950
  this.canvas.width = Math.round(width * ratio);
893
951
  this.canvas.height = Math.round(height * ratio);
894
952
  this.engine.resize(width, height, ratio);