isard 1.0.0 → 1.1.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 (179) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/{basemaps.d.ts → basemap/basemaps.d.ts} +2 -2
  3. package/dist/{basemaps.js → basemap/basemaps.js} +1 -1
  4. package/dist/basemap/basemaps.js.map +1 -0
  5. package/dist/{grid.d.ts → basemap/grid.d.ts} +1 -1
  6. package/dist/{grid.js → basemap/grid.js} +2 -2
  7. package/dist/basemap/grid.js.map +1 -0
  8. package/dist/basemap/mvt.js.map +1 -0
  9. package/dist/{pmtiles.d.ts → basemap/pmtiles.d.ts} +6 -0
  10. package/dist/{pmtiles.js → basemap/pmtiles.js} +2 -2
  11. package/dist/basemap/pmtiles.js.map +1 -0
  12. package/dist/{resample.d.ts → basemap/resample.d.ts} +9 -0
  13. package/dist/{resample.js → basemap/resample.js} +2 -2
  14. package/dist/basemap/resample.js.map +1 -0
  15. package/dist/{terrain.js → basemap/terrain.js} +1 -1
  16. package/dist/basemap/terrain.js.map +1 -0
  17. package/dist/{vectorstyle.js → basemap/vectorstyle.js} +1 -1
  18. package/dist/basemap/vectorstyle.js.map +1 -0
  19. package/dist/{vectortiles.d.ts → basemap/vectortiles.d.ts} +7 -7
  20. package/dist/{vectortiles.js → basemap/vectortiles.js} +16 -6
  21. package/dist/basemap/vectortiles.js.map +1 -0
  22. package/dist/{wmts.js → basemap/wmts.js} +3 -3
  23. package/dist/basemap/wmts.js.map +1 -0
  24. package/dist/basemap.worker.js +2 -2
  25. package/dist/basemap.worker.js.map +10 -10
  26. package/dist/bind/layers.d.ts +37 -0
  27. package/dist/bind/layers.js +130 -0
  28. package/dist/bind/layers.js.map +1 -0
  29. package/dist/{crs.d.ts → data/crs.d.ts} +1 -1
  30. package/dist/data/crs.js.map +1 -0
  31. package/dist/{gpx.d.ts → data/gpx.d.ts} +1 -1
  32. package/dist/data/gpx.js.map +1 -0
  33. package/dist/{kml.d.ts → data/kml.d.ts} +1 -1
  34. package/dist/data/kml.js.map +1 -0
  35. package/dist/{topojson.d.ts → data/topojson.d.ts} +1 -1
  36. package/dist/data/topojson.js.map +1 -0
  37. package/dist/data/xml.js.map +1 -0
  38. package/dist/decoder.worker.js +1 -1
  39. package/dist/decoder.worker.js.map +4 -4
  40. package/dist/{decoders.d.ts → engine/decoders.d.ts} +1 -1
  41. package/dist/engine/decoders.js.map +1 -0
  42. package/dist/{loader.d.ts → engine/loader.d.ts} +1 -1
  43. package/dist/{loader.js → engine/loader.js} +4 -0
  44. package/dist/engine/loader.js.map +1 -0
  45. package/dist/{protocol.d.ts → engine/protocol.d.ts} +1 -1
  46. package/dist/engine/protocol.js +3 -0
  47. package/dist/engine/protocol.js.map +1 -0
  48. package/dist/engine/requests.js.map +1 -0
  49. package/dist/engine-loader.d.ts +5 -1
  50. package/dist/engine-loader.js +3 -3
  51. package/dist/engine-loader.js.map +1 -1
  52. package/dist/formats.d.ts +3 -3
  53. package/dist/formats.js +3 -3
  54. package/dist/formats.js.map +1 -1
  55. package/dist/geoplateforme.d.ts +3 -3
  56. package/dist/geoplateforme.js +1 -1
  57. package/dist/geoplateforme.js.map +1 -1
  58. package/dist/index.d.ts +29 -29
  59. package/dist/index.js +18 -18
  60. package/dist/index.js.map +1 -1
  61. package/dist/isard_bg.wasm +0 -0
  62. package/dist/isard_core_bg.wasm +0 -0
  63. package/dist/layers/extrusions.js.map +1 -0
  64. package/dist/{features.js → layers/features.js} +3 -3
  65. package/dist/layers/features.js.map +1 -0
  66. package/dist/{glyphs.d.ts → layers/glyphs.d.ts} +3 -3
  67. package/dist/{glyphs.js → layers/glyphs.js} +11 -1
  68. package/dist/layers/glyphs.js.map +1 -0
  69. package/dist/{icons.d.ts → layers/icons.d.ts} +2 -2
  70. package/dist/{icons.js → layers/icons.js} +8 -1
  71. package/dist/layers/icons.js.map +1 -0
  72. package/dist/{layers.d.ts → layers/layers.d.ts} +8 -3
  73. package/dist/{layers.js → layers/layers.js} +2 -2
  74. package/dist/layers/layers.js.map +1 -0
  75. package/dist/{panoramas.d.ts → layers/panoramas.d.ts} +1 -1
  76. package/dist/{panoramas.js → layers/panoramas.js} +2 -2
  77. package/dist/layers/panoramas.js.map +1 -0
  78. package/dist/{pointclouds.d.ts → layers/pointclouds.d.ts} +2 -2
  79. package/dist/{pointclouds.js → layers/pointclouds.js} +1 -1
  80. package/dist/layers/pointclouds.js.map +1 -0
  81. package/dist/{symbols.d.ts → layers/symbols.d.ts} +2 -2
  82. package/dist/{symbols.js → layers/symbols.js} +1 -1
  83. package/dist/layers/symbols.js.map +1 -0
  84. package/dist/map.d.ts +15 -9
  85. package/dist/map.js +27 -17
  86. package/dist/map.js.map +1 -1
  87. package/dist/projections.d.ts +3 -3
  88. package/dist/projections.js +2 -2
  89. package/dist/projections.js.map +1 -1
  90. package/dist/react/index.d.ts +119 -0
  91. package/dist/react/index.js +409 -0
  92. package/dist/react/index.js.map +1 -0
  93. package/dist/settings.d.ts +1 -1
  94. package/dist/settings.js +2 -2
  95. package/dist/settings.js.map +1 -1
  96. package/dist/types.d.ts +5 -5
  97. package/dist/types.js +1 -0
  98. package/dist/types.js.map +1 -1
  99. package/dist/{controls.d.ts → ui/controls.d.ts} +1 -1
  100. package/dist/ui/controls.js.map +1 -0
  101. package/dist/{interaction.d.ts → ui/interaction.d.ts} +7 -3
  102. package/dist/{interaction.js → ui/interaction.js} +1 -1
  103. package/dist/ui/interaction.js.map +1 -0
  104. package/dist/{overlay.d.ts → ui/overlay.d.ts} +2 -2
  105. package/dist/ui/overlay.js.map +1 -0
  106. package/dist/ui/style.js.map +1 -0
  107. package/dist/{animation.d.ts → util/animation.d.ts} +6 -2
  108. package/dist/util/animation.js.map +1 -0
  109. package/dist/util/color.js.map +1 -0
  110. package/dist/util/geo.js.map +1 -0
  111. package/dist/util/lru.js.map +1 -0
  112. package/dist/{basemap.worker.d.ts → workers/basemap.worker.d.ts} +14 -4
  113. package/dist/workers/basemap.worker.js +647 -0
  114. package/dist/workers/basemap.worker.js.map +1 -0
  115. package/package.json +24 -1
  116. package/vite.js +1 -1
  117. package/dist/animation.js.map +0 -1
  118. package/dist/basemaps.js.map +0 -1
  119. package/dist/color.js.map +0 -1
  120. package/dist/controls.js.map +0 -1
  121. package/dist/crs.js.map +0 -1
  122. package/dist/decoders.js.map +0 -1
  123. package/dist/extrusions.js.map +0 -1
  124. package/dist/features.js.map +0 -1
  125. package/dist/geo.js.map +0 -1
  126. package/dist/glyphs.js.map +0 -1
  127. package/dist/gpx.js.map +0 -1
  128. package/dist/grid.js.map +0 -1
  129. package/dist/icons.js.map +0 -1
  130. package/dist/interaction.js.map +0 -1
  131. package/dist/kml.js.map +0 -1
  132. package/dist/layers.js.map +0 -1
  133. package/dist/loader.js.map +0 -1
  134. package/dist/lru.js.map +0 -1
  135. package/dist/mvt.js.map +0 -1
  136. package/dist/overlay.js.map +0 -1
  137. package/dist/panoramas.js.map +0 -1
  138. package/dist/pmtiles.js.map +0 -1
  139. package/dist/pointclouds.js.map +0 -1
  140. package/dist/protocol.js +0 -2
  141. package/dist/protocol.js.map +0 -1
  142. package/dist/requests.js.map +0 -1
  143. package/dist/resample.js.map +0 -1
  144. package/dist/style.js.map +0 -1
  145. package/dist/symbols.js.map +0 -1
  146. package/dist/terrain.js.map +0 -1
  147. package/dist/topojson.js.map +0 -1
  148. package/dist/vectorstyle.js.map +0 -1
  149. package/dist/vectortiles.js.map +0 -1
  150. package/dist/wmts.js.map +0 -1
  151. package/dist/xml.js.map +0 -1
  152. /package/dist/{mvt.d.ts → basemap/mvt.d.ts} +0 -0
  153. /package/dist/{mvt.js → basemap/mvt.js} +0 -0
  154. /package/dist/{terrain.d.ts → basemap/terrain.d.ts} +0 -0
  155. /package/dist/{vectorstyle.d.ts → basemap/vectorstyle.d.ts} +0 -0
  156. /package/dist/{wmts.d.ts → basemap/wmts.d.ts} +0 -0
  157. /package/dist/{crs.js → data/crs.js} +0 -0
  158. /package/dist/{gpx.js → data/gpx.js} +0 -0
  159. /package/dist/{kml.js → data/kml.js} +0 -0
  160. /package/dist/{topojson.js → data/topojson.js} +0 -0
  161. /package/dist/{xml.d.ts → data/xml.d.ts} +0 -0
  162. /package/dist/{xml.js → data/xml.js} +0 -0
  163. /package/dist/{decoders.js → engine/decoders.js} +0 -0
  164. /package/dist/{requests.d.ts → engine/requests.d.ts} +0 -0
  165. /package/dist/{requests.js → engine/requests.js} +0 -0
  166. /package/dist/{extrusions.d.ts → layers/extrusions.d.ts} +0 -0
  167. /package/dist/{extrusions.js → layers/extrusions.js} +0 -0
  168. /package/dist/{features.d.ts → layers/features.d.ts} +0 -0
  169. /package/dist/{controls.js → ui/controls.js} +0 -0
  170. /package/dist/{overlay.js → ui/overlay.js} +0 -0
  171. /package/dist/{style.d.ts → ui/style.d.ts} +0 -0
  172. /package/dist/{style.js → ui/style.js} +0 -0
  173. /package/dist/{animation.js → util/animation.js} +0 -0
  174. /package/dist/{color.d.ts → util/color.d.ts} +0 -0
  175. /package/dist/{color.js → util/color.js} +0 -0
  176. /package/dist/{geo.d.ts → util/geo.d.ts} +0 -0
  177. /package/dist/{geo.js → util/geo.js} +0 -0
  178. /package/dist/{lru.d.ts → util/lru.d.ts} +0 -0
  179. /package/dist/{lru.js → util/lru.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The settings of a map's engine from its options: the body, its halo, its relief, the sky. Kept by the map and\n * replayed on a new engine (after a context loss, or on the engine with 3D Tiles).\n */\nimport {\n BODY_TERRAINS,\n IGN_ATTRIBUTION,\n IMAGE_SERVER,\n imageServerTerrain,\n TERRAIN_TILES,\n TERRAIN_TILES_ATTRIBUTION,\n TERRAIN_URL,\n} from './basemaps.ts';\nimport { parseCssColor } from './color.ts';\nimport type { PngEncoding } from './terrain.ts';\nimport type {\n AtmosphereOptions,\n BodyOptions,\n CelestialBody,\n LoadingMode,\n TerrainModel,\n TerrainOptions,\n} from './types.ts';\n\n/** Decodes the relief tiles of a URL for the engine: 256 × 256 altitudes, null where there is no tile */\nexport type TerrainLoader = (z: number, x: number, y: number, signal: AbortSignal) => Promise<Float32Array | null>;\n\n/** Settings replayed on a new engine after a WebGL context loss */\nexport interface Settings {\n body: Required<BodyOptions>;\n zoomRange: [min: number, max: number];\n maxPitch: number;\n globe: boolean;\n sky: boolean;\n atmosphere: Float32Array | undefined;\n terrain:\n | {\n url: string;\n exaggeration: number;\n maxZoom: number;\n geoid: boolean;\n /** Decodes the tiles of `url` for the engine (an encoding other than raw floats) */\n loader?: TerrainLoader;\n /** Credits of the model */\n attribution?: string;\n }\n | undefined;\n loading: LoadingMode;\n background: [r: number, g: number, b: number];\n globeColor: [r: number, g: number, b: number];\n}\n\n/** The named bodies; a body's `color` is that of its globe under the tiles (the Earth's follows its basemap), its\n * `relief` the range of its ground (the Earth's dry land, from the Dead Sea to Everest). Mars: the sphere of its\n * equatorial radius (its data take planetocentric latitudes), a faint butterscotch halo of dust */\nconst BODIES: Record<Exclude<CelestialBody, BodyOptions>, Required<BodyOptions>> = {\n earth: { radius: 6378137, flattening: 1 / 298.257223563, atmosphere: true, color: '#cacaca', relief: [-450, 8900] },\n moon: { radius: 1737400, flattening: 0, atmosphere: false, color: '#77756f', relief: [-9200, 10800] },\n mars: {\n radius: 3396190,\n flattening: 0,\n atmosphere: 'rgba(232, 168, 120, 0.6)',\n color: '#b5714a',\n relief: [-8300, 21300],\n },\n};\n\n/** The Earth's halo, RGB 0-1 and its strength: what `atmosphere: true` draws */\nconst EARTH_HALO = Float32Array.of(0.42, 0.66, 1, 1);\n\n/** A body from the option, its defaults filled in */\nexport function bodySettings(body: CelestialBody | undefined): Required<BodyOptions> {\n if (body === undefined || typeof body === 'string') return BODIES[body ?? 'earth'];\n const relief: [number, number] = [-0.01 * body.radius, 0.01 * body.radius];\n return { flattening: 0, atmosphere: false, color: '#808080', relief, ...body };\n}\n\n/** The halo of an atmosphere for the engine (RGB 0-1 and its strength, the color's alpha): undefined for none */\nexport function haloSettings(atmosphere: boolean | string): Float32Array | undefined {\n if (atmosphere === true) return EARTH_HALO;\n const color = atmosphere === false ? undefined : parseCssColor(atmosphere);\n return color && Float32Array.from(color);\n}\n\n/** Relief settings from the option: undefined when off. On the Earth the Terrain Tiles by default (worldwide,\n * Terrarium PNGs decoded by `terrainLoader`) or the IGN terrain model (France, raised by the geoid); NASA's on the Moon\n * and Mars; an ArcGIS image service asked for in the body's Mercator. `terrainLoader`: the loader of PNG tiles in an\n * encoding, the same for the same tiles (the engine keeps its tiles when only the exaggeration changes) */\nexport function terrainSettings(\n terrain: boolean | TerrainModel | TerrainOptions | undefined,\n body: CelestialBody | undefined,\n radius: number,\n terrainLoader: (url: string, encoding: PngEncoding, floor?: number) => TerrainLoader,\n): Settings['terrain'] {\n if (!terrain) return undefined;\n let options: TerrainOptions = {};\n if (typeof terrain === 'string') options = { model: terrain };\n else if (terrain !== true) options = terrain;\n const earth = (body ?? 'earth') === 'earth';\n const exaggeration = options.exaggeration ?? 1;\n if (options.url === undefined && earth) {\n if (options.model === 'ign') {\n const geoid = options.geoid ?? true;\n return { url: TERRAIN_URL, exaggeration, maxZoom: options.maxZoom ?? 15, geoid, attribution: IGN_ATTRIBUTION };\n }\n return {\n url: TERRAIN_TILES.url,\n exaggeration,\n maxZoom: options.maxZoom ?? TERRAIN_TILES.maxZoom,\n geoid: options.geoid ?? false,\n // The sea floor of the model at sea level: the oceans stay flat under the basemap's water\n loader: terrainLoader(TERRAIN_TILES.url, 'terrarium', 0),\n attribution: TERRAIN_TILES_ATTRIBUTION,\n };\n }\n const preset = body === 'moon' || body === 'mars' ? BODY_TERRAINS[body] : undefined;\n const url = options.url ?? preset?.url;\n if (url === undefined) throw new Error('isard: the relief of this body needs a url');\n const encoding = options.encoding ?? 'float32';\n // PNG encodings are fetched tile by tile: a {bbox} or an image service would be fetched as it is\n if (\n encoding !== 'float32' &&\n (IMAGE_SERVER.test(url) || !/\\{z\\}/.test(url) || !/\\{x\\}/.test(url) || !/\\{y\\}/.test(url))\n ) {\n throw new Error(`isard: the '${encoding}' terrain encoding takes a tile URL with {z}, {x} and {y} (${url})`);\n }\n return {\n url: IMAGE_SERVER.test(url) ? imageServerTerrain(url, earth, radius) : url,\n exaggeration,\n maxZoom: options.maxZoom ?? (options.url === undefined && preset ? preset.maxZoom : 15),\n geoid: options.geoid ?? false,\n ...(encoding === 'float32' ? {} : { loader: terrainLoader(url, encoding) }),\n // NASA's credits for its models\n ...(options.url === undefined && preset ? { attribution: preset.attribution } : {}),\n };\n}\n\n/** Sky settings for the engine: colors (RGB 0-1) and blends, MapLibre's defaults */\nexport function atmosphereSettings(options: AtmosphereOptions | undefined): Float32Array | undefined {\n if (!options) return undefined;\n return Float32Array.from([\n ...rgb(options.skyColor ?? '#9cc7ec'),\n ...rgb(options.horizonColor ?? '#e8f1f8'),\n ...rgb(options.fogColor ?? '#f2f5f8'),\n options.skyHorizonBlend ?? 0.6,\n options.horizonFogBlend ?? 0.7,\n options.fogGroundBlend ?? 0.4,\n ]);\n}\n\n/** A CSS color to RGB 0-1 (its alpha dropped); black if unknown */\nexport function rgb(color: string): [r: number, g: number, b: number] {\n const [r, g, b] = parseCssColor(color) ?? [0, 0, 0, 1];\n return [r, g, b];\n}\n"]}
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The settings of a map's engine from its options: the body, its halo, its relief, the sky. Kept by the map and\n * replayed on a new engine (after a context loss, or on the engine with 3D Tiles).\n */\nimport {\n BODY_TERRAINS,\n IGN_ATTRIBUTION,\n IMAGE_SERVER,\n imageServerTerrain,\n TERRAIN_TILES,\n TERRAIN_TILES_ATTRIBUTION,\n TERRAIN_URL,\n} from './basemap/basemaps.ts';\nimport type { PngEncoding } from './basemap/terrain.ts';\nimport type {\n AtmosphereOptions,\n BodyOptions,\n CelestialBody,\n LoadingMode,\n TerrainModel,\n TerrainOptions,\n} from './types.ts';\nimport { parseCssColor } from './util/color.ts';\n\n/** Decodes the relief tiles of a URL for the engine: 256 × 256 altitudes, null where there is no tile */\nexport type TerrainLoader = (z: number, x: number, y: number, signal: AbortSignal) => Promise<Float32Array | null>;\n\n/** Settings replayed on a new engine after a WebGL context loss */\nexport interface Settings {\n body: Required<BodyOptions>;\n zoomRange: [min: number, max: number];\n maxPitch: number;\n globe: boolean;\n sky: boolean;\n atmosphere: Float32Array | undefined;\n terrain:\n | {\n url: string;\n exaggeration: number;\n maxZoom: number;\n geoid: boolean;\n /** Decodes the tiles of `url` for the engine (an encoding other than raw floats) */\n loader?: TerrainLoader;\n /** Credits of the model */\n attribution?: string;\n }\n | undefined;\n loading: LoadingMode;\n background: [r: number, g: number, b: number];\n globeColor: [r: number, g: number, b: number];\n}\n\n/** The named bodies; a body's `color` is that of its globe under the tiles (the Earth's follows its basemap), its\n * `relief` the range of its ground (the Earth's dry land, from the Dead Sea to Everest). Mars: the sphere of its\n * equatorial radius (its data take planetocentric latitudes), a faint butterscotch halo of dust */\nconst BODIES: Record<Exclude<CelestialBody, BodyOptions>, Required<BodyOptions>> = {\n earth: { radius: 6378137, flattening: 1 / 298.257223563, atmosphere: true, color: '#cacaca', relief: [-450, 8900] },\n moon: { radius: 1737400, flattening: 0, atmosphere: false, color: '#77756f', relief: [-9200, 10800] },\n mars: {\n radius: 3396190,\n flattening: 0,\n atmosphere: 'rgba(232, 168, 120, 0.6)',\n color: '#b5714a',\n relief: [-8300, 21300],\n },\n};\n\n/** The Earth's halo, RGB 0-1 and its strength: what `atmosphere: true` draws */\nconst EARTH_HALO = Float32Array.of(0.42, 0.66, 1, 1);\n\n/** A body from the option, its defaults filled in */\nexport function bodySettings(body: CelestialBody | undefined): Required<BodyOptions> {\n if (body === undefined || typeof body === 'string') return BODIES[body ?? 'earth'];\n const relief: [number, number] = [-0.01 * body.radius, 0.01 * body.radius];\n return { flattening: 0, atmosphere: false, color: '#808080', relief, ...body };\n}\n\n/** The halo of an atmosphere for the engine (RGB 0-1 and its strength, the color's alpha): undefined for none */\nexport function haloSettings(atmosphere: boolean | string): Float32Array | undefined {\n if (atmosphere === true) return EARTH_HALO;\n const color = atmosphere === false ? undefined : parseCssColor(atmosphere);\n return color && Float32Array.from(color);\n}\n\n/** Relief settings from the option: undefined when off. On the Earth the Terrain Tiles by default (worldwide,\n * Terrarium PNGs decoded by `terrainLoader`) or the IGN terrain model (France, raised by the geoid); NASA's on the Moon\n * and Mars; an ArcGIS image service asked for in the body's Mercator. `terrainLoader`: the loader of PNG tiles in an\n * encoding, the same for the same tiles (the engine keeps its tiles when only the exaggeration changes) */\nexport function terrainSettings(\n terrain: boolean | TerrainModel | TerrainOptions | undefined,\n body: CelestialBody | undefined,\n radius: number,\n terrainLoader: (url: string, encoding: PngEncoding, floor?: number) => TerrainLoader,\n): Settings['terrain'] {\n if (!terrain) return undefined;\n let options: TerrainOptions = {};\n if (typeof terrain === 'string') options = { model: terrain };\n else if (terrain !== true) options = terrain;\n const earth = (body ?? 'earth') === 'earth';\n const exaggeration = options.exaggeration ?? 1;\n if (options.url === undefined && earth) {\n if (options.model === 'ign') {\n const geoid = options.geoid ?? true;\n return { url: TERRAIN_URL, exaggeration, maxZoom: options.maxZoom ?? 15, geoid, attribution: IGN_ATTRIBUTION };\n }\n return {\n url: TERRAIN_TILES.url,\n exaggeration,\n maxZoom: options.maxZoom ?? TERRAIN_TILES.maxZoom,\n geoid: options.geoid ?? false,\n // The sea floor of the model at sea level: the oceans stay flat under the basemap's water\n loader: terrainLoader(TERRAIN_TILES.url, 'terrarium', 0),\n attribution: TERRAIN_TILES_ATTRIBUTION,\n };\n }\n const preset = body === 'moon' || body === 'mars' ? BODY_TERRAINS[body] : undefined;\n const url = options.url ?? preset?.url;\n if (url === undefined) throw new Error('isard: the relief of this body needs a url');\n const encoding = options.encoding ?? 'float32';\n // PNG encodings are fetched tile by tile: a {bbox} or an image service would be fetched as it is\n if (\n encoding !== 'float32' &&\n (IMAGE_SERVER.test(url) || !/\\{z\\}/.test(url) || !/\\{x\\}/.test(url) || !/\\{y\\}/.test(url))\n ) {\n throw new Error(`isard: the '${encoding}' terrain encoding takes a tile URL with {z}, {x} and {y} (${url})`);\n }\n return {\n url: IMAGE_SERVER.test(url) ? imageServerTerrain(url, earth, radius) : url,\n exaggeration,\n maxZoom: options.maxZoom ?? (options.url === undefined && preset ? preset.maxZoom : 15),\n geoid: options.geoid ?? false,\n ...(encoding === 'float32' ? {} : { loader: terrainLoader(url, encoding) }),\n // NASA's credits for its models\n ...(options.url === undefined && preset ? { attribution: preset.attribution } : {}),\n };\n}\n\n/** Sky settings for the engine: colors (RGB 0-1) and blends, MapLibre's defaults */\nexport function atmosphereSettings(options: AtmosphereOptions | undefined): Float32Array | undefined {\n if (!options) return undefined;\n return Float32Array.from([\n ...rgb(options.skyColor ?? '#9cc7ec'),\n ...rgb(options.horizonColor ?? '#e8f1f8'),\n ...rgb(options.fogColor ?? '#f2f5f8'),\n options.skyHorizonBlend ?? 0.6,\n options.horizonFogBlend ?? 0.7,\n options.fogGroundBlend ?? 0.4,\n ]);\n}\n\n/** A CSS color to RGB 0-1 (its alpha dropped); black if unknown */\nexport function rgb(color: string): [r: number, g: number, b: number] {\n const [r, g, b] = parseCssColor(color) ?? [0, 0, 0, 1];\n return [r, g, b];\n}\n"]}
package/dist/types.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  /** Public types of the `isard` package */
2
- import type { AttributionOptions } from './controls.ts';
3
- import type { DecoderUrls } from './decoders.ts';
4
- import type { Feature, Ramp, Size } from './features.ts';
5
- import type { TileGrid } from './grid.ts';
6
- import type { Layer } from './layers.ts';
2
+ import type { TileGrid } from './basemap/grid.ts';
3
+ import type { DecoderUrls } from './engine/decoders.ts';
4
+ import type { Feature, Ramp, Size } from './layers/features.ts';
5
+ import type { Layer } from './layers/layers.ts';
6
+ import type { AttributionOptions } from './ui/controls.ts';
7
7
  import type { Camera, Engine } from './wasm/isard.js';
8
8
  export type LonLat = [lon: number, lat: number];
9
9
  export type Point = [x: number, y: number];
package/dist/types.js CHANGED
@@ -1,2 +1,3 @@
1
+ /** Public types of the `isard` package */
1
2
  export {};
2
3
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["/** Public types of the `isard` package */\nimport type { AttributionOptions } from './controls.ts';\nimport type { DecoderUrls } from './decoders.ts';\nimport type { Feature, Ramp, Size } from './features.ts';\nimport type { TileGrid } from './grid.ts';\nimport type { Layer } from './layers.ts';\nimport type { Camera, Engine } from './wasm/isard.js';\n\nexport type LonLat = [lon: number, lat: number];\nexport type Point = [x: number, y: number];\n\n/**\n * The named basemaps. OpenFreeMap's vector styles, OpenStreetMap data worldwide, their labels above the other layers:\n * `osm-positron` (light grey, quiet: data over it reads first), `osm-liberty` and `osm-bright` (in colour). The\n * Géoplateforme's (IGN, France): rasters (`ign-plan`, `ign-plan-grey`, `ign-ortho`, the aerial photographs) or vector\n * tiles with their labels (`ign-plan-vector`, `ign-plan-grey-vector`, the PLAN.IGN styles).\n */\nexport type BasemapName =\n | 'osm-positron'\n | 'osm-liberty'\n | 'osm-bright'\n | 'ign-plan'\n | 'ign-plan-grey'\n | 'ign-ortho'\n | 'ign-plan-vector'\n | 'ign-plan-grey-vector'\n | 'none';\n\n/** A basemap by name (see `BasemapName`) */\nexport type Basemap = BasemapName;\n\n/**\n * The Earth's named terrain models. `'terrain-tiles'`: worldwide, the Terrain Tiles of AWS's open data registry\n * (SRTM, EU-DEM, GMTED… merged by Mapzen, 30 m in most places), the sea floor flattened at sea level. `'ign'`: France,\n * the IGN's RGE ALTI from the Géoplateforme (1 to 5 m), raised by the RAF20 geoid to heights above the ellipsoid.\n */\nexport type TerrainModel = 'terrain-tiles' | 'ign';\n\n/** How tiles encode their altitudes: `'float32'`, raw little-endian floats (`image/x-bil;bits=32`, an ArcGIS raw\n * grid); `'terrarium'`, the colors of a PNG, `R × 256 + G + B / 256 - 32768`; `'mapbox'`, those of Terrain-RGB,\n * `(R × 65536 + G × 256 + B) / 10 - 10000` */\nexport type TerrainEncoding = 'float32' | 'terrarium' | 'mapbox';\n\n/**\n * How tiles load and show. 'immediate' (default): everything visible loads, tiles show as soon as they arrive.\n * 'smooth': during flights the levels flown through are skipped, off-center tiles wait while the camera moves, tiles\n * fade in; fewer downloads, for slow networks or GPUs.\n */\nexport type LoadingMode = 'immediate' | 'smooth';\n\n/** 'globe': a sphere at low zoom, blending into Web Mercator between zooms 5 and 7, up to three levels later under a\n * tilted camera (it sees much farther than its center: the horizon stays curved) */\nexport type Projection = 'globe' | 'mercator';\n\n/** A body to draw the map on, other than the named ones (`CelestialBody`) */\nexport interface BodyOptions {\n /** Equatorial radius, metres */\n radius: number;\n /** Flattening of its ellipsoid, 0 for a sphere (default 0) */\n flattening?: number;\n /** An atmosphere: its halo around the globe, true for the Earth's light blue, or a CSS color (its alpha the\n * halo's strength) (default false) */\n atmosphere?: boolean | string;\n /** Color of the globe where no tile covers it (past the Web Mercator latitudes, 85°), a CSS color (default\n * `#808080`) */\n color?: string;\n /** Lowest and highest altitudes of its ground, metres around the ellipsoid: what its relief may raise into view\n * (default ±1 % of the radius) */\n relief?: [lowest: number, highest: number];\n}\n\n/**\n * The body the map is drawn on: 'earth' (WGS 84, the default), 'moon' (a sphere of 1 737 400 m, no atmosphere),\n * 'mars' (a sphere of 3 396 190 m, its equatorial radius, a thin dusty halo; planetocentric latitudes) or another\n * one. Zoom levels keep their meaning on screen (the Web Mercator tile pyramid), their metres follow the body:\n * altitudes, relief, buildings, 3D Tiles. Off the Earth, the map has none of the Earth's defaults: no basemap, no\n * credits, and space for its background; the Moon and Mars have NASA's relief for `terrain: true`.\n */\nexport type CelestialBody = 'earth' | 'moon' | 'mars' | BodyOptions;\n\nexport interface GeoMapOptions extends Partial<Camera> {\n /** The body the map is drawn on (default 'earth'); set at creation */\n body?: CelestialBody;\n /** Default 'globe' */\n projection?: Projection;\n /** Default 'immediate' */\n loading?: LoadingMode;\n /** The basemap (default 'osm-positron'; 'none' off the Earth) */\n basemap?: Basemap;\n /** Opacity of the IGN hillshade over the basemap (France, Géoplateforme), 0 for none (default 0) */\n hillshade?: number;\n /** Color behind the map (sky of tilted flat views), a CSS color (default `#f2f2f0`; black off the Earth) */\n background?: string;\n /** Space behind the globe: stars and atmosphere halo, fading out as the globe turns flat (default true) */\n sky?: boolean;\n /** Relief under the basemap: true for the body's terrain model (on the Earth the worldwide Terrain Tiles; NASA's on\n * the Moon and Mars: LOLA, MOLA), one of the Earth's models by name (`'ign'`: France, RGE ALTI), or its options\n * (default false; on another body, its `url` is required). Network layers are draped on it */\n terrain?: boolean | TerrainModel | TerrainOptions;\n minZoom?: number;\n maxZoom?: number;\n /** Highest pitch, degrees, up to 85 (default 70) */\n maxPitch?: number;\n /** Sky over the plane, seen when the camera is tilted towards the horizon, and the fog the ground fades into\n * (MapLibre's `setSky`); default none: the background color */\n atmosphere?: AtmosphereOptions;\n /** Mouse, touch and keyboard controls (default true) */\n interactive?: boolean;\n /** Keyboard controls once the map has the focus (it is reached with Tab): arrows pan, Shift + arrows rotate and\n * tilt, + and - zoom (Shift: two levels), 0 faces north and levels the view (default true; none when not\n * `interactive`) */\n keyboard?: boolean;\n /** Accessible name of the map, read by screen readers (default 'Map') */\n ariaLabel?: string;\n /** A preset of map options (`IGN_PRESETS`: `'ign'`, `'ign-3d'`, `'ign-ortho-3d'`), the other options over it */\n preset?: 'ign' | 'ign-3d' | 'ign-ortho-3d';\n /** The folder isard's files are served from (its engines, `isard_bg.wasm`, `isard_core_bg.wasm`,\n * `isard_points_bg.wasm`, and its workers, `decoder.worker.js`, `basemap.worker.js`): one option for a bundler that\n * moves them, the `…Url` options below for each one. `isard/vite` sets it for the whole page; default next to the\n * module */\n assetsUrl?: string | URL;\n /** Where to load the engine with 3D Tiles from (`isard_bg.wasm`), when a bundler does not resolve the default URL.\n * Given without `coreWasmUrl`, maps load this engine from the start */\n wasmUrl?: string | URL;\n /** Where to load the engine without 3D Tiles from (`isard_core_bg.wasm`, a third smaller), when a bundler does not\n * resolve the default URL. Maps load it first, and the engine with 3D Tiles (`wasmUrl`) for their first 3D Tiles\n * layer only */\n coreWasmUrl?: string | URL;\n /** Where the decoding workers load the point cloud module from (`isard_points_bg.wasm`, the LAZ decoder of COPC),\n * when a bundler does not resolve the default URL. Loaded with the first point cloud only */\n pointsWasmUrl?: string | URL;\n /** Load the engine with 3D Tiles from the start (default false: it is loaded when the first 3D Tiles layer or glTF\n * model is added, the map then moving its camera and layers onto it, a stall of about a frame or two). For a map that shows 3D Tiles\n * at once: one engine downloaded instead of two. `'preload'`: the map starts on the engine without 3D Tiles and\n * downloads and compiles the other once idle, without running it: its first 3D Tiles layer does not wait for the\n * download (for a map that will show 3D Tiles later, on demand) */\n tiles3d?: boolean | 'preload';\n /** Where to load the vector basemap worker from, when a bundler does not resolve the default URL */\n basemapWorkerUrl?: string | URL;\n /** Texture size of the vector basemap's tiles, pixels (default 512: lines and edges sharp at every zoom on a screen\n * of pixel ratio 1). 256: a quarter of the drawing in the workers, of the uploads and of the GPU memory, for lines\n * and edges a little softer between two zoom levels (the tiles are shown 181 to 362 CSS pixels wide) */\n basemapTileSize?: number;\n /** Glyphs of the symbol layers: a URL with `{fontstack}` and `{range}` (MapLibre's glyph format; default\n * OpenFreeMap's fonts, Noto Sans). A vector basemap's labels take the glyphs of its style */\n glyphs?: string;\n /** Workers decoding 3D Tiles off the main thread: a count, or false to decode on the main thread (default: cores - 1,\n * 1 to 4). False (or 0) also decodes the PNG relief and reprojects the equirectangular rasters on the main thread,\n * else done by the vector basemap's workers */\n workers?: number | false;\n /** Where to load the decoding worker from, when a bundler does not resolve the default URL */\n workerUrl?: string | URL;\n /** Folders of the Draco and Basis Universal decoders, loaded by the workers on first use (default: the official\n * builds on gstatic.com and jsDelivr; self-host them for offline or locked-down networks). They run through\n * `new Function`: a Content Security Policy needs `'unsafe-eval'` (see `DecoderUrls`) */\n decoders?: Partial<DecoderUrls>;\n /** Credits at the bottom right: false for none, or its options (default true: the credits of the basemap,\n * hillshade and relief in use, compact on maps narrower than 640 px) */\n attributionControl?: boolean | AttributionOptions;\n}\n\nexport interface TerrainOptions {\n /** One of the Earth's named models (default `'terrain-tiles'` on the Earth); unused with a `url` */\n model?: TerrainModel;\n /** Altitudes of 256 × 256 tiles in `encoding`: a WMS GetMap URL with {bbox} (EPSG:3857 on the Earth, the body's\n * Mercator metres elsewhere: the sphere of its radius), a tile URL with {z}, {x} and {y}, or an ArcGIS image service\n * (a URL ending in `/ImageServer`), asked for raw altitudes in the body's Mercator (default: the `model`'s; on the\n * Moon and Mars, NASA's Trek LOLA and MOLA models) */\n url?: string;\n /** How the tiles of `url` encode their altitudes (default `'float32'`); `'terrarium'` and `'mapbox'` take a URL with\n * {z}, {x} and {y} */\n encoding?: TerrainEncoding;\n /** Vertical exaggeration, 1 for the true relief (default 1) */\n exaggeration?: number;\n /** Finest level of the relief, up to 15 (default 15; 14 for the Terrain Tiles, 8 for the Moon's and Mars's models). It\n * starts at level 6 on the Earth, coarser on bodies of a larger relief for their size (3 on the Moon and Mars) */\n maxZoom?: number;\n /** Altitudes over mainland France raised by the height of the RAF20 geoid (the French one, 0 away from France), to\n * heights above the ellipsoid (those of 3D Tiles); false keeps the altitudes as served (NGF-IGN69 for the IGN's)\n * (default true for the `'ign'` model, false otherwise) */\n geoid?: boolean;\n}\n\n/** Sky, horizon and fog over the plane, with the names and meanings of MapLibre's `setSky` */\nexport interface AtmosphereOptions {\n /** A CSS color (default `#9cc7ec`) */\n skyColor?: string;\n /** (default `#e8f1f8`) */\n horizonColor?: string;\n /** (default `#f2f5f8`) */\n fogColor?: string;\n /** Blend from the horizon to the sky color, share of the field of view above the horizon, 0-1 (default 0.6) */\n skyHorizonBlend?: number;\n /** Blend from the horizon to the fog color below the horizon, 0-1 (default 0.7) */\n horizonFogBlend?: number;\n /** Share of the distance to the far plane over which the ground fades into the fog, 0-1 (default 0.4) */\n fogGroundBlend?: number;\n}\n\n/** What can be seen from a point (`GeoMap.setViewshed`); with several observers, the colors, the opacity and the\n * cone's color are the first one's */\nexport interface ViewshedOptions {\n /** The observer */\n position: LonLat;\n /** Metres above the ground (default 1.7, eye level) */\n height?: number;\n /** Metres around the observer that are tinted (default 1000) */\n range?: number;\n /** A CSS color for what is seen (default `#2f9e44`) */\n visibleColor?: string;\n /** A CSS color for what is hidden (default `#e03131`) */\n hiddenColor?: string;\n /** How strongly the colors tint the scene, multiplied into it so that its textures and shading stay, 0-1 (default\n * 0.7) */\n opacity?: number;\n /** A CSS color for the cone drawn in 3D (one way only): its fan through the axis, at the eye's height and tilted\n * with it, from the eye to the range; solid where nothing hides it, faint behind the scene; none by default */\n coneColor?: string;\n /** To look one way only (a camera, a lookout), degrees clockwise from north; all around without it */\n direction?: number;\n /** Degrees above the horizon the cone looks, negative below (default 0) */\n tilt?: number;\n /** Angle of view across, degrees (default 60) */\n fov?: number;\n /** Angle of view up and down, degrees (default 40) */\n verticalFov?: number;\n}\n\n/** An eye at street level (`GeoMap.setFirstPerson`) */\nexport interface FirstPersonView {\n /** Where it stands */\n lonLat: LonLat;\n /** Metres above the ground (default 1.7) */\n height?: number;\n /** Degrees clockwise from north it looks to */\n bearing: number;\n /** Degrees from straight down: 90 level (the default), 180 straight up */\n pitch?: number;\n /** Vertical field of view, degrees (default 75) */\n fov?: number;\n}\n\n/** Layers shown on one side of a vertical line only (`GeoMap.setSwipe`) */\nexport interface SwipeOptions {\n /** CSS pixels from the left of the map */\n position: number;\n layers: readonly Layer[];\n /** The side they show on (default 'left') */\n side?: 'left' | 'right';\n}\n\n/** Animation of a camera move */\nexport interface AnimationOptions {\n /** Milliseconds */\n duration?: number;\n /** Progress over time, both 0 to 1 */\n easing?: (t: number) => number;\n}\n\nexport interface FlyToOptions extends AnimationOptions {\n /** How far the flight zooms out on its way, as MapLibre's `curve` (default 1.42) */\n curve?: number;\n /** Average speed in screens per second when `duration` is not given (default 1.2) */\n speed?: number;\n}\n\n/**\n * Tile grid of a raster's URL. 'mercator': Web Mercator (XYZ, WMTS PM), the engine's own. 'equirectangular':\n * longitudes and latitudes (Plate Carrée, EPSG:4326-like), two 256 px tiles side by side at level 0, rows from the\n * north (NASA's Trek WMTS, WorldCRS84Quad). A `TileGrid`: the tile matrices of a WMTS in any CRS (Lambert-93…), or a\n * WMS asked for each tile's box in its CRS. The last two are reprojected into Web Mercator tiles by the map's workers\n * (in the page with `workers: false`).\n */\nexport type RasterGrid = 'mercator' | 'equirectangular' | TileGrid;\n\n/** What `RasterLayer.setStyle` changes */\nexport interface RasterStyle {\n opacity: number;\n /** 0 = greyscale, 1 = original colors */\n saturation: number;\n}\n\nexport interface RasterOptions {\n /** Tile URL with {z}, {x} and {y} (256 px tiles); unused with a `loader` */\n url: string;\n /** Tile grid of `url` (default 'mercator'); with 'equirectangular', `minZoom` and `maxZoom` are levels of that\n * grid; with a `TileGrid`, they are map zooms, by default those its matrices span */\n grid?: RasterGrid;\n minZoom?: number;\n maxZoom?: number;\n opacity?: number;\n /** 0 = greyscale, 1 = original colors */\n saturation?: number;\n /** Side of the tiles' textures, pixels (default 256): more for sharper tiles drawn by a `loader` */\n size?: number;\n /** Draws each tile instead of fetching `url`: an image of `size` × `size`, null for nothing there; a rejection is\n * retried like a network error */\n loader?: (z: number, x: number, y: number, signal: AbortSignal) => Promise<ImageBitmap | null>;\n /** Credits of the tiles, HTML: shown by the attribution control while the layer is on the map */\n attribution?: string;\n}\n\nexport interface NetworkStyle {\n /** Line width, CSS pixels, or zoom stops `[[zoom, width], …]` (default 2) */\n width: Size;\n /** Values above are drawn as unreached (default 1800) */\n max: number;\n /** Darker line every `contour` value units, 0 for none (default 0) */\n contour: number;\n opacity: number;\n /** Width of the halo drawn under the lines, CSS pixels or zoom stops, 0 for none (default 0): wide and faint, the\n * reached streets add up into a heat map that fills the blocks */\n halo: Size;\n /** Opacity of the halo at the middle of a line, fading quadratically to its sides (default 0.11) */\n haloOpacity: number;\n /** Colors from 0 to `max`: `[[fraction of max, color], …]` (default green to red) */\n ramp: Ramp | undefined;\n /** Color of the parts beyond `max` or unreached (default `rgba(140, 140, 140, 0.25)`) */\n unreachedColor: string;\n /** Share of `max` over which the colors fade out before it, 0 to 1 (default 0) */\n fade: number;\n}\n\nexport interface NetworkOptions extends Partial<NetworkStyle> {\n /** Node coordinates in degrees: lon0, lat0, lon1, lat1… */\n nodes: Float64Array;\n /** Edges as node index pairs: a0, b0, a1, b1… */\n edges: Uint32Array;\n /** Line of each edge, from A to B: the points of edge e are `points[start[e] .. start[e + 1]]` (lon, lat pairs,\n * counted in points); with fewer than two points an edge is straight. Default: all straight. */\n lines?: { start: Uint32Array; points: Float64Array };\n /** Per edge, the cost of travelling it from A to B then from B to A, in value units (Infinity: closed that way;\n * closed both ways: not drawn). A point along an edge then takes the quickest way there, min(value(A) + cost from\n * A, value(B) + cost from B), as a travel time does. Without costs, values are interpolated along the edges. */\n costs?: Float32Array;\n /** Width factor of each edge (default 1): rail lines wider than streets */\n edgeWidths?: Float32Array;\n}\n\nexport interface Tiles3dStyle {\n /** Screen-space error (CSS pixels) above which a tile is refined: 16 by default, lower is finer and heavier */\n maxScreenSpaceError: number;\n opacity: number;\n /** Size of the points of point cloud tiles (`.pnts`, glTF points), CSS pixels: 2 by default */\n pointSize?: number;\n /** A CSS color multiplying the textures of the meshes, the color of the untextured ones (buildings without\n * textures are light grey without it); none by default */\n color?: string;\n}\n\nexport interface Tiles3dOptions extends Partial<Tiles3dStyle> {\n /** URL of a `tileset.json` (3D Tiles 1.0 b3dm and pnts, 1.1 glb meshes and points, external tilesets) */\n url: string;\n /** Its heights are altitudes above the geoid (NGF-IGN69), as the IGN's Bâtiments 3D, rather than above the\n * ellipsoid (3D Tiles as specified): each tile raised by the RAF20 geoid, onto the IGN relief (default false) */\n geoid?: boolean;\n}\n\nexport interface MapPointerEvent {\n point: Point;\n /** Undefined above the horizon */\n lonLat: LonLat | undefined;\n}\n\n/** What 'hoverfeature' found under the pointer */\nexport interface MapHoverFeatureEvent extends MapPointerEvent {\n /** The feature under the pointer (see `GeoMap.pickFeature`), undefined if none */\n hit: FeatureHit | undefined;\n}\n\n/** A picked feature: its layer handle, its index there and, for line, circle, fill, extrusion, point cloud and 3D\n * Tiles layers, the feature itself (a building of 3D Tiles with its properties) */\nexport interface FeatureHit {\n layer: Layer;\n index: number;\n feature: Feature | undefined;\n}\n\nexport interface MapEvents {\n /** The camera started moving (a gesture, an animation or `setCamera`) */\n movestart: Camera;\n /** The camera moved */\n move: Camera;\n /** The camera stopped: no gesture held, no animation running */\n moveend: Camera;\n /** The map changed size (CSS pixels) */\n resize: { width: number; height: number };\n /** The pointer moved over the map (at most once per frame, not while dragging) */\n hover: MapPointerEvent;\n /** What is under the pointer, picked without stalling the GPU: a frame or two after 'hover', only while listened to\n * (radius and layers in `GeoMap.hoverPicking`) */\n hoverfeature: MapHoverFeatureEvent;\n /** Click without drag */\n click: MapPointerEvent;\n /** A frame was drawn; duration of the engine call in milliseconds */\n render: { ms: number };\n /** Everything in view is loaded and drawn, nothing moves: the end of a load, once after each change (as MapLibre's\n * `idle`). Tiles requested by the first frame count, so it never fires before they arrive. */\n idle: Record<string, never>;\n /** The pointer left the canvas (a mouse going out of the map, or onto a control or marker) */\n leave: Record<string, never>;\n}\n\n/** What a layer handle needs from its map */\nexport interface LayerHost {\n readonly engine: Engine;\n requestRender(): void;\n /** Forgets a removed layer */\n detach(layer: object): void;\n /** Moves a layer under `before`, or on top */\n moveLayer(layer: object, before: object | undefined): void;\n /** A layer created again in the engine (new id): put at the place of its old id, which is removed */\n replaceLayer(layer: object, old: number): void;\n /** Resolves once the map is idle (everything in view loaded and drawn) */\n whenIdle(): Promise<void>;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,0CAA0C","sourcesContent":["/** Public types of the `isard` package */\n\nimport type { TileGrid } from './basemap/grid.ts';\nimport type { DecoderUrls } from './engine/decoders.ts';\nimport type { Feature, Ramp, Size } from './layers/features.ts';\nimport type { Layer } from './layers/layers.ts';\nimport type { AttributionOptions } from './ui/controls.ts';\nimport type { Camera, Engine } from './wasm/isard.js';\n\nexport type LonLat = [lon: number, lat: number];\nexport type Point = [x: number, y: number];\n\n/**\n * The named basemaps. OpenFreeMap's vector styles, OpenStreetMap data worldwide, their labels above the other layers:\n * `osm-positron` (light grey, quiet: data over it reads first), `osm-liberty` and `osm-bright` (in colour). The\n * Géoplateforme's (IGN, France): rasters (`ign-plan`, `ign-plan-grey`, `ign-ortho`, the aerial photographs) or vector\n * tiles with their labels (`ign-plan-vector`, `ign-plan-grey-vector`, the PLAN.IGN styles).\n */\nexport type BasemapName =\n | 'osm-positron'\n | 'osm-liberty'\n | 'osm-bright'\n | 'ign-plan'\n | 'ign-plan-grey'\n | 'ign-ortho'\n | 'ign-plan-vector'\n | 'ign-plan-grey-vector'\n | 'none';\n\n/** A basemap by name (see `BasemapName`) */\nexport type Basemap = BasemapName;\n\n/**\n * The Earth's named terrain models. `'terrain-tiles'`: worldwide, the Terrain Tiles of AWS's open data registry\n * (SRTM, EU-DEM, GMTED… merged by Mapzen, 30 m in most places), the sea floor flattened at sea level. `'ign'`: France,\n * the IGN's RGE ALTI from the Géoplateforme (1 to 5 m), raised by the RAF20 geoid to heights above the ellipsoid.\n */\nexport type TerrainModel = 'terrain-tiles' | 'ign';\n\n/** How tiles encode their altitudes: `'float32'`, raw little-endian floats (`image/x-bil;bits=32`, an ArcGIS raw\n * grid); `'terrarium'`, the colors of a PNG, `R × 256 + G + B / 256 - 32768`; `'mapbox'`, those of Terrain-RGB,\n * `(R × 65536 + G × 256 + B) / 10 - 10000` */\nexport type TerrainEncoding = 'float32' | 'terrarium' | 'mapbox';\n\n/**\n * How tiles load and show. 'immediate' (default): everything visible loads, tiles show as soon as they arrive.\n * 'smooth': during flights the levels flown through are skipped, off-center tiles wait while the camera moves, tiles\n * fade in; fewer downloads, for slow networks or GPUs.\n */\nexport type LoadingMode = 'immediate' | 'smooth';\n\n/** 'globe': a sphere at low zoom, blending into Web Mercator between zooms 5 and 7, up to three levels later under a\n * tilted camera (it sees much farther than its center: the horizon stays curved) */\nexport type Projection = 'globe' | 'mercator';\n\n/** A body to draw the map on, other than the named ones (`CelestialBody`) */\nexport interface BodyOptions {\n /** Equatorial radius, metres */\n radius: number;\n /** Flattening of its ellipsoid, 0 for a sphere (default 0) */\n flattening?: number;\n /** An atmosphere: its halo around the globe, true for the Earth's light blue, or a CSS color (its alpha the\n * halo's strength) (default false) */\n atmosphere?: boolean | string;\n /** Color of the globe where no tile covers it (past the Web Mercator latitudes, 85°), a CSS color (default\n * `#808080`) */\n color?: string;\n /** Lowest and highest altitudes of its ground, metres around the ellipsoid: what its relief may raise into view\n * (default ±1 % of the radius) */\n relief?: [lowest: number, highest: number];\n}\n\n/**\n * The body the map is drawn on: 'earth' (WGS 84, the default), 'moon' (a sphere of 1 737 400 m, no atmosphere),\n * 'mars' (a sphere of 3 396 190 m, its equatorial radius, a thin dusty halo; planetocentric latitudes) or another\n * one. Zoom levels keep their meaning on screen (the Web Mercator tile pyramid), their metres follow the body:\n * altitudes, relief, buildings, 3D Tiles. Off the Earth, the map has none of the Earth's defaults: no basemap, no\n * credits, and space for its background; the Moon and Mars have NASA's relief for `terrain: true`.\n */\nexport type CelestialBody = 'earth' | 'moon' | 'mars' | BodyOptions;\n\nexport interface GeoMapOptions extends Partial<Camera> {\n /** The body the map is drawn on (default 'earth'); set at creation */\n body?: CelestialBody;\n /** Default 'globe' */\n projection?: Projection;\n /** Default 'immediate' */\n loading?: LoadingMode;\n /** The basemap (default 'osm-positron'; 'none' off the Earth) */\n basemap?: Basemap;\n /** Opacity of the IGN hillshade over the basemap (France, Géoplateforme), 0 for none (default 0) */\n hillshade?: number;\n /** Color behind the map (sky of tilted flat views), a CSS color (default `#f2f2f0`; black off the Earth) */\n background?: string;\n /** Space behind the globe: stars and atmosphere halo, fading out as the globe turns flat (default true) */\n sky?: boolean;\n /** Relief under the basemap: true for the body's terrain model (on the Earth the worldwide Terrain Tiles; NASA's on\n * the Moon and Mars: LOLA, MOLA), one of the Earth's models by name (`'ign'`: France, RGE ALTI), or its options\n * (default false; on another body, its `url` is required). Network layers are draped on it */\n terrain?: boolean | TerrainModel | TerrainOptions;\n minZoom?: number;\n maxZoom?: number;\n /** Highest pitch, degrees, up to 85 (default 70) */\n maxPitch?: number;\n /** Sky over the plane, seen when the camera is tilted towards the horizon, and the fog the ground fades into\n * (MapLibre's `setSky`); default none: the background color */\n atmosphere?: AtmosphereOptions;\n /** Mouse, touch and keyboard controls (default true) */\n interactive?: boolean;\n /** Keyboard controls once the map has the focus (it is reached with Tab): arrows pan, Shift + arrows rotate and\n * tilt, + and - zoom (Shift: two levels), 0 faces north and levels the view (default true; none when not\n * `interactive`) */\n keyboard?: boolean;\n /** Accessible name of the map, read by screen readers (default 'Map') */\n ariaLabel?: string;\n /** A preset of map options (`IGN_PRESETS`: `'ign'`, `'ign-3d'`, `'ign-ortho-3d'`), the other options over it */\n preset?: 'ign' | 'ign-3d' | 'ign-ortho-3d';\n /** The folder isard's files are served from (its engines, `isard_bg.wasm`, `isard_core_bg.wasm`,\n * `isard_points_bg.wasm`, and its workers, `decoder.worker.js`, `basemap.worker.js`): one option for a bundler that\n * moves them, the `…Url` options below for each one. `isard/vite` sets it for the whole page; default next to the\n * module */\n assetsUrl?: string | URL;\n /** Where to load the engine with 3D Tiles from (`isard_bg.wasm`), when a bundler does not resolve the default URL.\n * Given without `coreWasmUrl`, maps load this engine from the start */\n wasmUrl?: string | URL;\n /** Where to load the engine without 3D Tiles from (`isard_core_bg.wasm`, a third smaller), when a bundler does not\n * resolve the default URL. Maps load it first, and the engine with 3D Tiles (`wasmUrl`) for their first 3D Tiles\n * layer only */\n coreWasmUrl?: string | URL;\n /** Where the decoding workers load the point cloud module from (`isard_points_bg.wasm`, the LAZ decoder of COPC),\n * when a bundler does not resolve the default URL. Loaded with the first point cloud only */\n pointsWasmUrl?: string | URL;\n /** Load the engine with 3D Tiles from the start (default false: it is loaded when the first 3D Tiles layer or glTF\n * model is added, the map then moving its camera and layers onto it, a stall of about a frame or two). For a map that shows 3D Tiles\n * at once: one engine downloaded instead of two. `'preload'`: the map starts on the engine without 3D Tiles and\n * downloads and compiles the other once idle, without running it: its first 3D Tiles layer does not wait for the\n * download (for a map that will show 3D Tiles later, on demand) */\n tiles3d?: boolean | 'preload';\n /** Where to load the vector basemap worker from, when a bundler does not resolve the default URL */\n basemapWorkerUrl?: string | URL;\n /** Texture size of the vector basemap's tiles, pixels (default 512: lines and edges sharp at every zoom on a screen\n * of pixel ratio 1). 256: a quarter of the drawing in the workers, of the uploads and of the GPU memory, for lines\n * and edges a little softer between two zoom levels (the tiles are shown 181 to 362 CSS pixels wide) */\n basemapTileSize?: number;\n /** Glyphs of the symbol layers: a URL with `{fontstack}` and `{range}` (MapLibre's glyph format; default\n * OpenFreeMap's fonts, Noto Sans). A vector basemap's labels take the glyphs of its style */\n glyphs?: string;\n /** Workers decoding 3D Tiles off the main thread: a count, or false to decode on the main thread (default: cores - 1,\n * 1 to 4). False (or 0) also decodes the PNG relief and reprojects the equirectangular rasters on the main thread,\n * else done by the vector basemap's workers */\n workers?: number | false;\n /** Where to load the decoding worker from, when a bundler does not resolve the default URL */\n workerUrl?: string | URL;\n /** Folders of the Draco and Basis Universal decoders, loaded by the workers on first use (default: the official\n * builds on gstatic.com and jsDelivr; self-host them for offline or locked-down networks). They run through\n * `new Function`: a Content Security Policy needs `'unsafe-eval'` (see `DecoderUrls`) */\n decoders?: Partial<DecoderUrls>;\n /** Credits at the bottom right: false for none, or its options (default true: the credits of the basemap,\n * hillshade and relief in use, compact on maps narrower than 640 px) */\n attributionControl?: boolean | AttributionOptions;\n}\n\nexport interface TerrainOptions {\n /** One of the Earth's named models (default `'terrain-tiles'` on the Earth); unused with a `url` */\n model?: TerrainModel;\n /** Altitudes of 256 × 256 tiles in `encoding`: a WMS GetMap URL with {bbox} (EPSG:3857 on the Earth, the body's\n * Mercator metres elsewhere: the sphere of its radius), a tile URL with {z}, {x} and {y}, or an ArcGIS image service\n * (a URL ending in `/ImageServer`), asked for raw altitudes in the body's Mercator (default: the `model`'s; on the\n * Moon and Mars, NASA's Trek LOLA and MOLA models) */\n url?: string;\n /** How the tiles of `url` encode their altitudes (default `'float32'`); `'terrarium'` and `'mapbox'` take a URL with\n * {z}, {x} and {y} */\n encoding?: TerrainEncoding;\n /** Vertical exaggeration, 1 for the true relief (default 1) */\n exaggeration?: number;\n /** Finest level of the relief, up to 15 (default 15; 14 for the Terrain Tiles, 8 for the Moon's and Mars's models). It\n * starts at level 6 on the Earth, coarser on bodies of a larger relief for their size (3 on the Moon and Mars) */\n maxZoom?: number;\n /** Altitudes over mainland France raised by the height of the RAF20 geoid (the French one, 0 away from France), to\n * heights above the ellipsoid (those of 3D Tiles); false keeps the altitudes as served (NGF-IGN69 for the IGN's)\n * (default true for the `'ign'` model, false otherwise) */\n geoid?: boolean;\n}\n\n/** Sky, horizon and fog over the plane, with the names and meanings of MapLibre's `setSky` */\nexport interface AtmosphereOptions {\n /** A CSS color (default `#9cc7ec`) */\n skyColor?: string;\n /** (default `#e8f1f8`) */\n horizonColor?: string;\n /** (default `#f2f5f8`) */\n fogColor?: string;\n /** Blend from the horizon to the sky color, share of the field of view above the horizon, 0-1 (default 0.6) */\n skyHorizonBlend?: number;\n /** Blend from the horizon to the fog color below the horizon, 0-1 (default 0.7) */\n horizonFogBlend?: number;\n /** Share of the distance to the far plane over which the ground fades into the fog, 0-1 (default 0.4) */\n fogGroundBlend?: number;\n}\n\n/** What can be seen from a point (`GeoMap.setViewshed`); with several observers, the colors, the opacity and the\n * cone's color are the first one's */\nexport interface ViewshedOptions {\n /** The observer */\n position: LonLat;\n /** Metres above the ground (default 1.7, eye level) */\n height?: number;\n /** Metres around the observer that are tinted (default 1000) */\n range?: number;\n /** A CSS color for what is seen (default `#2f9e44`) */\n visibleColor?: string;\n /** A CSS color for what is hidden (default `#e03131`) */\n hiddenColor?: string;\n /** How strongly the colors tint the scene, multiplied into it so that its textures and shading stay, 0-1 (default\n * 0.7) */\n opacity?: number;\n /** A CSS color for the cone drawn in 3D (one way only): its fan through the axis, at the eye's height and tilted\n * with it, from the eye to the range; solid where nothing hides it, faint behind the scene; none by default */\n coneColor?: string;\n /** To look one way only (a camera, a lookout), degrees clockwise from north; all around without it */\n direction?: number;\n /** Degrees above the horizon the cone looks, negative below (default 0) */\n tilt?: number;\n /** Angle of view across, degrees (default 60) */\n fov?: number;\n /** Angle of view up and down, degrees (default 40) */\n verticalFov?: number;\n}\n\n/** An eye at street level (`GeoMap.setFirstPerson`) */\nexport interface FirstPersonView {\n /** Where it stands */\n lonLat: LonLat;\n /** Metres above the ground (default 1.7) */\n height?: number;\n /** Degrees clockwise from north it looks to */\n bearing: number;\n /** Degrees from straight down: 90 level (the default), 180 straight up */\n pitch?: number;\n /** Vertical field of view, degrees (default 75) */\n fov?: number;\n}\n\n/** Layers shown on one side of a vertical line only (`GeoMap.setSwipe`) */\nexport interface SwipeOptions {\n /** CSS pixels from the left of the map */\n position: number;\n layers: readonly Layer[];\n /** The side they show on (default 'left') */\n side?: 'left' | 'right';\n}\n\n/** Animation of a camera move */\nexport interface AnimationOptions {\n /** Milliseconds */\n duration?: number;\n /** Progress over time, both 0 to 1 */\n easing?: (t: number) => number;\n}\n\nexport interface FlyToOptions extends AnimationOptions {\n /** How far the flight zooms out on its way, as MapLibre's `curve` (default 1.42) */\n curve?: number;\n /** Average speed in screens per second when `duration` is not given (default 1.2) */\n speed?: number;\n}\n\n/**\n * Tile grid of a raster's URL. 'mercator': Web Mercator (XYZ, WMTS PM), the engine's own. 'equirectangular':\n * longitudes and latitudes (Plate Carrée, EPSG:4326-like), two 256 px tiles side by side at level 0, rows from the\n * north (NASA's Trek WMTS, WorldCRS84Quad). A `TileGrid`: the tile matrices of a WMTS in any CRS (Lambert-93…), or a\n * WMS asked for each tile's box in its CRS. The last two are reprojected into Web Mercator tiles by the map's workers\n * (in the page with `workers: false`).\n */\nexport type RasterGrid = 'mercator' | 'equirectangular' | TileGrid;\n\n/** What `RasterLayer.setStyle` changes */\nexport interface RasterStyle {\n opacity: number;\n /** 0 = greyscale, 1 = original colors */\n saturation: number;\n}\n\nexport interface RasterOptions {\n /** Tile URL with {z}, {x} and {y} (256 px tiles); unused with a `loader` */\n url: string;\n /** Tile grid of `url` (default 'mercator'); with 'equirectangular', `minZoom` and `maxZoom` are levels of that\n * grid; with a `TileGrid`, they are map zooms, by default those its matrices span */\n grid?: RasterGrid;\n minZoom?: number;\n maxZoom?: number;\n opacity?: number;\n /** 0 = greyscale, 1 = original colors */\n saturation?: number;\n /** Side of the tiles' textures, pixels (default 256): more for sharper tiles drawn by a `loader` */\n size?: number;\n /** Draws each tile instead of fetching `url`: an image of `size` × `size`, null for nothing there; a rejection is\n * retried like a network error */\n loader?: (z: number, x: number, y: number, signal: AbortSignal) => Promise<ImageBitmap | null>;\n /** Credits of the tiles, HTML: shown by the attribution control while the layer is on the map */\n attribution?: string;\n}\n\nexport interface NetworkStyle {\n /** Line width, CSS pixels, or zoom stops `[[zoom, width], …]` (default 2) */\n width: Size;\n /** Values above are drawn as unreached (default 1800) */\n max: number;\n /** Darker line every `contour` value units, 0 for none (default 0) */\n contour: number;\n opacity: number;\n /** Width of the halo drawn under the lines, CSS pixels or zoom stops, 0 for none (default 0): wide and faint, the\n * reached streets add up into a heat map that fills the blocks */\n halo: Size;\n /** Opacity of the halo at the middle of a line, fading quadratically to its sides (default 0.11) */\n haloOpacity: number;\n /** Colors from 0 to `max`: `[[fraction of max, color], …]` (default green to red) */\n ramp: Ramp | undefined;\n /** Color of the parts beyond `max` or unreached (default `rgba(140, 140, 140, 0.25)`) */\n unreachedColor: string;\n /** Share of `max` over which the colors fade out before it, 0 to 1 (default 0) */\n fade: number;\n}\n\nexport interface NetworkOptions extends Partial<NetworkStyle> {\n /** Node coordinates in degrees: lon0, lat0, lon1, lat1… */\n nodes: Float64Array;\n /** Edges as node index pairs: a0, b0, a1, b1… */\n edges: Uint32Array;\n /** Line of each edge, from A to B: the points of edge e are `points[start[e] .. start[e + 1]]` (lon, lat pairs,\n * counted in points); with fewer than two points an edge is straight. Default: all straight. */\n lines?: { start: Uint32Array; points: Float64Array };\n /** Per edge, the cost of travelling it from A to B then from B to A, in value units (Infinity: closed that way;\n * closed both ways: not drawn). A point along an edge then takes the quickest way there, min(value(A) + cost from\n * A, value(B) + cost from B), as a travel time does. Without costs, values are interpolated along the edges. */\n costs?: Float32Array;\n /** Width factor of each edge (default 1): rail lines wider than streets */\n edgeWidths?: Float32Array;\n}\n\nexport interface Tiles3dStyle {\n /** Screen-space error (CSS pixels) above which a tile is refined: 16 by default, lower is finer and heavier */\n maxScreenSpaceError: number;\n opacity: number;\n /** Size of the points of point cloud tiles (`.pnts`, glTF points), CSS pixels: 2 by default */\n pointSize?: number;\n /** A CSS color multiplying the textures of the meshes, the color of the untextured ones (buildings without\n * textures are light grey without it); none by default */\n color?: string;\n}\n\nexport interface Tiles3dOptions extends Partial<Tiles3dStyle> {\n /** URL of a `tileset.json` (3D Tiles 1.0 b3dm and pnts, 1.1 glb meshes and points, external tilesets) */\n url: string;\n /** Its heights are altitudes above the geoid (NGF-IGN69), as the IGN's Bâtiments 3D, rather than above the\n * ellipsoid (3D Tiles as specified): each tile raised by the RAF20 geoid, onto the IGN relief (default false) */\n geoid?: boolean;\n}\n\nexport interface MapPointerEvent {\n point: Point;\n /** Undefined above the horizon */\n lonLat: LonLat | undefined;\n}\n\n/** What 'hoverfeature' found under the pointer */\nexport interface MapHoverFeatureEvent extends MapPointerEvent {\n /** The feature under the pointer (see `GeoMap.pickFeature`), undefined if none */\n hit: FeatureHit | undefined;\n}\n\n/** A picked feature: its layer handle, its index there and, for line, circle, fill, extrusion, point cloud and 3D\n * Tiles layers, the feature itself (a building of 3D Tiles with its properties) */\nexport interface FeatureHit {\n layer: Layer;\n index: number;\n feature: Feature | undefined;\n}\n\nexport interface MapEvents {\n /** The camera started moving (a gesture, an animation or `setCamera`) */\n movestart: Camera;\n /** The camera moved */\n move: Camera;\n /** The camera stopped: no gesture held, no animation running */\n moveend: Camera;\n /** The map changed size (CSS pixels) */\n resize: { width: number; height: number };\n /** The pointer moved over the map (at most once per frame, not while dragging) */\n hover: MapPointerEvent;\n /** What is under the pointer, picked without stalling the GPU: a frame or two after 'hover', only while listened to\n * (radius and layers in `GeoMap.hoverPicking`) */\n hoverfeature: MapHoverFeatureEvent;\n /** Click without drag */\n click: MapPointerEvent;\n /** A frame was drawn; duration of the engine call in milliseconds */\n render: { ms: number };\n /** Everything in view is loaded and drawn, nothing moves: the end of a load, once after each change (as MapLibre's\n * `idle`). Tiles requested by the first frame count, so it never fires before they arrive. */\n idle: Record<string, never>;\n /** The pointer left the canvas (a mouse going out of the map, or onto a control or marker) */\n leave: Record<string, never>;\n}\n\n/** What a layer handle needs from its map */\nexport interface LayerHost {\n readonly engine: Engine;\n requestRender(): void;\n /** Forgets a removed layer */\n detach(layer: object): void;\n /** Moves a layer under `before`, or on top */\n moveLayer(layer: object, before: object | undefined): void;\n /** A layer created again in the engine (new id): put at the place of its old id, which is removed */\n replaceLayer(layer: object, old: number): void;\n /** Resolves once the map is idle (everything in view loaded and drawn) */\n whenIdle(): Promise<void>;\n}\n"]}
@@ -2,7 +2,7 @@
2
2
  * Controls: elements in a corner of the map. A control is anything with `onAdd` and `onRemove`, as in MapLibre, so
3
3
  * applications write their own; the navigation buttons and the attribution are built in.
4
4
  */
5
- import type { GeoMap } from './map.ts';
5
+ import type { GeoMap } from '../map.ts';
6
6
  export type ControlPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
7
7
  export interface Control {
8
8
  /** Builds the control's element; the map puts it in its corner */
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controls.js","sourceRoot":"","sources":["../../src/ui/controls.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Controls: elements in a corner of the map. A control is anything with `onAdd` and `onRemove`, as in MapLibre, so\n * applications write their own; the navigation buttons and the attribution are built in.\n */\nimport type { GeoMap } from '../map.ts';\n\nexport type ControlPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\n\nexport interface Control {\n /** Builds the control's element; the map puts it in its corner */\n onAdd(map: GeoMap): HTMLElement;\n /** Cleans up (listeners); the map removes the element */\n onRemove(map: GeoMap): void;\n}\n\nconst svg = (body: string) =>\n `<svg width=\"29\" height=\"29\" viewBox=\"0 0 29 29\" fill=\"currentColor\" aria-hidden=\"true\">${body}</svg>`;\nconst PLUS = svg(\n '<path d=\"M14.5 8.5a1 1 0 0 1 1 1v4h4a1 1 0 0 1 0 2h-4v4a1 1 0 0 1-2 0v-4h-4a1 1 0 0 1 0-2h4v-4a1 1 0 0 1 1-1z\"/>',\n);\nconst MINUS = svg('<path d=\"M9.5 13.5h10a1 1 0 0 1 0 2h-10a1 1 0 0 1 0-2z\"/>');\n/** Needle: red half to the north, grey half to the south */\nconst COMPASS = svg(\n '<path d=\"M10.5 14 14.5 6.5 18.5 14z\" fill=\"#e3342f\"/><path d=\"M10.5 15 14.5 22.5 18.5 15z\" fill=\"currentColor\" opacity=\"0.5\"/>',\n);\nconst INFO =\n '<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\"><path fill-rule=\"evenodd\" ' +\n 'd=\"M10 3a7 7 0 1 0 0 14 7 7 0 0 0 0-14zm-1 5.5h2V14H9zM10 5.5a1.1 1.1 0 1 1 0 2.2 1.1 1.1 0 0 1 0-2.2z\"/></svg>';\n\nfunction button(className: string, label: string, icon: string, onClick: () => void): HTMLButtonElement {\n const element = document.createElement('button');\n element.type = 'button';\n element.className = className;\n element.title = label;\n element.setAttribute('aria-label', label);\n element.innerHTML = icon;\n element.addEventListener('click', onClick);\n return element;\n}\n\nexport interface NavigationOptions {\n /** Zoom in and out buttons (default true) */\n showZoom?: boolean;\n /** Compass turning with the bearing; a click faces north and levels the view (default true) */\n showCompass?: boolean;\n /** The compass also tilts with the pitch (default false) */\n visualizePitch?: boolean;\n}\n\n/** Zoom buttons and compass */\nexport class NavigationControl implements Control {\n private readonly options: Required<NavigationOptions>;\n private stopListening: (() => void) | undefined;\n\n constructor(options: NavigationOptions = {}) {\n this.options = { showZoom: true, showCompass: true, visualizePitch: false, ...options };\n }\n\n onAdd(map: GeoMap): HTMLElement {\n const group = document.createElement('div');\n group.className = 'isard-ctrl-group';\n const zoomBy = (delta: number) => map.easeTo({ zoom: map.getCamera().zoom + delta }, 300);\n if (this.options.showZoom) {\n group.append(\n button('isard-ctrl-zoom-in', 'Zoom in', PLUS, () => zoomBy(1)),\n button('isard-ctrl-zoom-out', 'Zoom out', MINUS, () => zoomBy(-1)),\n );\n }\n if (this.options.showCompass) {\n const compass = button('isard-ctrl-compass', 'Reset bearing to north', COMPASS, () =>\n map.easeTo({ bearing: 0, pitch: 0 }, 300),\n );\n const needle = compass.firstElementChild as SVGElement;\n const turn = () => {\n const { bearing, pitch } = map.getCamera();\n // Seen from above when tilted: the needle lies back with the ground, squashed by cos(pitch)\n needle.style.transform = this.options.visualizePitch\n ? `scale(${1 / Math.cos((pitch * Math.PI) / 180) ** 0.5}) rotateX(${pitch}deg) rotateZ(${-bearing}deg)`\n : `rotate(${-bearing}deg)`;\n };\n turn();\n this.stopListening = map.on('move', turn);\n group.append(compass);\n }\n return group;\n }\n\n onRemove(): void {\n this.stopListening?.();\n this.stopListening = undefined;\n }\n}\n\nexport interface AttributionOptions {\n /** Folded into a small (i) button that shows the text on click (default: when the map is narrower than 640 px) */\n compact?: boolean;\n /** Attributions shown after those of the map's sources, HTML allowed (links open in a new tab) */\n customAttribution?: string | string[];\n}\n\n/** Credits of the data shown: those of the map's basemap, hillshade and relief (OpenFreeMap and OpenStreetMap, IGN,\n * the Terrain Tiles…, followed as they change), then the page's own */\nexport class AttributionControl implements Control {\n private observer: ResizeObserver | undefined;\n private stopListening: (() => void) | undefined;\n\n constructor(private readonly options: AttributionOptions = {}) {}\n\n onAdd(map: GeoMap): HTMLElement {\n const element = document.createElement('div');\n element.className = 'isard-attrib';\n const inner = document.createElement('div');\n inner.className = 'isard-attrib-inner';\n const custom = this.options.customAttribution ?? [];\n const render = () => {\n inner.innerHTML = [...map.attributions(), ...(typeof custom === 'string' ? [custom] : custom)].join(' | ');\n for (const link of inner.querySelectorAll('a')) {\n link.target = '_blank';\n link.rel = 'noopener noreferrer';\n }\n };\n render();\n this.stopListening = map.onAttributionChange(render);\n const toggle = button('isard-attrib-button', 'Toggle attribution', INFO, () =>\n toggle.setAttribute('aria-expanded', String(element.classList.toggle('isard-attrib-open'))),\n );\n toggle.setAttribute('aria-expanded', 'false');\n element.append(inner, toggle);\n const { compact } = this.options;\n if (compact !== undefined) {\n element.classList.toggle('isard-attrib-compact', compact);\n } else {\n // Follows the map's width; a narrowed map folds the text, starting closed\n const fold = () => {\n const narrow = map.getContainer().clientWidth < 640;\n if (narrow !== element.classList.contains('isard-attrib-compact')) {\n element.classList.remove('isard-attrib-open');\n toggle.setAttribute('aria-expanded', 'false');\n }\n element.classList.toggle('isard-attrib-compact', narrow);\n };\n fold();\n this.observer = new ResizeObserver(fold);\n this.observer.observe(map.getContainer());\n }\n return element;\n }\n\n onRemove(): void {\n this.observer?.disconnect();\n this.observer = undefined;\n this.stopListening?.();\n this.stopListening = undefined;\n }\n}\n"]}
@@ -1,6 +1,10 @@
1
- import type { GeoMap } from './map.ts';
2
- import type { Point } from './types.ts';
3
- import type { Camera } from './wasm/isard.js';
1
+ /**
2
+ * Mouse, touch and keyboard controls. Every gesture only updates the camera and asks for a frame: the engine draws at most
3
+ * once per display refresh, whatever the event rate of the device.
4
+ */
5
+ import type { GeoMap } from '../map.ts';
6
+ import type { Point } from '../types.ts';
7
+ import type { Camera } from '../wasm/isard.js';
4
8
  /** What a key does to the camera: a pan in CSS pixels, a zoom, rotation or tilt step, or facing north */
5
9
  export type KeyAction = {
6
10
  pan: Point;
@@ -2,7 +2,7 @@
2
2
  * Mouse, touch and keyboard controls. Every gesture only updates the camera and asks for a frame: the engine draws at most
3
3
  * once per display refresh, whatever the event rate of the device.
4
4
  */
5
- import { latitude, mercatorX, mercatorY } from "./geo.js";
5
+ import { latitude, mercatorX, mercatorY } from "../util/geo.js";
6
6
  /** Zoom levels per wheel pixel (a mouse notch is about 100 px: 1/3 of a level) */
7
7
  const WHEEL_RATE = 1 / 300;
8
8
  /** Share of the remaining wheel zoom applied per frame (smooth, about 150 ms to settle) */
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interaction.js","sourceRoot":"","sources":["../../src/ui/interaction.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Mouse, touch and keyboard controls. Every gesture only updates the camera and asks for a frame: the engine draws at most\n * once per display refresh, whatever the event rate of the device.\n */\n\nimport type { GeoMap } from '../map.ts';\nimport type { Point } from '../types.ts';\nimport { latitude, mercatorX, mercatorY } from '../util/geo.ts';\nimport type { Camera } from '../wasm/isard.js';\n\n/** Zoom levels per wheel pixel (a mouse notch is about 100 px: 1/3 of a level) */\nconst WHEEL_RATE = 1 / 300;\n/** Share of the remaining wheel zoom applied per frame (smooth, about 150 ms to settle) */\nconst WHEEL_EASE = 0.3;\n/** Degrees per pixel when rotating or tilting with the mouse */\nconst ROTATE_RATE = 0.4;\n/** A press that moves less than this (CSS pixels) is a click */\nconst CLICK_TOLERANCE = 4;\n/** Pan speed kept on release, decaying with this time constant (ms) */\nconst INERTIA_DECAY = 280;\n\n/** CSS pixels per arrow key press */\nconst KEY_PAN = 100;\n/** Degrees per Shift + left or right arrow */\nconst KEY_BEARING = 15;\n/** Degrees per Shift + up or down arrow */\nconst KEY_PITCH = 10;\n/** Duration of the moves made by keys, milliseconds */\nconst KEY_DURATION = 300;\n\n/** What a key does to the camera: a pan in CSS pixels, a zoom, rotation or tilt step, or facing north */\nexport type KeyAction = { pan: Point } | { zoom: number } | { bearing: number } | { pitch: number } | { reset: true };\n\n/** The action of a key (`KeyboardEvent.key`), as MapLibre's: arrows pan (with Shift: rotate and tilt), + and - zoom\n * (with Shift: two levels), 0 faces north and levels the view */\nexport function keyAction(key: string, shift: boolean): KeyAction | undefined {\n switch (key) {\n case 'ArrowLeft':\n return shift ? { bearing: -KEY_BEARING } : { pan: [-KEY_PAN, 0] };\n case 'ArrowRight':\n return shift ? { bearing: KEY_BEARING } : { pan: [KEY_PAN, 0] };\n case 'ArrowUp':\n return shift ? { pitch: KEY_PITCH } : { pan: [0, -KEY_PAN] };\n case 'ArrowDown':\n return shift ? { pitch: -KEY_PITCH } : { pan: [0, KEY_PAN] };\n case '+':\n case '=':\n return { zoom: shift ? 2 : 1 };\n case '-':\n case '_':\n return { zoom: shift ? -2 : -1 };\n case '0':\n return { reset: true };\n default:\n return undefined;\n }\n}\n\n/** The camera after a key's action: a pan moves the center by that many CSS pixels on screen (the ground in view,\n * turned with the bearing, stretched by the tilt) */\nexport function keyCamera(action: KeyAction, camera: Camera): Partial<Camera> {\n if ('zoom' in action) return { zoom: camera.zoom + action.zoom };\n if ('bearing' in action) return { bearing: camera.bearing + action.bearing };\n if ('pitch' in action) return { pitch: Math.max(0, camera.pitch + action.pitch) };\n if ('reset' in action) return { bearing: 0, pitch: 0 };\n const b = (camera.bearing * Math.PI) / 180;\n const [sx, sy] = [action.pan[0], action.pan[1] / Math.max(0.25, Math.cos((camera.pitch * Math.PI) / 180))];\n // Web Mercator units (0 to 1 across the world, y down); the world is 512 CSS pixels at zoom 0\n const world = 512 * 2 ** camera.zoom;\n const dx = (sx * Math.cos(b) - sy * Math.sin(b)) / world;\n const dy = (sx * Math.sin(b) + sy * Math.cos(b)) / world;\n const [lon, lat] = camera.center;\n const x = mercatorX(lon) + dx;\n const y = Math.max(0, Math.min(1, mercatorY(lat) + dy));\n const wrapped = ((((x * 360) % 360) + 360) % 360) - 180;\n return { center: [wrapped, latitude(y)] };\n}\n\n/** An element that takes the keys typed in it */\nfunction editable(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n return target.isContentEditable || ['INPUT', 'TEXTAREA', 'SELECT'].includes(target.tagName);\n}\n\ninterface Pointer {\n point: Point;\n start: Point;\n button: number;\n rotate: boolean;\n}\n\nexport class Interaction {\n private readonly pointers = new Map<number, Pointer>();\n private readonly cleanup: (() => void)[] = [];\n private wheel = { pending: 0, at: [0, 0] as Point };\n /** Recent pan moves, for the release speed: [time, dx, dy] */\n private trail: [number, number, number][] = [];\n private moved = false;\n /** The canvas's place on the page, read once: reading it on every pointer move would force a layout each time.\n * Read again after a resize, a scroll, and when a pointer comes in or goes down */\n private rect: DOMRect | undefined;\n /** A double click zooms in (Shift: out); off while the page takes double clicks (ending a drawing) */\n doubleClickZoom = true;\n\n constructor(\n private readonly map: GeoMap,\n options: { keyboard?: boolean } = {},\n ) {\n const canvas = map.canvas;\n const listen = <K extends keyof HTMLElementEventMap>(\n type: K,\n handler: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n ) => {\n canvas.addEventListener(type, handler, options);\n this.cleanup.push(() => canvas.removeEventListener(type, handler));\n };\n const moved = () => {\n this.rect = undefined;\n };\n listen('pointerenter', moved);\n // Scrolls of the page or of any element holding the map\n if (typeof addEventListener === 'function') {\n addEventListener('scroll', moved, { capture: true, passive: true });\n this.cleanup.push(() => removeEventListener('scroll', moved, { capture: true }));\n }\n this.cleanup.push(map.on('resize', moved));\n listen('pointerdown', (e) => {\n this.rect = undefined;\n this.down(e);\n });\n listen('pointermove', (e) => this.move(e));\n listen('pointerup', (e) => this.up(e));\n listen('pointercancel', (e) => this.up(e));\n listen('pointerleave', (e) => {\n if (e.pointerType !== 'mouse') return;\n map.hover(undefined);\n map.emit('leave', {});\n });\n // On the container, the wheel zooms over markers and popups too\n const container = map.getContainer();\n const wheel = (e: WheelEvent) => this.onWheel(e);\n container.addEventListener('wheel', wheel, { passive: false });\n this.cleanup.push(() => container.removeEventListener('wheel', wheel));\n listen('dblclick', (e) => {\n if (this.doubleClickZoom && !this.map.firstPerson) this.zoomBy(e.shiftKey ? -1 : 1, this.local(e));\n });\n listen('contextmenu', (e) => e.preventDefault());\n if (options.keyboard ?? true) {\n // On the container: the keys work with the focus on a marker or a control too\n const key = (e: KeyboardEvent) => this.onKey(e);\n container.addEventListener('keydown', key);\n this.cleanup.push(() => container.removeEventListener('keydown', key));\n }\n }\n\n destroy(): void {\n for (const off of this.cleanup) off();\n }\n\n /** A gesture holds the map (pointers down): the camera has not stopped moving */\n get active(): boolean {\n return this.pointers.size > 0;\n }\n\n private local(e: MouseEvent): Point {\n this.rect ??= this.map.canvas.getBoundingClientRect();\n return [e.clientX - this.rect.left, e.clientY - this.rect.top];\n }\n\n private down(e: PointerEvent): void {\n this.map.canvas.setPointerCapture(e.pointerId);\n const point = this.local(e);\n const rotate = e.button === 2 || e.ctrlKey || e.shiftKey;\n this.pointers.set(e.pointerId, { point, start: point, button: e.button, rotate });\n this.trail = [];\n this.moved = false;\n // Grabbing the map stops any running animation (inertia, wheel zoom, easeTo)\n this.wheel.pending = 0;\n this.map.animate(undefined);\n }\n\n private move(e: PointerEvent): void {\n const point = this.local(e);\n const p = this.pointers.get(e.pointerId);\n if (!p) {\n if (e.pointerType === 'mouse') this.map.hover(point);\n return;\n }\n const [dx, dy] = [point[0] - p.point[0], point[1] - p.point[1]];\n if (Math.hypot(point[0] - p.start[0], point[1] - p.start[1]) > CLICK_TOLERANCE) this.moved = true;\n const eye = this.map.firstPerson;\n if (eye) {\n // At street level the drag turns the eye, the scene following the pointer as if grabbed\n const degrees = eye.fov / Math.max(1, this.map.canvas.clientHeight);\n this.map.setFirstPerson({ ...eye, bearing: eye.bearing - dx * degrees, pitch: eye.pitch + dy * degrees });\n p.point = point;\n return;\n }\n const engine = this.map.engine;\n const other = [...this.pointers.values()].find((q) => q !== p);\n if (this.pointers.size === 2 && other) {\n // Pinch: zoom by the change of spread, turn by the change of angle, pan by the midpoint\n const before = Math.hypot(p.point[0] - other.point[0], p.point[1] - other.point[1]);\n const after = Math.hypot(point[0] - other.point[0], point[1] - other.point[1]);\n const angle = (q: Point) => Math.atan2(q[1] - other.point[1], q[0] - other.point[0]);\n const mid = (q: Point): Point => [(q[0] + other.point[0]) / 2, (q[1] + other.point[1]) / 2];\n engine.pan(...mid(p.point), ...mid(point));\n if (before > 0 && after > 0) engine.zoomAt(Math.log2(after / before), ...mid(point));\n engine.rotate((-(angle(point) - angle(p.point)) * 180) / Math.PI, 0);\n } else if (p.rotate) {\n engine.rotate(-dx * ROTATE_RATE, -dy * ROTATE_RATE);\n } else {\n engine.pan(p.point[0], p.point[1], point[0], point[1]);\n this.trail.push([e.timeStamp, dx, dy]);\n }\n p.point = point;\n this.map.requestRender();\n }\n\n private up(e: PointerEvent): void {\n const p = this.pointers.get(e.pointerId);\n if (!p) return;\n this.pointers.delete(e.pointerId);\n // The next frame sends 'moveend' if the camera stays\n this.map.requestRender();\n if (!this.moved && e.type === 'pointerup' && p.button === 0 && this.pointers.size === 0) {\n this.map.emit('click', { point: p.point, lonLat: this.map.unproject(p.point) });\n return;\n }\n if (!p.rotate && this.pointers.size === 0 && !this.map.firstPerson) this.inertia(e.timeStamp, p.point);\n }\n\n /** Keeps panning at the release speed (last 50 ms), decaying exponentially */\n private inertia(now: number, from: Point): void {\n const recent = this.trail.filter(([t]) => now - t < 50);\n const first = recent[0];\n if (!first || recent.length < 2) return;\n const span = Math.max(16, now - first[0]);\n let vx = recent.reduce((s, [, dx]) => s + dx, 0) / span;\n let vy = recent.reduce((s, [, , dy]) => s + dy, 0) / span;\n if (Math.hypot(vx, vy) < 0.1) return;\n let last = performance.now();\n let point = from;\n this.map.animate((t) => {\n const dt = Math.min(64, t - last);\n last = t;\n const decay = Math.exp(-dt / INERTIA_DECAY);\n const next: Point = [point[0] + vx * dt, point[1] + vy * dt];\n this.map.engine.pan(point[0], point[1], next[0], next[1]);\n point = next;\n vx *= decay;\n vy *= decay;\n return Math.hypot(vx, vy) > 0.02;\n });\n }\n\n private onWheel(e: WheelEvent): void {\n e.preventDefault();\n // Lines (Firefox mouse wheels) are about 33 px\n const pixels = e.deltaMode === 1 ? e.deltaY * 33 : e.deltaY;\n const eye = this.map.firstPerson;\n if (eye) {\n // At street level: a narrower or wider field of view\n this.map.setFirstPerson({ ...eye, fov: eye.fov * Math.exp(pixels * 0.001) });\n return;\n }\n this.zoomBy(\n Math.max(-1, Math.min(1, -pixels * WHEEL_RATE)),\n this.local(e),\n e.deltaMode === 0 && Math.abs(pixels) < 40,\n );\n }\n\n private onKey(e: KeyboardEvent): void {\n if (e.defaultPrevented || e.ctrlKey || e.metaKey || e.altKey || editable(e.target)) return;\n const action = keyAction(e.key, e.shiftKey);\n if (!action) return;\n e.preventDefault();\n const eye = this.map.firstPerson;\n if (eye) {\n // At street level the arrows turn the eye\n const turn = { ArrowLeft: [-10, 0], ArrowRight: [10, 0], ArrowUp: [0, 10], ArrowDown: [0, -10] }[e.key];\n if (turn)\n this.map.setFirstPerson({ ...eye, bearing: eye.bearing + (turn[0] ?? 0), pitch: eye.pitch + (turn[1] ?? 0) });\n return;\n }\n this.wheel.pending = 0;\n const reduced = typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches;\n this.map.easeTo(keyCamera(action, this.map.getCamera()), reduced ? 0 : KEY_DURATION);\n }\n\n /** Smooth zoom around a screen point; touchpads (`direct`) follow the fingers without easing */\n private zoomBy(delta: number, at: Point, direct = false): void {\n if (direct) {\n this.map.engine.zoomAt(delta, at[0], at[1]);\n this.map.requestRender();\n return;\n }\n // Accumulate: a second notch before the end of the first one adds to it\n this.wheel.pending += delta;\n this.wheel.at = at;\n this.map.animate(() => {\n const step = Math.abs(this.wheel.pending) < 0.002 ? this.wheel.pending : this.wheel.pending * WHEEL_EASE;\n this.wheel.pending -= step;\n this.map.engine.zoomAt(step, this.wheel.at[0], this.wheel.at[1]);\n return this.wheel.pending !== 0;\n });\n }\n}\n"]}
@@ -3,8 +3,8 @@
3
3
  * (camera moves, finer relief arriving), with a CSS transform from `map.project`: the browser only composites them,
4
4
  * nothing is laid out again.
5
5
  */
6
- import type { GeoMap } from './map.ts';
7
- import type { LonLat, Point } from './types.ts';
6
+ import type { GeoMap } from '../map.ts';
7
+ import type { LonLat, Point } from '../types.ts';
8
8
  /** Which part of the element sits on the position */
9
9
  export type Anchor = 'center' | 'top' | 'bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
10
10
  export interface MarkerOptions {
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlay.js","sourceRoot":"","sources":["../../src/ui/overlay.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * DOM overlays tied to a position: markers and popups. The map places them all in one pass after each frame it draws\n * (camera moves, finer relief arriving), with a CSS transform from `map.project`: the browser only composites them,\n * nothing is laid out again.\n */\nimport type { GeoMap } from '../map.ts';\nimport type { LonLat, Point } from '../types.ts';\n\n/** Which part of the element sits on the position */\nexport type Anchor =\n | 'center'\n | 'top'\n | 'bottom'\n | 'left'\n | 'right'\n | 'top-left'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-right';\n\nconst ANCHOR_TRANSLATE: Record<Anchor, string> = {\n center: 'translate(-50%, -50%)',\n top: 'translate(-50%, 0)',\n bottom: 'translate(-50%, -100%)',\n left: 'translate(0, -50%)',\n right: 'translate(-100%, -50%)',\n 'top-left': 'translate(0, 0)',\n 'top-right': 'translate(-100%, 0)',\n 'bottom-left': 'translate(0, -100%)',\n 'bottom-right': 'translate(-100%, -100%)',\n};\n\n/** Where the anchor lies within the element, CSS percentages: the stem of a raised marker starts there */\nconst ANCHOR_POINT: Record<Anchor, [string, string]> = {\n center: ['50%', '50%'],\n top: ['50%', '0'],\n bottom: ['50%', '100%'],\n left: ['0', '50%'],\n right: ['100%', '50%'],\n 'top-left': ['0', '0'],\n 'top-right': ['100%', '0'],\n 'bottom-left': ['0', '100%'],\n 'bottom-right': ['100%', '100%'],\n};\n\n/** Overlays further than this out of the canvas (CSS pixels) are hidden: no part of them can show, and huge\n * transforms near the horizon would only cost the compositor */\nconst MARGIN = 500;\n/** A press on a draggable marker that moves less than this (CSS pixels) is a click */\nconst DRAG_TOLERANCE = 3;\n\n/** @internal What the map places after each frame */\nexport interface Positioned {\n /** Places the overlay for the current camera; `size` is the canvas size in CSS pixels */\n position(size: Point): void;\n}\n\n/** Typed listeners of an overlay */\nclass Emitter<E> {\n private readonly listeners: { [K in keyof E]?: Set<(event: E[K]) => void> } = {};\n\n on<K extends keyof E>(type: K, listener: (event: E[K]) => void): () => void {\n const set = this.listeners[type] ?? new Set();\n this.listeners[type] = set;\n set.add(listener);\n return () => set.delete(listener);\n }\n\n emit<K extends keyof E>(type: K, event: E[K]): void {\n for (const listener of this.listeners[type] ?? []) listener(event);\n }\n}\n\n/** Moves `element` so that its anchor sits on `lonLat`, `height` metres above the ground, or hides it when the\n * position is out of sight; returns the screen point */\nfunction place(\n map: GeoMap,\n element: HTMLElement,\n lonLat: LonLat,\n height: number,\n anchor: Anchor,\n offset: Point,\n size: Point,\n): Point | undefined {\n const point = map.project(lonLat, height);\n const visible =\n point !== undefined &&\n point[0] > -MARGIN &&\n point[0] < size[0] + MARGIN &&\n point[1] > -MARGIN &&\n point[1] < size[1] + MARGIN;\n if (!visible) {\n element.style.display = 'none';\n return undefined;\n }\n element.style.display = '';\n // Whole pixels: a fractional translation blurs text and icons\n const x = Math.round(point[0] + offset[0]);\n const y = Math.round(point[1] + offset[1]);\n element.style.transform = `translate(${x}px, ${y}px) ${ANCHOR_TRANSLATE[anchor]}`;\n return point;\n}\n\n/** Round pin, its tip at the bottom: the default marker */\nfunction pin(): HTMLElement {\n const element = document.createElement('div');\n element.innerHTML =\n '<svg class=\"isard-marker-pin\" width=\"25\" height=\"34\" viewBox=\"0 0 25 34\" aria-hidden=\"true\">' +\n '<path fill=\"currentColor\" stroke=\"rgb(0 0 0 / 0.25)\" d=\"M12.5 33.5C12.5 33.5 .5 20.6 .5 12.5a12 12 0 0 1 24 0' +\n 'c0 8.1-12 21-12 21z\"/><circle cx=\"12.5\" cy=\"12.5\" r=\"4.5\" fill=\"#fff\"/></svg>';\n return element;\n}\n\nexport interface MarkerOptions {\n /** The element to show (default: a round pin) */\n element?: HTMLElement;\n /** Which part of the element sits on the position (default 'center' with an element of your own, 'bottom' for the\n * default pin) */\n anchor?: Anchor;\n /** Shift from the anchor, CSS pixels (default [0, 0]) */\n offset?: Point;\n /** The marker can be dragged over the map, on the relief (default false) */\n draggable?: boolean;\n /** Metres above the ground (default 0): a raised marker has a stem down to its position on the ground */\n height?: number;\n /** Classes added to the element, space separated */\n className?: string;\n}\n\nexport interface MarkerEvent {\n target: Marker;\n lonLat: LonLat;\n}\n\nexport interface MarkerEvents {\n dragstart: MarkerEvent;\n drag: MarkerEvent;\n dragend: MarkerEvent;\n}\n\n/** An element at a position on the map, optionally draggable */\nexport class Marker {\n private readonly element: HTMLElement;\n private readonly anchor: Anchor;\n private readonly events = new Emitter<MarkerEvents>();\n private offset: Point;\n private draggable: boolean;\n private lonLat: LonLat = [0, 0];\n private height: number;\n /** Metres above the ground of what the marker stands on, where its stem ends */\n private base = 0;\n /** The line from a raised marker down to the ground */\n private readonly stem: HTMLElement;\n private map: GeoMap | undefined;\n private popup: Popup | undefined;\n /** While pressed: the press point and the gap between the pointer and the marker's position */\n private grab: { start: Point; gap: Point } | undefined;\n private dragging = false;\n /** The click that ends a drag is not a click on the marker */\n private swallowClick = false;\n\n constructor(options: MarkerOptions = {}) {\n this.element = options.element ?? pin();\n this.anchor = options.anchor ?? (options.element ? 'center' : 'bottom');\n this.offset = options.offset ?? [0, 0];\n this.draggable = options.draggable ?? false;\n this.height = options.height ?? 0;\n this.stem = document.createElement('div');\n this.stem.className = 'isard-marker-stem';\n [this.stem.style.left, this.stem.style.top] = ANCHOR_POINT[this.anchor];\n this.element.append(this.stem);\n this.element.classList.add('isard-marker');\n if (options.className) this.element.classList.add(...options.className.split(/\\s+/).filter(Boolean));\n this.element.classList.toggle('isard-marker-draggable', this.draggable);\n this.element.addEventListener('pointerdown', (e) => this.down(e));\n this.element.addEventListener('pointermove', (e) => this.move(e));\n this.element.addEventListener('pointerup', (e) => this.up(e));\n this.element.addEventListener('pointercancel', (e) => this.up(e));\n this.element.addEventListener('click', (e) => this.click(e), { capture: true });\n }\n\n getElement(): HTMLElement {\n return this.element;\n }\n\n getLonLat(): LonLat {\n return [...this.lonLat];\n }\n\n setLonLat(lonLat: LonLat): this {\n this.lonLat = [lonLat[0], lonLat[1]];\n this.map?.positionOverlay(this);\n // An open popup of the marker goes with it\n if (this.popup?.isOpen()) this.popup.setLonLat(this.lonLat);\n return this;\n }\n\n getHeight(): number {\n return this.height;\n }\n\n /** Metres above the ground: a raised marker has a stem down to `base` metres, what it stands on (a roof, a mesh;\n * the ground by default); its popup is raised too */\n setHeight(height: number, base = 0): this {\n this.height = Number.isFinite(height) ? height : 0;\n this.base = Number.isFinite(base) ? Math.min(base, this.height) : 0;\n this.popup?.setHeight(this.height);\n this.map?.positionOverlay(this);\n return this;\n }\n\n setOffset(offset: Point): this {\n this.offset = [offset[0], offset[1]];\n this.map?.positionOverlay(this);\n return this;\n }\n\n setDraggable(draggable: boolean): this {\n this.draggable = draggable;\n this.element.classList.toggle('isard-marker-draggable', draggable);\n return this;\n }\n\n isDraggable(): boolean {\n return this.draggable;\n }\n\n /** A popup that a click on the marker opens and closes, at the marker's position; give it an offset clearing the\n * marker (with the default pin, [0, -34]) */\n setPopup(popup: Popup | undefined): this {\n this.popup?.remove();\n this.popup = popup;\n popup?.setHeight(this.height);\n return this;\n }\n\n getPopup(): Popup | undefined {\n return this.popup;\n }\n\n /** Opens the marker's popup, or closes it if open */\n togglePopup(): this {\n if (!this.popup || !this.map) return this;\n if (this.popup.isOpen()) this.popup.remove();\n else this.popup.setLonLat(this.lonLat).addTo(this.map);\n return this;\n }\n\n /** Listens to the drag of the marker; returns the function that stops listening */\n on<K extends keyof MarkerEvents>(type: K, listener: (event: MarkerEvents[K]) => void): () => void {\n return this.events.on(type, listener);\n }\n\n addTo(map: GeoMap): this {\n if (this.map === map) return this;\n this.remove();\n this.map = map;\n map.attachOverlay(this, this.element);\n return this;\n }\n\n remove(): this {\n this.popup?.remove();\n this.map?.detachOverlay(this, this.element);\n this.map = undefined;\n this.grab = undefined;\n this.dragging = false;\n this.element.classList.remove('isard-marker-dragging');\n return this;\n }\n\n /** @internal */\n position(size: Point): void {\n if (!this.map) return;\n const top = place(this.map, this.element, this.lonLat, this.height, this.anchor, this.offset, size);\n const ground = top && this.height !== this.base ? this.map.project(this.lonLat, this.base) : undefined;\n if (!top || !ground) {\n this.stem.style.display = 'none';\n return;\n }\n // From the anchor down to what it stands on, a line turned toward it\n const [dx, dy] = [ground[0] - top[0], ground[1] - top[1]];\n this.stem.style.display = '';\n this.stem.style.height = `${Math.hypot(dx, dy)}px`;\n this.stem.style.transform = `rotate(${Math.atan2(dy, dx) - Math.PI / 2}rad)`;\n }\n\n private local(e: PointerEvent): Point | undefined {\n const rect = this.map?.getCanvas().getBoundingClientRect();\n return rect && [e.clientX - rect.left, e.clientY - rect.top];\n }\n\n private down(e: PointerEvent): void {\n this.swallowClick = false;\n if (!this.draggable || !this.map || e.button !== 0) return;\n // The gap to the position on the ground, below a raised marker\n const point = this.map.project(this.lonLat);\n const at = this.local(e);\n if (!point || !at) return;\n // The map must not start panning under the marker\n e.stopPropagation();\n e.preventDefault();\n this.element.setPointerCapture(e.pointerId);\n // The grabbed spot of the marker stays under the pointer, wherever the element was pressed\n this.grab = { start: at, gap: [at[0] - point[0], at[1] - point[1]] };\n this.dragging = false;\n }\n\n private move(e: PointerEvent): void {\n const at = this.local(e);\n if (!this.grab || !this.map || !at) return;\n e.stopPropagation();\n const { start, gap } = this.grab;\n if (!this.dragging && Math.hypot(at[0] - start[0], at[1] - start[1]) < DRAG_TOLERANCE) return;\n // On the relief: the ground under the point, read back from the picking pass\n const lonLat = this.map.unproject([at[0] - gap[0], at[1] - gap[1]]);\n if (!lonLat) return;\n if (!this.dragging) {\n this.dragging = true;\n this.element.classList.add('isard-marker-dragging');\n this.events.emit('dragstart', { target: this, lonLat: this.getLonLat() });\n }\n this.setLonLat(lonLat);\n this.events.emit('drag', { target: this, lonLat: this.getLonLat() });\n }\n\n private up(e: PointerEvent): void {\n if (!this.grab) return;\n e.stopPropagation();\n this.grab = undefined;\n if (this.element.hasPointerCapture(e.pointerId)) this.element.releasePointerCapture(e.pointerId);\n if (!this.dragging) return;\n this.dragging = false;\n this.swallowClick = true;\n this.element.classList.remove('isard-marker-dragging');\n this.events.emit('dragend', { target: this, lonLat: this.getLonLat() });\n }\n\n private click(e: MouseEvent): void {\n if (this.swallowClick) {\n this.swallowClick = false;\n e.stopImmediatePropagation();\n e.preventDefault();\n return;\n }\n if (this.popup) this.togglePopup();\n }\n}\n\nexport interface PopupOptions {\n /** A × button in the corner (default true) */\n closeButton?: boolean;\n /** A click on the map elsewhere closes the popup (default true) */\n closeOnClick?: boolean;\n /** CSS max-width of the popup (default '240px') */\n maxWidth?: string;\n /** Classes added to the popup, space separated */\n className?: string;\n /** Which part of the popup sits on the position, its tip there (default 'bottom': the popup is above the point) */\n anchor?: Anchor;\n /** Shift from the anchor, CSS pixels (default [0, 0]) */\n offset?: Point;\n}\n\nexport interface PopupEvents {\n open: { target: Popup };\n close: { target: Popup };\n}\n\n/** A box of content at a position, its tip pointing at it */\nexport class Popup {\n private readonly container: HTMLElement;\n private readonly content: HTMLElement;\n private readonly closeButton: HTMLButtonElement | undefined;\n private readonly anchor: Anchor;\n private readonly closeOnClick: boolean;\n private readonly events = new Emitter<PopupEvents>();\n private offset: Point;\n private lonLat: LonLat = [0, 0];\n private height = 0;\n private map: GeoMap | undefined;\n private stopListening: (() => void) | undefined;\n\n constructor(options: PopupOptions = {}) {\n this.anchor = options.anchor ?? 'bottom';\n this.offset = options.offset ?? [0, 0];\n this.closeOnClick = options.closeOnClick ?? true;\n this.container = document.createElement('div');\n this.container.className = `isard-popup isard-popup-anchor-${this.anchor}`;\n if (options.className) this.container.classList.add(...options.className.split(/\\s+/).filter(Boolean));\n this.container.style.maxWidth = options.maxWidth ?? '240px';\n const tip = document.createElement('div');\n tip.className = 'isard-popup-tip';\n this.content = document.createElement('div');\n this.content.className = 'isard-popup-content';\n if (options.closeButton ?? true) {\n this.container.classList.add('isard-popup-has-close');\n this.closeButton = document.createElement('button');\n this.closeButton.type = 'button';\n this.closeButton.className = 'isard-popup-close';\n this.closeButton.setAttribute('aria-label', 'Close popup');\n this.closeButton.textContent = '×';\n this.closeButton.addEventListener('click', () => this.remove());\n this.content.append(this.closeButton);\n }\n this.container.append(tip, this.content);\n }\n\n getElement(): HTMLElement {\n return this.container;\n }\n\n getLonLat(): LonLat {\n return [...this.lonLat];\n }\n\n setLonLat(lonLat: LonLat): this {\n this.lonLat = [lonLat[0], lonLat[1]];\n this.map?.positionOverlay(this);\n return this;\n }\n\n setOffset(offset: Point): this {\n this.offset = [offset[0], offset[1]];\n this.map?.positionOverlay(this);\n return this;\n }\n\n getHeight(): number {\n return this.height;\n }\n\n /** Metres above the ground (default 0); a marker's popup follows the marker's height */\n setHeight(height: number): this {\n this.height = Number.isFinite(height) ? height : 0;\n this.map?.positionOverlay(this);\n return this;\n }\n\n /** Content from an HTML string: only for trusted HTML (use `setText` for user or remote data) */\n setHTML(html: string): this {\n const template = document.createElement('template');\n template.innerHTML = html;\n return this.setDOMContent(template.content);\n }\n\n setText(text: string): this {\n return this.setDOMContent(document.createTextNode(text));\n }\n\n setDOMContent(node: Node): this {\n this.content.replaceChildren(node);\n if (this.closeButton) this.content.append(this.closeButton);\n this.map?.positionOverlay(this);\n return this;\n }\n\n isOpen(): boolean {\n return this.map !== undefined;\n }\n\n /** Listens to the popup opening or closing; returns the function that stops listening */\n on<K extends keyof PopupEvents>(type: K, listener: (event: PopupEvents[K]) => void): () => void {\n return this.events.on(type, listener);\n }\n\n addTo(map: GeoMap): this {\n if (this.map === map) return this;\n this.remove();\n this.map = map;\n map.attachOverlay(this, this.container);\n if (this.closeOnClick) {\n // From the next task on: a popup opened by a map click must not be closed by that same click\n queueMicrotask(() => {\n if (this.map === map && !this.stopListening) this.stopListening = map.on('click', () => this.remove());\n });\n }\n this.events.emit('open', { target: this });\n return this;\n }\n\n remove(): this {\n if (!this.map) return this;\n this.stopListening?.();\n this.stopListening = undefined;\n this.map.detachOverlay(this, this.container);\n this.map = undefined;\n this.events.emit('close', { target: this });\n return this;\n }\n\n /** @internal */\n position(size: Point): void {\n if (this.map) place(this.map, this.container, this.lonLat, this.height, this.anchor, this.offset, size);\n }\n}\n\nexport interface PanelOptions {\n /** The element shown in 3D (a video, an iframe, an image…), laid out at its CSS size */\n element: HTMLElement;\n /** Its width on the ground, metres; its height follows its CSS aspect */\n width: number;\n /** Degrees clockwise from north the side it faces (default 0: it faces north, read from the north) */\n heading?: number;\n /** Degrees it leans back from upright (default 0: standing; 90: lying flat) */\n pitch?: number;\n /** Metres of its bottom edge above the ground (the relief; default 0) */\n height?: number;\n /** Classes added to the element, space separated */\n className?: string;\n}\n\n/** `a × b`, 4 × 4 column-major */\nfunction multiply(a: ArrayLike<number>, b: ArrayLike<number>): number[] {\n const out = new Array<number>(16).fill(0);\n for (let c = 0; c < 4; c++) {\n for (let r = 0; r < 4; r++) {\n let sum = 0;\n for (let k = 0; k < 4; k++) sum += (a[k * 4 + r] ?? 0) * (b[c * 4 + k] ?? 0);\n out[c * 4 + r] = sum;\n }\n }\n return out;\n}\n\n/**\n * An element standing in 3D at a position: a video, a web page, a sign, `width` metres wide on the ground, facing\n * `heading`. Placed after each frame by a CSS 3D transform (the element is not drawn by WebGL: the scene does not\n * hide it); hidden when its position is behind the camera\n */\nexport class Panel {\n private readonly element: HTMLElement;\n private lonLat: LonLat = [0, 0];\n private width: number;\n private heading: number;\n private pitch: number;\n private height: number;\n private map: GeoMap | undefined;\n /** Its CSS size, read once it is on the page (`resize` reads it again) */\n private size: Point | undefined;\n\n constructor(options: PanelOptions) {\n this.element = options.element;\n this.width = options.width;\n this.heading = options.heading ?? 0;\n this.pitch = options.pitch ?? 0;\n this.height = options.height ?? 0;\n this.element.classList.add('isard-panel');\n if (options.className) this.element.classList.add(...options.className.split(/\\s+/).filter(Boolean));\n }\n\n getElement(): HTMLElement {\n return this.element;\n }\n\n getLonLat(): LonLat {\n return [...this.lonLat];\n }\n\n setLonLat(lonLat: LonLat): this {\n this.lonLat = [lonLat[0], lonLat[1]];\n this.map?.positionOverlay(this);\n return this;\n }\n\n /** Width (metres), heading and pitch (degrees), height of its bottom edge (metres), as in `PanelOptions` */\n setPlacement(placement: Partial<Pick<PanelOptions, 'width' | 'heading' | 'pitch' | 'height'>>): this {\n this.width = placement.width ?? this.width;\n this.heading = placement.heading ?? this.heading;\n this.pitch = placement.pitch ?? this.pitch;\n this.height = placement.height ?? this.height;\n this.map?.positionOverlay(this);\n return this;\n }\n\n /** Reads the element's CSS size again (after it changed) */\n resize(): this {\n this.size = undefined;\n this.map?.positionOverlay(this);\n return this;\n }\n\n addTo(map: GeoMap): this {\n if (this.map === map) return this;\n this.remove();\n this.map = map;\n map.attachOverlay(this, this.element);\n return this;\n }\n\n remove(): this {\n this.map?.detachOverlay(this, this.element);\n this.map = undefined;\n this.size = undefined;\n return this;\n }\n\n /** @internal */\n position(viewport: Point): void {\n const map = this.map;\n if (!map) return;\n this.size ??= [this.element.offsetWidth || 300, this.element.offsetHeight || 150];\n const [w, h] = this.size;\n const ground = map.elevationAt(this.lonLat) ?? 0;\n const local = map.engine.localMatrix(this.lonLat[0], this.lonLat[1], ground);\n // The element's pixels to the local frame (metres, x east, y north, z up): its bottom edge centered on the\n // position, `height` up, facing `heading`, leant back by `pitch`\n const rad = Math.PI / 180;\n const [hd, pt] = [this.heading * rad, this.pitch * rad];\n const s = this.width / w;\n // Across it (left to right as read from the side it faces), and up it\n const [ax, ay] = [-Math.cos(hd), Math.sin(hd)];\n const [ux, uy, uz] = [-Math.sin(hd) * Math.sin(pt), -Math.cos(hd) * Math.sin(pt), Math.cos(pt)];\n const top = h * s;\n const origin = [-ax * (this.width / 2) + ux * top, -ay * (this.width / 2) + uy * top, this.height + uz * top];\n const toLocal = [ax * s, ay * s, 0, 0, -ux * s, -uy * s, -uz * s, 0, 0, 0, 0, 0, ...origin, 1];\n // Clip space to the map's CSS pixels; the depth flattened\n const [vw, vh] = viewport;\n const toScreen = [vw / 2, 0, 0, 0, 0, -vh / 2, 0, 0, 0, 0, 0, 0, vw / 2, vh / 2, 0, 1];\n const clip = multiply(local, toLocal);\n // Behind the camera (its center): hidden\n const centerW = (clip[3] ?? 0) * (w / 2) + (clip[7] ?? 0) * (h / 2) + (clip[15] ?? 0);\n // Hidden without touching its display (the page's layout of its content)\n if (!(centerW > 0)) {\n this.element.style.visibility = 'hidden';\n return;\n }\n this.element.style.visibility = '';\n // Its depth axis the identity, out of the rest: its points have no depth, and a transform that cannot be\n // inverted is not drawn\n const m = multiply(toScreen, clip);\n m.splice(8, 4, 0, 0, 1, 0);\n for (const k of [2, 6, 14]) m[k] = 0;\n this.element.style.transform = `matrix3d(${m.join(',')})`;\n }\n}\n"]}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style.js","sourceRoot":"","sources":["../../src/ui/style.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,GAAG,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmHX,CAAC;AAEF,MAAM,MAAM,GAAG,IAAI,OAAO,EAAY,CAAC;AAEvC,mHAAmH;AACnH,MAAM,UAAU,WAAW,CAAC,GAAa;IACvC,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO;IAC5B,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChB,MAAM,KAAK,GAAG,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IACzC,KAAK,CAAC,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC;IACzB,KAAK,CAAC,WAAW,GAAG,GAAG,CAAC;IACxB,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC1B,CAAC","sourcesContent":["/**\n * Styles of the DOM overlays (markers, popups, controls), injected once per document so the package needs no CSS\n * file. Colors are custom properties, defaults on the root with no specificity: an application restyles them on any\n * element around the map (its container's class may be replaced by a framework: nothing depends on it).\n */\n\nconst CSS = `\n:where(:root) {\n --isard-ctrl-bg: #fff;\n --isard-ctrl-fg: #333;\n --isard-ctrl-hover: rgb(0 0 0 / 0.05);\n --isard-ctrl-active: #1d2433;\n --isard-ctrl-active-fg: #fff;\n --isard-ctrl-border: #ddd;\n --isard-ctrl-shadow: 0 0 0 2px rgb(0 0 0 / 0.1);\n --isard-popup-bg: #fff;\n --isard-popup-fg: #1d2433;\n --isard-marker-color: #3a6fd8;\n --isard-attrib-bg: rgb(255 255 255 / 0.5);\n --isard-attrib-fg: rgb(0 0 0 / 0.75);\n --isard-focus: #3a6fd8;\n}\n.isard-canvas:focus { outline: none; }\n.isard-canvas:focus-visible { outline: 2px solid var(--isard-focus); outline-offset: -2px; }\n.isard-overlay { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 1; }\n.isard-ctrl-top-left, .isard-ctrl-top-right, .isard-ctrl-bottom-left, .isard-ctrl-bottom-right {\n position: absolute; pointer-events: none; z-index: 2;\n}\n.isard-ctrl-top-left { top: 0; left: 0; }\n.isard-ctrl-top-right { top: 0; right: 0; }\n.isard-ctrl-bottom-left { bottom: 0; left: 0; }\n.isard-ctrl-bottom-right { bottom: 0; right: 0; }\n.isard-ctrl { clear: both; pointer-events: auto; transform: translate(0, 0); }\n.isard-ctrl-top-left .isard-ctrl { float: left; margin: 10px 0 0 10px; }\n.isard-ctrl-top-right .isard-ctrl { float: right; margin: 10px 10px 0 0; }\n.isard-ctrl-bottom-left .isard-ctrl { float: left; margin: 0 0 10px 10px; }\n.isard-ctrl-bottom-right .isard-ctrl { float: right; margin: 0 10px 10px 0; }\n.isard-ctrl-group { background: var(--isard-ctrl-bg); border-radius: 4px; box-shadow: var(--isard-ctrl-shadow); }\n.isard-ctrl-group button {\n display: block; width: 29px; height: 29px; padding: 0; margin: 0; border: 0; box-sizing: border-box;\n background: transparent; color: var(--isard-ctrl-fg); cursor: pointer; font: inherit;\n}\n.isard-ctrl-group button + button { border-top: 1px solid var(--isard-ctrl-border); }\n.isard-ctrl-group button:first-child { border-radius: 4px 4px 0 0; }\n.isard-ctrl-group button:last-child { border-radius: 0 0 4px 4px; }\n.isard-ctrl-group button:only-child { border-radius: inherit; }\n.isard-ctrl-group button:hover { background-color: var(--isard-ctrl-hover); }\n.isard-ctrl-group button:focus-visible { outline: 2px solid var(--isard-ctrl-active); outline-offset: -2px; }\n.isard-ctrl-group button.active { background: var(--isard-ctrl-active); color: var(--isard-ctrl-active-fg); }\n.isard-ctrl-group button svg { display: block; margin: auto; pointer-events: none; }\n.isard-ctrl-compass svg { transition: transform 0.05s; }\n.isard-marker { position: absolute; top: 0; left: 0; pointer-events: auto; will-change: transform; }\n.isard-marker-draggable { cursor: grab; touch-action: none; }\n.isard-marker-dragging { cursor: grabbing; }\n.isard-marker-stem { position: absolute; z-index: -1; width: 2px; margin-left: -1px; transform-origin: top center; background: var(--isard-marker-color); opacity: 0.8; pointer-events: none; }\n.isard-marker-stem::after { content: \"\"; position: absolute; bottom: -3px; left: -2px; width: 6px; height: 6px; border-radius: 50%; background: inherit; }\n.isard-marker-pin { display: block; color: var(--isard-marker-color); filter: drop-shadow(0 1px 2px rgb(0 0 0 / 0.35)); }\n.isard-panel { position: absolute; top: 0; left: 0; transform-origin: 0 0; pointer-events: auto; will-change: transform; }\n.isard-popup {\n position: absolute; top: 0; left: 0; display: flex; pointer-events: none; will-change: transform; z-index: 1;\n color: var(--isard-popup-fg);\n}\n.isard-popup-anchor-top, .isard-popup-anchor-top-left, .isard-popup-anchor-top-right { flex-direction: column; }\n.isard-popup-anchor-bottom, .isard-popup-anchor-bottom-left, .isard-popup-anchor-bottom-right {\n flex-direction: column-reverse;\n}\n.isard-popup-anchor-left { flex-direction: row; }\n.isard-popup-anchor-right { flex-direction: row-reverse; }\n.isard-popup-tip { width: 0; height: 0; border: 10px solid transparent; z-index: 1; }\n.isard-popup-anchor-top .isard-popup-tip { align-self: center; border-top: none; border-bottom-color: var(--isard-popup-bg); }\n.isard-popup-anchor-top-left .isard-popup-tip {\n align-self: flex-start; border-top: none; border-left: none; border-bottom-color: var(--isard-popup-bg);\n}\n.isard-popup-anchor-top-right .isard-popup-tip {\n align-self: flex-end; border-top: none; border-right: none; border-bottom-color: var(--isard-popup-bg);\n}\n.isard-popup-anchor-bottom .isard-popup-tip { align-self: center; border-bottom: none; border-top-color: var(--isard-popup-bg); }\n.isard-popup-anchor-bottom-left .isard-popup-tip {\n align-self: flex-start; border-bottom: none; border-left: none; border-top-color: var(--isard-popup-bg);\n}\n.isard-popup-anchor-bottom-right .isard-popup-tip {\n align-self: flex-end; border-bottom: none; border-right: none; border-top-color: var(--isard-popup-bg);\n}\n.isard-popup-anchor-left .isard-popup-tip { align-self: center; border-left: none; border-right-color: var(--isard-popup-bg); }\n.isard-popup-anchor-right .isard-popup-tip { align-self: center; border-right: none; border-left-color: var(--isard-popup-bg); }\n.isard-popup-content {\n position: relative; padding: 12px 14px; border-radius: 4px; background: var(--isard-popup-bg);\n box-shadow: 0 1px 4px rgb(0 0 0 / 0.2); pointer-events: auto; overflow-wrap: break-word;\n}\n.isard-popup-has-close .isard-popup-content { padding-right: 26px; }\n.isard-popup-anchor-top-left .isard-popup-content { border-top-left-radius: 0; }\n.isard-popup-anchor-top-right .isard-popup-content { border-top-right-radius: 0; }\n.isard-popup-anchor-bottom-left .isard-popup-content { border-bottom-left-radius: 0; }\n.isard-popup-anchor-bottom-right .isard-popup-content { border-bottom-right-radius: 0; }\n.isard-popup-close {\n position: absolute; top: 0; right: 0; width: 22px; height: 22px; padding: 0; border: 0; border-radius: 0 4px 0 4px;\n background: transparent; color: inherit; font: 18px/22px system-ui, sans-serif; cursor: pointer;\n}\n.isard-popup-close:hover { background: rgb(0 0 0 / 0.05); }\n.isard-popup-close:focus-visible, .isard-attrib-button:focus-visible, .isard-attrib a:focus-visible {\n outline: 2px solid var(--isard-focus); outline-offset: -2px;\n}\n.isard-attrib {\n display: flex; align-items: center; gap: 4px; padding: 0 5px; border-radius: 4px; background: var(--isard-attrib-bg);\n color: var(--isard-attrib-fg); font: 12px/20px system-ui, sans-serif;\n}\n.isard-ctrl-bottom-right .isard-ctrl.isard-attrib, .isard-ctrl-bottom-left .isard-ctrl.isard-attrib { margin-bottom: 0; }\n.isard-ctrl-bottom-right .isard-ctrl.isard-attrib { margin-right: 0; border-radius: 4px 0 0 0; }\n.isard-ctrl-bottom-left .isard-ctrl.isard-attrib { margin-left: 0; border-radius: 0 4px 0 0; }\n.isard-attrib a { color: inherit; text-decoration: none; }\n.isard-attrib a:hover { text-decoration: underline; }\n.isard-attrib-button {\n display: none; width: 24px; height: 24px; padding: 0; border: 0; border-radius: 12px; flex: none;\n background: var(--isard-ctrl-bg); color: var(--isard-ctrl-fg); cursor: pointer;\n}\n.isard-attrib-button svg { display: block; margin: auto; }\n.isard-ctrl.isard-attrib.isard-attrib-compact { min-height: 24px; padding: 2px; border-radius: 12px; margin: 0 10px 10px; }\n.isard-attrib-compact .isard-attrib-button { display: block; }\n.isard-attrib-compact .isard-attrib-inner { display: none; padding: 0 6px 0 2px; }\n.isard-attrib-compact.isard-attrib-open { background: var(--isard-ctrl-bg); }\n.isard-attrib-compact.isard-attrib-open .isard-attrib-inner { display: block; }\n`;\n\nconst styled = new WeakSet<Document>();\n\n/** Adds the overlay styles to a document, once; first in the head so application rules win at equal specificity */\nexport function injectStyle(doc: Document): void {\n if (styled.has(doc)) return;\n styled.add(doc);\n const style = doc.createElement('style');\n style.dataset.isard = '';\n style.textContent = CSS;\n doc.head.prepend(style);\n}\n"]}
@@ -1,5 +1,9 @@
1
- import type { AnimationOptions, FlyToOptions } from './types.ts';
2
- import type { Camera, Engine } from './wasm/isard.js';
1
+ /**
2
+ * Camera animations: each is a step run every frame by the map (`GeoMap.animate`) until it returns false, setting the
3
+ * camera of the engine in use at that frame (it may be replaced during a flight).
4
+ */
5
+ import type { AnimationOptions, FlyToOptions } from '../types.ts';
6
+ import type { Camera, Engine } from '../wasm/isard.js';
3
7
  /** A step of an animation, at `now` (milliseconds, the frame's time): false once done */
4
8
  export type Step = (now: number) => boolean;
5
9
  /** What a step needs of the engine, read at each frame */
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animation.js","sourceRoot":"","sources":["../../src/util/animation.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Camera animations: each is a step run every frame by the map (`GeoMap.animate`) until it returns false, setting the\n * camera of the engine in use at that frame (it may be replaced during a flight).\n */\n\nimport type { AnimationOptions, FlyToOptions } from '../types.ts';\nimport type { Camera, Engine } from '../wasm/isard.js';\nimport { fromMercator, toMercator } from './geo.ts';\n\n/** A step of an animation, at `now` (milliseconds, the frame's time): false once done */\nexport type Step = (now: number) => boolean;\n\n/** What a step needs of the engine, read at each frame */\ntype Target = () => Pick<Engine, 'setCamera' | 'clearPreload'>;\n\n/** MapLibre's default easing: cubic Bézier (0.25, 0.1, 0.25, 1) */\nexport function defaultEasing(t: number): number {\n if (t <= 0 || t >= 1) return Math.max(0, Math.min(1, t));\n // Solve x(u) = t for the curve parameter, Newton then bisection\n const [x1, y1, x2, y2] = [0.25, 0.1, 0.25, 1];\n const bezier = (u: number, a: number, b: number) => 3 * a * u * (1 - u) ** 2 + 3 * b * u * u * (1 - u) + u ** 3;\n let u = t;\n for (let i = 0; i < 8; i += 1) {\n const x = bezier(u, x1, x2) - t;\n const dx = 3 * x1 * (1 - u) ** 2 + 6 * (x2 - x1) * u * (1 - u) + 3 * (1 - x2) * u * u;\n if (Math.abs(x) < 1e-6 || dx === 0) break;\n u = Math.max(0, Math.min(1, u - x / dx));\n }\n return bezier(u, y1, y2);\n}\n\n/** The step of an animated move from `from` to `to`: over `duration` milliseconds (or the options), ease-out by\n * default, the bearing turning the shortest way round */\nexport function easeTo(engine: Target, from: Camera, to: Camera, options: number | AnimationOptions = 600): Step {\n const { duration = 600, easing = (t: number) => 1 - (1 - t) ** 3 } =\n typeof options === 'number' ? { duration: options } : options;\n // Shortest way round\n const turn = ((to.bearing - from.bearing + 540) % 360) - 180;\n const start = performance.now();\n return (now) => {\n if (now - start >= duration) engine().clearPreload();\n const t = duration > 0 ? Math.min(1, (now - start) / duration) : 1;\n const k = easing(t);\n const mix = (a: number, b: number) => a + (b - a) * k;\n engine().setCamera(\n mix(from.center[0], to.center[0]),\n mix(from.center[1], to.center[1]),\n mix(from.zoom, to.zoom),\n mix(from.pitch, to.pitch),\n from.bearing + turn * k,\n );\n return t < 1;\n };\n}\n\n/**\n * The step of a flight from `from` to `to` that zooms out on its way and back in (van Wijk and Nuij's optimal path, as\n * MapLibre's `flyTo`): long moves stay readable. Pitch and bearing follow the progress. `viewport`: the larger side of\n * the canvas, CSS pixels.\n */\nexport function flyTo(engine: Target, from: Camera, to: Camera, viewport: number, options: FlyToOptions = {}): Step {\n const { curve: rho = 1.42, speed = 1.2, easing = defaultEasing } = options;\n const [x0, y0] = toMercator(from.center);\n const [x1, y1] = toMercator(to.center);\n // Across the antimeridian, the short way\n const dx = x1 - x0 - Math.round(x1 - x0);\n const dy = y1 - y0;\n // In pixels at the start zoom (512 px world at zoom 0)\n const world = 512 * 2 ** from.zoom;\n const u1 = Math.hypot(dx, dy) * world;\n const w0 = Math.max(viewport, 1);\n const w1 = w0 / 2 ** (to.zoom - from.zoom);\n const rho2 = rho * rho;\n const r = (i: 0 | 1) => {\n const b = (w1 * w1 - w0 * w0 + (i ? -1 : 1) * rho2 * rho2 * u1 * u1) / (2 * (i ? w1 : w0) * rho2 * u1);\n return Math.log(Math.sqrt(b * b + 1) - b);\n };\n // No move on the ground (or nearly): a plain zoom\n const still = u1 < 1e-6 || !Number.isFinite(r(0)) || !Number.isFinite(r(1));\n const r0 = still ? 0 : r(0);\n const length = still ? Math.abs(Math.log(w1 / w0)) / rho : (r(1) - r0) / rho;\n const width = (s: number) =>\n still ? Math.exp((w1 < w0 ? -1 : 1) * rho * s) : Math.cosh(r0) / Math.cosh(r0 + rho * s);\n const along = (s: number) =>\n still ? 0 : (w0 * ((Math.cosh(r0) * Math.tanh(r0 + rho * s) - Math.sinh(r0)) / rho2)) / u1;\n const duration = options.duration ?? (1000 * length) / speed;\n const turn = ((to.bearing - from.bearing + 540) % 360) - 180;\n const start = performance.now();\n return (now) => {\n if (now - start >= duration) engine().clearPreload();\n const t = duration > 0 ? Math.min(1, (now - start) / duration) : 1;\n const k = easing(t);\n const s = k * length;\n const u = t >= 1 ? 1 : along(s);\n const zoom = t >= 1 ? to.zoom : from.zoom + Math.log2(1 / width(s));\n const [lon, lat] = fromMercator([x0 + dx * u, y0 + dy * u]);\n engine().setCamera(lon, lat, zoom, from.pitch + (to.pitch - from.pitch) * k, from.bearing + turn * k);\n return t < 1;\n };\n}\n"]}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color.js","sourceRoot":"","sources":["../../src/util/color.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * CSS colors to RGBA 0-1: `#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`, `rgb()` and `rgba()`, `hsl()` and `hsla()` (comma\n * or space syntax, `/` before the alpha, percentages), the CSS named colors and `transparent`. No DOM: the workers use\n * it too.\n */\n\nexport type Rgba = [r: number, g: number, b: number, a: number];\n\n/** The CSS named colors, as name and `rrggbb` pairs */\nconst NAMES =\n 'aliceblue f0f8ff antiquewhite faebd7 aqua 00ffff aquamarine 7fffd4 azure f0ffff beige f5f5dc bisque ffe4c4 ' +\n 'black 000000 blanchedalmond ffebcd blue 0000ff blueviolet 8a2be2 brown a52a2a burlywood deb887 cadetblue 5f9ea0 ' +\n 'chartreuse 7fff00 chocolate d2691e coral ff7f50 cornflowerblue 6495ed cornsilk fff8dc crimson dc143c ' +\n 'cyan 00ffff darkblue 00008b darkcyan 008b8b darkgoldenrod b8860b darkgray a9a9a9 darkgreen 006400 ' +\n 'darkgrey a9a9a9 darkkhaki bdb76b darkmagenta 8b008b darkolivegreen 556b2f darkorange ff8c00 darkorchid 9932cc ' +\n 'darkred 8b0000 darksalmon e9967a darkseagreen 8fbc8f darkslateblue 483d8b darkslategray 2f4f4f ' +\n 'darkslategrey 2f4f4f darkturquoise 00ced1 darkviolet 9400d3 deeppink ff1493 deepskyblue 00bfff dimgray 696969 ' +\n 'dimgrey 696969 dodgerblue 1e90ff firebrick b22222 floralwhite fffaf0 forestgreen 228b22 fuchsia ff00ff ' +\n 'gainsboro dcdcdc ghostwhite f8f8ff gold ffd700 goldenrod daa520 gray 808080 green 008000 greenyellow adff2f ' +\n 'grey 808080 honeydew f0fff0 hotpink ff69b4 indianred cd5c5c indigo 4b0082 ivory fffff0 khaki f0e68c ' +\n 'lavender e6e6fa lavenderblush fff0f5 lawngreen 7cfc00 lemonchiffon fffacd lightblue add8e6 lightcoral f08080 ' +\n 'lightcyan e0ffff lightgoldenrodyellow fafad2 lightgray d3d3d3 lightgreen 90ee90 lightgrey d3d3d3 ' +\n 'lightpink ffb6c1 lightsalmon ffa07a lightseagreen 20b2aa lightskyblue 87cefa lightslategray 778899 ' +\n 'lightslategrey 778899 lightsteelblue b0c4de lightyellow ffffe0 lime 00ff00 limegreen 32cd32 linen faf0e6 ' +\n 'magenta ff00ff maroon 800000 mediumaquamarine 66cdaa mediumblue 0000cd mediumorchid ba55d3 ' +\n 'mediumpurple 9370db mediumseagreen 3cb371 mediumslateblue 7b68ee mediumspringgreen 00fa9a ' +\n 'mediumturquoise 48d1cc mediumvioletred c71585 midnightblue 191970 mintcream f5fffa mistyrose ffe4e1 ' +\n 'moccasin ffe4b5 navajowhite ffdead navy 000080 oldlace fdf5e6 olive 808000 olivedrab 6b8e23 orange ffa500 ' +\n 'orangered ff4500 orchid da70d6 palegoldenrod eee8aa palegreen 98fb98 paleturquoise afeeee ' +\n 'palevioletred db7093 papayawhip ffefd5 peachpuff ffdab9 peru cd853f pink ffc0cb plum dda0dd ' +\n 'powderblue b0e0e6 purple 800080 rebeccapurple 663399 red ff0000 rosybrown bc8f8f royalblue 4169e1 ' +\n 'saddlebrown 8b4513 salmon fa8072 sandybrown f4a460 seagreen 2e8b57 seashell fff5ee sienna a0522d ' +\n 'silver c0c0c0 skyblue 87ceeb slateblue 6a5acd slategray 708090 slategrey 708090 snow fffafa ' +\n 'springgreen 00ff7f steelblue 4682b4 tan d2b48c teal 008080 thistle d8bfd8 tomato ff6347 turquoise 40e0d0 ' +\n 'violet ee82ee wheat f5deb3 white ffffff whitesmoke f5f5f5 yellow ffff00 yellowgreen 9acd32';\n\nlet named: Map<string, string> | undefined;\n\nfunction namedHex(name: string): string | undefined {\n if (!named) {\n named = new Map();\n const words = NAMES.split(' ');\n for (let i = 0; i + 1 < words.length; i += 2) named.set(words[i] as string, words[i + 1] as string);\n }\n return named.get(name);\n}\n\nconst clamp = (v: number) => (Number.isFinite(v) ? Math.max(0, Math.min(1, v)) : 0);\n\nfunction hex(digits: string): Rgba | undefined {\n if (!/^[0-9a-f]+$/.test(digits) || ![3, 4, 6, 8].includes(digits.length)) return undefined;\n const full = digits.length <= 4 ? [...digits].map((h) => h + h).join('') : digits;\n const v = (i: number) => Number.parseInt(full.slice(i, i + 2), 16) / 255;\n return [v(0), v(2), v(4), full.length === 8 ? v(6) : 1];\n}\n\n/** An alpha: a number from 0 to 1 or a percentage */\nfunction alpha(p: string | undefined): number {\n if (p === undefined) return 1;\n return clamp(p.endsWith('%') ? Number.parseFloat(p) / 100 : Number.parseFloat(p));\n}\n\nfunction hsl(h: number, s: number, l: number): [number, number, number] {\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n const p = 2 * l - q;\n const hue = (t: number) => {\n const u = ((t % 1) + 1) % 1;\n if (u < 1 / 6) return p + (q - p) * 6 * u;\n if (u < 1 / 2) return q;\n if (u < 2 / 3) return p + (q - p) * (2 / 3 - u) * 6;\n return p;\n };\n return [hue(h + 1 / 3), hue(h), hue(h - 1 / 3)];\n}\n\n/** A CSS color to RGBA 0-1; undefined if it is not one */\nexport function parseCssColor(value: unknown): Rgba | undefined {\n if (typeof value !== 'string') return undefined;\n const c = value.trim().toLowerCase();\n if (c.startsWith('#')) return hex(c.slice(1));\n if (c === 'transparent') return [0, 0, 0, 0];\n const name = namedHex(c);\n if (name) return hex(name);\n const match = /^(rgba?|hsla?)\\(([^)]*)\\)$/.exec(c);\n if (!match?.[1] || match[2] === undefined) return undefined;\n const parts = match[2].split(/[\\s,/]+/).filter(Boolean);\n if (parts.length < 3 || parts.slice(0, 3).some((p) => Number.isNaN(Number.parseFloat(p)))) return undefined;\n const a = alpha(parts[3]);\n if (match[1].startsWith('rgb')) {\n const channel = (p: string) => clamp(p.endsWith('%') ? Number.parseFloat(p) / 100 : Number.parseFloat(p) / 255);\n return [channel(parts[0] as string), channel(parts[1] as string), channel(parts[2] as string), a];\n }\n const h = Number.parseFloat(parts[0] as string) / 360;\n const [r, g, b] = hsl(\n h,\n clamp(Number.parseFloat(parts[1] as string) / 100),\n clamp(Number.parseFloat(parts[2] as string) / 100),\n );\n return [r, g, b, a];\n}\n"]}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geo.js","sourceRoot":"","sources":["../../src/util/geo.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,sEAAsE;AACtE,MAAM,OAAO,GAAG,kBAAkB,CAAC;AAEnC,0CAA0C;AAC1C,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,OAAO,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AAC3B,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC;IACzE,OAAO,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC;AACzE,CAAC;AAED,0CAA0C;AAC1C,MAAM,UAAU,SAAS,CAAC,CAAS;IACjC,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC;AACvB,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,QAAQ,CAAC,CAAS;IAChC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;AACvE,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,UAAU,CAAC,CAAC,GAAG,EAAE,GAAG,CAA0C;IAC5E,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAA4B;IAC5D,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,CAAC","sourcesContent":["/**\n * Web Mercator in [0, 1] across the world (y towards the south), for the page and the workers alike: the positions\n * sent to the engine, the tiles of a view, the flights, the label candidates of the vector tiles.\n */\n\n/** The latitude where Web Mercator is square: the edges of the map */\nconst MAX_LAT = 85.051128779806589;\n\n/** Mercator x of a longitude (degrees) */\nexport function mercatorX(lon: number): number {\n return (lon + 180) / 360;\n}\n\n/** Mercator y of a latitude (degrees), clamped to the edges of the map */\nexport function mercatorY(lat: number): number {\n const phi = (Math.max(-MAX_LAT, Math.min(MAX_LAT, lat)) * Math.PI) / 180;\n return 0.5 - Math.log(Math.tan(Math.PI / 4 + phi / 2)) / (2 * Math.PI);\n}\n\n/** Longitude (degrees) of a Mercator x */\nexport function longitude(x: number): number {\n return x * 360 - 180;\n}\n\n/** Latitude (degrees) of a Mercator y */\nexport function latitude(y: number): number {\n return (Math.atan(Math.sinh(Math.PI * (1 - 2 * y))) * 180) / Math.PI;\n}\n\n/** Mercator x, y of a longitude and latitude */\nexport function toMercator([lon, lat]: readonly [number, number, ...unknown[]]): [x: number, y: number] {\n return [mercatorX(lon), mercatorY(lat)];\n}\n\n/** Longitude and latitude of a Mercator x, y */\nexport function fromMercator([x, y]: readonly [number, number]): [lon: number, lat: number] {\n return [longitude(x), latitude(y)];\n}\n"]}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lru.js","sourceRoot":"","sources":["../../src/util/lru.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,OAAO,GAAG;IAKL;IACU;IALF,OAAO,GAAG,IAAI,GAAG,EAAQ,CAAC;IAE3C,0EAA0E;IAC1E,YACS,QAAgB,EACN,KAAkC;QAD5C,aAAQ,GAAR,QAAQ,CAAQ;QACN,UAAK,GAAL,KAAK,CAA6B;IAClD,CAAC;IAEJ,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;IAED,0EAA0E;IAC1E,GAAG,CAAC,GAAM;QACR,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC/B,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,8CAA8C;IAC9C,GAAG,CAAC,GAAM;QACR,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;IAED,sGAAsG;IACtG,GAAG,CAAC,GAAM,EAAE,KAAQ;QAClB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC7B,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACzC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ;gBAAE,MAAM;YAC9C,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC5B,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,MAAM,CAAC,GAAM;QACX,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IAED,4CAA4C;IAC5C,MAAM;QACJ,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;IAC/B,CAAC;IAED,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;CACF","sourcesContent":["/**\n * A cache keeping its most recently used entries (the decoded tiles and images of the workers, the source tiles of a\n * reprojection, the labels of the vector tiles): a `Map` in order of use, the least recent dropped past `capacity`.\n */\nexport class Lru<K, V> {\n private readonly entries = new Map<K, V>();\n\n /** `evict`: told of each entry dropped for room (not of those deleted) */\n constructor(\n public capacity: number,\n private readonly evict?: (value: V, key: K) => void,\n ) {}\n\n get size(): number {\n return this.entries.size;\n }\n\n /** The value of a key, now the most recently used; undefined if absent */\n get(key: K): V | undefined {\n const value = this.entries.get(key);\n if (value !== undefined) {\n this.entries.delete(key);\n this.entries.set(key, value);\n }\n return value;\n }\n\n /** Whether a key is kept, without using it */\n has(key: K): boolean {\n return this.entries.has(key);\n }\n\n /** Adds or replaces a value, the most recently used; drops the least recent ones past the capacity */\n set(key: K, value: V): void {\n this.entries.delete(key);\n this.entries.set(key, value);\n for (const [oldest, old] of this.entries) {\n if (this.entries.size <= this.capacity) break;\n this.entries.delete(oldest);\n this.evict?.(old, oldest);\n }\n }\n\n delete(key: K): boolean {\n return this.entries.delete(key);\n }\n\n /** The values, least recently used first */\n values(): IterableIterator<V> {\n return this.entries.values();\n }\n\n clear(): void {\n this.entries.clear();\n }\n}\n"]}
@@ -1,7 +1,17 @@
1
- import { type HeaderRules } from './requests.ts';
2
- import { type Job } from './resample.ts';
3
- import { type PngEncoding } from './terrain.ts';
4
- import { type LabelCandidate, type RasterSource, type StyleLayer } from './vectorstyle.ts';
1
+ /**
2
+ * Worker of the vector basemaps: fetches and decodes vector tiles (kept for the tiles that share them), draws their
3
+ * fills, lines and circles with a MapLibre style into images (Canvas 2D, off the main thread) for the raster pool,
4
+ * with the style's raster layers under them, and lists the label candidates of the style's symbol layers (their texts
5
+ * and icons) for the page to shape and place. Extrusions are drawn flat, as fills. It also decodes the altitudes of PNG relief tiles and
6
+ * draws the rasters reprojected from other grids (planned by the page), for the map's other layers.
7
+ *
8
+ * A raster tile of level z covers 256 CSS pixels at map zoom z - 1 (MapLibre's 512 px convention): it is drawn from
9
+ * the vector tile of level z - 1 (or the deepest one the source has), with the style at that zoom.
10
+ */
11
+ import { type Job } from '../basemap/resample.ts';
12
+ import { type PngEncoding } from '../basemap/terrain.ts';
13
+ import { type LabelCandidate, type RasterSource, type StyleLayer } from '../basemap/vectorstyle.ts';
14
+ import { type HeaderRules } from '../engine/requests.ts';
5
15
  export type { LabelCandidate, RasterSource };
6
16
  /** Fetch priority of a request (`fetch`'s `priority`, a hint to the browser) */
7
17
  export type Priority = 'high' | 'low' | 'auto';