isard 0.8.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/dist/basemaps.d.ts +3 -3
- package/dist/basemaps.js +2 -14
- package/dist/basemaps.js.map +1 -1
- package/dist/controls.d.ts +4 -3
- package/dist/controls.js +0 -8
- package/dist/controls.js.map +1 -1
- package/dist/engine-loader.d.ts +11 -4
- package/dist/engine-loader.js +36 -5
- package/dist/engine-loader.js.map +1 -1
- package/dist/geoplateforme.d.ts +51 -1
- package/dist/geoplateforme.js +34 -0
- package/dist/geoplateforme.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/isard_bg.wasm +0 -0
- package/dist/isard_core_bg.wasm +0 -0
- package/dist/layers.d.ts +3 -2
- package/dist/layers.js +15 -4
- package/dist/layers.js.map +1 -1
- package/dist/map.d.ts +78 -3
- package/dist/map.js +93 -12
- package/dist/map.js.map +1 -1
- package/dist/types.d.ts +11 -7
- package/dist/types.js.map +1 -1
- package/dist/vectortiles.d.ts +2 -2
- package/dist/vectortiles.js +4 -3
- package/dist/vectortiles.js.map +1 -1
- package/package.json +8 -2
- package/vite.d.ts +17 -0
- package/vite.js +64 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,35 @@
|
|
|
3
3
|
Every notable change of `isard` (published as `@ign-junn/isard` up to 0.1.1). The format follows [Keep a Changelog](https://keepachangelog.com), the
|
|
4
4
|
versions [Semantic Versioning](https://semver.org) (before 1.0.0, a minor version may change an API).
|
|
5
5
|
|
|
6
|
+
## [1.0.0] - 2026-10-21
|
|
7
|
+
|
|
8
|
+
The first stable version: its API is kept until 2.0 (additions only in between).
|
|
9
|
+
|
|
10
|
+
### Removed
|
|
11
|
+
|
|
12
|
+
The forms deprecated since 0.4 to 0.6, for an API to keep from 1.0 on:
|
|
13
|
+
|
|
14
|
+
- The former names of the Géoplateforme basemaps (`'plan'`, `'plan-grey'`, `'plan-vector'`, `'plan-grey-vector'`,
|
|
15
|
+
`'ortho'`, and the `LegacyBasemap` type): an error names the new one (`'ign-plan'`…).
|
|
16
|
+
- The positional `RasterLayer.setStyle(opacity, saturation)`: `setStyle({ opacity, saturation })`.
|
|
17
|
+
- `DEFAULT_ATTRIBUTION`: `IGN_ATTRIBUTION`.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- `isard/vite`, a Vite plugin: nothing else to configure for a Vite application (the package kept out of the
|
|
22
|
+
dependency pre-bundling and allowed to the development server; in a build, the engines and workers copied to
|
|
23
|
+
`dist/isard/` and the maps of the page told where they are, the engines not copied twice).
|
|
24
|
+
- `assetsUrl`: the one folder isard's five files are served from, instead of five URLs.
|
|
25
|
+
- IGN presets: `preset: 'ign' | 'ign-3d' | 'ign-ortho-3d'` (`IGN_PRESETS`), the other options over them;
|
|
26
|
+
`bdtopoBuildings(box)` (the BD TOPO buildings of a box, raised to their height) and `batiments3d()` (the IGN's
|
|
27
|
+
Bâtiments 3D, `geoid` set, colored), the options of their layers in a call.
|
|
28
|
+
- `map.add({ type, ...options })`: a layer from a configuration (`LayerSpec`: `lines`, `circles`, `fills`, `symbols`,
|
|
29
|
+
`extrusions`, `raster`, `ground`, `network`, `tiles3d`, `pointcloud`, `models`); `layer.ready`, resolved once the
|
|
30
|
+
map has drawn the layer.
|
|
31
|
+
- The map's methods grouped by theme, the same as its own: `map.camera` (`get`, `set`, `easeTo`, `flyTo`, `bounds`,
|
|
32
|
+
`firstPerson`, `setFirstPerson`, `project`, `unproject`), `map.query` (`feature`, `surface`, `surfaceAt`,
|
|
33
|
+
`elevationAt`, `metersPerPixel`), `map.effects` (`viewshed`, `swipe`).
|
|
34
|
+
|
|
6
35
|
## [0.8.0] - 2026-10-21
|
|
7
36
|
|
|
8
37
|
### Added
|
package/dist/basemaps.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/** The basemaps by name: OpenFreeMap's vector styles (OpenStreetMap data, worldwide) and the Géoplateforme's (IGN,
|
|
2
2
|
* France), the credits of the sources, and the relief of each body */
|
|
3
3
|
import { IGN_ATTRIBUTION } from './geoplateforme.ts';
|
|
4
|
-
import type {
|
|
4
|
+
import type { BasemapName, RasterOptions } from './types.ts';
|
|
5
5
|
export { IGN_ATTRIBUTION };
|
|
6
6
|
/** The raster basemaps of the Géoplateforme (WMTS, Web Mercator), crediting the IGN */
|
|
7
7
|
export declare const BASEMAPS: Record<'ign-plan' | 'ign-plan-grey' | 'ign-ortho', RasterOptions>;
|
|
8
|
-
/**
|
|
9
|
-
export declare
|
|
8
|
+
/** The former names of the Géoplateforme basemaps (before 0.5), and their names now: an error tells it */
|
|
9
|
+
export declare const RENAMED_BASEMAPS: Record<string, BasemapName>;
|
|
10
10
|
/** Credits of OpenFreeMap's basemaps, as its TileJSON gives them */
|
|
11
11
|
export declare const OPENFREEMAP_ATTRIBUTION: string;
|
|
12
12
|
/** Credits of the Terrain Tiles of AWS's open data registry (Mapzen's Terrarium tiles) and of their sources */
|
package/dist/basemaps.js
CHANGED
|
@@ -9,26 +9,14 @@ export const BASEMAPS = {
|
|
|
9
9
|
'ign-plan-grey': geoplateformeWmts(PLAN, { saturation: 0 }),
|
|
10
10
|
'ign-ortho': geoplateformeWmts('ORTHOIMAGERY.ORTHOPHOTOS', { format: 'image/jpeg' }),
|
|
11
11
|
};
|
|
12
|
-
/** The former names of the Géoplateforme basemaps,
|
|
13
|
-
const
|
|
12
|
+
/** The former names of the Géoplateforme basemaps (before 0.5), and their names now: an error tells it */
|
|
13
|
+
export const RENAMED_BASEMAPS = {
|
|
14
14
|
plan: 'ign-plan',
|
|
15
15
|
'plan-grey': 'ign-plan-grey',
|
|
16
16
|
ortho: 'ign-ortho',
|
|
17
17
|
'plan-vector': 'ign-plan-vector',
|
|
18
18
|
'plan-grey-vector': 'ign-plan-grey-vector',
|
|
19
19
|
};
|
|
20
|
-
const warned = new Set();
|
|
21
|
-
/** A basemap by its current name: a former one is warned about once, then taken under its new name */
|
|
22
|
-
export function basemapName(basemap) {
|
|
23
|
-
const renamed = LEGACY[basemap];
|
|
24
|
-
if (!renamed)
|
|
25
|
-
return basemap;
|
|
26
|
-
if (!warned.has(basemap)) {
|
|
27
|
-
warned.add(basemap);
|
|
28
|
-
console.warn(`isard: the basemap '${basemap}' is deprecated, it is now named '${renamed}'`);
|
|
29
|
-
}
|
|
30
|
-
return renamed;
|
|
31
|
-
}
|
|
32
20
|
/** Credits of OpenFreeMap's basemaps, as its TileJSON gives them */
|
|
33
21
|
export const OPENFREEMAP_ATTRIBUTION = '<a href="https://openfreemap.org">OpenFreeMap</a> <a href="https://www.openmaptiles.org/">© OpenMapTiles</a> ' +
|
|
34
22
|
'Data from <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>';
|
package/dist/basemaps.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"basemaps.js","sourceRoot":"","sources":["../src/basemaps.ts"],"names":[],"mappings":"AAAA;sEACsE;AACtE,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGxE,OAAO,EAAE,eAAe,EAAE,CAAC;AAE3B,MAAM,IAAI,GAAG,mCAAmC,CAAC;AAEjD,uFAAuF;AACvF,MAAM,CAAC,MAAM,QAAQ,GAAsE;IACzF,UAAU,EAAE,iBAAiB,CAAC,IAAI,CAAC;IACnC,eAAe,EAAE,iBAAiB,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;IAC3D,WAAW,EAAE,iBAAiB,CAAC,0BAA0B,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;CACrF,CAAC;AAEF,
|
|
1
|
+
{"version":3,"file":"basemaps.js","sourceRoot":"","sources":["../src/basemaps.ts"],"names":[],"mappings":"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","sourcesContent":["/** The basemaps by name: OpenFreeMap's vector styles (OpenStreetMap data, worldwide) and the Géoplateforme's (IGN,\n * France), the credits of the sources, and the relief of each body */\nimport { geoplateformeWmts, IGN_ATTRIBUTION } from './geoplateforme.ts';\nimport type { BasemapName, RasterOptions } from './types.ts';\n\nexport { IGN_ATTRIBUTION };\n\nconst PLAN = 'GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2';\n\n/** The raster basemaps of the Géoplateforme (WMTS, Web Mercator), crediting the IGN */\nexport const BASEMAPS: Record<'ign-plan' | 'ign-plan-grey' | 'ign-ortho', RasterOptions> = {\n 'ign-plan': geoplateformeWmts(PLAN),\n 'ign-plan-grey': geoplateformeWmts(PLAN, { saturation: 0 }),\n 'ign-ortho': geoplateformeWmts('ORTHOIMAGERY.ORTHOPHOTOS', { format: 'image/jpeg' }),\n};\n\n/** The former names of the Géoplateforme basemaps (before 0.5), and their names now: an error tells it */\nexport const RENAMED_BASEMAPS: Record<string, BasemapName> = {\n plan: 'ign-plan',\n 'plan-grey': 'ign-plan-grey',\n ortho: 'ign-ortho',\n 'plan-vector': 'ign-plan-vector',\n 'plan-grey-vector': 'ign-plan-grey-vector',\n};\n\n/** Credits of OpenFreeMap's basemaps, as its TileJSON gives them */\nexport const OPENFREEMAP_ATTRIBUTION =\n '<a href=\"https://openfreemap.org\">OpenFreeMap</a> <a href=\"https://www.openmaptiles.org/\">© OpenMapTiles</a> ' +\n 'Data from <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a>';\n\n/** Credits of the Terrain Tiles of AWS's open data registry (Mapzen's Terrarium tiles) and of their sources */\nexport const TERRAIN_TILES_ATTRIBUTION =\n '<a href=\"https://github.com/tilezen/joerd/blob/master/docs/attribution.md\">Terrain Tiles</a> (Mapzen, AWS)';\n\n/** IGN hillshade, grey on transparent, zooms 6 to 17 */\nexport const HILLSHADE: RasterOptions = geoplateformeWmts('IGNF_ELEVATION.ELEVATIONGRIDCOVERAGE.SHADOW', {\n minZoom: 6,\n maxZoom: 17,\n});\n\n/** IGN terrain model (RGE ALTI and its fill-ins, France), raw altitudes in metres from the Géoplateforme WMS */\nexport const TERRAIN_URL =\n 'https://data.geopf.fr/wms-r/wms?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&LAYERS=ELEVATION.ELEVATIONGRIDCOVERAGE.HIGHRES' +\n '&STYLES=&CRS=EPSG:3857&BBOX={bbox}&WIDTH=256&HEIGHT=256&FORMAT=image/x-bil;bits=32';\n\n/** The relief of the Moon and Mars by default: NASA's Trek image services (ArcGIS), raw 32-bit altitudes in metres\n * asked for in the body's Mercator, with their credits. The Moon: LOLA's global model, 128 pixels per degree (237 m);\n * Mars: MOLA's, 128 and 64 pixels per degree merged (463 m), above the areoid */\nexport const BODY_TERRAINS = {\n moon: {\n url: 'https://trek.nasa.gov/moon/trekarcgis/rest/services/LRO_LOLA_DEM_Global_128ppd_v04/ImageServer',\n maxZoom: 8,\n attribution: '<a href=\"https://trek.nasa.gov/moon/\">NASA Moon Trek</a>: LOLA terrain model, NASA/GSFC/MIT',\n },\n mars: {\n url: 'https://trek.nasa.gov/mars/trekarcgis/rest/services/mola128_mola64_merge_90Nto90S_SimpleC_clon0/ImageServer',\n maxZoom: 8,\n attribution: '<a href=\"https://trek.nasa.gov/mars/\">NASA Mars Trek</a>: MOLA terrain model, NASA/JPL/GSFC',\n },\n} as const;\n\n/** An ArcGIS image service (a URL ending in `/ImageServer`) */\nexport const IMAGE_SERVER = /\\/ImageServer\\/?$/;\n\n/**\n * The `exportImage` template of an ArcGIS image service for the relief: 256 × 256 raw 32-bit floats (`bsq`, followed\n * by its validity mask) of the box `{bbox}` in the Mercator of the body. On the Earth, Web Mercator (EPSG:3857);\n * elsewhere, a Mercator on the sphere of `radius` metres (Web Mercator's own formulas), given in WKT.\n */\nexport function imageServerTerrain(url: string, earth: boolean, radius: number): string {\n const crs = earth\n ? '3857'\n : encodeURIComponent(\n JSON.stringify({\n wkt:\n `PROJCS[\"Mercator\",GEOGCS[\"GCS\",DATUM[\"D\",SPHEROID[\"S\",${radius},0]],PRIMEM[\"Reference_Meridian\",0],` +\n 'UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Mercator\"],PARAMETER[\"False_Easting\",0],' +\n 'PARAMETER[\"False_Northing\",0],PARAMETER[\"Central_Meridian\",0],PARAMETER[\"Standard_Parallel_1\",0],' +\n 'UNIT[\"Meter\",1]]',\n }),\n );\n return (\n `${url.replace(/\\/$/, '')}/exportImage?f=image&format=bsq&pixelType=F32&size=256,256` +\n `&bboxSR=${crs}&imageSR=${crs}&bbox={bbox}`\n );\n}\n\n/** The Earth's relief for `terrain: true`: the Terrain Tiles of AWS's open data registry, worldwide (SRTM, EU-DEM,\n * GMTED… merged by Mapzen), Terrarium PNGs of 256 px to level 14, altitudes above the mean sea level */\nexport const TERRAIN_TILES = {\n url: 'https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png',\n maxZoom: 14,\n} as const;\n\n/** Sea color of each basemap, for the globe under the tiles (polar caps), RGB 0-1 */\nexport const SEA: Record<BasemapName, [r: number, g: number, b: number]> = {\n 'osm-positron': [0.761, 0.784, 0.792],\n 'osm-liberty': [0.62, 0.741, 1],\n 'osm-bright': [0.682, 0.812, 0.886],\n 'ign-plan': [0.667, 0.835, 0.914],\n 'ign-plan-grey': [0.792, 0.792, 0.792],\n 'ign-plan-vector': [0.667, 0.835, 0.914],\n 'ign-plan-grey-vector': [0.792, 0.792, 0.792],\n 'ign-ortho': [0.039, 0.231, 0.349],\n none: [0.85, 0.85, 0.83],\n};\n"]}
|
package/dist/controls.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Controls: elements in a corner of the map. A control is anything with `onAdd` and `onRemove`, as in MapLibre, so
|
|
3
|
+
* applications write their own; the navigation buttons and the attribution are built in.
|
|
4
|
+
*/
|
|
1
5
|
import type { GeoMap } from './map.ts';
|
|
2
6
|
export type ControlPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
3
7
|
export interface Control {
|
|
@@ -22,9 +26,6 @@ export declare class NavigationControl implements Control {
|
|
|
22
26
|
onAdd(map: GeoMap): HTMLElement;
|
|
23
27
|
onRemove(): void;
|
|
24
28
|
}
|
|
25
|
-
/** @deprecated The Géoplateforme's credits, now `IGN_ATTRIBUTION`: the attribution control shows those of the sources
|
|
26
|
-
* in use */
|
|
27
|
-
export declare const DEFAULT_ATTRIBUTION = "<a href=\"https://www.ign.fr/\">\u00A9 IGN</a> \u2013 <a href=\"https://geoservices.ign.fr/\">G\u00E9oplateforme</a>";
|
|
28
29
|
export interface AttributionOptions {
|
|
29
30
|
/** Folded into a small (i) button that shows the text on click (default: when the map is narrower than 640 px) */
|
|
30
31
|
compact?: boolean;
|
package/dist/controls.js
CHANGED
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Controls: elements in a corner of the map. A control is anything with `onAdd` and `onRemove`, as in MapLibre, so
|
|
3
|
-
* applications write their own; the navigation buttons and the attribution are built in.
|
|
4
|
-
*/
|
|
5
|
-
import { IGN_ATTRIBUTION } from "./geoplateforme.js";
|
|
6
1
|
const svg = (body) => `<svg width="29" height="29" viewBox="0 0 29 29" fill="currentColor" aria-hidden="true">${body}</svg>`;
|
|
7
2
|
const PLUS = svg('<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"/>');
|
|
8
3
|
const MINUS = svg('<path d="M9.5 13.5h10a1 1 0 0 1 0 2h-10a1 1 0 0 1 0-2z"/>');
|
|
@@ -55,9 +50,6 @@ export class NavigationControl {
|
|
|
55
50
|
this.stopListening = undefined;
|
|
56
51
|
}
|
|
57
52
|
}
|
|
58
|
-
/** @deprecated The Géoplateforme's credits, now `IGN_ATTRIBUTION`: the attribution control shows those of the sources
|
|
59
|
-
* in use */
|
|
60
|
-
export const DEFAULT_ATTRIBUTION = IGN_ATTRIBUTION;
|
|
61
53
|
/** Credits of the data shown: those of the map's basemap, hillshade and relief (OpenFreeMap and OpenStreetMap, IGN,
|
|
62
54
|
* the Terrain Tiles…, followed as they change), then the page's own */
|
|
63
55
|
export class AttributionControl {
|
package/dist/controls.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controls.js","sourceRoot":"","sources":["../src/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 { IGN_ATTRIBUTION } from './geoplateforme.ts';\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\n/** @deprecated The Géoplateforme's credits, now `IGN_ATTRIBUTION`: the attribution control shows those of the sources\n * in use */\nexport const DEFAULT_ATTRIBUTION = IGN_ATTRIBUTION;\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
|
+
{"version":3,"file":"controls.js","sourceRoot":"","sources":["../src/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"]}
|
package/dist/engine-loader.d.ts
CHANGED
|
@@ -10,8 +10,15 @@ export interface Bindings {
|
|
|
10
10
|
}
|
|
11
11
|
/** `core`: the engine without 3D Tiles; `full`: with them */
|
|
12
12
|
export type EngineKind = 'core' | 'full';
|
|
13
|
-
/**
|
|
14
|
-
export
|
|
13
|
+
/** The files a map loads at run time, next to the module unless given elsewhere */
|
|
14
|
+
export type AssetFile = 'isard_bg.wasm' | 'isard_core_bg.wasm' | 'isard_points_bg.wasm' | 'decoder.worker.js' | 'basemap.worker.js';
|
|
15
|
+
/**
|
|
16
|
+
* Where a file of isard is loaded from: its own option, else in the folder `assetsUrl` (the option, or the page's
|
|
17
|
+
* as `isard/vite` sets it), else next to the module (`import.meta.url`)
|
|
18
|
+
*/
|
|
19
|
+
export declare function assetUrl(file: AssetFile, explicit: string | URL | undefined, assetsUrl?: string | URL): string | URL;
|
|
20
|
+
/** Where a build of the engine is loaded from: the option, the assets' folder, or next to the module */
|
|
21
|
+
export declare function engineUrl(kind: EngineKind, options: Pick<GeoMapOptions, 'wasmUrl' | 'coreWasmUrl' | 'assetsUrl'>): string | URL;
|
|
15
22
|
/** A build compiled and instantiated with its bindings (once per page, unless it failed) */
|
|
16
23
|
export declare function loadEngine(kind: EngineKind, url: string | URL): Promise<Bindings>;
|
|
17
24
|
/** The full engine for a map on the core one, resolved in a task of its own, not in the one that instantiated it:
|
|
@@ -22,10 +29,10 @@ export declare function loadFullEngineLater(url: string | URL): Promise<Bindings
|
|
|
22
29
|
export declare function preloadFullEngine(url: string | URL, wanted: () => boolean): void;
|
|
23
30
|
/** Where the workers load the point cloud module from (`isard_points_bg.wasm`, the LAZ decoder): the option, or next
|
|
24
31
|
* to the module; absolute, the workers being elsewhere */
|
|
25
|
-
export declare function pointsUrl(options: Pick<GeoMapOptions, 'pointsWasmUrl'>): string;
|
|
32
|
+
export declare function pointsUrl(options: Pick<GeoMapOptions, 'pointsWasmUrl' | 'assetsUrl'>): string;
|
|
26
33
|
/** The decoding workers of 3D Tiles and point clouds, running the full engine's module, unless turned off (`workers:
|
|
27
34
|
* false` or 0, or no workers in this environment) */
|
|
28
|
-
export declare function startTileLoader(module: WebAssembly.Module, options: Pick<GeoMapOptions, 'workers' | 'workerUrl' | 'decoders' | 'pointsWasmUrl'>, engine: Engine): TileLoader | undefined;
|
|
35
|
+
export declare function startTileLoader(module: WebAssembly.Module, options: Pick<GeoMapOptions, 'workers' | 'workerUrl' | 'decoders' | 'pointsWasmUrl' | 'assetsUrl'>, engine: Engine): TileLoader | undefined;
|
|
29
36
|
/** The engine of a destroyed map: every method a no-op returning undefined, but the camera (the last one) and the
|
|
30
37
|
* bounds, which late callers read */
|
|
31
38
|
export declare function destroyedEngine(camera: Camera): Engine;
|
package/dist/engine-loader.js
CHANGED
|
@@ -19,11 +19,42 @@ export function forgetEngines() {
|
|
|
19
19
|
delete modules[kind];
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
-
/**
|
|
22
|
+
/** The folder the assets are served from for the whole page, as `isard/vite` sets it; undefined: next to the module */
|
|
23
|
+
function pageAssets() {
|
|
24
|
+
const url = globalThis.isardAssetsUrl;
|
|
25
|
+
return typeof url === 'string' ? url : undefined;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Where a file of isard is loaded from: its own option, else in the folder `assetsUrl` (the option, or the page's
|
|
29
|
+
* as `isard/vite` sets it), else next to the module (`import.meta.url`)
|
|
30
|
+
*/
|
|
31
|
+
export function assetUrl(file, explicit, assetsUrl) {
|
|
32
|
+
if (explicit)
|
|
33
|
+
return explicit;
|
|
34
|
+
const folder = assetsUrl ?? pageAssets();
|
|
35
|
+
if (folder) {
|
|
36
|
+
const base = typeof document === 'undefined' ? undefined : document.baseURI;
|
|
37
|
+
const dir = String(folder).endsWith('/') ? String(folder) : `${String(folder)}/`;
|
|
38
|
+
return new URL(file, base ? new URL(dir, base) : dir);
|
|
39
|
+
}
|
|
40
|
+
switch (file) {
|
|
41
|
+
case 'isard_bg.wasm':
|
|
42
|
+
return new URL('./isard_bg.wasm', import.meta.url);
|
|
43
|
+
case 'isard_core_bg.wasm':
|
|
44
|
+
return new URL('./isard_core_bg.wasm', import.meta.url);
|
|
45
|
+
case 'isard_points_bg.wasm':
|
|
46
|
+
return new URL('./isard_points_bg.wasm', import.meta.url);
|
|
47
|
+
case 'decoder.worker.js':
|
|
48
|
+
return new URL('./decoder.worker.js', import.meta.url);
|
|
49
|
+
default:
|
|
50
|
+
return new URL('./basemap.worker.js', import.meta.url);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** Where a build of the engine is loaded from: the option, the assets' folder, or next to the module */
|
|
23
54
|
export function engineUrl(kind, options) {
|
|
24
55
|
return kind === 'full'
|
|
25
|
-
? (
|
|
26
|
-
: (
|
|
56
|
+
? assetUrl('isard_bg.wasm', options.wasmUrl, options.assetsUrl)
|
|
57
|
+
: assetUrl('isard_core_bg.wasm', options.coreWasmUrl, options.assetsUrl);
|
|
27
58
|
}
|
|
28
59
|
/** Downloads and compiles a build (once per page, unless it failed: a later call tries again) */
|
|
29
60
|
function compileEngine(kind, url) {
|
|
@@ -90,7 +121,7 @@ async function compile(url) {
|
|
|
90
121
|
/** Where the workers load the point cloud module from (`isard_points_bg.wasm`, the LAZ decoder): the option, or next
|
|
91
122
|
* to the module; absolute, the workers being elsewhere */
|
|
92
123
|
export function pointsUrl(options) {
|
|
93
|
-
const url =
|
|
124
|
+
const url = assetUrl('isard_points_bg.wasm', options.pointsWasmUrl, options.assetsUrl);
|
|
94
125
|
const base = typeof document === 'undefined' ? undefined : document.baseURI;
|
|
95
126
|
return base ? new URL(url, base).href : String(url);
|
|
96
127
|
}
|
|
@@ -101,7 +132,7 @@ export function startTileLoader(module, options, engine) {
|
|
|
101
132
|
const workers = count ?? defaultWorkerCount();
|
|
102
133
|
if (workers === false || workers <= 0 || typeof Worker === 'undefined')
|
|
103
134
|
return undefined;
|
|
104
|
-
return new TileLoader(module,
|
|
135
|
+
return new TileLoader(module, assetUrl('decoder.worker.js', workerUrl, options.assetsUrl), workers, { ...DEFAULT_DECODERS, ...decoders }, engine.textureFormats(), pointsUrl(options));
|
|
105
136
|
}
|
|
106
137
|
/** The engine of a destroyed map: every method a no-op returning undefined, but the camera (the last one) and the
|
|
107
138
|
* bounds, which late callers read */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine-loader.js","sourceRoot":"","sources":["../src/engine-loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAmBtD;;gGAEgG;AAChG,MAAM,OAAO,GAA2D,EAAE,CAAC;AAC3E;wFACwF;AACxF,MAAM,OAAO,GAA+E,EAAE,CAAC;AAE/F,mDAAmD;AACnD,MAAM,UAAU,aAAa;IAC3B,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,MAAM,CAAU,EAAE,CAAC;QAC7C,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;QACrB,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,SAAS,CAAC,IAAgB,EAAE,OAAuD;IACjG,OAAO,IAAI,KAAK,MAAM;QACpB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,IAAI,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,IAAI,IAAI,GAAG,CAAC,sBAAsB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAChF,CAAC;AAED,iGAAiG;AACjG,SAAS,aAAa,CAAC,IAAgB,EAAE,GAAiB;IACxD,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QACtD,gEAAgE;QAChE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;QACrB,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC;IAC1B,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,UAAU,CAAC,IAAgB,EAAE,GAAiB;IAC5D,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,OAAO,GAAG,CAAC,KAAK,IAAI,EAAE;QAC1B,gFAAgF;QAChF,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC3C,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC;YACxB,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC;SAC7E,CAAC,CAAC;QACH,MAAM,QAAQ,CAAC,OAAO,CAAC,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC,CAAC;QACnD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAgC,EAAE,CAAC;IACvE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QAC5B,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;QACrB,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;IACxB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;oDACoD;AACpD,MAAM,UAAU,mBAAmB,CAAC,GAAiB;IACnD,OAAO,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,CACjC,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,OAAO,CAAW,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CACzF,CAAC;AACJ,CAAC;AAED;uCACuC;AACvC,MAAM,UAAU,iBAAiB,CAAC,GAAiB,EAAE,MAAqB;IACxE,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,IAAI,MAAM,EAAE;YAAE,aAAa,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAClE,CAAC,CAAC;IACF,IAAI,OAAO,mBAAmB,KAAK,UAAU;QAAE,mBAAmB,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;;QACxF,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AAC5B,CAAC;AAED,KAAK,UAAU,OAAO,CAAC,GAAiB;IACtC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,CAAC,QAAQ,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,GAAG,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACtG,IAAI,CAAC;QACH,OAAO,MAAM,WAAW,CAAC,gBAAgB,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,4CAA4C;QAC5C,OAAO,WAAW,CAAC,OAAO,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC;AAED;0DAC0D;AAC1D,MAAM,UAAU,SAAS,CAAC,OAA6C;IACrE,MAAM,GAAG,GAAG,OAAO,CAAC,aAAa,IAAI,IAAI,GAAG,CAAC,wBAAwB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxF,MAAM,IAAI,GAAG,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;IAC5E,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACtD,CAAC;AAED;qDACqD;AACrD,MAAM,UAAU,eAAe,CAC7B,MAA0B,EAC1B,OAAoF,EACpF,MAAc;IAEd,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IACxD,MAAM,OAAO,GAAG,KAAK,IAAI,kBAAkB,EAAE,CAAC;IAC9C,IAAI,OAAO,KAAK,KAAK,IAAI,OAAO,IAAI,CAAC,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO,SAAS,CAAC;IACzF,OAAO,IAAI,UAAU,CACnB,MAAM,EACN,SAAS,IAAI,IAAI,GAAG,CAAC,qBAAqB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAC5D,OAAO,EACP,EAAE,GAAG,gBAAgB,EAAE,GAAG,QAAQ,EAAE,EACpC,MAAM,CAAC,cAAc,EAAE,EACvB,SAAS,CAAC,OAAO,CAAC,CACnB,CAAC;AACJ,CAAC;AAED;qCACqC;AACrC,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,OAAO,IAAI,KAAK,CACd,EAAE,EACF;QACE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE;YACf,IAAI,IAAI,KAAK,QAAQ;gBAAE,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC;YAC3C,IAAI,IAAI,KAAK,QAAQ;gBAAE,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;YACxE,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC;QACzB,CAAC;KACF,CACQ,CAAC;AACd,CAAC","sourcesContent":["/**\n * The two builds of the engine, downloaded, compiled and instantiated once per page; the decoding workers of 3D Tiles\n * that run the full one; the engine of a destroyed map.\n */\nimport { DEFAULT_DECODERS } from './decoders.ts';\nimport { TileLoader } from './loader.ts';\nimport type { GeoMapOptions } from './types.ts';\nimport { defaultWorkerCount } from './vectortiles.ts';\nimport type { Camera, Engine } from './wasm/isard.js';\n\n/** The class of an engine build: its constructor and its static `customMatrix` (custom layers) */\nexport type EngineClass = (new (\n canvas: HTMLCanvasElement,\n redraw: () => void,\n) => Engine) &\n Pick<typeof Engine, 'customMatrix' | 'geoidHeight'>;\n\n/** An engine loaded: its compiled module and its class */\nexport interface Bindings {\n module: WebAssembly.Module;\n Engine: EngineClass;\n}\n\n/** `core`: the engine without 3D Tiles; `full`: with them */\nexport type EngineKind = 'core' | 'full';\n\n/** The two builds of the engine, each compiled once per page: `core` without 3D Tiles (a third smaller), loaded by\n * every map; `full` with them, loaded for the first 3D Tiles layer, its module shared with the decoding workers. The\n * core engine has the same API but the 3D Tiles methods: its class is typed as the full one. */\nconst engines: { core?: Promise<Bindings>; full?: Promise<Bindings> } = {};\n/** The modules compiled (downloaded and compiled off the main thread, not instantiated): `tiles3d: 'preload'`\n * compiles the full engine ahead, its first 3D Tiles layer then only instantiates it */\nconst modules: { core?: Promise<WebAssembly.Module>; full?: Promise<WebAssembly.Module> } = {};\n\n/** @internal Forgets the engines loaded (tests) */\nexport function forgetEngines(): void {\n for (const kind of ['core', 'full'] as const) {\n delete engines[kind];\n delete modules[kind];\n }\n}\n\n/** Where a build of the engine is loaded from: the option, or next to the module */\nexport function engineUrl(kind: EngineKind, options: Pick<GeoMapOptions, 'wasmUrl' | 'coreWasmUrl'>): string | URL {\n return kind === 'full'\n ? (options.wasmUrl ?? new URL('./isard_bg.wasm', import.meta.url))\n : (options.coreWasmUrl ?? new URL('./isard_core_bg.wasm', import.meta.url));\n}\n\n/** Downloads and compiles a build (once per page, unless it failed: a later call tries again) */\nfunction compileEngine(kind: EngineKind, url: string | URL): Promise<WebAssembly.Module> {\n const compiled = modules[kind];\n if (compiled) return compiled;\n const compiling = compile(url).catch((error: unknown) => {\n // A later call tries again (a network error, a wrong URL fixed)\n delete modules[kind];\n throw error;\n });\n modules[kind] = compiling;\n return compiling;\n}\n\n/** A build compiled and instantiated with its bindings (once per page, unless it failed) */\nexport function loadEngine(kind: EngineKind, url: string | URL): Promise<Bindings> {\n const loaded = engines[kind];\n if (loaded) return loaded;\n const loading = (async () => {\n // The bindings by dynamic import: an application bundles the ones it loads only\n const [module, bindings] = await Promise.all([\n compileEngine(kind, url),\n kind === 'core' ? import('./wasm/isard_core.js') : import('./wasm/isard.js'),\n ]);\n await bindings.default({ module_or_path: module });\n return { module, Engine: bindings.Engine as unknown as EngineClass };\n })().catch((error: unknown) => {\n delete engines[kind];\n throw error;\n });\n engines[kind] = loading;\n return loading;\n}\n\n/** The full engine for a map on the core one, resolved in a task of its own, not in the one that instantiated it:\n * the map rebuilt on it there, two shorter tasks */\nexport function loadFullEngineLater(url: string | URL): Promise<Bindings> {\n return loadEngine('full', url).then(\n (bindings) => new Promise<Bindings>((resolve) => setTimeout(() => resolve(bindings), 0)),\n );\n}\n\n/** Downloads and compiles the full engine when the page is idle, without running it; a failure is left to the first\n * 3D Tiles layer, which tries again */\nexport function preloadFullEngine(url: string | URL, wanted: () => boolean): void {\n const start = () => {\n if (wanted()) compileEngine('full', url).catch(() => undefined);\n };\n if (typeof requestIdleCallback === 'function') requestIdleCallback(start, { timeout: 2000 });\n else setTimeout(start, 0);\n}\n\nasync function compile(url: string | URL): Promise<WebAssembly.Module> {\n const response = await fetch(url);\n if (!response.ok) throw new Error(`isard: failed to load the engine from ${url}: ${response.status}`);\n try {\n return await WebAssembly.compileStreaming(response.clone());\n } catch {\n // Servers that do not send application/wasm\n return WebAssembly.compile(await response.arrayBuffer());\n }\n}\n\n/** Where the workers load the point cloud module from (`isard_points_bg.wasm`, the LAZ decoder): the option, or next\n * to the module; absolute, the workers being elsewhere */\nexport function pointsUrl(options: Pick<GeoMapOptions, 'pointsWasmUrl'>): string {\n const url = options.pointsWasmUrl ?? new URL('./isard_points_bg.wasm', import.meta.url);\n const base = typeof document === 'undefined' ? undefined : document.baseURI;\n return base ? new URL(url, base).href : String(url);\n}\n\n/** The decoding workers of 3D Tiles and point clouds, running the full engine's module, unless turned off (`workers:\n * false` or 0, or no workers in this environment) */\nexport function startTileLoader(\n module: WebAssembly.Module,\n options: Pick<GeoMapOptions, 'workers' | 'workerUrl' | 'decoders' | 'pointsWasmUrl'>,\n engine: Engine,\n): TileLoader | undefined {\n const { workers: count, workerUrl, decoders } = options;\n const workers = count ?? defaultWorkerCount();\n if (workers === false || workers <= 0 || typeof Worker === 'undefined') return undefined;\n return new TileLoader(\n module,\n workerUrl ?? new URL('./decoder.worker.js', import.meta.url),\n workers,\n { ...DEFAULT_DECODERS, ...decoders },\n engine.textureFormats(),\n pointsUrl(options),\n );\n}\n\n/** The engine of a destroyed map: every method a no-op returning undefined, but the camera (the last one) and the\n * bounds, which late callers read */\nexport function destroyedEngine(camera: Camera): Engine {\n return new Proxy(\n {},\n {\n get: (_, name) => {\n if (name === 'camera') return () => camera;\n if (name === 'bounds') return () => Float64Array.of(-180, -85, 180, 85);\n return () => undefined;\n },\n },\n ) as Engine;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"engine-loader.js","sourceRoot":"","sources":["../src/engine-loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The two builds of the engine, downloaded, compiled and instantiated once per page; the decoding workers of 3D Tiles\n * that run the full one; the engine of a destroyed map.\n */\nimport { DEFAULT_DECODERS } from './decoders.ts';\nimport { TileLoader } from './loader.ts';\nimport type { GeoMapOptions } from './types.ts';\nimport { defaultWorkerCount } from './vectortiles.ts';\nimport type { Camera, Engine } from './wasm/isard.js';\n\n/** The class of an engine build: its constructor and its static `customMatrix` (custom layers) */\nexport type EngineClass = (new (\n canvas: HTMLCanvasElement,\n redraw: () => void,\n) => Engine) &\n Pick<typeof Engine, 'customMatrix' | 'geoidHeight'>;\n\n/** An engine loaded: its compiled module and its class */\nexport interface Bindings {\n module: WebAssembly.Module;\n Engine: EngineClass;\n}\n\n/** `core`: the engine without 3D Tiles; `full`: with them */\nexport type EngineKind = 'core' | 'full';\n\n/** The two builds of the engine, each compiled once per page: `core` without 3D Tiles (a third smaller), loaded by\n * every map; `full` with them, loaded for the first 3D Tiles layer, its module shared with the decoding workers. The\n * core engine has the same API but the 3D Tiles methods: its class is typed as the full one. */\nconst engines: { core?: Promise<Bindings>; full?: Promise<Bindings> } = {};\n/** The modules compiled (downloaded and compiled off the main thread, not instantiated): `tiles3d: 'preload'`\n * compiles the full engine ahead, its first 3D Tiles layer then only instantiates it */\nconst modules: { core?: Promise<WebAssembly.Module>; full?: Promise<WebAssembly.Module> } = {};\n\n/** @internal Forgets the engines loaded (tests) */\nexport function forgetEngines(): void {\n for (const kind of ['core', 'full'] as const) {\n delete engines[kind];\n delete modules[kind];\n }\n}\n\n/** The files a map loads at run time, next to the module unless given elsewhere */\nexport type AssetFile =\n | 'isard_bg.wasm'\n | 'isard_core_bg.wasm'\n | 'isard_points_bg.wasm'\n | 'decoder.worker.js'\n | 'basemap.worker.js';\n\n/** The folder the assets are served from for the whole page, as `isard/vite` sets it; undefined: next to the module */\nfunction pageAssets(): string | undefined {\n const url = (globalThis as { isardAssetsUrl?: unknown }).isardAssetsUrl;\n return typeof url === 'string' ? url : undefined;\n}\n\n/**\n * Where a file of isard is loaded from: its own option, else in the folder `assetsUrl` (the option, or the page's\n * as `isard/vite` sets it), else next to the module (`import.meta.url`)\n */\nexport function assetUrl(file: AssetFile, explicit: string | URL | undefined, assetsUrl?: string | URL): string | URL {\n if (explicit) return explicit;\n const folder = assetsUrl ?? pageAssets();\n if (folder) {\n const base = typeof document === 'undefined' ? undefined : document.baseURI;\n const dir = String(folder).endsWith('/') ? String(folder) : `${String(folder)}/`;\n return new URL(file, base ? new URL(dir, base) : dir);\n }\n switch (file) {\n case 'isard_bg.wasm':\n return new URL('./isard_bg.wasm', import.meta.url);\n case 'isard_core_bg.wasm':\n return new URL('./isard_core_bg.wasm', import.meta.url);\n case 'isard_points_bg.wasm':\n return new URL('./isard_points_bg.wasm', import.meta.url);\n case 'decoder.worker.js':\n return new URL('./decoder.worker.js', import.meta.url);\n default:\n return new URL('./basemap.worker.js', import.meta.url);\n }\n}\n\n/** Where a build of the engine is loaded from: the option, the assets' folder, or next to the module */\nexport function engineUrl(\n kind: EngineKind,\n options: Pick<GeoMapOptions, 'wasmUrl' | 'coreWasmUrl' | 'assetsUrl'>,\n): string | URL {\n return kind === 'full'\n ? assetUrl('isard_bg.wasm', options.wasmUrl, options.assetsUrl)\n : assetUrl('isard_core_bg.wasm', options.coreWasmUrl, options.assetsUrl);\n}\n\n/** Downloads and compiles a build (once per page, unless it failed: a later call tries again) */\nfunction compileEngine(kind: EngineKind, url: string | URL): Promise<WebAssembly.Module> {\n const compiled = modules[kind];\n if (compiled) return compiled;\n const compiling = compile(url).catch((error: unknown) => {\n // A later call tries again (a network error, a wrong URL fixed)\n delete modules[kind];\n throw error;\n });\n modules[kind] = compiling;\n return compiling;\n}\n\n/** A build compiled and instantiated with its bindings (once per page, unless it failed) */\nexport function loadEngine(kind: EngineKind, url: string | URL): Promise<Bindings> {\n const loaded = engines[kind];\n if (loaded) return loaded;\n const loading = (async () => {\n // The bindings by dynamic import: an application bundles the ones it loads only\n const [module, bindings] = await Promise.all([\n compileEngine(kind, url),\n kind === 'core' ? import('./wasm/isard_core.js') : import('./wasm/isard.js'),\n ]);\n await bindings.default({ module_or_path: module });\n return { module, Engine: bindings.Engine as unknown as EngineClass };\n })().catch((error: unknown) => {\n delete engines[kind];\n throw error;\n });\n engines[kind] = loading;\n return loading;\n}\n\n/** The full engine for a map on the core one, resolved in a task of its own, not in the one that instantiated it:\n * the map rebuilt on it there, two shorter tasks */\nexport function loadFullEngineLater(url: string | URL): Promise<Bindings> {\n return loadEngine('full', url).then(\n (bindings) => new Promise<Bindings>((resolve) => setTimeout(() => resolve(bindings), 0)),\n );\n}\n\n/** Downloads and compiles the full engine when the page is idle, without running it; a failure is left to the first\n * 3D Tiles layer, which tries again */\nexport function preloadFullEngine(url: string | URL, wanted: () => boolean): void {\n const start = () => {\n if (wanted()) compileEngine('full', url).catch(() => undefined);\n };\n if (typeof requestIdleCallback === 'function') requestIdleCallback(start, { timeout: 2000 });\n else setTimeout(start, 0);\n}\n\nasync function compile(url: string | URL): Promise<WebAssembly.Module> {\n const response = await fetch(url);\n if (!response.ok) throw new Error(`isard: failed to load the engine from ${url}: ${response.status}`);\n try {\n return await WebAssembly.compileStreaming(response.clone());\n } catch {\n // Servers that do not send application/wasm\n return WebAssembly.compile(await response.arrayBuffer());\n }\n}\n\n/** Where the workers load the point cloud module from (`isard_points_bg.wasm`, the LAZ decoder): the option, or next\n * to the module; absolute, the workers being elsewhere */\nexport function pointsUrl(options: Pick<GeoMapOptions, 'pointsWasmUrl' | 'assetsUrl'>): string {\n const url = assetUrl('isard_points_bg.wasm', options.pointsWasmUrl, options.assetsUrl);\n const base = typeof document === 'undefined' ? undefined : document.baseURI;\n return base ? new URL(url, base).href : String(url);\n}\n\n/** The decoding workers of 3D Tiles and point clouds, running the full engine's module, unless turned off (`workers:\n * false` or 0, or no workers in this environment) */\nexport function startTileLoader(\n module: WebAssembly.Module,\n options: Pick<GeoMapOptions, 'workers' | 'workerUrl' | 'decoders' | 'pointsWasmUrl' | 'assetsUrl'>,\n engine: Engine,\n): TileLoader | undefined {\n const { workers: count, workerUrl, decoders } = options;\n const workers = count ?? defaultWorkerCount();\n if (workers === false || workers <= 0 || typeof Worker === 'undefined') return undefined;\n return new TileLoader(\n module,\n assetUrl('decoder.worker.js', workerUrl, options.assetsUrl),\n workers,\n { ...DEFAULT_DECODERS, ...decoders },\n engine.textureFormats(),\n pointsUrl(options),\n );\n}\n\n/** The engine of a destroyed map: every method a no-op returning undefined, but the camera (the last one) and the\n * bounds, which late callers read */\nexport function destroyedEngine(camera: Camera): Engine {\n return new Proxy(\n {},\n {\n get: (_, name) => {\n if (name === 'camera') return () => camera;\n if (name === 'bounds') return () => Float64Array.of(-180, -85, 180, 85);\n return () => undefined;\n },\n },\n ) as Engine;\n}\n"]}
|
package/dist/geoplateforme.d.ts
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
* GeoJSON. Its basemaps, hillshade, terrain model and vector styles are named options of the map (`'ign-plan'`,
|
|
4
4
|
* `hillshade`, `terrain: 'ign'`, `PLAN_STYLES`); the rasters credit the IGN by themselves.
|
|
5
5
|
*/
|
|
6
|
+
import type { ExtrusionOptions } from './extrusions.ts';
|
|
6
7
|
import type { FeatureCollection, Properties } from './features.ts';
|
|
7
8
|
import type { TileGrid } from './grid.ts';
|
|
8
|
-
import type { RasterOptions } from './types.ts';
|
|
9
|
+
import type { RasterOptions, Tiles3dOptions } from './types.ts';
|
|
9
10
|
/** Credits of the Géoplateforme's data: its basemaps, hillshade, terrain model, rasters and features */
|
|
10
11
|
export declare const IGN_ATTRIBUTION = "<a href=\"https://www.ign.fr/\">\u00A9 IGN</a> \u2013 <a href=\"https://geoservices.ign.fr/\">G\u00E9oplateforme</a>";
|
|
11
12
|
/**
|
|
@@ -50,3 +51,52 @@ export declare function geoplateformeWfs<P = Properties>(typeName: string, [west
|
|
|
50
51
|
signal?: AbortSignal;
|
|
51
52
|
srsName?: string;
|
|
52
53
|
}): Promise<FeatureCollection<P>>;
|
|
54
|
+
/** Map presets over France, the IGN's data in a word: spread into `GeoMap.create`'s options or named by `preset` */
|
|
55
|
+
export declare const IGN_PRESETS: {
|
|
56
|
+
/** PLAN IGN (vector, grey) seen from above */
|
|
57
|
+
readonly ign: {
|
|
58
|
+
readonly basemap: "ign-plan-grey-vector";
|
|
59
|
+
readonly projection: "mercator";
|
|
60
|
+
};
|
|
61
|
+
/** PLAN IGN over the IGN relief (RGE ALTI), for 3D: buildings, meshes, viewsheds */
|
|
62
|
+
readonly 'ign-3d': {
|
|
63
|
+
readonly basemap: "ign-plan-grey-vector";
|
|
64
|
+
readonly terrain: {
|
|
65
|
+
readonly model: "ign";
|
|
66
|
+
};
|
|
67
|
+
readonly projection: "mercator";
|
|
68
|
+
readonly pitch: 55;
|
|
69
|
+
};
|
|
70
|
+
/** The IGN orthophotos over the IGN relief */
|
|
71
|
+
readonly 'ign-ortho-3d': {
|
|
72
|
+
readonly basemap: "ign-ortho";
|
|
73
|
+
readonly terrain: {
|
|
74
|
+
readonly model: "ign";
|
|
75
|
+
};
|
|
76
|
+
readonly projection: "mercator";
|
|
77
|
+
readonly pitch: 55;
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
/** A preset of `IGN_PRESETS` by name */
|
|
81
|
+
export type IgnPreset = keyof typeof IGN_PRESETS;
|
|
82
|
+
/** The IGN's Bâtiments 3D (France, 3D Tiles 1.1): its tileset */
|
|
83
|
+
export declare const BATIMENTS_3D_URL = "https://prd-ign-mut-bat3.s3.sbg.io.cloud.ovh.net/tileset.json";
|
|
84
|
+
/**
|
|
85
|
+
* The IGN's Bâtiments 3D as a 3D Tiles layer, ready for `map.addTiles3d`: their heights are altitudes (NGF-IGN69),
|
|
86
|
+
* raised by the geoid onto the IGN relief; untextured, colored and shaded; picked with their BD TOPO attributes
|
|
87
|
+
* (`cleabs`, `hauteur`, `nature`, `usage_1`…). Its server sends no CORS headers yet: from a page of another origin,
|
|
88
|
+
* through a proxy (`url`)
|
|
89
|
+
*/
|
|
90
|
+
export declare function batiments3d(options?: Partial<Tiles3dOptions>): Tiles3dOptions;
|
|
91
|
+
/** What a building of the BD TOPO gives its extrusion */
|
|
92
|
+
export interface BdTopoBuilding {
|
|
93
|
+
hauteur: number | null;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* The BD TOPO buildings of a box (west, south, east, north, degrees) as an extrusion layer, ready for
|
|
97
|
+
* `map.addExtrusions`: from the Géoplateforme's WFS, raised to their `hauteur` (`defaultHeight` without one)
|
|
98
|
+
*/
|
|
99
|
+
export declare function bdtopoBuildings(box: [number, number, number, number], options?: Partial<ExtrusionOptions<BdTopoBuilding>> & {
|
|
100
|
+
defaultHeight?: number;
|
|
101
|
+
signal?: AbortSignal;
|
|
102
|
+
}): Promise<ExtrusionOptions<BdTopoBuilding>>;
|
package/dist/geoplateforme.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Géoplateforme's data (IGN, France; open, no key): its WMTS and WMS rasters as raster layers, its WFS features as
|
|
3
|
+
* GeoJSON. Its basemaps, hillshade, terrain model and vector styles are named options of the map (`'ign-plan'`,
|
|
4
|
+
* `hillshade`, `terrain: 'ign'`, `PLAN_STYLES`); the rasters credit the IGN by themselves.
|
|
5
|
+
*/
|
|
1
6
|
import { withHeaders } from "./requests.js";
|
|
2
7
|
/** Credits of the Géoplateforme's data: its basemaps, hillshade, terrain model, rasters and features */
|
|
3
8
|
export const IGN_ATTRIBUTION = '<a href="https://www.ign.fr/">© IGN</a> – <a href="https://geoservices.ign.fr/">Géoplateforme</a>';
|
|
@@ -112,4 +117,33 @@ export async function geoplateformeWfs(typeName, [west, south, east, north], opt
|
|
|
112
117
|
.filter((f) => f.id === undefined || (!seen.has(f.id) && seen.add(f.id) !== undefined));
|
|
113
118
|
return { ...first, features };
|
|
114
119
|
}
|
|
120
|
+
/** Map presets over France, the IGN's data in a word: spread into `GeoMap.create`'s options or named by `preset` */
|
|
121
|
+
export const IGN_PRESETS = {
|
|
122
|
+
/** PLAN IGN (vector, grey) seen from above */
|
|
123
|
+
ign: { basemap: 'ign-plan-grey-vector', projection: 'mercator' },
|
|
124
|
+
/** PLAN IGN over the IGN relief (RGE ALTI), for 3D: buildings, meshes, viewsheds */
|
|
125
|
+
'ign-3d': { basemap: 'ign-plan-grey-vector', terrain: { model: 'ign' }, projection: 'mercator', pitch: 55 },
|
|
126
|
+
/** The IGN orthophotos over the IGN relief */
|
|
127
|
+
'ign-ortho-3d': { basemap: 'ign-ortho', terrain: { model: 'ign' }, projection: 'mercator', pitch: 55 },
|
|
128
|
+
};
|
|
129
|
+
/** The IGN's Bâtiments 3D (France, 3D Tiles 1.1): its tileset */
|
|
130
|
+
export const BATIMENTS_3D_URL = 'https://prd-ign-mut-bat3.s3.sbg.io.cloud.ovh.net/tileset.json';
|
|
131
|
+
/**
|
|
132
|
+
* The IGN's Bâtiments 3D as a 3D Tiles layer, ready for `map.addTiles3d`: their heights are altitudes (NGF-IGN69),
|
|
133
|
+
* raised by the geoid onto the IGN relief; untextured, colored and shaded; picked with their BD TOPO attributes
|
|
134
|
+
* (`cleabs`, `hauteur`, `nature`, `usage_1`…). Its server sends no CORS headers yet: from a page of another origin,
|
|
135
|
+
* through a proxy (`url`)
|
|
136
|
+
*/
|
|
137
|
+
export function batiments3d(options = {}) {
|
|
138
|
+
return { url: BATIMENTS_3D_URL, geoid: true, color: '#e4e1d8', maxScreenSpaceError: 16, ...options };
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* The BD TOPO buildings of a box (west, south, east, north, degrees) as an extrusion layer, ready for
|
|
142
|
+
* `map.addExtrusions`: from the Géoplateforme's WFS, raised to their `hauteur` (`defaultHeight` without one)
|
|
143
|
+
*/
|
|
144
|
+
export async function bdtopoBuildings(box, options = {}) {
|
|
145
|
+
const { defaultHeight = 6, signal, ...style } = options;
|
|
146
|
+
const data = await geoplateformeWfs('BDTOPO_V3:batiment', box, signal ? { signal } : {});
|
|
147
|
+
return { data, height: (p) => p.hauteur ?? defaultHeight, color: '#e4e1d8', ...style };
|
|
148
|
+
}
|
|
115
149
|
//# sourceMappingURL=geoplateforme.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geoplateforme.js","sourceRoot":"","sources":["../src/geoplateforme.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Géoplateforme's data (IGN, France; open, no key): its WMTS and WMS rasters as raster layers, its WFS features as\n * GeoJSON. Its basemaps, hillshade, terrain model and vector styles are named options of the map (`'ign-plan'`,\n * `hillshade`, `terrain: 'ign'`, `PLAN_STYLES`); the rasters credit the IGN by themselves.\n */\nimport type { FeatureCollection, Properties } from './features.ts';\nimport type { TileGrid, TileMatrix } from './grid.ts';\nimport { withHeaders } from './requests.ts';\nimport type { RasterOptions } from './types.ts';\n\n/** Credits of the Géoplateforme's data: its basemaps, hillshade, terrain model, rasters and features */\nexport const IGN_ATTRIBUTION =\n '<a href=\"https://www.ign.fr/\">© IGN</a> – <a href=\"https://geoservices.ign.fr/\">Géoplateforme</a>';\n\n/** France (metropolitan, Corsica included) in longitudes and latitudes, where the Géoplateforme's Lambert-93 layers\n * lie */\nconst FRANCE: [number, number, number, number] = [-5.5, 41, 10, 51.5];\n\n/**\n * The Géoplateforme's Lambert-93 tile matrix sets of 5 and 10 cm (`2154_10cm_6_20`, `2154_5cm_6_22`…: one pyramid,\n * 209 715.2 m per pixel at level 0, halved at each level, from the corner (0, 12 000 000)), levels `min` to `max`, over\n * France\n */\nexport function lambert93Grid(name: string, min: number, max: number): TileGrid {\n const matrices: TileMatrix[] = [];\n for (let level = min; level <= max; level += 1) {\n matrices.push({ id: level, resolution: 209715.2 / 2 ** level, origin: [0, 12000000] });\n }\n return { crs: 'EPSG:2154', matrices, bounds: FRANCE, name };\n}\n\n/**\n * A layer of the Géoplateforme's WMTS as raster options for `addRaster`, crediting the IGN:\n * `geoplateformeWmts('ORTHOIMAGERY.ORTHOPHOTOS', { format: 'image/jpeg' })`. The layer names are those of its\n * capabilities (https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetCapabilities). In its Web Mercator grid (`PM`) by\n * default; a Lambert-93 layer in its matrix set (`matrixSet: '2154_10cm_6_20'`, a set of 5 or 10 cm, read from the\n * capabilities) or another `grid` (from `wmtsGrid`, its set named) is reprojected by the map\n */\nexport function geoplateformeWmts(\n layer: string,\n options: { format?: string; style?: string; matrixSet?: string } & Omit<RasterOptions, 'url'> = {},\n): RasterOptions {\n const { format = 'image/png', style = 'normal', matrixSet, ...raster } = options;\n const set = (typeof raster.grid === 'object' ? raster.grid.name : undefined) ?? matrixSet ?? 'PM';\n const lambert = /^2154_(?:5|10)cm_(\\d+)_(\\d+)$/.exec(set);\n if (lambert && raster.grid === undefined) raster.grid = lambert93Grid(set, Number(lambert[1]), Number(lambert[2]));\n else if (set !== 'PM' && raster.grid === undefined) {\n throw new Error(`isard: the grid of the matrix set ${set}: wmtsGrid(capabilities, '${layer}', '${set}')`);\n }\n return {\n ...(raster.grid === undefined ? { maxZoom: 19 } : {}),\n attribution: IGN_ATTRIBUTION,\n ...raster,\n url:\n `https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&STYLE=${encodeURIComponent(style)}` +\n `&TILEMATRIXSET=${encodeURIComponent(set)}&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}` +\n `&LAYER=${encodeURIComponent(layer)}&FORMAT=${format}`,\n };\n}\n\n/**\n * Layers of the Géoplateforme's WMS (raster, `wms-r`) as raster options for `addRaster`, crediting the IGN: 256 px\n * images of each tile, transparent where empty. `geoplateformeWms('CADASTRALPARCELS.PARCELLAIRE_EXPRESS')`. Asked for\n * in EPSG:3857, or in `crs` (`'EPSG:2154'`: the box of each tile in Lambert-93, at the tile's `size`, reprojected by\n * the map; `'EPSG:4326'` is asked for as CRS:84, longitude first)\n */\nexport function geoplateformeWms(\n layers: string,\n options: { format?: string; styles?: string; crs?: string } & Omit<RasterOptions, 'url'> = {},\n): RasterOptions {\n const { format = 'image/png', styles = '', crs = 'EPSG:3857', ...raster } = options;\n const projected = crs !== 'EPSG:3857';\n // WMS 1.3 puts the latitude first in EPSG:4326; {bbox} is x, y\n const asked = crs === 'EPSG:4326' ? 'CRS:84' : crs;\n return {\n maxZoom: 20,\n attribution: IGN_ATTRIBUTION,\n ...(projected ? { grid: { crs, ...(crs === 'EPSG:2154' ? { bounds: FRANCE } : {}) } } : {}),\n ...raster,\n url:\n `https://data.geopf.fr/wms-r/wms?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=${asked}&BBOX={bbox}` +\n // Reprojected, the image of each tile at its size\n `&${projected ? 'WIDTH={width}&HEIGHT={height}' : 'WIDTH=256&HEIGHT=256'}&TRANSPARENT=TRUE` +\n `&LAYERS=${encodeURIComponent(layers)}` +\n `&STYLES=${encodeURIComponent(styles)}&FORMAT=${format}`,\n };\n}\n\n/** Features the Géoplateforme's WFS returns per request at most */\nconst WFS_PAGE = 5000;\n\n/**\n * Features of the Géoplateforme's WFS in a box (west, south, east, north, degrees), as GeoJSON in longitudes and\n * latitudes: `await geoplateformeWfs('BDTOPO_V3:batiment', [2.41, 48.84, 2.43, 48.85])`. At most `count` features\n * (default 50 000), asked by pages of 5000: the first one tells how many there are, the others are asked together.\n * The type names are those of its capabilities (BD TOPO, ADMIN EXPRESS…). With `srsName` (`'EPSG:2154'`), the\n * features come in that CRS (the box stays in degrees), the collection naming it in its `crs` member: the feature\n * layers reproject it by themselves\n */\nexport async function geoplateformeWfs<P = Properties>(\n typeName: string,\n [west, south, east, north]: [number, number, number, number],\n options: { count?: number; signal?: AbortSignal; srsName?: string } = {},\n): Promise<FeatureCollection<P>> {\n const limit = Math.max(1, options.count ?? 50_000);\n const page = async (start: number, count: number) => {\n const url = new URL('https://data.geopf.fr/wfs/ows');\n url.search = new URLSearchParams({\n SERVICE: 'WFS',\n VERSION: '2.0.0',\n REQUEST: 'GetFeature',\n TYPENAMES: typeName,\n OUTPUTFORMAT: 'application/json',\n SRSNAME: options.srsName ?? 'EPSG:4326',\n // WFS 2.0 in EPSG:4326: latitude first\n BBOX: `${south},${west},${north},${east},urn:ogc:def:crs:EPSG::4326`,\n COUNT: String(count),\n // The first page as a single request always was\n ...(start > 0 ? { STARTINDEX: String(start) } : {}),\n }).toString();\n const response = await fetch(url, withHeaders(url, options.signal ? { signal: options.signal } : {}));\n if (!response.ok) throw new Error(`isard: ${typeName}: ${response.status}`);\n return response.json() as Promise<FeatureCollection<P> & { numberMatched?: number | string }>;\n };\n const first = await page(0, Math.min(WFS_PAGE, limit));\n const matched = Number(first.numberMatched);\n const total = Math.min(Number.isFinite(matched) ? matched : 0, limit);\n if (first.features.length < WFS_PAGE || total <= first.features.length) return first;\n const starts: number[] = [];\n for (let start = first.features.length; start < total; start += WFS_PAGE) starts.push(start);\n const rest = await Promise.all(starts.map((start) => page(start, Math.min(WFS_PAGE, total - start))));\n // Pages may overlap where the server's order shifts: each feature once, by its id\n const seen = new Set<unknown>();\n const features = [first, ...rest]\n .flatMap((r) => r.features)\n .filter((f) => f.id === undefined || (!seen.has(f.id) && seen.add(f.id) !== undefined));\n return { ...first, features };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"geoplateforme.js","sourceRoot":"","sources":["../src/geoplateforme.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG5C,wGAAwG;AACxG,MAAM,CAAC,MAAM,eAAe,GAC1B,mGAAmG,CAAC;AAEtG;SACS;AACT,MAAM,MAAM,GAAqC,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;AAEtE;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,GAAW,EAAE,GAAW;IAClE,MAAM,QAAQ,GAAiB,EAAE,CAAC;IAClC,KAAK,IAAI,KAAK,GAAG,GAAG,EAAE,KAAK,IAAI,GAAG,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC/C,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,GAAG,CAAC,IAAI,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;IACzF,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAC9D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAa,EACb,UAAgG,EAAE;IAElG,MAAM,EAAE,MAAM,GAAG,WAAW,EAAE,KAAK,GAAG,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC;IACjF,MAAM,GAAG,GAAG,CAAC,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,IAAI,CAAC;IAClG,MAAM,OAAO,GAAG,+BAA+B,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1D,IAAI,OAAO,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS;QAAE,MAAM,CAAC,IAAI,GAAG,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SAC9G,IAAI,GAAG,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,qCAAqC,GAAG,6BAA6B,KAAK,OAAO,GAAG,IAAI,CAAC,CAAC;IAC5G,CAAC;IACD,OAAO;QACL,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,WAAW,EAAE,eAAe;QAC5B,GAAG,MAAM;QACT,GAAG,EACD,+EAA+E,kBAAkB,CAAC,KAAK,CAAC,EAAE;YAC1G,kBAAkB,kBAAkB,CAAC,GAAG,CAAC,yCAAyC;YAClF,UAAU,kBAAkB,CAAC,KAAK,CAAC,WAAW,MAAM,EAAE;KACzD,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAAc,EACd,UAA2F,EAAE;IAE7F,MAAM,EAAE,MAAM,GAAG,WAAW,EAAE,MAAM,GAAG,EAAE,EAAE,GAAG,GAAG,WAAW,EAAE,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC;IACpF,MAAM,SAAS,GAAG,GAAG,KAAK,WAAW,CAAC;IACtC,+DAA+D;IAC/D,MAAM,KAAK,GAAG,GAAG,KAAK,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC;IACnD,OAAO;QACL,OAAO,EAAE,EAAE;QACX,WAAW,EAAE,eAAe;QAC5B,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,KAAK,WAAW,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3F,GAAG,MAAM;QACT,GAAG,EACD,gFAAgF,KAAK,cAAc;YACnG,kDAAkD;YAClD,IAAI,SAAS,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,sBAAsB,mBAAmB;YAC3F,WAAW,kBAAkB,CAAC,MAAM,CAAC,EAAE;YACvC,WAAW,kBAAkB,CAAC,MAAM,CAAC,WAAW,MAAM,EAAE;KAC3D,CAAC;AACJ,CAAC;AAED,mEAAmE;AACnE,MAAM,QAAQ,GAAG,IAAI,CAAC;AAEtB;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,QAAgB,EAChB,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAmC,EAC5D,UAAsE,EAAE;IAExE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,IAAI,MAAM,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,KAAK,EAAE,KAAa,EAAE,KAAa,EAAE,EAAE;QAClD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,+BAA+B,CAAC,CAAC;QACrD,GAAG,CAAC,MAAM,GAAG,IAAI,eAAe,CAAC;YAC/B,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,OAAO;YAChB,OAAO,EAAE,YAAY;YACrB,SAAS,EAAE,QAAQ;YACnB,YAAY,EAAE,kBAAkB;YAChC,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,WAAW;YACvC,uCAAuC;YACvC,IAAI,EAAE,GAAG,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,6BAA6B;YACpE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC;YACpB,gDAAgD;YAChD,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACpD,CAAC,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACtG,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,UAAU,QAAQ,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC5E,OAAO,QAAQ,CAAC,IAAI,EAAyE,CAAC;IAChG,CAAC,CAAC;IACF,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACtE,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,QAAQ,IAAI,KAAK,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACrF,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,IAAI,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG,KAAK,EAAE,KAAK,IAAI,QAAQ;QAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7F,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACtG,kFAAkF;IAClF,MAAM,IAAI,GAAG,IAAI,GAAG,EAAW,CAAC;IAChC,MAAM,QAAQ,GAAG,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC;SAC9B,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;SAC1B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC;IAC1F,OAAO,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,CAAC;AAChC,CAAC;AAED,oHAAoH;AACpH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,8CAA8C;IAC9C,GAAG,EAAE,EAAE,OAAO,EAAE,sBAAsB,EAAE,UAAU,EAAE,UAAU,EAAE;IAChE,oFAAoF;IACpF,QAAQ,EAAE,EAAE,OAAO,EAAE,sBAAsB,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE;IAC3G,8CAA8C;IAC9C,cAAc,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE;CACtD,CAAC;AAKnD,iEAAiE;AACjE,MAAM,CAAC,MAAM,gBAAgB,GAAG,+DAA+D,CAAC;AAEhG;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,UAAmC,EAAE;IAC/D,OAAO,EAAE,GAAG,EAAE,gBAAgB,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC;AACvG,CAAC;AAOD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAAqC,EACrC,UAAwG,EAAE;IAE1G,MAAM,EAAE,aAAa,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IACxD,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAiB,oBAAoB,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACzG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,CAAC;AACzF,CAAC","sourcesContent":["/**\n * The Géoplateforme's data (IGN, France; open, no key): its WMTS and WMS rasters as raster layers, its WFS features as\n * GeoJSON. Its basemaps, hillshade, terrain model and vector styles are named options of the map (`'ign-plan'`,\n * `hillshade`, `terrain: 'ign'`, `PLAN_STYLES`); the rasters credit the IGN by themselves.\n */\n\nimport type { ExtrusionOptions } from './extrusions.ts';\nimport type { FeatureCollection, Properties } from './features.ts';\nimport type { TileGrid, TileMatrix } from './grid.ts';\nimport { withHeaders } from './requests.ts';\nimport type { GeoMapOptions, RasterOptions, Tiles3dOptions } from './types.ts';\n\n/** Credits of the Géoplateforme's data: its basemaps, hillshade, terrain model, rasters and features */\nexport const IGN_ATTRIBUTION =\n '<a href=\"https://www.ign.fr/\">© IGN</a> – <a href=\"https://geoservices.ign.fr/\">Géoplateforme</a>';\n\n/** France (metropolitan, Corsica included) in longitudes and latitudes, where the Géoplateforme's Lambert-93 layers\n * lie */\nconst FRANCE: [number, number, number, number] = [-5.5, 41, 10, 51.5];\n\n/**\n * The Géoplateforme's Lambert-93 tile matrix sets of 5 and 10 cm (`2154_10cm_6_20`, `2154_5cm_6_22`…: one pyramid,\n * 209 715.2 m per pixel at level 0, halved at each level, from the corner (0, 12 000 000)), levels `min` to `max`, over\n * France\n */\nexport function lambert93Grid(name: string, min: number, max: number): TileGrid {\n const matrices: TileMatrix[] = [];\n for (let level = min; level <= max; level += 1) {\n matrices.push({ id: level, resolution: 209715.2 / 2 ** level, origin: [0, 12000000] });\n }\n return { crs: 'EPSG:2154', matrices, bounds: FRANCE, name };\n}\n\n/**\n * A layer of the Géoplateforme's WMTS as raster options for `addRaster`, crediting the IGN:\n * `geoplateformeWmts('ORTHOIMAGERY.ORTHOPHOTOS', { format: 'image/jpeg' })`. The layer names are those of its\n * capabilities (https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetCapabilities). In its Web Mercator grid (`PM`) by\n * default; a Lambert-93 layer in its matrix set (`matrixSet: '2154_10cm_6_20'`, a set of 5 or 10 cm, read from the\n * capabilities) or another `grid` (from `wmtsGrid`, its set named) is reprojected by the map\n */\nexport function geoplateformeWmts(\n layer: string,\n options: { format?: string; style?: string; matrixSet?: string } & Omit<RasterOptions, 'url'> = {},\n): RasterOptions {\n const { format = 'image/png', style = 'normal', matrixSet, ...raster } = options;\n const set = (typeof raster.grid === 'object' ? raster.grid.name : undefined) ?? matrixSet ?? 'PM';\n const lambert = /^2154_(?:5|10)cm_(\\d+)_(\\d+)$/.exec(set);\n if (lambert && raster.grid === undefined) raster.grid = lambert93Grid(set, Number(lambert[1]), Number(lambert[2]));\n else if (set !== 'PM' && raster.grid === undefined) {\n throw new Error(`isard: the grid of the matrix set ${set}: wmtsGrid(capabilities, '${layer}', '${set}')`);\n }\n return {\n ...(raster.grid === undefined ? { maxZoom: 19 } : {}),\n attribution: IGN_ATTRIBUTION,\n ...raster,\n url:\n `https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&STYLE=${encodeURIComponent(style)}` +\n `&TILEMATRIXSET=${encodeURIComponent(set)}&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}` +\n `&LAYER=${encodeURIComponent(layer)}&FORMAT=${format}`,\n };\n}\n\n/**\n * Layers of the Géoplateforme's WMS (raster, `wms-r`) as raster options for `addRaster`, crediting the IGN: 256 px\n * images of each tile, transparent where empty. `geoplateformeWms('CADASTRALPARCELS.PARCELLAIRE_EXPRESS')`. Asked for\n * in EPSG:3857, or in `crs` (`'EPSG:2154'`: the box of each tile in Lambert-93, at the tile's `size`, reprojected by\n * the map; `'EPSG:4326'` is asked for as CRS:84, longitude first)\n */\nexport function geoplateformeWms(\n layers: string,\n options: { format?: string; styles?: string; crs?: string } & Omit<RasterOptions, 'url'> = {},\n): RasterOptions {\n const { format = 'image/png', styles = '', crs = 'EPSG:3857', ...raster } = options;\n const projected = crs !== 'EPSG:3857';\n // WMS 1.3 puts the latitude first in EPSG:4326; {bbox} is x, y\n const asked = crs === 'EPSG:4326' ? 'CRS:84' : crs;\n return {\n maxZoom: 20,\n attribution: IGN_ATTRIBUTION,\n ...(projected ? { grid: { crs, ...(crs === 'EPSG:2154' ? { bounds: FRANCE } : {}) } } : {}),\n ...raster,\n url:\n `https://data.geopf.fr/wms-r/wms?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=${asked}&BBOX={bbox}` +\n // Reprojected, the image of each tile at its size\n `&${projected ? 'WIDTH={width}&HEIGHT={height}' : 'WIDTH=256&HEIGHT=256'}&TRANSPARENT=TRUE` +\n `&LAYERS=${encodeURIComponent(layers)}` +\n `&STYLES=${encodeURIComponent(styles)}&FORMAT=${format}`,\n };\n}\n\n/** Features the Géoplateforme's WFS returns per request at most */\nconst WFS_PAGE = 5000;\n\n/**\n * Features of the Géoplateforme's WFS in a box (west, south, east, north, degrees), as GeoJSON in longitudes and\n * latitudes: `await geoplateformeWfs('BDTOPO_V3:batiment', [2.41, 48.84, 2.43, 48.85])`. At most `count` features\n * (default 50 000), asked by pages of 5000: the first one tells how many there are, the others are asked together.\n * The type names are those of its capabilities (BD TOPO, ADMIN EXPRESS…). With `srsName` (`'EPSG:2154'`), the\n * features come in that CRS (the box stays in degrees), the collection naming it in its `crs` member: the feature\n * layers reproject it by themselves\n */\nexport async function geoplateformeWfs<P = Properties>(\n typeName: string,\n [west, south, east, north]: [number, number, number, number],\n options: { count?: number; signal?: AbortSignal; srsName?: string } = {},\n): Promise<FeatureCollection<P>> {\n const limit = Math.max(1, options.count ?? 50_000);\n const page = async (start: number, count: number) => {\n const url = new URL('https://data.geopf.fr/wfs/ows');\n url.search = new URLSearchParams({\n SERVICE: 'WFS',\n VERSION: '2.0.0',\n REQUEST: 'GetFeature',\n TYPENAMES: typeName,\n OUTPUTFORMAT: 'application/json',\n SRSNAME: options.srsName ?? 'EPSG:4326',\n // WFS 2.0 in EPSG:4326: latitude first\n BBOX: `${south},${west},${north},${east},urn:ogc:def:crs:EPSG::4326`,\n COUNT: String(count),\n // The first page as a single request always was\n ...(start > 0 ? { STARTINDEX: String(start) } : {}),\n }).toString();\n const response = await fetch(url, withHeaders(url, options.signal ? { signal: options.signal } : {}));\n if (!response.ok) throw new Error(`isard: ${typeName}: ${response.status}`);\n return response.json() as Promise<FeatureCollection<P> & { numberMatched?: number | string }>;\n };\n const first = await page(0, Math.min(WFS_PAGE, limit));\n const matched = Number(first.numberMatched);\n const total = Math.min(Number.isFinite(matched) ? matched : 0, limit);\n if (first.features.length < WFS_PAGE || total <= first.features.length) return first;\n const starts: number[] = [];\n for (let start = first.features.length; start < total; start += WFS_PAGE) starts.push(start);\n const rest = await Promise.all(starts.map((start) => page(start, Math.min(WFS_PAGE, total - start))));\n // Pages may overlap where the server's order shifts: each feature once, by its id\n const seen = new Set<unknown>();\n const features = [first, ...rest]\n .flatMap((r) => r.features)\n .filter((f) => f.id === undefined || (!seen.has(f.id) && seen.add(f.id) !== undefined));\n return { ...first, features };\n}\n\n/** Map presets over France, the IGN's data in a word: spread into `GeoMap.create`'s options or named by `preset` */\nexport const IGN_PRESETS = {\n /** PLAN IGN (vector, grey) seen from above */\n ign: { basemap: 'ign-plan-grey-vector', projection: 'mercator' },\n /** PLAN IGN over the IGN relief (RGE ALTI), for 3D: buildings, meshes, viewsheds */\n 'ign-3d': { basemap: 'ign-plan-grey-vector', terrain: { model: 'ign' }, projection: 'mercator', pitch: 55 },\n /** The IGN orthophotos over the IGN relief */\n 'ign-ortho-3d': { basemap: 'ign-ortho', terrain: { model: 'ign' }, projection: 'mercator', pitch: 55 },\n} as const satisfies Record<string, GeoMapOptions>;\n\n/** A preset of `IGN_PRESETS` by name */\nexport type IgnPreset = keyof typeof IGN_PRESETS;\n\n/** The IGN's Bâtiments 3D (France, 3D Tiles 1.1): its tileset */\nexport const BATIMENTS_3D_URL = 'https://prd-ign-mut-bat3.s3.sbg.io.cloud.ovh.net/tileset.json';\n\n/**\n * The IGN's Bâtiments 3D as a 3D Tiles layer, ready for `map.addTiles3d`: their heights are altitudes (NGF-IGN69),\n * raised by the geoid onto the IGN relief; untextured, colored and shaded; picked with their BD TOPO attributes\n * (`cleabs`, `hauteur`, `nature`, `usage_1`…). Its server sends no CORS headers yet: from a page of another origin,\n * through a proxy (`url`)\n */\nexport function batiments3d(options: Partial<Tiles3dOptions> = {}): Tiles3dOptions {\n return { url: BATIMENTS_3D_URL, geoid: true, color: '#e4e1d8', maxScreenSpaceError: 16, ...options };\n}\n\n/** What a building of the BD TOPO gives its extrusion */\nexport interface BdTopoBuilding {\n hauteur: number | null;\n}\n\n/**\n * The BD TOPO buildings of a box (west, south, east, north, degrees) as an extrusion layer, ready for\n * `map.addExtrusions`: from the Géoplateforme's WFS, raised to their `hauteur` (`defaultHeight` without one)\n */\nexport async function bdtopoBuildings(\n box: [number, number, number, number],\n options: Partial<ExtrusionOptions<BdTopoBuilding>> & { defaultHeight?: number; signal?: AbortSignal } = {},\n): Promise<ExtrusionOptions<BdTopoBuilding>> {\n const { defaultHeight = 6, signal, ...style } = options;\n const data = await geoplateformeWfs<BdTopoBuilding>('BDTOPO_V3:batiment', box, signal ? { signal } : {});\n return { data, height: (p) => p.hauteur ?? defaultHeight, color: '#e4e1d8', ...style };\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,14 +12,14 @@
|
|
|
12
12
|
* ```
|
|
13
13
|
*/
|
|
14
14
|
export { OPENFREEMAP_ATTRIBUTION, TERRAIN_TILES_ATTRIBUTION } from './basemaps.ts';
|
|
15
|
-
export { AttributionControl, type AttributionOptions, type Control, type ControlPosition,
|
|
15
|
+
export { AttributionControl, type AttributionOptions, type Control, type ControlPosition, NavigationControl, type NavigationOptions, } from './controls.ts';
|
|
16
16
|
export { type Crs, type CrsLike, getCrs, lambertConformalConic, registerCrs, reproject, transverseMercator, } from './crs.ts';
|
|
17
17
|
export type { DecoderUrls } from './decoders.ts';
|
|
18
18
|
export type { ExtrusionOptions, ExtrusionStyle, PolygonArrays, TileKey } from './extrusions.ts';
|
|
19
19
|
export { ExtrusionLayer } from './extrusions.ts';
|
|
20
20
|
export type { CircleOptions, CircleStyle, Feature, FeatureCollection, FeatureData, FeatureLayerStyle, FillOptions, FillStyle, Geometry, LineOptions, LineStyle, Placement, Position, Properties, Ramp, Size, Stops, Styled, } from './features.ts';
|
|
21
21
|
export { CircleLayer, FeatureLayer, FillLayer, interpolate, LineLayer, parseColor } from './features.ts';
|
|
22
|
-
export { geoplateformeWfs, geoplateformeWms, geoplateformeWmts, IGN_ATTRIBUTION } from './geoplateforme.ts';
|
|
22
|
+
export { BATIMENTS_3D_URL, type BdTopoBuilding, batiments3d, bdtopoBuildings, geoplateformeWfs, geoplateformeWms, geoplateformeWmts, IGN_ATTRIBUTION, IGN_PRESETS, type IgnPreset, } from './geoplateforme.ts';
|
|
23
23
|
export type { TextPart } from './glyphs.ts';
|
|
24
24
|
export { DEFAULT_FONT, GLYPHS_URL } from './glyphs.ts';
|
|
25
25
|
export { parseGpx } from './gpx.ts';
|
|
@@ -28,7 +28,7 @@ export type { ImageOptions, Pixels, SpriteIcon } from './icons.ts';
|
|
|
28
28
|
export { parseKml } from './kml.ts';
|
|
29
29
|
export type { CustomFrame, CustomLayerInterface, GroundOptions, GroundTexture, ModelInstance, ModelOptions, } from './layers.ts';
|
|
30
30
|
export { CustomLayer, GroundLayer, Layer, ModelLayer, NetworkLayer, RasterLayer, Tiles3dLayer, } from './layers.ts';
|
|
31
|
-
export { GeoMap } from './map.ts';
|
|
31
|
+
export { GeoMap, type LayerSpec } from './map.ts';
|
|
32
32
|
export { type Anchor, Marker, type MarkerEvent, type MarkerEvents, type MarkerOptions, Panel, type PanelOptions, Popup, type PopupEvents, type PopupOptions, } from './overlay.ts';
|
|
33
33
|
export { type Panorama, type PanoramaOptions, Panoramas } from './panoramas.ts';
|
|
34
34
|
export { PMTiles, type PmtilesEntry, type PmtilesHeader, type PmtilesTileType, tileIdToZxy, zxyToTileId, } from './pmtiles.ts';
|
|
@@ -38,7 +38,7 @@ export { setRequestHeaders } from './requests.ts';
|
|
|
38
38
|
export type { Overlap, SymbolOptions, SymbolStyle } from './symbols.ts';
|
|
39
39
|
export { SymbolLayer } from './symbols.ts';
|
|
40
40
|
export { parseTopoJson, type TopoGeometry, type Topology } from './topojson.ts';
|
|
41
|
-
export type { AnimationOptions, AtmosphereOptions, Basemap, BasemapName, BodyOptions, CelestialBody, FeatureHit, FirstPersonView, FlyToOptions, GeoMapOptions,
|
|
41
|
+
export type { AnimationOptions, AtmosphereOptions, Basemap, BasemapName, BodyOptions, CelestialBody, FeatureHit, FirstPersonView, FlyToOptions, GeoMapOptions, LoadingMode, LonLat, MapEvents, MapHoverFeatureEvent, MapPointerEvent, NetworkOptions, NetworkStyle, Point, Projection, RasterGrid, RasterOptions, RasterStyle, SwipeOptions, TerrainEncoding, TerrainModel, TerrainOptions, Tiles3dOptions, Tiles3dStyle, ViewshedOptions, } from './types.ts';
|
|
42
42
|
export type { CandidateIcon, CandidateOverlap, Json, LabelCandidate, RasterSource, Style, StyleLayer, } from './vectorstyle.ts';
|
|
43
43
|
export type { PmtilesOptions, VectorTilesOptions } from './vectortiles.ts';
|
|
44
44
|
export { basicStyle, OPENFREEMAP_STYLES, PLAN_STYLES, VectorTiles } from './vectortiles.ts';
|