isard 1.7.0 → 1.8.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 +22 -0
- package/dist/bind/layers.d.ts +10 -3
- package/dist/bind/layers.js +11 -4
- package/dist/bind/layers.js.map +1 -1
- package/dist/geoplateforme.d.ts +2 -2
- package/dist/geoplateforme.js +2 -2
- package/dist/geoplateforme.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/isard_bg.wasm +0 -0
- package/dist/isard_core_bg.wasm +0 -0
- package/dist/isard_grid_bg.wasm +0 -0
- package/dist/panoramax.d.ts +15 -2
- package/dist/panoramax.js +36 -17
- package/dist/panoramax.js.map +1 -1
- package/dist/react/CustomLayer.js +5 -4
- package/dist/react/CustomLayer.js.map +1 -1
- package/dist/react/Layer.d.ts +1 -1
- package/dist/react/Layer.js +6 -5
- package/dist/react/Layer.js.map +1 -1
- package/dist/react/VectorGeometry.js +5 -4
- package/dist/react/VectorGeometry.js.map +1 -1
- package/dist/react/context.d.ts +3 -0
- package/dist/react/context.js +8 -1
- package/dist/react/context.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,28 @@
|
|
|
3
3
|
Every notable change of `isard`. 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
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- React: the layers of the components are drawn in their declared order even when one comes later than another: a
|
|
11
|
+
`<Geometry>` waits for its tiles, so a `<Layer type="tiles3d">` declared after it came first and the ground of the
|
|
12
|
+
geometry was drawn over the buildings. Each component takes its place when it first renders (`LayerOrder.rank`);
|
|
13
|
+
the Bâtiments 3D example drops its `order={1}`.
|
|
14
|
+
|
|
15
|
+
## [1.8.0] - 2026-10-26
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- `panoramaxSequence(sequence, { around, max, api })` reads a long sequence around a photo (the page holding it, then
|
|
20
|
+
half before and half after): a survey car's day is thousands of photos, the 2000 first of them far from the one
|
|
21
|
+
clicked. The Panoramax example walks a 360° photo's sequence from that photo.
|
|
22
|
+
- The Panoramax 360° example (TypeScript and React): a walk in a survey car's 360° photos along the Louvre, each
|
|
23
|
+
projected onto the city around.
|
|
24
|
+
- The Bâtiments 3D example (TypeScript and React): the IGN's buildings of France in 3D (a beta, its server now
|
|
25
|
+
answering isard's documentation) over the 3D vector map in place of its raised buildings, picked with their BD TOPO
|
|
26
|
+
attributes, by day and by night.
|
|
27
|
+
|
|
6
28
|
## [1.7.0] - 2026-10-26
|
|
7
29
|
|
|
8
30
|
### Added
|
package/dist/bind/layers.d.ts
CHANGED
|
@@ -34,13 +34,20 @@ export declare const addBoundLayer: (map: GeoMap, { values, ...spec }: BoundLaye
|
|
|
34
34
|
export declare const rebuildBoundLayer: (map: GeoMap, old: Layer, { values, ...spec }: BoundLayerSpec) => Layer;
|
|
35
35
|
/**
|
|
36
36
|
* The layers of a binding in their declared order: `order` (default 0) from the bottom up, layers of the same order by
|
|
37
|
-
*
|
|
37
|
+
* their `rank` (where they were declared: a component's taken when it first renders, before its layer may wait for
|
|
38
|
+
* something, its tiles or its data), else by the time they came. A layer added or made anew is moved under the first
|
|
39
|
+
* layer above it
|
|
38
40
|
*/
|
|
39
41
|
export declare class LayerOrder {
|
|
40
42
|
private readonly entries;
|
|
41
43
|
private seq;
|
|
42
|
-
/**
|
|
43
|
-
|
|
44
|
+
/** The next rank: a component's place among the others, taken as React renders them in their declared order */
|
|
45
|
+
rank(): number;
|
|
46
|
+
/** Places a new layer (at its `rank`, else after every other), or a layer made anew in place of `old` */
|
|
47
|
+
place(layer: Layer, order: number, { old, rank }?: {
|
|
48
|
+
old?: Layer | undefined;
|
|
49
|
+
rank?: number | undefined;
|
|
50
|
+
}): void;
|
|
44
51
|
/** Forgets a layer removed */
|
|
45
52
|
remove(layer: Layer): void;
|
|
46
53
|
}
|
package/dist/bind/layers.js
CHANGED
|
@@ -133,13 +133,20 @@ export const rebuildBoundLayer = (map, old, { values, ...spec }) => {
|
|
|
133
133
|
};
|
|
134
134
|
/**
|
|
135
135
|
* The layers of a binding in their declared order: `order` (default 0) from the bottom up, layers of the same order by
|
|
136
|
-
*
|
|
136
|
+
* their `rank` (where they were declared: a component's taken when it first renders, before its layer may wait for
|
|
137
|
+
* something, its tiles or its data), else by the time they came. A layer added or made anew is moved under the first
|
|
138
|
+
* layer above it
|
|
137
139
|
*/
|
|
138
140
|
export class LayerOrder {
|
|
139
141
|
entries = [];
|
|
140
142
|
seq = 0;
|
|
141
|
-
/**
|
|
142
|
-
|
|
143
|
+
/** The next rank: a component's place among the others, taken as React renders them in their declared order */
|
|
144
|
+
rank() {
|
|
145
|
+
this.seq += 1;
|
|
146
|
+
return this.seq;
|
|
147
|
+
}
|
|
148
|
+
/** Places a new layer (at its `rank`, else after every other), or a layer made anew in place of `old` */
|
|
149
|
+
place(layer, order, { old, rank } = {}) {
|
|
143
150
|
const index = old ? this.entries.findIndex((e) => e.layer === old) : -1;
|
|
144
151
|
const entry = index >= 0 ? this.entries[index] : undefined;
|
|
145
152
|
if (entry) {
|
|
@@ -147,7 +154,7 @@ export class LayerOrder {
|
|
|
147
154
|
entry.order = order;
|
|
148
155
|
}
|
|
149
156
|
else {
|
|
150
|
-
this.entries.push({ layer, order, seq: this.
|
|
157
|
+
this.entries.push({ layer, order, seq: rank ?? this.rank() });
|
|
151
158
|
}
|
|
152
159
|
this.entries.sort((a, b) => a.order - b.order || a.seq - b.seq);
|
|
153
160
|
const at = this.entries.findIndex((e) => e.layer === layer);
|
package/dist/bind/layers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layers.js","sourceRoot":"","sources":["../../src/bind/layers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,qGAAqG;AACrG,MAAM,UAAU,GAA2D;IACzE,KAAK,EAAE,KAAK;IACZ,OAAO,EAAE,KAAK;IACd,KAAK,EAAE,KAAK;IACZ,OAAO,EAAE,KAAK;IACd,UAAU,EAAE,KAAK;IACjB,MAAM,EAAE,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;IAC1C,OAAO,EAAE,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,CAAC,CAAC;IACjH,OAAO,EAAE,IAAI,GAAG,CAAC,CAAC,qBAAqB,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;IAC1E,UAAU,EAAE,IAAI,GAAG,CAAC;QAClB,SAAS;QACT,WAAW;QACX,cAAc;QACd,UAAU;QACV,OAAO;QACP,KAAK;QACL,iBAAiB;QACjB,gBAAgB;QAChB,eAAe;QACf,gBAAgB;QAChB,qBAAqB;QACrB,aAAa;KACd,CAAC;IACF,MAAM,EAAE,IAAI,GAAG,EAAE;IACjB,KAAK,EAAE,IAAI,GAAG,EAAE;IAChB,MAAM,EAAE,IAAI,GAAG,EAAE;IACjB,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;CAC5E,CAAC;AAEF,+DAA+D;AAC/D,MAAM,WAAW,GAA4D;IAC3E,KAAK,EAAE,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC5C,OAAO,EAAE,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC9C,KAAK,EAAE,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC5C,OAAO,EAAE,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACpC,UAAU,EAAE,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACjD,OAAO,EAAE,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;IACnD,MAAM,EAAE,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAC;IACnD,MAAM,EAAE,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IACzC,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;CACtD,CAAC;AAEF,iDAAiD;AACjD,MAAM,MAAM,GAAG,CAAC,IAAoB,EAAwB,EAAE,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AAY7F;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAoB,EAAE,IAAoB,EAA2B,EAAE;IACjG,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAEtD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC3B,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,MAAM,GAA6C,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC;IAChG,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CACnE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CACvE,CAAC;IAEF,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAExC,MAAM,OAAO,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,KAAK,QAAQ,IAAI,CAAC,SAAS,KAAK,KAAK,IAAI,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAEjG,mFAAmF;IACnF,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACtG,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;QACnB,IAAI,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC;YAAE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;;YAC/C,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAkBF,sDAAsD;AACtD,MAAM,GAAG,GAAG,CAAC,KAAY,EAAE,MAAc,EAAE,GAAG,IAAe,EAAQ,EAAE;IACrE,MAAM,MAAM,GAAY,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAEnD,IAAI,OAAO,MAAM,KAAK,UAAU;QAAE,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AAC9D,CAAC,CAAC;AAEF,+DAA+D;AAC/D,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,KAAY,EACZ,IAAoB,EACpB,MAAgD,EAC1C,EAAE;IACR,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1B,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;IAEvB,IAAI,MAAM,IAAI,GAAG;QAAE,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IACnD,IAAI,QAAQ,IAAI,GAAG;QAAE,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzD,IAAI,QAAQ,IAAI,GAAG;QAAE,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzD,IAAI,OAAO,IAAI,GAAG;QAAE,GAAG,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;IACtD,IAAI,QAAQ,IAAI,GAAG;QAAE,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;SACtE,IAAI,MAAM,IAAI,GAAG;QAAE,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IACxD,IAAI,SAAS,IAAI,GAAG;QAAE,GAAG,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC;IACpE,IAAI,OAAO,IAAI,GAAG;QAAE,GAAG,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;IACtD,IAAI,YAAY,IAAI,GAAG;QAAE,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;IACrE,IAAI,WAAW,IAAI,GAAG,IAAI,mBAAmB,IAAI,GAAG,EAAE,CAAC;QACrD,GAAG,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC;IACnF,CAAC;IACD,IAAI,UAAU,IAAI,GAAG,EAAE,CAAC;QACtB,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE;YAC3D,GAAG,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;IACL,CAAC;IACD,IAAI,UAAU,IAAI,GAAG,EAAE,CAAC;QACtB,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE;YAC7D,GAAG,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;IACL,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,GAAG,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;AACjF,CAAC,CAAC;AAEF,wDAAwD;AACxD,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAW,EAAE,EAAE,MAAM,EAAE,GAAG,IAAI,EAAkB,EAAS,EAAE;IACvF,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,IAAiB,CAAC,CAAC;IAEzC,IAAI,MAAM;QAAE,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;IAE5C,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,mFAAmF;AACnF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,GAAW,EAAE,GAAU,EAAE,EAAE,MAAM,EAAE,GAAG,IAAI,EAAkB,EAAS,EAAE;IACvG,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,EAAE,IAAiB,CAAC,CAAC;IAEvD,IAAI,MAAM;QAAE,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;IAE5C,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,OAAO,UAAU;IACJ,OAAO,GAAmD,EAAE,CAAC;IACtE,GAAG,GAAG,CAAC,CAAC;IAEhB,iEAAiE;IACjE,KAAK,CAAC,KAAY,EAAE,KAAa,EAAE,GAAW;QAC5C,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACxE,MAAM,KAAK,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAE3D,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC;YACpB,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC;QACtB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QAEhE,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;QAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC;QAE1C,IAAI,KAAK;YAAE,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC;IAED,8BAA8B;IAC9B,MAAM,CAAC,KAAY;QACjB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;QAE/D,IAAI,KAAK,IAAI,CAAC;YAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAChD,CAAC;CACF","sourcesContent":["/**\n * What a framework's binding (isard/react, isard/vue) does when the description of a layer changes: the least the\n * layer needs (its data, its style, its instances), or a new layer in its place when what changed is set at creation\n * (its URL, its grid, its nodes). Free of any framework.\n */\n\nimport type { Layer } from '../layers/layers.ts';\nimport type { GeoMap, LayerSpec } from '../map.ts';\n\n/** A layer as a binding describes it: the options of `map.add`, and the values of its features or nodes\n * (`setValues`: what colors them by a ramp) */\nexport type BoundLayerSpec<P = Record<string, unknown>> = LayerSpec<P> & { values?: Float32Array };\n\n/** The keys `setStyle` takes, by layer type; `'all'`: every key but the data (the feature layers) */\nconst STYLE_KEYS: Record<LayerSpec['type'], 'all' | ReadonlySet<string>> = {\n lines: 'all',\n circles: 'all',\n fills: 'all',\n symbols: 'all',\n extrusions: 'all',\n raster: new Set(['opacity', 'saturation']),\n network: new Set(['width', 'max', 'contour', 'opacity', 'halo', 'haloOpacity', 'ramp', 'unreachedColor', 'fade']),\n tiles3d: new Set(['maxScreenSpaceError', 'opacity', 'pointSize', 'color']),\n pointcloud: new Set([\n 'colorBy',\n 'pointSize',\n 'maxPointSize',\n 'sizeMode',\n 'shape',\n 'edl',\n 'classifications',\n 'elevationRange',\n 'elevationRamp',\n 'intensityRange',\n 'maxScreenSpaceError',\n 'pointBudget',\n ]),\n models: new Set(),\n trees: new Set(),\n ground: new Set(),\n flow: new Set(['colors', 'width', 'opacity', 'height', 'speed', 'density']),\n};\n\n/** Keys a layer takes by a method of its own, by layer type */\nconst OWN_SETTERS: Partial<Record<LayerSpec['type'], ReadonlySet<string>>> = {\n lines: new Set(['data', 'filter', 'values']),\n circles: new Set(['data', 'filter', 'values']),\n fills: new Set(['data', 'filter', 'values']),\n symbols: new Set(['data', 'filter']),\n extrusions: new Set(['data', 'filter', 'values']),\n network: new Set(['costs', 'edgeWidths', 'values']),\n models: new Set(['instances', 'altitudeReference']),\n ground: new Set(['uniforms', 'textures']),\n flow: new Set(['field', 'fields', 'time', 'playing']),\n};\n\n/** The keys of a description and their values */\nconst fields = (spec: BoundLayerSpec): Map<string, unknown> => new Map(Object.entries(spec));\n\n/** What to do with a layer whose description went from `prev` to `next` */\nexport type LayerChange =\n | { rebuild: true }\n | {\n rebuild: false;\n /** The keys changed, with their new values */\n style: Record<string, unknown>;\n own: Record<string, unknown>;\n };\n\n/**\n * The change from one description to the next, or `undefined` when nothing changed. Values are compared by identity:\n * data, functions and arrays given anew at each render are changes (keep them in a memo)\n */\nexport const layerChange = (prev: BoundLayerSpec, next: BoundLayerSpec): LayerChange | undefined => {\n if (prev.type !== next.type) return { rebuild: true };\n\n const before = fields(prev);\n const after = fields(next);\n const styleKeys = STYLE_KEYS[next.type];\n const own = OWN_SETTERS[next.type];\n const change: Extract<LayerChange, { rebuild: false }> = { rebuild: false, style: {}, own: {} };\n const keys = [...new Set([...before.keys(), ...after.keys()])].filter(\n (key) => key !== 'type' && !Object.is(before.get(key), after.get(key)),\n );\n\n if (keys.length === 0) return undefined;\n\n const isStyle = (key: string) => key !== 'before' && (styleKeys === 'all' || styleKeys.has(key));\n\n // A style or setting taken away: the layer goes back to its defaults, as made anew\n if (keys.some((key) => !after.has(key) || !(own?.has(key) || isStyle(key)))) return { rebuild: true };\n keys.forEach((key) => {\n if (own?.has(key)) change.own[key] = after.get(key);\n else change.style[key] = after.get(key);\n });\n\n return change;\n};\n\n/** The methods a change calls on a layer, those of its type */\ntype Setter =\n | 'setStyle'\n | 'setData'\n | 'setFilter'\n | 'setValues'\n | 'setCosts'\n | 'setEdgeWidths'\n | 'setInstances'\n | 'setUniform'\n | 'setTexture'\n | 'setField'\n | 'setFields'\n | 'setTime'\n | 'setPlaying';\n\n/** Calls a setter of the layer, if its type has it */\nconst set = (layer: Layer, setter: Setter, ...args: unknown[]): void => {\n const method: unknown = Reflect.get(layer, setter);\n\n if (typeof method === 'function') method.apply(layer, args);\n};\n\n/** Applies a change that keeps the layer (`rebuild: false`) */\nexport const applyLayerChange = (\n layer: Layer,\n next: BoundLayerSpec,\n change: Extract<LayerChange, { rebuild: false }>,\n): void => {\n const spec = fields(next);\n const own = change.own;\n\n if ('data' in own) set(layer, 'setData', own.data);\n if ('filter' in own) set(layer, 'setFilter', own.filter);\n if ('values' in own) set(layer, 'setValues', own.values);\n if ('field' in own) set(layer, 'setField', own.field);\n if ('fields' in own) set(layer, 'setFields', own.fields, spec.get('time'));\n else if ('time' in own) set(layer, 'setTime', own.time);\n if ('playing' in own) set(layer, 'setPlaying', own.playing ?? true);\n if ('costs' in own) set(layer, 'setCosts', own.costs);\n if ('edgeWidths' in own) set(layer, 'setEdgeWidths', own.edgeWidths);\n if ('instances' in own || 'altitudeReference' in own) {\n set(layer, 'setInstances', spec.get('instances'), spec.get('altitudeReference'));\n }\n if ('uniforms' in own) {\n Object.entries(own.uniforms ?? {}).forEach(([name, value]) => {\n set(layer, 'setUniform', name, value);\n });\n }\n if ('textures' in own) {\n Object.entries(own.textures ?? {}).forEach(([name, texture]) => {\n set(layer, 'setTexture', name, texture);\n });\n }\n if (Object.keys(change.style).length > 0) set(layer, 'setStyle', change.style);\n};\n\n/** Adds a layer from its description, its values set */\nexport const addBoundLayer = (map: GeoMap, { values, ...spec }: BoundLayerSpec): Layer => {\n const layer = map.add(spec as LayerSpec);\n\n if (values) set(layer, 'setValues', values);\n\n return layer;\n};\n\n/** A layer made anew from its description in the place of `old`, its values set */\nexport const rebuildBoundLayer = (map: GeoMap, old: Layer, { values, ...spec }: BoundLayerSpec): Layer => {\n const layer = map.rebuildLayer(old, spec as LayerSpec);\n\n if (values) set(layer, 'setValues', values);\n\n return layer;\n};\n\n/**\n * The layers of a binding in their declared order: `order` (default 0) from the bottom up, layers of the same order by\n * the time they came. A layer added or made anew is moved under the first layer above it\n */\nexport class LayerOrder {\n private readonly entries: { layer: Layer; order: number; seq: number }[] = [];\n private seq = 0;\n\n /** Places a new layer, or a layer made anew in place of `old` */\n place(layer: Layer, order: number, old?: Layer): void {\n const index = old ? this.entries.findIndex((e) => e.layer === old) : -1;\n const entry = index >= 0 ? this.entries[index] : undefined;\n\n if (entry) {\n entry.layer = layer;\n entry.order = order;\n } else {\n this.entries.push({ layer, order, seq: this.seq++ });\n }\n this.entries.sort((a, b) => a.order - b.order || a.seq - b.seq);\n\n const at = this.entries.findIndex((e) => e.layer === layer);\n const above = this.entries[at + 1]?.layer;\n\n if (above) layer.moveBefore(above);\n }\n\n /** Forgets a layer removed */\n remove(layer: Layer): void {\n const index = this.entries.findIndex((e) => e.layer === layer);\n\n if (index >= 0) this.entries.splice(index, 1);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"layers.js","sourceRoot":"","sources":["../../src/bind/layers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What a framework's binding (isard/react, isard/vue) does when the description of a layer changes: the least the\n * layer needs (its data, its style, its instances), or a new layer in its place when what changed is set at creation\n * (its URL, its grid, its nodes). Free of any framework.\n */\n\nimport type { Layer } from '../layers/layers.ts';\nimport type { GeoMap, LayerSpec } from '../map.ts';\n\n/** A layer as a binding describes it: the options of `map.add`, and the values of its features or nodes\n * (`setValues`: what colors them by a ramp) */\nexport type BoundLayerSpec<P = Record<string, unknown>> = LayerSpec<P> & { values?: Float32Array };\n\n/** The keys `setStyle` takes, by layer type; `'all'`: every key but the data (the feature layers) */\nconst STYLE_KEYS: Record<LayerSpec['type'], 'all' | ReadonlySet<string>> = {\n lines: 'all',\n circles: 'all',\n fills: 'all',\n symbols: 'all',\n extrusions: 'all',\n raster: new Set(['opacity', 'saturation']),\n network: new Set(['width', 'max', 'contour', 'opacity', 'halo', 'haloOpacity', 'ramp', 'unreachedColor', 'fade']),\n tiles3d: new Set(['maxScreenSpaceError', 'opacity', 'pointSize', 'color']),\n pointcloud: new Set([\n 'colorBy',\n 'pointSize',\n 'maxPointSize',\n 'sizeMode',\n 'shape',\n 'edl',\n 'classifications',\n 'elevationRange',\n 'elevationRamp',\n 'intensityRange',\n 'maxScreenSpaceError',\n 'pointBudget',\n ]),\n models: new Set(),\n trees: new Set(),\n ground: new Set(),\n flow: new Set(['colors', 'width', 'opacity', 'height', 'speed', 'density']),\n};\n\n/** Keys a layer takes by a method of its own, by layer type */\nconst OWN_SETTERS: Partial<Record<LayerSpec['type'], ReadonlySet<string>>> = {\n lines: new Set(['data', 'filter', 'values']),\n circles: new Set(['data', 'filter', 'values']),\n fills: new Set(['data', 'filter', 'values']),\n symbols: new Set(['data', 'filter']),\n extrusions: new Set(['data', 'filter', 'values']),\n network: new Set(['costs', 'edgeWidths', 'values']),\n models: new Set(['instances', 'altitudeReference']),\n ground: new Set(['uniforms', 'textures']),\n flow: new Set(['field', 'fields', 'time', 'playing']),\n};\n\n/** The keys of a description and their values */\nconst fields = (spec: BoundLayerSpec): Map<string, unknown> => new Map(Object.entries(spec));\n\n/** What to do with a layer whose description went from `prev` to `next` */\nexport type LayerChange =\n | { rebuild: true }\n | {\n rebuild: false;\n /** The keys changed, with their new values */\n style: Record<string, unknown>;\n own: Record<string, unknown>;\n };\n\n/**\n * The change from one description to the next, or `undefined` when nothing changed. Values are compared by identity:\n * data, functions and arrays given anew at each render are changes (keep them in a memo)\n */\nexport const layerChange = (prev: BoundLayerSpec, next: BoundLayerSpec): LayerChange | undefined => {\n if (prev.type !== next.type) return { rebuild: true };\n\n const before = fields(prev);\n const after = fields(next);\n const styleKeys = STYLE_KEYS[next.type];\n const own = OWN_SETTERS[next.type];\n const change: Extract<LayerChange, { rebuild: false }> = { rebuild: false, style: {}, own: {} };\n const keys = [...new Set([...before.keys(), ...after.keys()])].filter(\n (key) => key !== 'type' && !Object.is(before.get(key), after.get(key)),\n );\n\n if (keys.length === 0) return undefined;\n\n const isStyle = (key: string) => key !== 'before' && (styleKeys === 'all' || styleKeys.has(key));\n\n // A style or setting taken away: the layer goes back to its defaults, as made anew\n if (keys.some((key) => !after.has(key) || !(own?.has(key) || isStyle(key)))) return { rebuild: true };\n keys.forEach((key) => {\n if (own?.has(key)) change.own[key] = after.get(key);\n else change.style[key] = after.get(key);\n });\n\n return change;\n};\n\n/** The methods a change calls on a layer, those of its type */\ntype Setter =\n | 'setStyle'\n | 'setData'\n | 'setFilter'\n | 'setValues'\n | 'setCosts'\n | 'setEdgeWidths'\n | 'setInstances'\n | 'setUniform'\n | 'setTexture'\n | 'setField'\n | 'setFields'\n | 'setTime'\n | 'setPlaying';\n\n/** Calls a setter of the layer, if its type has it */\nconst set = (layer: Layer, setter: Setter, ...args: unknown[]): void => {\n const method: unknown = Reflect.get(layer, setter);\n\n if (typeof method === 'function') method.apply(layer, args);\n};\n\n/** Applies a change that keeps the layer (`rebuild: false`) */\nexport const applyLayerChange = (\n layer: Layer,\n next: BoundLayerSpec,\n change: Extract<LayerChange, { rebuild: false }>,\n): void => {\n const spec = fields(next);\n const own = change.own;\n\n if ('data' in own) set(layer, 'setData', own.data);\n if ('filter' in own) set(layer, 'setFilter', own.filter);\n if ('values' in own) set(layer, 'setValues', own.values);\n if ('field' in own) set(layer, 'setField', own.field);\n if ('fields' in own) set(layer, 'setFields', own.fields, spec.get('time'));\n else if ('time' in own) set(layer, 'setTime', own.time);\n if ('playing' in own) set(layer, 'setPlaying', own.playing ?? true);\n if ('costs' in own) set(layer, 'setCosts', own.costs);\n if ('edgeWidths' in own) set(layer, 'setEdgeWidths', own.edgeWidths);\n if ('instances' in own || 'altitudeReference' in own) {\n set(layer, 'setInstances', spec.get('instances'), spec.get('altitudeReference'));\n }\n if ('uniforms' in own) {\n Object.entries(own.uniforms ?? {}).forEach(([name, value]) => {\n set(layer, 'setUniform', name, value);\n });\n }\n if ('textures' in own) {\n Object.entries(own.textures ?? {}).forEach(([name, texture]) => {\n set(layer, 'setTexture', name, texture);\n });\n }\n if (Object.keys(change.style).length > 0) set(layer, 'setStyle', change.style);\n};\n\n/** Adds a layer from its description, its values set */\nexport const addBoundLayer = (map: GeoMap, { values, ...spec }: BoundLayerSpec): Layer => {\n const layer = map.add(spec as LayerSpec);\n\n if (values) set(layer, 'setValues', values);\n\n return layer;\n};\n\n/** A layer made anew from its description in the place of `old`, its values set */\nexport const rebuildBoundLayer = (map: GeoMap, old: Layer, { values, ...spec }: BoundLayerSpec): Layer => {\n const layer = map.rebuildLayer(old, spec as LayerSpec);\n\n if (values) set(layer, 'setValues', values);\n\n return layer;\n};\n\n/**\n * The layers of a binding in their declared order: `order` (default 0) from the bottom up, layers of the same order by\n * their `rank` (where they were declared: a component's taken when it first renders, before its layer may wait for\n * something, its tiles or its data), else by the time they came. A layer added or made anew is moved under the first\n * layer above it\n */\nexport class LayerOrder {\n private readonly entries: { layer: Layer; order: number; seq: number }[] = [];\n private seq = 0;\n\n /** The next rank: a component's place among the others, taken as React renders them in their declared order */\n rank(): number {\n this.seq += 1;\n\n return this.seq;\n }\n\n /** Places a new layer (at its `rank`, else after every other), or a layer made anew in place of `old` */\n place(layer: Layer, order: number, { old, rank }: { old?: Layer | undefined; rank?: number | undefined } = {}): void {\n const index = old ? this.entries.findIndex((e) => e.layer === old) : -1;\n const entry = index >= 0 ? this.entries[index] : undefined;\n\n if (entry) {\n entry.layer = layer;\n entry.order = order;\n } else {\n this.entries.push({ layer, order, seq: rank ?? this.rank() });\n }\n this.entries.sort((a, b) => a.order - b.order || a.seq - b.seq);\n\n const at = this.entries.findIndex((e) => e.layer === layer);\n const above = this.entries[at + 1]?.layer;\n\n if (above) layer.moveBefore(above);\n }\n\n /** Forgets a layer removed */\n remove(layer: Layer): void {\n const index = this.entries.findIndex((e) => e.layer === layer);\n\n if (index >= 0) this.entries.splice(index, 1);\n }\n}\n"]}
|
package/dist/geoplateforme.d.ts
CHANGED
|
@@ -84,8 +84,8 @@ export declare const BATIMENTS_3D_URL = "https://prd-ign-mut-bat3.s3.sbg.io.clou
|
|
|
84
84
|
/**
|
|
85
85
|
* The IGN's Bâtiments 3D as a 3D Tiles layer, ready for `map.addTiles3d`: their heights are altitudes (NGF-IGN69),
|
|
86
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`…).
|
|
88
|
-
* through a proxy (`url`)
|
|
87
|
+
* (`cleabs`, `hauteur`, `nature`, `usage_1`…). A beta: its server answers the pages of a few origins only (the IGN's
|
|
88
|
+
* sites, isard's documentation); from another, through a proxy (`url`)
|
|
89
89
|
*/
|
|
90
90
|
export declare const batiments3d: (options?: Partial<Tiles3dOptions>) => Tiles3dOptions;
|
|
91
91
|
/** What a building of the BD TOPO gives its extrusion: its height to the eaves (`hauteur`), the altitudes of its foot,
|
package/dist/geoplateforme.js
CHANGED
|
@@ -134,8 +134,8 @@ export const BATIMENTS_3D_URL = 'https://prd-ign-mut-bat3.s3.sbg.io.cloud.ovh.ne
|
|
|
134
134
|
/**
|
|
135
135
|
* The IGN's Bâtiments 3D as a 3D Tiles layer, ready for `map.addTiles3d`: their heights are altitudes (NGF-IGN69),
|
|
136
136
|
* raised by the geoid onto the IGN relief; untextured, colored and shaded; picked with their BD TOPO attributes
|
|
137
|
-
* (`cleabs`, `hauteur`, `nature`, `usage_1`…).
|
|
138
|
-
* through a proxy (`url`)
|
|
137
|
+
* (`cleabs`, `hauteur`, `nature`, `usage_1`…). A beta: its server answers the pages of a few origins only (the IGN's
|
|
138
|
+
* sites, isard's documentation); from another, through a proxy (`url`)
|
|
139
139
|
*/
|
|
140
140
|
export const batiments3d = (options = {}) => {
|
|
141
141
|
return { url: BATIMENTS_3D_URL, geoid: true, color: '#e4e1d8', maxScreenSpaceError: 16, ...options };
|
|
@@ -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 */\n\nimport type { TileGrid, TileMatrix } from './basemap/grid.ts';\nimport { withHeaders } from './engine/requests.ts';\nimport type { ExtrusionOptions } from './layers/extrusions.ts';\nimport type { FeatureCollection, Properties } from './layers/features.ts';\nimport type { GeoMapOptions, RasterOptions, Tiles3dOptions } from './types.ts';\nimport { isRecord } from './util/guards.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 const lambert93Grid = (name: string, min: number, max: number): TileGrid => {\n const matrices = Array.from({ length: Math.max(0, max - min + 1) }, (_, i): TileMatrix => {\n const level = min + i;\n\n return { id: level, resolution: 209715.2 / 2 ** level, origin: [0, 12000000] };\n });\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 const 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\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\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 const 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\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/** A page of WFS features in GeoJSON, with the number of features matched (a string from some servers) */\ntype WfsPage<P> = FeatureCollection<P> & { numberMatched?: number | string };\n\nconst isWfsPage = <P>(value: unknown): value is WfsPage<P> =>\n typeof value === 'object' && value !== null && 'features' in value && Array.isArray(value.features);\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 const geoplateformeWfs = async <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\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\n const response = await fetch(url, withHeaders(url, options.signal ? { signal: options.signal } : {}));\n\n if (!response.ok) throw new Error(`isard: ${typeName}: ${response.status}`);\n\n const json: unknown = await response.json();\n\n if (!isWfsPage<P>(json)) throw new Error(`isard: ${typeName}: not a GeoJSON feature collection`);\n\n return json;\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\n if (first.features.length < WFS_PAGE || total <= first.features.length) return first;\n\n const starts = Array.from(\n { length: Math.ceil((total - first.features.length) / WFS_PAGE) },\n (_, i) => first.features.length + i * WFS_PAGE,\n );\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\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 const 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: its height to the eaves (`hauteur`), the altitudes of its foot,\n * its eaves and its ridge (metres; the ridge's known in some places only) */\nexport interface BdTopoBuilding {\n hauteur: number | null;\n altitude_minimale_sol?: number | null;\n altitude_minimale_toit?: number | null;\n altitude_maximale_toit?: number | null;\n}\n\n/** Metres under which a BD TOPO roof, from its eaves to its ridge, is drawn flat */\nconst FLAT_ROOF_METRES = 0.5;\n\n/** A BD TOPO building's roof over its eaves (metres, from its ridge's and its eaves' altitudes), undefined unknown */\nconst roofOver = (p: BdTopoBuilding): number | undefined => {\n const [eaves, ridge] = [p.altitude_minimale_toit, p.altitude_maximale_toit];\n\n return typeof eaves === 'number' && typeof ridge === 'number' && ridge >= eaves ? ridge - eaves : undefined;\n};\n\n/**\n * A BD TOPO building's height, roof and roof height as `addExtrusions` takes them: raised to its ridge, its roof as\n * high as from its eaves to its ridge (flat under half a metre), where the BD TOPO gives its ridge's altitude (most of\n * the towns, not Paris yet); else to its `hauteur` (`defaultHeight` without one), its roof generated from its outline\n * within it\n */\nexport const bdtopoRoofs = (\n defaultHeight = 6,\n): Pick<ExtrusionOptions<BdTopoBuilding>, 'height' | 'roof' | 'roofHeight'> => ({\n height: (p) => (p.hauteur ?? defaultHeight) + (roofOver(p) ?? 0),\n roof: (p) => {\n const over = roofOver(p);\n\n return over === undefined || over >= FLAT_ROOF_METRES ? 'generated' : 'flat';\n },\n roofHeight: (p) => roofOver(p) ?? Number.NaN,\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 ridge under a roof of its height where the BD\n * TOPO gives it (`bdtopoRoofs`), else to their `hauteur` (`defaultHeight` without one)\n */\nexport const bdtopoBuildings = async (\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\n return { data, ...bdtopoRoofs(defaultHeight), color: '#e4e1d8', ...style };\n};\n\n/** A place the Géoplateforme's geocoding found: its label, position and kind */\nexport interface GeocodedPlace {\n /** The full label (`10 Rue de Rivoli, 75004 Paris`) */\n label: string;\n lonLat: [lon: number, lat: number];\n /** `'address'` (a street address) or `'place'` (a place name: a town, a monument, a summit) */\n kind: 'address' | 'place';\n}\n\nconst GEOCODING_URL = 'https://data.geopf.fr/geocodage/completion';\n\n/** One result of the completion service: what is read of it, checked (JSON from elsewhere) */\nconst isCompletion = (value: unknown): value is { fulltext: string; x: number; y: number; kind?: unknown } =>\n isRecord(value) && typeof value.fulltext === 'string' && Number.isFinite(value.x) && Number.isFinite(value.y);\n\n/**\n * Places of France matching `text` as it is typed, from the Géoplateforme's completion service (addresses and place\n * names, no key), the best first; an empty list for a text under 3 characters\n */\nexport const geoplateformeGeocode = async (\n text: string,\n options: { count?: number; signal?: AbortSignal } = {},\n): Promise<GeocodedPlace[]> => {\n if (text.trim().length < 3) return [];\n\n const url = `${GEOCODING_URL}?text=${encodeURIComponent(text)}&type=StreetAddress,PositionOfInterest&maximumResponses=${options.count ?? 10}`;\n const response = await fetch(url, withHeaders(url, options.signal ? { signal: options.signal } : {}));\n\n if (!response.ok) throw new Error(`isard: geocoding: ${response.status}`);\n\n const json: unknown = await response.json();\n const results = isRecord(json) && Array.isArray(json.results) ? json.results : [];\n\n return results.filter(isCompletion).map((r) => ({\n label: r.fulltext,\n lonLat: [r.x, r.y],\n kind: r.kind === 'StreetAddress' || r.kind === 'housenumber' || r.kind === 'street' ? 'address' : 'place',\n }));\n};\n"]}
|
|
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 */\n\nimport type { TileGrid, TileMatrix } from './basemap/grid.ts';\nimport { withHeaders } from './engine/requests.ts';\nimport type { ExtrusionOptions } from './layers/extrusions.ts';\nimport type { FeatureCollection, Properties } from './layers/features.ts';\nimport type { GeoMapOptions, RasterOptions, Tiles3dOptions } from './types.ts';\nimport { isRecord } from './util/guards.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 const lambert93Grid = (name: string, min: number, max: number): TileGrid => {\n const matrices = Array.from({ length: Math.max(0, max - min + 1) }, (_, i): TileMatrix => {\n const level = min + i;\n\n return { id: level, resolution: 209715.2 / 2 ** level, origin: [0, 12000000] };\n });\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 const 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\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\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 const 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\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/** A page of WFS features in GeoJSON, with the number of features matched (a string from some servers) */\ntype WfsPage<P> = FeatureCollection<P> & { numberMatched?: number | string };\n\nconst isWfsPage = <P>(value: unknown): value is WfsPage<P> =>\n typeof value === 'object' && value !== null && 'features' in value && Array.isArray(value.features);\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 const geoplateformeWfs = async <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\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\n const response = await fetch(url, withHeaders(url, options.signal ? { signal: options.signal } : {}));\n\n if (!response.ok) throw new Error(`isard: ${typeName}: ${response.status}`);\n\n const json: unknown = await response.json();\n\n if (!isWfsPage<P>(json)) throw new Error(`isard: ${typeName}: not a GeoJSON feature collection`);\n\n return json;\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\n if (first.features.length < WFS_PAGE || total <= first.features.length) return first;\n\n const starts = Array.from(\n { length: Math.ceil((total - first.features.length) / WFS_PAGE) },\n (_, i) => first.features.length + i * WFS_PAGE,\n );\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\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`…). A beta: its server answers the pages of a few origins only (the IGN's\n * sites, isard's documentation); from another, through a proxy (`url`)\n */\nexport const 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: its height to the eaves (`hauteur`), the altitudes of its foot,\n * its eaves and its ridge (metres; the ridge's known in some places only) */\nexport interface BdTopoBuilding {\n hauteur: number | null;\n altitude_minimale_sol?: number | null;\n altitude_minimale_toit?: number | null;\n altitude_maximale_toit?: number | null;\n}\n\n/** Metres under which a BD TOPO roof, from its eaves to its ridge, is drawn flat */\nconst FLAT_ROOF_METRES = 0.5;\n\n/** A BD TOPO building's roof over its eaves (metres, from its ridge's and its eaves' altitudes), undefined unknown */\nconst roofOver = (p: BdTopoBuilding): number | undefined => {\n const [eaves, ridge] = [p.altitude_minimale_toit, p.altitude_maximale_toit];\n\n return typeof eaves === 'number' && typeof ridge === 'number' && ridge >= eaves ? ridge - eaves : undefined;\n};\n\n/**\n * A BD TOPO building's height, roof and roof height as `addExtrusions` takes them: raised to its ridge, its roof as\n * high as from its eaves to its ridge (flat under half a metre), where the BD TOPO gives its ridge's altitude (most of\n * the towns, not Paris yet); else to its `hauteur` (`defaultHeight` without one), its roof generated from its outline\n * within it\n */\nexport const bdtopoRoofs = (\n defaultHeight = 6,\n): Pick<ExtrusionOptions<BdTopoBuilding>, 'height' | 'roof' | 'roofHeight'> => ({\n height: (p) => (p.hauteur ?? defaultHeight) + (roofOver(p) ?? 0),\n roof: (p) => {\n const over = roofOver(p);\n\n return over === undefined || over >= FLAT_ROOF_METRES ? 'generated' : 'flat';\n },\n roofHeight: (p) => roofOver(p) ?? Number.NaN,\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 ridge under a roof of its height where the BD\n * TOPO gives it (`bdtopoRoofs`), else to their `hauteur` (`defaultHeight` without one)\n */\nexport const bdtopoBuildings = async (\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\n return { data, ...bdtopoRoofs(defaultHeight), color: '#e4e1d8', ...style };\n};\n\n/** A place the Géoplateforme's geocoding found: its label, position and kind */\nexport interface GeocodedPlace {\n /** The full label (`10 Rue de Rivoli, 75004 Paris`) */\n label: string;\n lonLat: [lon: number, lat: number];\n /** `'address'` (a street address) or `'place'` (a place name: a town, a monument, a summit) */\n kind: 'address' | 'place';\n}\n\nconst GEOCODING_URL = 'https://data.geopf.fr/geocodage/completion';\n\n/** One result of the completion service: what is read of it, checked (JSON from elsewhere) */\nconst isCompletion = (value: unknown): value is { fulltext: string; x: number; y: number; kind?: unknown } =>\n isRecord(value) && typeof value.fulltext === 'string' && Number.isFinite(value.x) && Number.isFinite(value.y);\n\n/**\n * Places of France matching `text` as it is typed, from the Géoplateforme's completion service (addresses and place\n * names, no key), the best first; an empty list for a text under 3 characters\n */\nexport const geoplateformeGeocode = async (\n text: string,\n options: { count?: number; signal?: AbortSignal } = {},\n): Promise<GeocodedPlace[]> => {\n if (text.trim().length < 3) return [];\n\n const url = `${GEOCODING_URL}?text=${encodeURIComponent(text)}&type=StreetAddress,PositionOfInterest&maximumResponses=${options.count ?? 10}`;\n const response = await fetch(url, withHeaders(url, options.signal ? { signal: options.signal } : {}));\n\n if (!response.ok) throw new Error(`isard: geocoding: ${response.status}`);\n\n const json: unknown = await response.json();\n const results = isRecord(json) && Array.isArray(json.results) ? json.results : [];\n\n return results.filter(isCompletion).map((r) => ({\n label: r.fulltext,\n lonLat: [r.x, r.y],\n kind: r.kind === 'StreetAddress' || r.kind === 'housenumber' || r.kind === 'street' ? 'address' : 'place',\n }));\n};\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -59,7 +59,7 @@ export { type TreeKind, type TreeOptions, treeKind } from './layers/trees.ts';
|
|
|
59
59
|
export { type VectorFeature, VectorLayer, type VectorSublayer } from './layers/vectors.ts';
|
|
60
60
|
export type { HoverPicking } from './map/hover-pick.ts';
|
|
61
61
|
export { GeoMap, type LayerSpec } from './map.ts';
|
|
62
|
-
export { PANORAMAX_API, type PanoramaxPicture, panoramaxPanoramas, panoramaxPhoto, panoramaxPicture, panoramaxSequence, panoramaxStyle, } from './panoramax.ts';
|
|
62
|
+
export { PANORAMAX_API, type PanoramaxPicture, type PanoramaxSequenceOptions, panoramaxPanoramas, panoramaxPhoto, panoramaxPicture, panoramaxSequence, panoramaxStyle, } from './panoramax.ts';
|
|
63
63
|
export type { AnimationOptions, AtmosphereOptions, Basemap, BasemapName, BodyOptions, CelestialBody, FeatureHit, FirstPersonView, FlyToOptions, GeoMapOptions, LoadingMode, LonLat, MapEvents, MapHoverFeatureEvent, MapPointerEvent, NetworkOptions, NetworkStyle, Point, Projection, RasterGrid, RasterOptions, RasterStyle, SunOptions, SwipeOptions, TerrainEncoding, TerrainModel, TerrainOptions, Tiles3dOptions, Tiles3dStyle, ViewshedOptions, } from './types.ts';
|
|
64
64
|
export { AttributionControl, type AttributionOptions, type Control, type ControlPosition, NavigationControl, type NavigationOptions, } from './ui/controls.ts';
|
|
65
65
|
export { MinimapControl, type MinimapOptions } from './ui/minimap.ts';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAE3F,OAAO,EACL,OAAO,EAIP,WAAW,EACX,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAuB,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAmB,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAmB9E,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACxF,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAsB,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjG,OAAO,EAGL,MAAM,EACN,qBAAqB,EACrB,WAAW,EACX,SAAS,EACT,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAOL,OAAO,EACP,OAAO,GACR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAoC,MAAM,oBAAoB,CAAC;AAErF,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EACL,gBAAgB,EAEhB,WAAW,EACX,eAAe,EACf,WAAW,EAEX,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,WAAW,EAEX,aAAa,GACd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAa,MAAM,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE3D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAqBxD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEhH,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEtF,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAU9D,OAAO,EACL,WAAW,EACX,WAAW,EACX,KAAK,EACL,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAY,GACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAKL,SAAS,GAEV,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAqB,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEnE,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE3F,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAmC,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,EAAsB,WAAW,EAAuB,MAAM,qBAAqB,CAAC;AAE3F,OAAO,EAAE,MAAM,EAAkB,MAAM,UAAU,CAAC;AAClD,OAAO,EACL,aAAa,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * isard: a WebGL2 map engine for large, interactive data layers, labels and 3D Tiles.\n *\n * ```ts\n * import { GeoMap } from 'isard';\n * const map = await GeoMap.create(container, { center: [2.4246, 48.8457], zoom: 13 });\n * const network = map.addNetwork({ nodes, edges, max: 1800, contour: 300 });\n * map.on('hover', ({ lonLat }) => lonLat && network.setValues(travelTimes(lonLat)));\n * map.addTiles3d({ url: 'https://…/tileset.json' });\n * map.addControl(new NavigationControl());\n * new Marker().setLonLat([2.4246, 48.8457]).setPopup(new Popup({ offset: [0, -34] }).setText('Here')).addTo(map);\n * ```\n */\nexport { OPENFREEMAP_ATTRIBUTION, TERRAIN_TILES_ATTRIBUTION } from './basemap/basemaps.ts';\nexport type { TileGrid, TileMatrix } from './basemap/grid.ts';\nexport {\n PMTiles,\n type PmtilesEntry,\n type PmtilesHeader,\n type PmtilesTileType,\n tileIdToZxy,\n zxyToTileId,\n} from './basemap/pmtiles.ts';\nexport { basicStyle, type PmtilesOptions } from './basemap/pmtileslayer.ts';\nexport { coniferModel, type TreeColors, treeModel } from './basemap/trees.ts';\nexport type {\n CandidateIcon,\n CandidateOverlap,\n Json,\n LabelCandidate,\n RasterSource,\n Style,\n StyleLayer,\n} from './basemap/vectorstyle.ts';\nexport type { VectorExtrusionOptions } from './basemap/vectortiles/extrusions.ts';\nexport type { FurnitureOptions } from './basemap/vectortiles/furniture.ts';\nexport type { LabelsOptions } from './basemap/vectortiles/labels.ts';\nexport type { LampsOptions } from './basemap/vectortiles/lamps.ts';\nexport type { StreetWindLayer, StreetWindOptions } from './basemap/vectortiles/street-wind.ts';\nexport type { LoadedStyle } from './basemap/vectortiles/style.ts';\nexport type { TreesOptions } from './basemap/vectortiles/trees.ts';\nexport type { VectorsOptions } from './basemap/vectortiles/vectors.ts';\nexport type { VectorTilesOptions } from './basemap/vectortiles.ts';\nexport { OPENFREEMAP_STYLES, PLAN_STYLES, VectorTiles } from './basemap/vectortiles.ts';\nexport { parseWmtsGrid, wmtsGrid } from './basemap/wmts.ts';\nexport { type ColladaImages, colladaImages, loadCollada, parseCollada } from './data/collada.ts';\nexport {\n type Crs,\n type CrsLike,\n getCrs,\n lambertConformalConic,\n registerCrs,\n reproject,\n transverseMercator,\n} from './data/crs.ts';\nexport { parseGpx } from './data/gpx.ts';\nexport {\n type IfcElement,\n type IfcModel,\n type IfcOptions,\n type IfcPlace,\n type IfcProperties,\n type IfcStorey,\n loadIfc,\n WEB_IFC,\n} from './data/ifc.ts';\nexport { parseKml } from './data/kml.ts';\nexport { parseTopoJson, type TopoGeometry, type Topology } from './data/topojson.ts';\nexport type { DecoderUrls } from './engine/decoders.ts';\nexport { setRequestHeaders } from './engine/requests.ts';\nexport {\n BATIMENTS_3D_URL,\n type BdTopoBuilding,\n batiments3d,\n bdtopoBuildings,\n bdtopoRoofs,\n type GeocodedPlace,\n geoplateformeGeocode,\n geoplateformeWfs,\n geoplateformeWms,\n geoplateformeWmts,\n IGN_ATTRIBUTION,\n IGN_PRESETS,\n type IgnPreset,\n lambert93Grid,\n} from './geoplateforme.ts';\nexport { type Grid, windAt, windFields } from './grids.ts';\nexport type { ExtrusionOptions, ExtrusionStyle, PolygonArrays, TileKey } from './layers/extrusions.ts';\nexport { ExtrusionLayer } from './layers/extrusions.ts';\nexport type {\n CircleOptions,\n CircleStyle,\n Feature,\n FeatureCollection,\n FeatureData,\n FeatureLayerStyle,\n FillOptions,\n FillStyle,\n Geometry,\n LineOptions,\n LineStyle,\n Placement,\n Position,\n Properties,\n Ramp,\n Size,\n Stops,\n Styled,\n} from './layers/features.ts';\nexport { CircleLayer, FeatureLayer, FillLayer, interpolate, LineLayer, parseColor } from './layers/features.ts';\nexport type { FlowField, FlowOptions, FlowStyle, TimedField } from './layers/flow.ts';\nexport { FlowLayer, flowFieldFromImage, flowFieldsFromImage } from './layers/flow.ts';\nexport type { TextPart } from './layers/glyphs.ts';\nexport { DEFAULT_FONT, GLYPHS_URL } from './layers/glyphs.ts';\nexport type { ImageOptions, Pixels, SpriteIcon } from './layers/icons.ts';\nexport type {\n CustomFrame,\n CustomLayerInterface,\n GroundOptions,\n GroundTexture,\n ModelInstance,\n ModelOptions,\n} from './layers/layers.ts';\nexport {\n CustomLayer,\n GroundLayer,\n Layer,\n ModelLayer,\n NetworkLayer,\n RasterLayer,\n Tiles3dLayer,\n} from './layers/layers.ts';\nexport {\n type CalibratedPanoramaOptions,\n type Panorama,\n type PanoramaOptions,\n type PanoramaPhoto,\n Panoramas,\n type PhotoPanoramaOptions,\n} from './layers/panoramas.ts';\nexport { type PhotoOptions, photoModel } from './layers/photos.ts';\nexport type { ClassStyle, PointCloudOptions, PointCloudStyle, PointColor } from './layers/pointclouds.ts';\nexport { CLASSIFICATIONS, ELEVATION_RAMP, PointCloudLayer } from './layers/pointclouds.ts';\nexport type { Overlap, SymbolOptions, SymbolStyle } from './layers/symbols.ts';\nexport { SymbolLayer } from './layers/symbols.ts';\nexport { type TreeKind, type TreeOptions, treeKind } from './layers/trees.ts';\nexport { type VectorFeature, VectorLayer, type VectorSublayer } from './layers/vectors.ts';\nexport type { HoverPicking } from './map/hover-pick.ts';\nexport { GeoMap, type LayerSpec } from './map.ts';\nexport {\n PANORAMAX_API,\n type PanoramaxPicture,\n type PanoramaxSequenceOptions,\n panoramaxPanoramas,\n panoramaxPhoto,\n panoramaxPicture,\n panoramaxSequence,\n panoramaxStyle,\n} from './panoramax.ts';\nexport type {\n AnimationOptions,\n AtmosphereOptions,\n Basemap,\n BasemapName,\n BodyOptions,\n CelestialBody,\n FeatureHit,\n FirstPersonView,\n FlyToOptions,\n GeoMapOptions,\n LoadingMode,\n LonLat,\n MapEvents,\n MapHoverFeatureEvent,\n MapPointerEvent,\n NetworkOptions,\n NetworkStyle,\n Point,\n Projection,\n RasterGrid,\n RasterOptions,\n RasterStyle,\n SunOptions,\n SwipeOptions,\n TerrainEncoding,\n TerrainModel,\n TerrainOptions,\n Tiles3dOptions,\n Tiles3dStyle,\n ViewshedOptions,\n} from './types.ts';\nexport {\n AttributionControl,\n type AttributionOptions,\n type Control,\n type ControlPosition,\n NavigationControl,\n type NavigationOptions,\n} from './ui/controls.ts';\nexport { MinimapControl, type MinimapOptions } from './ui/minimap.ts';\nexport {\n type Anchor,\n Marker,\n type MarkerEvent,\n type MarkerEvents,\n type MarkerOptions,\n Panel,\n type PanelOptions,\n Popup,\n type PopupEvents,\n type PopupOptions,\n} from './ui/overlay.ts';\nexport { lengthLabel, roundLength, ScaleControl, type ScaleOptions } from './ui/scale.ts';\nexport { SearchControl, type SearchOptions } from './ui/search.ts';\nexport type { RoofMode } from './util/roofs.ts';\nexport { sunPosition } from './util/sun.ts';\nexport type {\n Camera,\n NetworkStats,\n PickHit,\n PickResult,\n PointCloudInfo,\n PointCloudPoint,\n PointCloudStats,\n RasterLayerStats,\n Tiles3dStats,\n} from './wasm/isard.js';\n"]}
|
package/dist/isard_bg.wasm
CHANGED
|
Binary file
|
package/dist/isard_core_bg.wasm
CHANGED
|
Binary file
|
package/dist/isard_grid_bg.wasm
CHANGED
|
Binary file
|
package/dist/panoramax.d.ts
CHANGED
|
@@ -48,8 +48,21 @@ export declare const pictureOf: (item: unknown) => PanoramaxPicture | undefined;
|
|
|
48
48
|
export declare const panoramaxPicture: (id: string, api?: string) => Promise<PanoramaxPicture>;
|
|
49
49
|
/** A Panoramax photo as `map.addPhoto` takes it: its image of 2048 pixels across, where it was taken, facing its way */
|
|
50
50
|
export declare const panoramaxPhoto: (picture: PanoramaxPicture) => PhotoOptions;
|
|
51
|
-
/**
|
|
52
|
-
export
|
|
51
|
+
/** Where `panoramaxSequence` reads a sequence */
|
|
52
|
+
export interface PanoramaxSequenceOptions {
|
|
53
|
+
/** The instance's STAC API (default the IGN's) */
|
|
54
|
+
api?: string;
|
|
55
|
+
/** Photos at most (default 2000) */
|
|
56
|
+
max?: number;
|
|
57
|
+
/** A photo's id: the photos around it, half before and half after (a long sequence: a survey car's day), instead of
|
|
58
|
+
* the sequence's first */
|
|
59
|
+
around?: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The photos of a sequence in their order (its STAC items, page after page), `max` at most: from its first, or
|
|
63
|
+
* `around` a photo (the page holding it, then those before and after). `options` may be the API's URL alone
|
|
64
|
+
*/
|
|
65
|
+
export declare const panoramaxSequence: (sequence: string, options?: string | PanoramaxSequenceOptions, maxPictures?: number) => Promise<PanoramaxPicture[]>;
|
|
53
66
|
/** The 360° photos of a sequence as `map.addPanoramas({ photos })` takes them: their images of 2048 pixels across,
|
|
54
67
|
* where they were taken, their middles facing their headings */
|
|
55
68
|
export declare const panoramaxPanoramas: (pictures: readonly PanoramaxPicture[]) => PanoramaPhoto[];
|
package/dist/panoramax.js
CHANGED
|
@@ -70,24 +70,43 @@ export const panoramaxPhoto = (picture) => ({
|
|
|
70
70
|
projection: picture.projection,
|
|
71
71
|
fov: picture.fov,
|
|
72
72
|
});
|
|
73
|
-
/**
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
73
|
+
/** A page of a sequence's STAC items: its photos, the pages before and after it */
|
|
74
|
+
const sequencePage = async (url) => {
|
|
75
|
+
const response = await fetch(url, withHeaders(url));
|
|
76
|
+
if (!response.ok)
|
|
77
|
+
throw new Error(`isard: ${url}: ${response.status}`);
|
|
78
|
+
const body = await response.json();
|
|
79
|
+
const items = isRecord(body) && Array.isArray(body.features) ? body.features : [];
|
|
80
|
+
return {
|
|
81
|
+
pictures: items.flatMap((item) => pictureOf(item) ?? []),
|
|
82
|
+
prev: isRecord(body) ? linkOf(body.links, 'prev') : undefined,
|
|
83
|
+
next: isRecord(body) ? linkOf(body.links, 'next') : undefined,
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* The photos of a sequence in their order (its STAC items, page after page), `max` at most: from its first, or
|
|
88
|
+
* `around` a photo (the page holding it, then those before and after). `options` may be the API's URL alone
|
|
89
|
+
*/
|
|
90
|
+
export const panoramaxSequence = async (sequence, options = {}, maxPictures) => {
|
|
91
|
+
const { api = PANORAMAX_API, max = maxPictures ?? 2000, around, } = typeof options === 'string' ? { api: options } : options;
|
|
92
|
+
const items = `${api}/collections/${encodeURIComponent(sequence)}/items?limit=500`;
|
|
93
|
+
const first = await sequencePage(around ? `${items}&withPicture=${encodeURIComponent(around)}` : items);
|
|
94
|
+
const pictures = first.pictures;
|
|
95
|
+
/** Where the photo asked for is (-1 without): as many before it, and after it, as half `max` */
|
|
96
|
+
const at = () => pictures.findIndex((p) => p.id === around);
|
|
97
|
+
let [prev, next] = [around ? first.prev : undefined, first.next];
|
|
98
|
+
while (prev && at() >= 0 && at() < Math.floor(max / 2)) {
|
|
99
|
+
const page = await sequencePage(prev);
|
|
100
|
+
pictures.unshift(...page.pictures);
|
|
101
|
+
prev = page.prev;
|
|
102
|
+
}
|
|
103
|
+
while (next && pictures.length - at() - 1 < (around ? Math.ceil(max / 2) : max)) {
|
|
104
|
+
const page = await sequencePage(next);
|
|
105
|
+
pictures.push(...page.pictures);
|
|
106
|
+
next = page.next;
|
|
89
107
|
}
|
|
90
|
-
|
|
108
|
+
const start = Math.max(0, Math.min(at() - Math.floor(max / 2), pictures.length - max));
|
|
109
|
+
return pictures.slice(start, start + max);
|
|
91
110
|
};
|
|
92
111
|
/** The 360° photos of a sequence as `map.addPanoramas({ photos })` takes them: their images of 2048 pixels across,
|
|
93
112
|
* where they were taken, their middles facing their headings */
|
package/dist/panoramax.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"panoramax.js","sourceRoot":"","sources":["../src/panoramax.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAInD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,mCAAmC;AACnC,MAAM,CAAC,MAAM,aAAa,GAAG,8BAA8B,CAAC;AAE5D;2EAC2E;AAC3E,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAG,GAAG,aAAa,EAAU,EAAE,CAAC,GAAG,GAAG,iBAAiB,CAAC;AA6BvF,kDAAkD;AAClD,MAAM,IAAI,GAAG,CAAC,KAAc,EAAU,EAAE,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAElF,+CAA+C;AAC/C,MAAM,MAAM,GAAG,CAAC,KAAc,EAAE,GAAW,EAAsB,EAAE;IACjE,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAEhG,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AACnE,CAAC,CAAC;AAEF,+DAA+D;AAC/D,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAE,GAAW,EAAsB,EAAE,CACnE,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;AAErD,mDAAmD;AACnD,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAa,EAAgC,EAAE;IACvE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACxG,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACjD,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;IACnF,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9F,MAAM,GAAG,GAAG,OAAO,MAAM,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IACjF,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5G,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAEvF,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;IAEtF,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAEzE,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACjB,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;QAC/B,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC;QAClB,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC5C,OAAO,EAAE,OAAO,CAAC,CAAC,cAAc,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;QACtE,UAAU,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,MAAM;QACnD,GAAG;QACH,MAAM,EAAE,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QACtG,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE;QACpE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC;QACtC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;QACxB,GAAG,CAAC,QAAQ,IAAI,EAAE,QAAQ,EAAE,CAAC;QAC7B,GAAG,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,CAAC;KACtB,CAAC;AACJ,CAAC,CAAC;AAEF,gGAAgG;AAChG,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EAAE,EAAU,EAAE,GAAG,GAAG,aAAa,EAA6B,EAAE;IACnG,MAAM,GAAG,GAAG,GAAG,GAAG,eAAe,kBAAkB,CAAC,EAAE,CAAC,EAAE,CAAC;IAC1D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IAEpD,IAAI,CAAC,QAAQ,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,UAAU,GAAG,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAEvE,MAAM,IAAI,GAAY,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC5C,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAEzG,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,EAAE,EAAE,CAAC,CAAC;IAEjE,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEF,wHAAwH;AACxH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,OAAyB,EAAgB,EAAE,CAAC,CAAC;IAC1E,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE;IACtB,MAAM,EAAE,OAAO,CAAC,MAAM;IACtB,OAAO,EAAE,OAAO,CAAC,OAAO;IACxB,UAAU,EAAE,OAAO,CAAC,UAAU;IAC9B,GAAG,EAAE,OAAO,CAAC,GAAG;CACjB,CAAC,CAAC;AAEH,+FAA+F;AAC/F,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,EACpC,QAAgB,EAChB,GAAG,GAAG,aAAa,EACnB,GAAG,GAAG,IAAI,EACmB,EAAE;IAC/B,MAAM,QAAQ,GAAuB,EAAE,CAAC;IACxC,IAAI,GAAG,GAAuB,GAAG,GAAG,gBAAgB,kBAAkB,CAAC,QAAQ,CAAC,kBAAkB,CAAC;IAEnG,OAAO,GAAG,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;QAEpD,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,UAAU,GAAG,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAEvE,MAAM,IAAI,GAAY,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC5C,MAAM,KAAK,GAAc,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QAE7F,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACrB,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;YAEhC,IAAI,OAAO;gBAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QACH,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAChE,CAAC;IAED,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAChC,CAAC,CAAC;AAEF;gEACgE;AAChE,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,QAAqC,EAAmB,EAAE,CAC3F,QAAQ;KACL,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,iBAAiB,CAAC;KACjD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC","sourcesContent":["/**\n * Panoramax (https://panoramax.fr), the open street-level photos of the IGN and OpenStreetMap France: its sequences\n * and photos as vector tiles with their MapLibre style (`map.vectorTiles({ style: panoramaxStyle() })`), a photo's\n * data from its STAC API (`panoramaxPicture`) and the photo standing where it was taken (`panoramaxPhoto` for\n * `map.addPhoto`). Its API answers any page (CORS), no key.\n */\n\nimport { withHeaders } from './engine/requests.ts';\nimport type { PanoramaPhoto } from './layers/panoramas.ts';\nimport type { PhotoOptions } from './layers/photos.ts';\nimport type { LonLat } from './types.ts';\nimport { isRecord } from './util/guards.ts';\n\n/** The IGN's Panoramax instance */\nexport const PANORAMAX_API = 'https://panoramax.ign.fr/api';\n\n/** Panoramax's style of an instance: its sequences (lines), its photos (circles, from zoom 15: their `id`, `heading`,\n * `type`: `flat` or `equirectangular`, `ts`) and their density far away */\nexport const panoramaxStyle = (api = PANORAMAX_API): string => `${api}/map/style.json`;\n\n/** A Panoramax photo: where and when it was taken, the way it looked, its images, who took it and its licence */\nexport interface PanoramaxPicture {\n id: string;\n /** Its sequence */\n sequence: string;\n lonLat: LonLat;\n /** When it was taken (ISO 8601, its time zone's) */\n date: string;\n /** Degrees clockwise from the north of its middle */\n heading: number;\n /** A flat photo, or a 360° one (equirectangular) */\n projection: 'flat' | 'equirectangular';\n /** Its field of view across, degrees (360 for a 360° photo) */\n fov: number;\n /** Its width over its height (its camera's sensor; 4 / 3 when unknown) */\n aspect: number;\n /** Its images: 2048 pixels across (`sd`), the original (`hd`), 500 pixels (`thumbnail`) */\n images: { sd: string; hd: string; thumbnail: string };\n /** Who took it (an account or an organization) */\n producer: string;\n /** Its licence's id (`etalab-2.0`, `CC-BY-SA-4.0`…) */\n license: string;\n /** The photos before and after it in its sequence */\n previous?: string;\n next?: string;\n}\n\n/** A value of a record as a string, '' without */\nconst text = (value: unknown): string => (typeof value === 'string' ? value : '');\n\n/** The URL of a STAC link (`next`, `prev`…) */\nconst linkOf = (links: unknown, rel: string): string | undefined => {\n const link = Array.isArray(links) ? links.find((l) => isRecord(l) && l.rel === rel) : undefined;\n\n return isRecord(link) ? text(link.href) || undefined : undefined;\n};\n\n/** The id of a photo a STAC link points to (`…/items/<id>`) */\nconst linkedId = (links: unknown, rel: string): string | undefined =>\n linkOf(links, rel)?.split('/').at(-1) || undefined;\n\n/** A photo from its STAC item (`/search?ids=…`) */\nexport const pictureOf = (item: unknown): PanoramaxPicture | undefined => {\n if (!isRecord(item) || !isRecord(item.properties) || !isRecord(item.geometry) || !isRecord(item.assets)) {\n return undefined;\n }\n\n const { properties: p, geometry, assets } = item;\n const [lon, lat] = Array.isArray(geometry.coordinates) ? geometry.coordinates : [];\n const camera = isRecord(p['pers:interior_orientation']) ? p['pers:interior_orientation'] : {};\n const fov = typeof camera.field_of_view === 'number' ? camera.field_of_view : 70;\n const [width, height] = Array.isArray(camera.sensor_array_dimensions) ? camera.sensor_array_dimensions : [];\n const href = (name: string) => (isRecord(assets[name]) ? text(assets[name].href) : '');\n\n const [previous, next] = [linkedId(item.links, 'prev'), linkedId(item.links, 'next')];\n\n if (typeof lon !== 'number' || typeof lat !== 'number') return undefined;\n\n return {\n id: text(item.id),\n sequence: text(item.collection),\n lonLat: [lon, lat],\n date: text(p.datetimetz) || text(p.datetime),\n heading: typeof p['view:azimuth'] === 'number' ? p['view:azimuth'] : 0,\n projection: fov >= 360 ? 'equirectangular' : 'flat',\n fov,\n aspect: typeof width === 'number' && typeof height === 'number' && height > 0 ? width / height : 4 / 3,\n images: { sd: href('sd'), hd: href('hd'), thumbnail: href('thumb') },\n producer: text(p['geovisio:producer']),\n license: text(p.license),\n ...(previous && { previous }),\n ...(next && { next }),\n };\n};\n\n/** A Panoramax photo by its id (a picture's `id` in its tiles), from the instance's STAC API */\nexport const panoramaxPicture = async (id: string, api = PANORAMAX_API): Promise<PanoramaxPicture> => {\n const url = `${api}/search?ids=${encodeURIComponent(id)}`;\n const response = await fetch(url, withHeaders(url));\n\n if (!response.ok) throw new Error(`isard: ${url}: ${response.status}`);\n\n const body: unknown = await response.json();\n const picture = isRecord(body) && Array.isArray(body.features) ? pictureOf(body.features[0]) : undefined;\n\n if (!picture) throw new Error(`isard: no Panoramax photo ${id}`);\n\n return picture;\n};\n\n/** A Panoramax photo as `map.addPhoto` takes it: its image of 2048 pixels across, where it was taken, facing its way */\nexport const panoramaxPhoto = (picture: PanoramaxPicture): PhotoOptions => ({\n url: picture.images.sd,\n lonLat: picture.lonLat,\n heading: picture.heading,\n projection: picture.projection,\n fov: picture.fov,\n});\n\n/** The photos of a sequence in their order (its STAC items, page after page), `max` at most */\nexport const panoramaxSequence = async (\n sequence: string,\n api = PANORAMAX_API,\n max = 2000,\n): Promise<PanoramaxPicture[]> => {\n const pictures: PanoramaxPicture[] = [];\n let url: string | undefined = `${api}/collections/${encodeURIComponent(sequence)}/items?limit=500`;\n\n while (url && pictures.length < max) {\n const response = await fetch(url, withHeaders(url));\n\n if (!response.ok) throw new Error(`isard: ${url}: ${response.status}`);\n\n const body: unknown = await response.json();\n const items: unknown[] = isRecord(body) && Array.isArray(body.features) ? body.features : [];\n\n items.forEach((item) => {\n const picture = pictureOf(item);\n\n if (picture) pictures.push(picture);\n });\n url = isRecord(body) ? linkOf(body.links, 'next') : undefined;\n }\n\n return pictures.slice(0, max);\n};\n\n/** The 360° photos of a sequence as `map.addPanoramas({ photos })` takes them: their images of 2048 pixels across,\n * where they were taken, their middles facing their headings */\nexport const panoramaxPanoramas = (pictures: readonly PanoramaxPicture[]): PanoramaPhoto[] =>\n pictures\n .filter((p) => p.projection === 'equirectangular')\n .map((p) => ({ id: p.id, url: p.images.sd, lonLat: p.lonLat, heading: p.heading }));\n"]}
|
|
1
|
+
{"version":3,"file":"panoramax.js","sourceRoot":"","sources":["../src/panoramax.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Panoramax (https://panoramax.fr), the open street-level photos of the IGN and OpenStreetMap France: its sequences\n * and photos as vector tiles with their MapLibre style (`map.vectorTiles({ style: panoramaxStyle() })`), a photo's\n * data from its STAC API (`panoramaxPicture`) and the photo standing where it was taken (`panoramaxPhoto` for\n * `map.addPhoto`). Its API answers any page (CORS), no key.\n */\n\nimport { withHeaders } from './engine/requests.ts';\nimport type { PanoramaPhoto } from './layers/panoramas.ts';\nimport type { PhotoOptions } from './layers/photos.ts';\nimport type { LonLat } from './types.ts';\nimport { isRecord } from './util/guards.ts';\n\n/** The IGN's Panoramax instance */\nexport const PANORAMAX_API = 'https://panoramax.ign.fr/api';\n\n/** Panoramax's style of an instance: its sequences (lines), its photos (circles, from zoom 15: their `id`, `heading`,\n * `type`: `flat` or `equirectangular`, `ts`) and their density far away */\nexport const panoramaxStyle = (api = PANORAMAX_API): string => `${api}/map/style.json`;\n\n/** A Panoramax photo: where and when it was taken, the way it looked, its images, who took it and its licence */\nexport interface PanoramaxPicture {\n id: string;\n /** Its sequence */\n sequence: string;\n lonLat: LonLat;\n /** When it was taken (ISO 8601, its time zone's) */\n date: string;\n /** Degrees clockwise from the north of its middle */\n heading: number;\n /** A flat photo, or a 360° one (equirectangular) */\n projection: 'flat' | 'equirectangular';\n /** Its field of view across, degrees (360 for a 360° photo) */\n fov: number;\n /** Its width over its height (its camera's sensor; 4 / 3 when unknown) */\n aspect: number;\n /** Its images: 2048 pixels across (`sd`), the original (`hd`), 500 pixels (`thumbnail`) */\n images: { sd: string; hd: string; thumbnail: string };\n /** Who took it (an account or an organization) */\n producer: string;\n /** Its licence's id (`etalab-2.0`, `CC-BY-SA-4.0`…) */\n license: string;\n /** The photos before and after it in its sequence */\n previous?: string;\n next?: string;\n}\n\n/** A value of a record as a string, '' without */\nconst text = (value: unknown): string => (typeof value === 'string' ? value : '');\n\n/** The URL of a STAC link (`next`, `prev`…) */\nconst linkOf = (links: unknown, rel: string): string | undefined => {\n const link = Array.isArray(links) ? links.find((l) => isRecord(l) && l.rel === rel) : undefined;\n\n return isRecord(link) ? text(link.href) || undefined : undefined;\n};\n\n/** The id of a photo a STAC link points to (`…/items/<id>`) */\nconst linkedId = (links: unknown, rel: string): string | undefined =>\n linkOf(links, rel)?.split('/').at(-1) || undefined;\n\n/** A photo from its STAC item (`/search?ids=…`) */\nexport const pictureOf = (item: unknown): PanoramaxPicture | undefined => {\n if (!isRecord(item) || !isRecord(item.properties) || !isRecord(item.geometry) || !isRecord(item.assets)) {\n return undefined;\n }\n\n const { properties: p, geometry, assets } = item;\n const [lon, lat] = Array.isArray(geometry.coordinates) ? geometry.coordinates : [];\n const camera = isRecord(p['pers:interior_orientation']) ? p['pers:interior_orientation'] : {};\n const fov = typeof camera.field_of_view === 'number' ? camera.field_of_view : 70;\n const [width, height] = Array.isArray(camera.sensor_array_dimensions) ? camera.sensor_array_dimensions : [];\n const href = (name: string) => (isRecord(assets[name]) ? text(assets[name].href) : '');\n\n const [previous, next] = [linkedId(item.links, 'prev'), linkedId(item.links, 'next')];\n\n if (typeof lon !== 'number' || typeof lat !== 'number') return undefined;\n\n return {\n id: text(item.id),\n sequence: text(item.collection),\n lonLat: [lon, lat],\n date: text(p.datetimetz) || text(p.datetime),\n heading: typeof p['view:azimuth'] === 'number' ? p['view:azimuth'] : 0,\n projection: fov >= 360 ? 'equirectangular' : 'flat',\n fov,\n aspect: typeof width === 'number' && typeof height === 'number' && height > 0 ? width / height : 4 / 3,\n images: { sd: href('sd'), hd: href('hd'), thumbnail: href('thumb') },\n producer: text(p['geovisio:producer']),\n license: text(p.license),\n ...(previous && { previous }),\n ...(next && { next }),\n };\n};\n\n/** A Panoramax photo by its id (a picture's `id` in its tiles), from the instance's STAC API */\nexport const panoramaxPicture = async (id: string, api = PANORAMAX_API): Promise<PanoramaxPicture> => {\n const url = `${api}/search?ids=${encodeURIComponent(id)}`;\n const response = await fetch(url, withHeaders(url));\n\n if (!response.ok) throw new Error(`isard: ${url}: ${response.status}`);\n\n const body: unknown = await response.json();\n const picture = isRecord(body) && Array.isArray(body.features) ? pictureOf(body.features[0]) : undefined;\n\n if (!picture) throw new Error(`isard: no Panoramax photo ${id}`);\n\n return picture;\n};\n\n/** A Panoramax photo as `map.addPhoto` takes it: its image of 2048 pixels across, where it was taken, facing its way */\nexport const panoramaxPhoto = (picture: PanoramaxPicture): PhotoOptions => ({\n url: picture.images.sd,\n lonLat: picture.lonLat,\n heading: picture.heading,\n projection: picture.projection,\n fov: picture.fov,\n});\n\n/** Where `panoramaxSequence` reads a sequence */\nexport interface PanoramaxSequenceOptions {\n /** The instance's STAC API (default the IGN's) */\n api?: string;\n /** Photos at most (default 2000) */\n max?: number;\n /** A photo's id: the photos around it, half before and half after (a long sequence: a survey car's day), instead of\n * the sequence's first */\n around?: string;\n}\n\n/** A page of a sequence's STAC items: its photos, the pages before and after it */\nconst sequencePage = async (url: string) => {\n const response = await fetch(url, withHeaders(url));\n\n if (!response.ok) throw new Error(`isard: ${url}: ${response.status}`);\n\n const body: unknown = await response.json();\n const items: unknown[] = isRecord(body) && Array.isArray(body.features) ? body.features : [];\n\n return {\n pictures: items.flatMap((item) => pictureOf(item) ?? []),\n prev: isRecord(body) ? linkOf(body.links, 'prev') : undefined,\n next: isRecord(body) ? linkOf(body.links, 'next') : undefined,\n };\n};\n\n/**\n * The photos of a sequence in their order (its STAC items, page after page), `max` at most: from its first, or\n * `around` a photo (the page holding it, then those before and after). `options` may be the API's URL alone\n */\nexport const panoramaxSequence = async (\n sequence: string,\n options: string | PanoramaxSequenceOptions = {},\n maxPictures?: number,\n): Promise<PanoramaxPicture[]> => {\n const {\n api = PANORAMAX_API,\n max = maxPictures ?? 2000,\n around,\n } = typeof options === 'string' ? { api: options } : options;\n const items = `${api}/collections/${encodeURIComponent(sequence)}/items?limit=500`;\n const first = await sequencePage(around ? `${items}&withPicture=${encodeURIComponent(around)}` : items);\n const pictures = first.pictures;\n /** Where the photo asked for is (-1 without): as many before it, and after it, as half `max` */\n const at = () => pictures.findIndex((p) => p.id === around);\n let [prev, next] = [around ? first.prev : undefined, first.next];\n\n while (prev && at() >= 0 && at() < Math.floor(max / 2)) {\n const page = await sequencePage(prev);\n\n pictures.unshift(...page.pictures);\n prev = page.prev;\n }\n while (next && pictures.length - at() - 1 < (around ? Math.ceil(max / 2) : max)) {\n const page = await sequencePage(next);\n\n pictures.push(...page.pictures);\n next = page.next;\n }\n\n const start = Math.max(0, Math.min(at() - Math.floor(max / 2), pictures.length - max));\n\n return pictures.slice(start, start + max);\n};\n\n/** The 360° photos of a sequence as `map.addPanoramas({ photos })` takes them: their images of 2048 pixels across,\n * where they were taken, their middles facing their headings */\nexport const panoramaxPanoramas = (pictures: readonly PanoramaxPicture[]): PanoramaPhoto[] =>\n pictures\n .filter((p) => p.projection === 'equirectangular')\n .map((p) => ({ id: p.id, url: p.images.sd, lonLat: p.lonLat, heading: p.heading }));\n"]}
|
|
@@ -1,29 +1,30 @@
|
|
|
1
1
|
/** `<CustomLayer>`: your WebGL code or a three.js scene among the layers of the components */
|
|
2
2
|
import { useContext, useEffect, useRef } from 'react';
|
|
3
|
-
import { MapContext } from "./context.js";
|
|
3
|
+
import { MapContext, useRank } from "./context.js";
|
|
4
4
|
/** Your WebGL code or a three.js scene drawn in the map's frame and depth, among the layers of the components */
|
|
5
5
|
export const CustomLayer = ({ layer, order = 0 }) => {
|
|
6
6
|
const binding = useContext(MapContext);
|
|
7
7
|
const initialOrder = useRef(order);
|
|
8
8
|
const handle = useRef(undefined);
|
|
9
|
+
const rank = useRank();
|
|
9
10
|
// Added once the map is there, in the declared order; removed when unmounted, made anew when the layer object changes
|
|
10
11
|
useEffect(() => {
|
|
11
12
|
if (!binding)
|
|
12
13
|
return;
|
|
13
14
|
const custom = binding.map.addCustomLayer(layer);
|
|
14
15
|
handle.current = custom;
|
|
15
|
-
binding.order.place(custom, initialOrder.current);
|
|
16
|
+
binding.order.place(custom, initialOrder.current, { rank });
|
|
16
17
|
return () => {
|
|
17
18
|
handle.current = undefined;
|
|
18
19
|
binding.order.remove(custom);
|
|
19
20
|
if (binding.map.hasLayer(custom))
|
|
20
21
|
custom.remove();
|
|
21
22
|
};
|
|
22
|
-
}, [binding, layer]);
|
|
23
|
+
}, [binding, layer, rank]);
|
|
23
24
|
// A new `order`: moved to its new place among the layers of the components
|
|
24
25
|
useEffect(() => {
|
|
25
26
|
if (binding && handle.current)
|
|
26
|
-
binding.order.place(handle.current, order, handle.current);
|
|
27
|
+
binding.order.place(handle.current, order, { old: handle.current });
|
|
27
28
|
}, [binding, order]);
|
|
28
29
|
return null;
|
|
29
30
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CustomLayer.js","sourceRoot":"","sources":["../../src/react/CustomLayer.tsx"],"names":[],"mappings":"AAAA,8FAA8F;AAE9F,OAAO,EAAkB,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAEtE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"CustomLayer.js","sourceRoot":"","sources":["../../src/react/CustomLayer.tsx"],"names":[],"mappings":"AAAA,8FAA8F;AAE9F,OAAO,EAAkB,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAEtE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AASnD,iHAAiH;AACjH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC,EAAoB,EAAa,EAAE;IAC/E,MAAM,OAAO,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IACvC,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,CAAc,SAAS,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IAEvB,sHAAsH;IACtH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAEjD,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC;QACxB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,YAAY,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAE5D,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,OAAO,GAAG,SAAS,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC7B,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAAE,MAAM,CAAC,MAAM,EAAE,CAAC;QACpD,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;IAE3B,2EAA2E;IAC3E,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,IAAI,MAAM,CAAC,OAAO;YAAE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IACrG,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;IAErB,OAAO,IAAI,CAAC;AACd,CAAC,CAAC","sourcesContent":["/** `<CustomLayer>`: your WebGL code or a three.js scene among the layers of the components */\n\nimport { type ReactNode, useContext, useEffect, useRef } from 'react';\nimport type { CustomLayerInterface, Layer as LayerHandle } from '../layers/layers.ts';\nimport { MapContext, useRank } from './context.ts';\n\nexport interface CustomLayerProps {\n /** Your WebGL code: `onAdd`, `render`, `onRemove` (see `map.addCustomLayer`); another object makes it anew */\n layer: CustomLayerInterface;\n /** Its place among the layers of the components (as `<Layer order>`) */\n order?: number;\n}\n\n/** Your WebGL code or a three.js scene drawn in the map's frame and depth, among the layers of the components */\nexport const CustomLayer = ({ layer, order = 0 }: CustomLayerProps): ReactNode => {\n const binding = useContext(MapContext);\n const initialOrder = useRef(order);\n const handle = useRef<LayerHandle>(undefined);\n const rank = useRank();\n\n // Added once the map is there, in the declared order; removed when unmounted, made anew when the layer object changes\n useEffect(() => {\n if (!binding) return;\n\n const custom = binding.map.addCustomLayer(layer);\n\n handle.current = custom;\n binding.order.place(custom, initialOrder.current, { rank });\n\n return () => {\n handle.current = undefined;\n binding.order.remove(custom);\n if (binding.map.hasLayer(custom)) custom.remove();\n };\n }, [binding, layer, rank]);\n\n // A new `order`: moved to its new place among the layers of the components\n useEffect(() => {\n if (binding && handle.current) binding.order.place(handle.current, order, { old: handle.current });\n }, [binding, order]);\n\n return null;\n};\n"]}
|
package/dist/react/Layer.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export type LayerType = LayerSpec['type'];
|
|
|
29
29
|
export type LayerProps<P = Record<string, unknown>, T extends LayerType = LayerType> = Extract<BoundLayerSpec<P>, {
|
|
30
30
|
type: T;
|
|
31
31
|
}> & {
|
|
32
|
-
/** Its place among the layers of the components: from the bottom up, the same order
|
|
32
|
+
/** Its place among the layers of the components: from the bottom up, the same order as declared (default 0) */
|
|
33
33
|
order?: number;
|
|
34
34
|
/** The layer, once created and each time it is made anew */
|
|
35
35
|
onLayer?: (layer: LayerHandles<P>[T]) => void;
|
package/dist/react/Layer.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* declared order */
|
|
3
3
|
import { forwardRef, useContext, useEffect, useImperativeHandle, useRef, useState, } from 'react';
|
|
4
4
|
import { addBoundLayer, applyLayerChange, layerChange, rebuildBoundLayer, } from "../bind/layers.js";
|
|
5
|
-
import { MapContext, SwipeContext } from "./context.js";
|
|
5
|
+
import { MapContext, SwipeContext, useRank } from "./context.js";
|
|
6
6
|
const LayerComponent = forwardRef(function Layer(props, ref) {
|
|
7
7
|
const binding = useContext(MapContext);
|
|
8
8
|
const swipe = useContext(SwipeContext);
|
|
@@ -11,6 +11,7 @@ const LayerComponent = forwardRef(function Layer(props, ref) {
|
|
|
11
11
|
const mounted = useRef(undefined);
|
|
12
12
|
const latest = useRef({ spec, order, onLayer });
|
|
13
13
|
const [layer, setLayer] = useState();
|
|
14
|
+
const rank = useRank();
|
|
14
15
|
latest.current = { spec, order, onLayer };
|
|
15
16
|
useImperativeHandle(ref, () => layer, [layer]);
|
|
16
17
|
// Added once the map is there, removed when unmounted (or when the map goes)
|
|
@@ -19,7 +20,7 @@ const LayerComponent = forwardRef(function Layer(props, ref) {
|
|
|
19
20
|
return;
|
|
20
21
|
const { spec, order, onLayer } = latest.current;
|
|
21
22
|
const created = addBoundLayer(binding.map, spec);
|
|
22
|
-
binding.order.place(created, order);
|
|
23
|
+
binding.order.place(created, order, { rank });
|
|
23
24
|
mounted.current = { layer: created, spec, order };
|
|
24
25
|
swipe?.set(created);
|
|
25
26
|
setLayer(created);
|
|
@@ -34,7 +35,7 @@ const LayerComponent = forwardRef(function Layer(props, ref) {
|
|
|
34
35
|
if (binding.map.hasLayer(current.layer))
|
|
35
36
|
current.layer.remove();
|
|
36
37
|
};
|
|
37
|
-
}, [binding, swipe]);
|
|
38
|
+
}, [binding, swipe, rank]);
|
|
38
39
|
// Each render: what changed sent, or the layer made anew in its place
|
|
39
40
|
useEffect(() => {
|
|
40
41
|
const current = mounted.current;
|
|
@@ -45,7 +46,7 @@ const LayerComponent = forwardRef(function Layer(props, ref) {
|
|
|
45
46
|
if (change?.rebuild) {
|
|
46
47
|
const old = current.layer;
|
|
47
48
|
const fresh = rebuildBoundLayer(binding.map, old, spec);
|
|
48
|
-
binding.order.place(fresh, order, old);
|
|
49
|
+
binding.order.place(fresh, order, { old });
|
|
49
50
|
swipe?.unset(old);
|
|
50
51
|
swipe?.set(fresh);
|
|
51
52
|
current.layer = fresh;
|
|
@@ -58,7 +59,7 @@ const LayerComponent = forwardRef(function Layer(props, ref) {
|
|
|
58
59
|
applyLayerChange(current.layer, spec, change);
|
|
59
60
|
if (current.order !== order) {
|
|
60
61
|
current.order = order;
|
|
61
|
-
binding.order.place(current.layer, order, current.layer);
|
|
62
|
+
binding.order.place(current.layer, order, { old: current.layer });
|
|
62
63
|
}
|
|
63
64
|
});
|
|
64
65
|
return null;
|
package/dist/react/Layer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Layer.js","sourceRoot":"","sources":["../../src/react/Layer.tsx"],"names":[],"mappings":"AAAA;oBACoB;AAEpB,OAAO,EACL,UAAU,EAGV,UAAU,EACV,SAAS,EACT,mBAAmB,EACnB,MAAM,EACN,QAAQ,GACT,MAAM,OAAO,CAAC;AACf,OAAO,EACL,aAAa,EACb,gBAAgB,EAEhB,WAAW,EACX,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAe3B,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"Layer.js","sourceRoot":"","sources":["../../src/react/Layer.tsx"],"names":[],"mappings":"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","sourcesContent":["/** `<Layer>`: a layer added when it mounts, updated by the least its props need, removed when it unmounts, in its\n * declared order */\n\nimport {\n forwardRef,\n type ReactNode,\n type Ref,\n useContext,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from 'react';\nimport {\n addBoundLayer,\n applyLayerChange,\n type BoundLayerSpec,\n layerChange,\n rebuildBoundLayer,\n} from '../bind/layers.ts';\nimport type { ExtrusionLayer } from '../layers/extrusions.ts';\nimport type { CircleLayer, FillLayer, LineLayer } from '../layers/features.ts';\nimport type { FlowLayer } from '../layers/flow.ts';\nimport type {\n GroundLayer,\n Layer as LayerHandle,\n ModelLayer,\n NetworkLayer,\n RasterLayer,\n Tiles3dLayer,\n} from '../layers/layers.ts';\nimport type { PointCloudLayer } from '../layers/pointclouds.ts';\nimport type { SymbolLayer } from '../layers/symbols.ts';\nimport type { LayerSpec } from '../map.ts';\nimport { MapContext, SwipeContext, useRank } from './context.ts';\n\n/** The handle of a layer by its type */\nexport interface LayerHandles<P = Record<string, unknown>> {\n lines: LineLayer<P>;\n circles: CircleLayer<P>;\n fills: FillLayer<P>;\n symbols: SymbolLayer<P>;\n extrusions: ExtrusionLayer<P>;\n raster: RasterLayer;\n ground: GroundLayer;\n network: NetworkLayer;\n tiles3d: Tiles3dLayer;\n pointcloud: PointCloudLayer;\n models: ModelLayer;\n trees: ModelLayer;\n flow: FlowLayer;\n}\n\nexport type LayerType = LayerSpec['type'];\n\nexport type LayerProps<P = Record<string, unknown>, T extends LayerType = LayerType> = Extract<\n BoundLayerSpec<P>,\n { type: T }\n> & {\n /** Its place among the layers of the components: from the bottom up, the same order as declared (default 0) */\n order?: number;\n /** The layer, once created and each time it is made anew */\n onLayer?: (layer: LayerHandles<P>[T]) => void;\n ref?: Ref<LayerHandles<P>[T] | undefined>;\n};\n\ninterface Mounted {\n layer: LayerHandle;\n spec: BoundLayerSpec;\n order: number;\n}\n\nconst LayerComponent = forwardRef<LayerHandle | undefined, Omit<LayerProps, 'ref'>>(function Layer(props, ref) {\n const binding = useContext(MapContext);\n const swipe = useContext(SwipeContext);\n const { order = 0, onLayer, ...rest } = props;\n const spec = rest as BoundLayerSpec;\n const mounted = useRef<Mounted>(undefined);\n const latest = useRef({ spec, order, onLayer });\n const [layer, setLayer] = useState<LayerHandle>();\n const rank = useRank();\n\n latest.current = { spec, order, onLayer };\n useImperativeHandle(ref, () => layer, [layer]);\n\n // Added once the map is there, removed when unmounted (or when the map goes)\n useEffect(() => {\n if (!binding) return;\n\n const { spec, order, onLayer } = latest.current;\n const created = addBoundLayer(binding.map, spec);\n\n binding.order.place(created, order, { rank });\n mounted.current = { layer: created, spec, order };\n swipe?.set(created);\n setLayer(created);\n onLayer?.(created as never);\n\n return () => {\n const current = mounted.current;\n\n mounted.current = undefined;\n if (!current) return;\n binding.order.remove(current.layer);\n swipe?.unset(current.layer);\n if (binding.map.hasLayer(current.layer)) current.layer.remove();\n };\n }, [binding, swipe, rank]);\n\n // Each render: what changed sent, or the layer made anew in its place\n useEffect(() => {\n const current = mounted.current;\n\n if (!binding || !current) return;\n\n const change = layerChange(current.spec, spec);\n\n current.spec = spec;\n if (change?.rebuild) {\n const old = current.layer;\n const fresh = rebuildBoundLayer(binding.map, old, spec);\n\n binding.order.place(fresh, order, { old });\n swipe?.unset(old);\n swipe?.set(fresh);\n current.layer = fresh;\n current.order = order;\n setLayer(fresh);\n latest.current.onLayer?.(fresh as never);\n\n return;\n }\n\n if (change) applyLayerChange(current.layer, spec, change);\n if (current.order !== order) {\n current.order = order;\n binding.order.place(current.layer, order, { old: current.layer });\n }\n });\n\n return null;\n});\n\n/**\n * A layer: the options of its `add…` method with its `type` (`map.add`), and `values` for the layers colored by\n * values. A change of data, style, filter, values or instances updates it; a change of what is set at creation (its\n * URL, grid, nodes…) makes it anew, in its place. Data, functions and arrays are compared by identity: keep them in a\n * memo or a state. The ref and `onLayer` give its handle, typed by its `type`; the properties of its features are\n * inferred from its data or its style functions (`<Layer<Building> …>` to name them)\n */\nexport const Layer = LayerComponent as <P = Record<string, unknown>, T extends LayerType = LayerType>(\n props: LayerProps<P, T>,\n) => ReactNode;\n"]}
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
/** `<Geometry>`: the fills, lines and buildings of the vector tiles around drawn as geometry (`VectorTiles.vectors`),
|
|
3
3
|
* among the layers of the components; `<VectorGeometry>`, the same with tiles of its own */
|
|
4
4
|
import { forwardRef, useContext, useEffect, useImperativeHandle, useRef, useState, } from 'react';
|
|
5
|
-
import { MapContext, SwipeContext, VectorTilesContext } from "./context.js";
|
|
5
|
+
import { MapContext, SwipeContext, useRank, VectorTilesContext } from "./context.js";
|
|
6
6
|
import { VectorTiles } from "./VectorTiles.js";
|
|
7
7
|
/** The paint properties of `next` that differ from those of `sent`, as `[layer, name, value]` */
|
|
8
8
|
const changed = (sent, next) => Object.entries(next ?? {}).flatMap(([layer, properties]) => Object.entries(properties)
|
|
@@ -16,6 +16,7 @@ const GeometryComponent = forwardRef(function Geometry({ layers, streets, roofs,
|
|
|
16
16
|
/** The paint properties sent to the current layer */
|
|
17
17
|
const sent = useRef(undefined);
|
|
18
18
|
const [layer, setLayer] = useState();
|
|
19
|
+
const rank = useRank();
|
|
19
20
|
latest.current = { order, onLayer };
|
|
20
21
|
useImperativeHandle(ref, () => layer, [layer]);
|
|
21
22
|
// The geometry layer created once the tiles are there, in the declared order; made anew when the layers kept, the
|
|
@@ -28,7 +29,7 @@ const GeometryComponent = forwardRef(function Geometry({ layers, streets, roofs,
|
|
|
28
29
|
...(streets && { streets }),
|
|
29
30
|
...(roofs && { roofs }),
|
|
30
31
|
});
|
|
31
|
-
binding.order.place(created, latest.current.order);
|
|
32
|
+
binding.order.place(created, latest.current.order, { rank });
|
|
32
33
|
swipe?.set(created);
|
|
33
34
|
sent.current = undefined;
|
|
34
35
|
setLayer(created);
|
|
@@ -41,7 +42,7 @@ const GeometryComponent = forwardRef(function Geometry({ layers, streets, roofs,
|
|
|
41
42
|
created.remove();
|
|
42
43
|
setLayer(undefined);
|
|
43
44
|
};
|
|
44
|
-
}, [binding, swipe, tiles, layers, streets, roofs]);
|
|
45
|
+
}, [binding, swipe, tiles, layers, streets, roofs, rank]);
|
|
45
46
|
// The paint properties changed since the last ones sent (all of them to a layer made anew), those of a function
|
|
46
47
|
// once the style is loaded; a later render or layer drops the wait
|
|
47
48
|
useEffect(() => {
|
|
@@ -81,7 +82,7 @@ const GeometryComponent = forwardRef(function Geometry({ layers, streets, roofs,
|
|
|
81
82
|
// A new `order`: moved to its new place among the layers of the components
|
|
82
83
|
useEffect(() => {
|
|
83
84
|
if (binding && layer)
|
|
84
|
-
binding.order.place(layer, order, layer);
|
|
85
|
+
binding.order.place(layer, order, { old: layer });
|
|
85
86
|
}, [binding, layer, order]);
|
|
86
87
|
return null;
|
|
87
88
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VectorGeometry.js","sourceRoot":"","sources":["../../src/react/VectorGeometry.tsx"],"names":[],"mappings":"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","sourcesContent":["/** `<Geometry>`: the fills, lines and buildings of the vector tiles around drawn as geometry (`VectorTiles.vectors`),\n * among the layers of the components; `<VectorGeometry>`, the same with tiles of its own */\n\nimport {\n forwardRef,\n type ReactNode,\n type Ref,\n useContext,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from 'react';\nimport type { Style, StyleLayer } from '../basemap/vectorstyle.ts';\nimport type { VectorLayer, VectorSublayer } from '../layers/vectors.ts';\nimport type { RoofMode } from '../util/roofs.ts';\nimport { MapContext, SwipeContext, VectorTilesContext } from './context.ts';\nimport { VectorTiles } from './VectorTiles.tsx';\n\nexport interface GeometryProps {\n /** The style layers drawn (default all its fills and lines); another function makes the layer anew, so keep it in a\n * memo or at the module's level */\n layers?: (layer: StyleLayer) => boolean;\n /** The line layers that glow at night (default those whose id names a road); another function makes the layer anew,\n * as `layers` */\n streets?: (layer: StyleLayer) => boolean;\n /** The buildings' roofs (as `vectors({ roofs })`: `'data'` by default); another one makes the layer anew */\n roofs?: RoofMode;\n /** The buildings' walls show their windows (default false: `setFacades`, the tiles not cut again) */\n facades?: boolean;\n /** Paint properties over the style's (`setPaintProperty`), by style layer id, or by style layer drawn once the style\n * is loaded (a function of its id, kind, source layer): compared by value, only those changed sent; one taken out\n * keeps its last value */\n paint?: Paint | ((layer: VectorSublayer) => Record<string, unknown> | undefined);\n /** Shown (default true) */\n visible?: boolean;\n /** Its place among the layers of the components (as `<Layer order>`) */\n order?: number;\n /** The layer, once created and each time it is made anew */\n onLayer?: (layer: VectorLayer) => void;\n ref?: Ref<VectorLayer | undefined>;\n}\n\nexport interface VectorGeometryProps extends GeometryProps {\n /** A style URL or object (default OpenFreeMap's Positron); another one makes the layer anew */\n style?: string | Style;\n}\n\n/** Paint properties by style layer id */\ntype Paint = Record<string, Record<string, unknown>>;\n\n/** The paint properties of `next` that differ from those of `sent`, as `[layer, name, value]` */\nconst changed = (sent: Paint | undefined, next: Paint | undefined): [layer: string, name: string, value: unknown][] =>\n Object.entries(next ?? {}).flatMap(([layer, properties]) =>\n Object.entries(properties)\n .filter(([name, value]) => JSON.stringify(sent?.[layer]?.[name]) !== JSON.stringify(value))\n .map(([name, value]): [string, string, unknown] => [layer, name, value]),\n );\n\nconst GeometryComponent = forwardRef<VectorLayer | undefined, Omit<GeometryProps, 'ref'>>(function Geometry(\n { layers, streets, roofs, facades = false, paint, visible = true, order = 0, onLayer },\n ref,\n) {\n const binding = useContext(MapContext);\n const tiles = useContext(VectorTilesContext);\n const swipe = useContext(SwipeContext);\n const latest = useRef({ order, onLayer });\n /** The paint properties sent to the current layer */\n const sent = useRef<Paint>(undefined);\n const [layer, setLayer] = useState<VectorLayer>();\n\n latest.current = { order, onLayer };\n useImperativeHandle(ref, () => layer, [layer]);\n\n // The geometry layer created once the tiles are there, in the declared order; made anew when the layers kept, the\n // streets or the roofs change; removed when unmounted\n useEffect(() => {\n if (!binding || !tiles) return;\n\n const created = tiles.vectors({\n ...(layers && { layers }),\n ...(streets && { streets }),\n ...(roofs && { roofs }),\n });\n\n binding.order.place(created, latest.current.order);\n swipe?.set(created);\n sent.current = undefined;\n setLayer(created);\n latest.current.onLayer?.(created);\n\n return () => {\n binding.order.remove(created);\n swipe?.unset(created);\n // Gone already with its tiles, or with the map\n if (binding.map.hasLayer(created)) created.remove();\n setLayer(undefined);\n };\n }, [binding, swipe, tiles, layers, streets, roofs]);\n\n // The paint properties changed since the last ones sent (all of them to a layer made anew), those of a function\n // once the style is loaded; a later render or layer drops the wait\n useEffect(() => {\n if (!layer) return;\n\n const apply = (next: Paint | undefined) => {\n changed(sent.current, next).forEach(([id, name, value]) => {\n layer.setPaintProperty(id, name, value);\n });\n sent.current = next;\n };\n\n if (typeof paint !== 'function') {\n apply(paint);\n\n return;\n }\n\n const wait = { live: true };\n\n layer.ready.then(\n () => {\n if (!wait.live) return;\n apply(\n Object.fromEntries(\n layer.layers.flatMap((l) => {\n const properties = paint(l);\n\n return properties ? [[l.id, properties]] : [];\n }),\n ),\n );\n },\n () => undefined,\n );\n\n return () => {\n wait.live = false;\n };\n }, [layer, paint]);\n\n // The walls' windows shown or not\n useEffect(() => {\n layer?.setFacades(facades);\n }, [layer, facades]);\n\n // Shown or hidden\n useEffect(() => {\n layer?.setVisible(visible);\n }, [layer, visible]);\n\n // A new `order`: moved to its new place among the layers of the components\n useEffect(() => {\n if (binding && layer) binding.order.place(layer, order, layer);\n }, [binding, layer, order]);\n\n return null;\n});\n\n/**\n * The fills, lines and buildings of the vector tiles around (`<VectorTiles>`) drawn as geometry on the globe and the\n * relief (`VectorTiles.vectors`): sharp at any zoom and pitch, restyled by `paint` without cutting the tiles again,\n * picked by feature (`map.pickFeature`). The ref and `onLayer` give its handle (`VectorLayer`: `layers`, `featureAt`,\n * `ready`)\n */\nexport const Geometry = GeometryComponent as (props: GeometryProps) => ReactNode;\n\nconst VectorGeometryComponent = forwardRef<VectorLayer | undefined, Omit<VectorGeometryProps, 'ref'>>(\n function VectorGeometry({ style, ...props }, ref) {\n return (\n <VectorTiles {...(style === undefined ? {} : { style })}>\n <GeometryComponent ref={ref} {...props} />\n </VectorTiles>\n );\n },\n);\n\n/**\n * The fills and lines of a MapLibre style drawn as geometry, with tiles of its own: a `<Geometry>` in a\n * `<VectorTiles>` of its `style`. Beside its trees, labels or lamps, a `<VectorTiles>` with each of them as children\n * shares one set of tiles\n */\nexport const VectorGeometry = VectorGeometryComponent as (props: VectorGeometryProps) => ReactNode;\n"]}
|
|
1
|
+
{"version":3,"file":"VectorGeometry.js","sourceRoot":"","sources":["../../src/react/VectorGeometry.tsx"],"names":[],"mappings":"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","sourcesContent":["/** `<Geometry>`: the fills, lines and buildings of the vector tiles around drawn as geometry (`VectorTiles.vectors`),\n * among the layers of the components; `<VectorGeometry>`, the same with tiles of its own */\n\nimport {\n forwardRef,\n type ReactNode,\n type Ref,\n useContext,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from 'react';\nimport type { Style, StyleLayer } from '../basemap/vectorstyle.ts';\nimport type { VectorLayer, VectorSublayer } from '../layers/vectors.ts';\nimport type { RoofMode } from '../util/roofs.ts';\nimport { MapContext, SwipeContext, useRank, VectorTilesContext } from './context.ts';\nimport { VectorTiles } from './VectorTiles.tsx';\n\nexport interface GeometryProps {\n /** The style layers drawn (default all its fills and lines); another function makes the layer anew, so keep it in a\n * memo or at the module's level */\n layers?: (layer: StyleLayer) => boolean;\n /** The line layers that glow at night (default those whose id names a road); another function makes the layer anew,\n * as `layers` */\n streets?: (layer: StyleLayer) => boolean;\n /** The buildings' roofs (as `vectors({ roofs })`: `'data'` by default); another one makes the layer anew */\n roofs?: RoofMode;\n /** The buildings' walls show their windows (default false: `setFacades`, the tiles not cut again) */\n facades?: boolean;\n /** Paint properties over the style's (`setPaintProperty`), by style layer id, or by style layer drawn once the style\n * is loaded (a function of its id, kind, source layer): compared by value, only those changed sent; one taken out\n * keeps its last value */\n paint?: Paint | ((layer: VectorSublayer) => Record<string, unknown> | undefined);\n /** Shown (default true) */\n visible?: boolean;\n /** Its place among the layers of the components (as `<Layer order>`) */\n order?: number;\n /** The layer, once created and each time it is made anew */\n onLayer?: (layer: VectorLayer) => void;\n ref?: Ref<VectorLayer | undefined>;\n}\n\nexport interface VectorGeometryProps extends GeometryProps {\n /** A style URL or object (default OpenFreeMap's Positron); another one makes the layer anew */\n style?: string | Style;\n}\n\n/** Paint properties by style layer id */\ntype Paint = Record<string, Record<string, unknown>>;\n\n/** The paint properties of `next` that differ from those of `sent`, as `[layer, name, value]` */\nconst changed = (sent: Paint | undefined, next: Paint | undefined): [layer: string, name: string, value: unknown][] =>\n Object.entries(next ?? {}).flatMap(([layer, properties]) =>\n Object.entries(properties)\n .filter(([name, value]) => JSON.stringify(sent?.[layer]?.[name]) !== JSON.stringify(value))\n .map(([name, value]): [string, string, unknown] => [layer, name, value]),\n );\n\nconst GeometryComponent = forwardRef<VectorLayer | undefined, Omit<GeometryProps, 'ref'>>(function Geometry(\n { layers, streets, roofs, facades = false, paint, visible = true, order = 0, onLayer },\n ref,\n) {\n const binding = useContext(MapContext);\n const tiles = useContext(VectorTilesContext);\n const swipe = useContext(SwipeContext);\n const latest = useRef({ order, onLayer });\n /** The paint properties sent to the current layer */\n const sent = useRef<Paint>(undefined);\n const [layer, setLayer] = useState<VectorLayer>();\n const rank = useRank();\n\n latest.current = { order, onLayer };\n useImperativeHandle(ref, () => layer, [layer]);\n\n // The geometry layer created once the tiles are there, in the declared order; made anew when the layers kept, the\n // streets or the roofs change; removed when unmounted\n useEffect(() => {\n if (!binding || !tiles) return;\n\n const created = tiles.vectors({\n ...(layers && { layers }),\n ...(streets && { streets }),\n ...(roofs && { roofs }),\n });\n\n binding.order.place(created, latest.current.order, { rank });\n swipe?.set(created);\n sent.current = undefined;\n setLayer(created);\n latest.current.onLayer?.(created);\n\n return () => {\n binding.order.remove(created);\n swipe?.unset(created);\n // Gone already with its tiles, or with the map\n if (binding.map.hasLayer(created)) created.remove();\n setLayer(undefined);\n };\n }, [binding, swipe, tiles, layers, streets, roofs, rank]);\n\n // The paint properties changed since the last ones sent (all of them to a layer made anew), those of a function\n // once the style is loaded; a later render or layer drops the wait\n useEffect(() => {\n if (!layer) return;\n\n const apply = (next: Paint | undefined) => {\n changed(sent.current, next).forEach(([id, name, value]) => {\n layer.setPaintProperty(id, name, value);\n });\n sent.current = next;\n };\n\n if (typeof paint !== 'function') {\n apply(paint);\n\n return;\n }\n\n const wait = { live: true };\n\n layer.ready.then(\n () => {\n if (!wait.live) return;\n apply(\n Object.fromEntries(\n layer.layers.flatMap((l) => {\n const properties = paint(l);\n\n return properties ? [[l.id, properties]] : [];\n }),\n ),\n );\n },\n () => undefined,\n );\n\n return () => {\n wait.live = false;\n };\n }, [layer, paint]);\n\n // The walls' windows shown or not\n useEffect(() => {\n layer?.setFacades(facades);\n }, [layer, facades]);\n\n // Shown or hidden\n useEffect(() => {\n layer?.setVisible(visible);\n }, [layer, visible]);\n\n // A new `order`: moved to its new place among the layers of the components\n useEffect(() => {\n if (binding && layer) binding.order.place(layer, order, { old: layer });\n }, [binding, layer, order]);\n\n return null;\n});\n\n/**\n * The fills, lines and buildings of the vector tiles around (`<VectorTiles>`) drawn as geometry on the globe and the\n * relief (`VectorTiles.vectors`): sharp at any zoom and pitch, restyled by `paint` without cutting the tiles again,\n * picked by feature (`map.pickFeature`). The ref and `onLayer` give its handle (`VectorLayer`: `layers`, `featureAt`,\n * `ready`)\n */\nexport const Geometry = GeometryComponent as (props: GeometryProps) => ReactNode;\n\nconst VectorGeometryComponent = forwardRef<VectorLayer | undefined, Omit<VectorGeometryProps, 'ref'>>(\n function VectorGeometry({ style, ...props }, ref) {\n return (\n <VectorTiles {...(style === undefined ? {} : { style })}>\n <GeometryComponent ref={ref} {...props} />\n </VectorTiles>\n );\n },\n);\n\n/**\n * The fills and lines of a MapLibre style drawn as geometry, with tiles of its own: a `<Geometry>` in a\n * `<VectorTiles>` of its `style`. Beside its trees, labels or lamps, a `<VectorTiles>` with each of them as children\n * shares one set of tiles\n */\nexport const VectorGeometry = VectorGeometryComponent as (props: VectorGeometryProps) => ReactNode;\n"]}
|
package/dist/react/context.d.ts
CHANGED
|
@@ -28,6 +28,9 @@ export declare const MarkerContext: import("react").Context<{
|
|
|
28
28
|
} | undefined>;
|
|
29
29
|
/** The vector tiles of the `<VectorTiles>` around, once the map is there */
|
|
30
30
|
export declare const VectorTilesContext: import("react").Context<VectorTiles | undefined>;
|
|
31
|
+
/** A component's rank among the layers of the components (`LayerOrder.rank`): taken at its first render, in the
|
|
32
|
+
* declared order, kept after */
|
|
33
|
+
export declare const useRank: () => number | undefined;
|
|
31
34
|
/** The map of the `<IsardMap>` around, once created (undefined before) */
|
|
32
35
|
export declare const useMap: () => GeoMap | undefined;
|
|
33
36
|
/** Listens to an event of the map around while the component is mounted; the listener may change at each render */
|
package/dist/react/context.js
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
/** What the components of a map share: the map, the order of their layers, the viewsheds, the swipe and the marker
|
|
2
2
|
* around; the hooks */
|
|
3
|
-
import { createContext, useContext, useEffect, useRef } from 'react';
|
|
3
|
+
import { createContext, useContext, useEffect, useRef, useState } from 'react';
|
|
4
4
|
export const MapContext = createContext(undefined);
|
|
5
5
|
export const SwipeContext = createContext(undefined);
|
|
6
6
|
/** The marker of a `<Marker>` around and its position (a `<Popup>` in it opens on its click, at that position) */
|
|
7
7
|
export const MarkerContext = createContext(undefined);
|
|
8
8
|
/** The vector tiles of the `<VectorTiles>` around, once the map is there */
|
|
9
9
|
export const VectorTilesContext = createContext(undefined);
|
|
10
|
+
/** A component's rank among the layers of the components (`LayerOrder.rank`): taken at its first render, in the
|
|
11
|
+
* declared order, kept after */
|
|
12
|
+
export const useRank = () => {
|
|
13
|
+
const binding = useContext(MapContext);
|
|
14
|
+
const [rank] = useState(() => binding?.order.rank());
|
|
15
|
+
return rank;
|
|
16
|
+
};
|
|
10
17
|
/** The map of the `<IsardMap>` around, once created (undefined before) */
|
|
11
18
|
export const useMap = () => useContext(MapContext)?.map;
|
|
12
19
|
/** Listens to an event of the map around while the component is mounted; the listener may change at each render */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/react/context.ts"],"names":[],"mappings":"AAAA;uBACuB;AAEvB,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/react/context.ts"],"names":[],"mappings":"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","sourcesContent":["/** What the components of a map share: the map, the order of their layers, the viewsheds, the swipe and the marker\n * around; the hooks */\n\nimport { createContext, useContext, useEffect, useRef, useState } from 'react';\nimport type { VectorTiles } from '../basemap/vectortiles.ts';\nimport type { LayerOrder } from '../bind/layers.ts';\nimport type { Layer as LayerHandle } from '../layers/layers.ts';\nimport type { GeoMap } from '../map.ts';\nimport type { LonLat, MapEvents, ViewshedOptions } from '../types.ts';\nimport type { Marker as MarkerHandle } from '../ui/overlay.ts';\n\nexport interface Binding {\n map: GeoMap;\n order: LayerOrder;\n /** The observers of the `<Viewshed>` components, set on the map together */\n viewsheds: Map<object, ViewshedOptions>;\n applyViewsheds(): void;\n}\n\nexport const MapContext = createContext<Binding | undefined>(undefined);\n\n/** The layers of a `<Swipe>` around, its `<Layer>` children joining it; `other`: the group of its `<SwipeOther>` */\nexport interface SwipeGroup {\n set(layer: LayerHandle): void;\n unset(layer: LayerHandle): void;\n other?: SwipeGroup;\n}\n\nexport const SwipeContext = createContext<SwipeGroup | undefined>(undefined);\n\n/** The marker of a `<Marker>` around and its position (a `<Popup>` in it opens on its click, at that position) */\nexport const MarkerContext = createContext<{ marker: MarkerHandle; lonLat: LonLat } | undefined>(undefined);\n\n/** The vector tiles of the `<VectorTiles>` around, once the map is there */\nexport const VectorTilesContext = createContext<VectorTiles | undefined>(undefined);\n\n/** A component's rank among the layers of the components (`LayerOrder.rank`): taken at its first render, in the\n * declared order, kept after */\nexport const useRank = (): number | undefined => {\n const binding = useContext(MapContext);\n const [rank] = useState(() => binding?.order.rank());\n\n return rank;\n};\n\n/** The map of the `<IsardMap>` around, once created (undefined before) */\nexport const useMap = (): GeoMap | undefined => useContext(MapContext)?.map;\n\n/** Listens to an event of the map around while the component is mounted; the listener may change at each render */\nexport const useMapEvent = <K extends keyof MapEvents>(type: K, listener: (event: MapEvents[K]) => void): void => {\n const map = useMap();\n const latest = useRef(listener);\n\n latest.current = listener;\n // Listening while mounted, to the listener of the last render; stops when unmounted or the map changes\n useEffect(() => map?.on(type, (event) => latest.current(event)), [map, type]);\n};\n\n/** The entries of an object whose value is defined (`exactOptionalPropertyTypes`) */\nexport const defined = <T extends object>(object: T): { [K in keyof T]?: Exclude<T[K], undefined> } =>\n Object.fromEntries(Object.entries(object).filter(([, value]) => value !== undefined)) as {\n [K in keyof T]?: Exclude<T[K], undefined>;\n };\n\n/** Numbers standing for the values compared by identity in `propsKey`, the next one */\nconst identities = { of: new WeakMap<object, number>(), next: 1 };\n\n/** The number of a value compared by identity */\nconst identity = (value: object): number => {\n const known = identities.of.get(value);\n\n if (known !== undefined) return known;\n identities.of.set(value, identities.next);\n identities.next += 1;\n\n return identities.next - 1;\n};\n\n/** A value compared by identity: a function, a class's instance (a layer), binary data */\nconst byIdentity = (value: unknown): value is object =>\n typeof value === 'function' ||\n (typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n Object.getPrototypeOf(value) !== Object.prototype &&\n Object.getPrototypeOf(value) !== null);\n\n/** A key of options that changes when they do: plain data compared by value (an object written inline in the JSX\n * keeps its key), functions, layers and binary data by identity */\nexport const propsKey = (options: object): string =>\n JSON.stringify(options, (_, value: unknown) => (byIdentity(value) ? `#${identity(value)}` : value));\n\n/** The same options while their `propsKey` stays: an object written inline in the JSX, the same from render to render\n * until a value in it changes */\nexport const useStableOptions = <T extends object>(options: T): T => {\n const kept = useRef({ key: propsKey(options), options });\n const key = propsKey(options);\n\n if (kept.current.key !== key) kept.current = { key, options };\n\n return kept.current.options;\n};\n"]}
|
package/package.json
CHANGED