isard 1.1.0 → 1.2.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 +33 -0
- package/dist/basemap/basemaps.d.ts +1 -1
- package/dist/basemap/basemaps.js +2 -2
- package/dist/basemap/basemaps.js.map +1 -1
- package/dist/basemap/grid.d.ts +5 -5
- package/dist/basemap/grid.js +59 -65
- package/dist/basemap/grid.js.map +1 -1
- package/dist/basemap/mvt.d.ts +1 -1
- package/dist/basemap/mvt.js +6 -6
- package/dist/basemap/mvt.js.map +1 -1
- package/dist/basemap/pmtiles.d.ts +10 -10
- package/dist/basemap/pmtiles.js +39 -31
- package/dist/basemap/pmtiles.js.map +1 -1
- package/dist/basemap/resample.d.ts +2 -2
- package/dist/basemap/resample.js +16 -14
- package/dist/basemap/resample.js.map +1 -1
- package/dist/basemap/terrain.d.ts +3 -3
- package/dist/basemap/terrain.js +6 -6
- package/dist/basemap/terrain.js.map +1 -1
- package/dist/basemap/vectorstyle.d.ts +12 -10
- package/dist/basemap/vectorstyle.js +128 -110
- package/dist/basemap/vectorstyle.js.map +1 -1
- package/dist/basemap/vectortiles.d.ts +11 -11
- package/dist/basemap/vectortiles.js +141 -103
- package/dist/basemap/vectortiles.js.map +1 -1
- package/dist/basemap/wmts.d.ts +3 -3
- package/dist/basemap/wmts.js +16 -11
- package/dist/basemap/wmts.js.map +1 -1
- package/dist/basemap.worker.js +2 -2
- package/dist/basemap.worker.js.map +14 -13
- package/dist/bind/layers.d.ts +13 -4
- package/dist/bind/layers.js +64 -40
- package/dist/bind/layers.js.map +1 -1
- package/dist/data/crs.d.ts +10 -10
- package/dist/data/crs.js +38 -34
- package/dist/data/crs.js.map +1 -1
- package/dist/data/gpx.d.ts +1 -1
- package/dist/data/gpx.js +20 -20
- package/dist/data/gpx.js.map +1 -1
- package/dist/data/kml.d.ts +1 -1
- package/dist/data/kml.js +42 -39
- package/dist/data/kml.js.map +1 -1
- package/dist/data/topojson.d.ts +1 -1
- package/dist/data/topojson.js +15 -10
- package/dist/data/topojson.js.map +1 -1
- package/dist/data/xml.d.ts +5 -5
- package/dist/data/xml.js +19 -18
- package/dist/data/xml.js.map +1 -1
- package/dist/decoder.worker.js +4 -4
- package/dist/decoder.worker.js.map +6 -6
- package/dist/engine/decoders.d.ts +2 -2
- package/dist/engine/decoders.js +28 -25
- package/dist/engine/decoders.js.map +1 -1
- package/dist/engine/loader.js +13 -14
- package/dist/engine/loader.js.map +1 -1
- package/dist/engine/requests.d.ts +1 -1
- package/dist/engine/requests.js +19 -16
- package/dist/engine/requests.js.map +1 -1
- package/dist/engine-loader.d.ts +8 -8
- package/dist/engine-loader.js +27 -27
- package/dist/engine-loader.js.map +1 -1
- package/dist/geoplateforme.d.ts +10 -10
- package/dist/geoplateforme.js +22 -20
- package/dist/geoplateforme.js.map +1 -1
- package/dist/index.d.ts +1 -0
- 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_points_bg.wasm +0 -0
- package/dist/layers/extrusions.d.ts +1 -1
- package/dist/layers/extrusions.js +10 -5
- package/dist/layers/extrusions.js.map +1 -1
- package/dist/layers/features.d.ts +10 -10
- package/dist/layers/features.js +41 -42
- package/dist/layers/features.js.map +1 -1
- package/dist/layers/glyphs.d.ts +3 -3
- package/dist/layers/glyphs.js +34 -40
- package/dist/layers/glyphs.js.map +1 -1
- package/dist/layers/icons.d.ts +8 -8
- package/dist/layers/icons.js +76 -68
- package/dist/layers/icons.js.map +1 -1
- package/dist/layers/layers.d.ts +1 -1
- package/dist/layers/layers.js +33 -29
- package/dist/layers/layers.js.map +1 -1
- package/dist/layers/panoramas.d.ts +2 -2
- package/dist/layers/panoramas.js +52 -41
- package/dist/layers/panoramas.js.map +1 -1
- package/dist/layers/pointclouds.d.ts +3 -3
- package/dist/layers/pointclouds.js +25 -33
- package/dist/layers/pointclouds.js.map +1 -1
- package/dist/layers/symbols.d.ts +1 -1
- package/dist/layers/symbols.js +68 -71
- package/dist/layers/symbols.js.map +1 -1
- package/dist/map/basemap-layers.d.ts +26 -0
- package/dist/map/basemap-layers.js +61 -0
- package/dist/map/basemap-layers.js.map +1 -0
- package/dist/map/canvas.d.ts +17 -0
- package/dist/map/canvas.js +56 -0
- package/dist/map/canvas.js.map +1 -0
- package/dist/map/checks.d.ts +11 -0
- package/dist/map/checks.js +39 -0
- package/dist/map/checks.js.map +1 -0
- package/dist/map/credits.d.ts +17 -0
- package/dist/map/credits.js +34 -0
- package/dist/map/credits.js.map +1 -0
- package/dist/map/engine-settings.d.ts +15 -0
- package/dist/map/engine-settings.js +45 -0
- package/dist/map/engine-settings.js.map +1 -0
- package/dist/map/engines.d.ts +41 -0
- package/dist/map/engines.js +77 -0
- package/dist/map/engines.js.map +1 -0
- package/dist/map/events.d.ts +14 -0
- package/dist/map/events.js +46 -0
- package/dist/map/events.js.map +1 -0
- package/dist/map/frame-loop.d.ts +61 -0
- package/dist/map/frame-loop.js +139 -0
- package/dist/map/frame-loop.js.map +1 -0
- package/dist/map/hover-pick.d.ts +30 -0
- package/dist/map/hover-pick.js +56 -0
- package/dist/map/hover-pick.js.map +1 -0
- package/dist/map/layer-spec.d.ts +42 -0
- package/dist/map/layer-spec.js +34 -0
- package/dist/map/layer-spec.js.map +1 -0
- package/dist/map/layer-stack.d.ts +36 -0
- package/dist/map/layer-stack.js +101 -0
- package/dist/map/layer-stack.js.map +1 -0
- package/dist/map/overlay-host.d.ts +36 -0
- package/dist/map/overlay-host.js +101 -0
- package/dist/map/overlay-host.js.map +1 -0
- package/dist/map/panorama-host.d.ts +5 -0
- package/dist/map/panorama-host.js +32 -0
- package/dist/map/panorama-host.js.map +1 -0
- package/dist/map/raster-source.d.ts +11 -0
- package/dist/map/raster-source.js +26 -0
- package/dist/map/raster-source.js.map +1 -0
- package/dist/map/symbol-atlases.d.ts +26 -0
- package/dist/map/symbol-atlases.js +59 -0
- package/dist/map/symbol-atlases.js.map +1 -0
- package/dist/map/viewshed.d.ts +5 -0
- package/dist/map/viewshed.js +28 -0
- package/dist/map/viewshed.js.map +1 -0
- package/dist/map/workers.d.ts +46 -0
- package/dist/map/workers.js +73 -0
- package/dist/map/workers.js.map +1 -0
- package/dist/map.d.ts +33 -120
- package/dist/map.js +164 -689
- package/dist/map.js.map +1 -1
- package/dist/react/Control.d.ts +11 -0
- package/dist/react/Control.js +18 -0
- package/dist/react/Control.js.map +1 -0
- package/dist/react/CustomLayer.d.ts +11 -0
- package/dist/react/CustomLayer.js +30 -0
- package/dist/react/CustomLayer.js.map +1 -0
- package/dist/react/IsardMap.d.ts +43 -0
- package/dist/react/IsardMap.js +146 -0
- package/dist/react/IsardMap.js.map +1 -0
- package/dist/react/Layer.d.ts +42 -0
- package/dist/react/Layer.js +74 -0
- package/dist/react/Layer.js.map +1 -0
- package/dist/react/Marker.d.ts +24 -0
- package/dist/react/Marker.js +53 -0
- package/dist/react/Marker.js.map +1 -0
- package/dist/react/Panel.d.ts +11 -0
- package/dist/react/Panel.js +37 -0
- package/dist/react/Panel.js.map +1 -0
- package/dist/react/Popup.d.ts +18 -0
- package/dist/react/Popup.js +60 -0
- package/dist/react/Popup.js.map +1 -0
- package/dist/react/Swipe.d.ts +9 -0
- package/dist/react/Swipe.js +41 -0
- package/dist/react/Swipe.js.map +1 -0
- package/dist/react/Viewshed.d.ts +5 -0
- package/dist/react/Viewshed.js +28 -0
- package/dist/react/Viewshed.js.map +1 -0
- package/dist/react/context.d.ts +32 -0
- package/dist/react/context.js +20 -0
- package/dist/react/context.js.map +1 -0
- package/dist/react/index.d.ts +15 -108
- package/dist/react/index.js +10 -397
- package/dist/react/index.js.map +1 -1
- package/dist/settings.d.ts +5 -9
- package/dist/settings.js +17 -15
- package/dist/settings.js.map +1 -1
- package/dist/types.d.ts +3 -3
- package/dist/types.js.map +1 -1
- package/dist/ui/controls.js +6 -4
- package/dist/ui/controls.js.map +1 -1
- package/dist/ui/interaction.d.ts +2 -2
- package/dist/ui/interaction.js +8 -7
- package/dist/ui/interaction.js.map +1 -1
- package/dist/ui/overlay.js +18 -20
- package/dist/ui/overlay.js.map +1 -1
- package/dist/ui/style.d.ts +1 -1
- package/dist/ui/style.js +2 -2
- package/dist/ui/style.js.map +1 -1
- package/dist/util/animation.d.ts +3 -3
- package/dist/util/animation.js +6 -6
- package/dist/util/animation.js.map +1 -1
- package/dist/util/color.d.ts +1 -1
- package/dist/util/color.js +14 -16
- package/dist/util/color.js.map +1 -1
- package/dist/util/geo.d.ts +6 -6
- package/dist/util/geo.js +12 -12
- package/dist/util/geo.js.map +1 -1
- package/dist/util/guards.d.ts +7 -0
- package/dist/util/guards.js +8 -0
- package/dist/util/guards.js.map +1 -0
- package/dist/util/lru.js.map +1 -1
- package/dist/wasm/isard.d.ts +168 -0
- package/dist/wasm/isard.js +146 -0
- package/dist/wasm/isard_core.d.ts +144 -0
- package/dist/wasm/isard_core.js +122 -0
- package/dist/workers/basemap.worker.d.ts +3 -3
- package/dist/workers/basemap.worker.js +94 -83
- package/dist/workers/basemap.worker.js.map +1 -1
- package/package.json +1 -1
package/dist/basemap/terrain.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { withHeaders } from "../engine/requests.js";
|
|
7
7
|
const SIZE = 256;
|
|
8
8
|
/** Altitudes (metres, rows from the north) of RGBA pixels in an encoding; below `floor` raised to it */
|
|
9
|
-
export
|
|
9
|
+
export const decodeHeights = (rgba, encoding, floor = Number.NEGATIVE_INFINITY) => {
|
|
10
10
|
const n = rgba.length >> 2;
|
|
11
11
|
const out = new Float32Array(n);
|
|
12
12
|
// A loop per encoding, without allocations: 65 536 pixels a tile
|
|
@@ -23,12 +23,12 @@ export function decodeHeights(rgba, encoding, floor = Number.NEGATIVE_INFINITY)
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
return out;
|
|
26
|
-
}
|
|
26
|
+
};
|
|
27
27
|
/**
|
|
28
28
|
* The altitudes of the PNG tile at `url`: 256 × 256, null where the server has no tile; a network or server error
|
|
29
29
|
* rejects (the engine retries). Where it runs: in a worker of the map, or in the page without workers
|
|
30
30
|
*/
|
|
31
|
-
export async
|
|
31
|
+
export const fetchHeights = async (url, encoding, floor, signal, surface) => {
|
|
32
32
|
const response = await fetch(url, withHeaders(url, { signal }));
|
|
33
33
|
if (response.status === 404 || response.status === 204 || response.status === 410)
|
|
34
34
|
return null;
|
|
@@ -53,17 +53,17 @@ export async function fetchHeights(url, encoding, floor, signal, surface) {
|
|
|
53
53
|
finally {
|
|
54
54
|
bitmap.close();
|
|
55
55
|
}
|
|
56
|
-
}
|
|
56
|
+
};
|
|
57
57
|
/**
|
|
58
58
|
* A loader of the engine's relief for PNG tiles of `url` ({z}, {x}, {y}) in an encoding: 256 × 256 altitudes, null
|
|
59
59
|
* where the server has no tile; a network or server error rejects (retried). `floor`: the lowest altitude kept (the
|
|
60
60
|
* sea floor of a worldwide model flattened at sea level). `remote`: decodes in a worker when it can
|
|
61
61
|
*/
|
|
62
|
-
export
|
|
62
|
+
export const encodedTerrainLoader = (url, encoding, floor, remote) => {
|
|
63
63
|
const surface = {};
|
|
64
64
|
return (z, x, y, signal) => {
|
|
65
65
|
const tile = url.replaceAll('{z}', String(z)).replaceAll('{x}', String(x)).replaceAll('{y}', String(y));
|
|
66
66
|
return remote?.(tile, encoding, floor, [z, x, y], signal) ?? fetchHeights(tile, encoding, floor, signal, surface);
|
|
67
67
|
};
|
|
68
|
-
}
|
|
68
|
+
};
|
|
69
69
|
//# sourceMappingURL=terrain.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terrain.js","sourceRoot":"","sources":["../../src/basemap/terrain.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAKpD,MAAM,IAAI,GAAG,GAAG,CAAC;AAEjB,wGAAwG;AACxG,MAAM,
|
|
1
|
+
{"version":3,"file":"terrain.js","sourceRoot":"","sources":["../../src/basemap/terrain.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Altitudes encoded in the colors of PNG tiles, for the relief: Terrarium (Mapzen, the Terrain Tiles of AWS) and\n * Terrain-RGB (Mapbox, MapTiler). The engine reads raw floats only; a loader gives it the altitudes of each tile,\n * decoded in a worker of the map's pool (OffscreenCanvas), or in the page when the map has no workers.\n */\nimport { withHeaders } from '../engine/requests.ts';\n\n/** The encodings of altitudes in the colors of PNG tiles */\nexport type PngEncoding = 'terrarium' | 'mapbox';\n\nconst SIZE = 256;\n\n/** Altitudes (metres, rows from the north) of RGBA pixels in an encoding; below `floor` raised to it */\nexport const decodeHeights = (\n rgba: Uint8ClampedArray | Uint8Array,\n encoding: PngEncoding,\n floor = Number.NEGATIVE_INFINITY,\n): Float32Array => {\n const n = rgba.length >> 2;\n const out = new Float32Array(n);\n\n // A loop per encoding, without allocations: 65 536 pixels a tile\n if (encoding === 'terrarium') {\n for (let i = 0, j = 0; i < n; i += 1, j += 4) {\n const h = (rgba[j] as number) * 256 + (rgba[j + 1] as number) + (rgba[j + 2] as number) / 256 - 32768;\n\n out[i] = h > floor ? h : floor;\n }\n } else {\n for (let i = 0, j = 0; i < n; i += 1, j += 4) {\n const h = -10000 + ((rgba[j] as number) * 65536 + (rgba[j + 1] as number) * 256 + (rgba[j + 2] as number)) * 0.1;\n\n out[i] = h > floor ? h : floor;\n }\n }\n\n return out;\n};\n\n/** Where the tiles are drawn and read back, made on first use and kept (each tile drawn and read at once) */\nexport interface Surface {\n canvas?: OffscreenCanvas;\n}\n\n/**\n * The altitudes of the PNG tile at `url`: 256 × 256, null where the server has no tile; a network or server error\n * rejects (the engine retries). Where it runs: in a worker of the map, or in the page without workers\n */\nexport const fetchHeights = async (\n url: string,\n encoding: PngEncoding,\n floor: number | undefined,\n signal: AbortSignal,\n surface: Surface,\n): Promise<Float32Array | null> => {\n const response = await fetch(url, withHeaders(url, { signal }));\n\n if (response.status === 404 || response.status === 204 || response.status === 410) return null;\n if (!response.ok) throw new Error(`${response.url}: ${response.status}`);\n\n // The colors as stored: no color management, no premultiplied alpha\n const bitmap = await createImageBitmap(await response.blob(), {\n premultiplyAlpha: 'none',\n colorSpaceConversion: 'none',\n });\n\n try {\n surface.canvas ??= new OffscreenCanvas(SIZE, SIZE);\n\n const g = surface.canvas.getContext('2d', { willReadFrequently: true });\n\n if (!g) throw new Error('no 2D context');\n // Another size is resampled to the nearest pixel: an interpolated color is no altitude\n g.imageSmoothingEnabled = false;\n g.clearRect(0, 0, SIZE, SIZE);\n g.drawImage(bitmap, 0, 0, SIZE, SIZE);\n\n return decodeHeights(g.getImageData(0, 0, SIZE, SIZE).data, encoding, floor);\n } finally {\n bitmap.close();\n }\n};\n\n/** `fetchHeights` run in a worker for tile `z`/`x`/`y`; undefined when the map has no workers (run in the page) */\nexport type RemoteHeights = (\n url: string,\n encoding: PngEncoding,\n floor: number | undefined,\n tile: [z: number, x: number, y: number],\n signal: AbortSignal,\n) => Promise<Float32Array | null> | undefined;\n\n/**\n * A loader of the engine's relief for PNG tiles of `url` ({z}, {x}, {y}) in an encoding: 256 × 256 altitudes, null\n * where the server has no tile; a network or server error rejects (retried). `floor`: the lowest altitude kept (the\n * sea floor of a worldwide model flattened at sea level). `remote`: decodes in a worker when it can\n */\nexport const encodedTerrainLoader = (\n url: string,\n encoding: PngEncoding,\n floor?: number,\n remote?: RemoteHeights,\n): ((z: number, x: number, y: number, signal: AbortSignal) => Promise<Float32Array | null>) => {\n const surface: Surface = {};\n\n return (z, x, y, signal) => {\n const tile = url.replaceAll('{z}', String(z)).replaceAll('{x}', String(x)).replaceAll('{y}', String(y));\n\n return remote?.(tile, encoding, floor, [z, x, y], signal) ?? fetchHeights(tile, encoding, floor, signal, surface);\n };\n};\n"]}
|
|
@@ -31,6 +31,8 @@ export interface Style {
|
|
|
31
31
|
url: string;
|
|
32
32
|
}[];
|
|
33
33
|
}
|
|
34
|
+
/** A MapLibre style, as far as the basemap reads it: its sources and its layers (an id and a type each) */
|
|
35
|
+
export declare const isStyle: (value: unknown) => value is Style;
|
|
34
36
|
/** A raster source of a style: its tile URL, its deepest level and the CSS pixels of its tiles (MapLibre's
|
|
35
37
|
* `tileSize`: 512 by default) */
|
|
36
38
|
export interface RasterSource {
|
|
@@ -90,23 +92,23 @@ export interface Context {
|
|
|
90
92
|
/** 'Point', 'LineString' or 'Polygon' */
|
|
91
93
|
type: string;
|
|
92
94
|
}
|
|
93
|
-
export declare
|
|
95
|
+
export declare const context: (feature: TileFeature, zoom: number) => Context;
|
|
94
96
|
/** A color to RGBA 0-1, undefined if it is not one */
|
|
95
|
-
export declare
|
|
96
|
-
export declare
|
|
97
|
+
export declare const color: (value: unknown) => [number, number, number, number] | undefined;
|
|
98
|
+
export declare const css: ([r, g, b, a]: [number, number, number, number]) => string;
|
|
97
99
|
/** Whether a value is an expression (an array starting with a known operator), not a literal array */
|
|
98
|
-
export declare
|
|
99
|
-
export declare
|
|
100
|
-
export declare
|
|
100
|
+
export declare const isExpression: (e: unknown) => e is Json[];
|
|
101
|
+
export declare const evaluate: (e: Json, ctx: Context) => unknown;
|
|
102
|
+
export declare const filter: (f: Json | undefined, ctx: Context) => boolean;
|
|
101
103
|
/** Whether a value depends on the feature (else only on the zoom, evaluated once per tile) */
|
|
102
|
-
export declare
|
|
104
|
+
export declare const isFeatureDependent: (e: Json | undefined) => boolean;
|
|
103
105
|
/** A `{token}` text field (or an expression) to the text of a feature */
|
|
104
|
-
export declare
|
|
106
|
+
export declare const text: (field: Json | undefined, ctx: Context) => string;
|
|
105
107
|
/** The font of a label from the first of its `text-font`: a family without its weight takes the regular one */
|
|
106
|
-
export declare
|
|
108
|
+
export declare const labelFont: (font: string) => string;
|
|
107
109
|
/**
|
|
108
110
|
* A value of the zoom only (an expression: `interpolate`, `step` of `["zoom"]`) as stops `[[zoom, value], …]` for the
|
|
109
111
|
* engine, which interpolates them linearly: evaluated at its own stops and at the whole zooms between (an exponential
|
|
110
112
|
* curve followed closely), a step kept sharp just before its threshold
|
|
111
113
|
*/
|
|
112
|
-
export declare
|
|
114
|
+
export declare const zoomStops: (e: Json) => [number, number][];
|
|
@@ -7,42 +7,51 @@
|
|
|
7
7
|
* interpolated in RGBA, `{token}` text fields.
|
|
8
8
|
*/
|
|
9
9
|
import { parseCssColor } from "../util/color.js";
|
|
10
|
+
import { isRecord } from "../util/guards.js";
|
|
11
|
+
/** A MapLibre style, as far as the basemap reads it: its sources and its layers (an id and a type each) */
|
|
12
|
+
export const isStyle = (value) => isRecord(value) &&
|
|
13
|
+
isRecord(value.sources) &&
|
|
14
|
+
Object.values(value.sources).every((s) => isRecord(s) && typeof s.type === 'string') &&
|
|
15
|
+
Array.isArray(value.layers) &&
|
|
16
|
+
value.layers.every((l) => isRecord(l) && typeof l.id === 'string' && typeof l.type === 'string');
|
|
10
17
|
const TYPES = ['Unknown', 'Point', 'LineString', 'Polygon'];
|
|
11
|
-
export
|
|
18
|
+
export const context = (feature, zoom) => {
|
|
12
19
|
return { zoom, properties: feature.properties, type: TYPES[feature.type] ?? 'Unknown' };
|
|
13
|
-
}
|
|
20
|
+
};
|
|
14
21
|
// ── Colors ──
|
|
15
22
|
/** A color to RGBA 0-1, undefined if it is not one */
|
|
16
|
-
export
|
|
23
|
+
export const color = (value) => {
|
|
17
24
|
return parseCssColor(value);
|
|
18
|
-
}
|
|
19
|
-
export
|
|
25
|
+
};
|
|
26
|
+
export const css = ([r, g, b, a]) => {
|
|
20
27
|
return `rgba(${Math.round(r * 255)},${Math.round(g * 255)},${Math.round(b * 255)},${a})`;
|
|
21
|
-
}
|
|
28
|
+
};
|
|
22
29
|
// ── Interpolation ──
|
|
23
30
|
/** Factor between two stops: linear, or exponential of `base` */
|
|
24
|
-
|
|
31
|
+
const factor = (x, x0, x1, base = 1) => {
|
|
25
32
|
const d = x1 - x0;
|
|
26
33
|
if (d === 0)
|
|
27
34
|
return 0;
|
|
28
35
|
const t = x - x0;
|
|
29
36
|
return base === 1 ? t / d : (base ** t - 1) / (base ** d - 1);
|
|
30
|
-
}
|
|
31
|
-
|
|
37
|
+
};
|
|
38
|
+
const mix = (a, b, t) => {
|
|
32
39
|
if (typeof a === 'number' && typeof b === 'number')
|
|
33
40
|
return a + (b - a) * t;
|
|
34
41
|
const ca = color(a);
|
|
35
42
|
const cb = color(b);
|
|
36
|
-
if (ca && cb)
|
|
37
|
-
|
|
43
|
+
if (ca && cb) {
|
|
44
|
+
const lerp = (i) => ca[i] + (cb[i] - ca[i]) * t;
|
|
45
|
+
return css([lerp(0), lerp(1), lerp(2), lerp(3)]);
|
|
46
|
+
}
|
|
38
47
|
if (Array.isArray(a) && Array.isArray(b))
|
|
39
48
|
return a.map((v, i) => mix(v, b[i], t));
|
|
40
49
|
return t < 0.5 ? a : b;
|
|
41
|
-
}
|
|
42
|
-
|
|
50
|
+
};
|
|
51
|
+
const isFunction = (v) => {
|
|
43
52
|
return typeof v === 'object' && v !== null && !Array.isArray(v) && Array.isArray(v.stops);
|
|
44
|
-
}
|
|
45
|
-
|
|
53
|
+
};
|
|
54
|
+
const legacy = (f, ctx) => {
|
|
46
55
|
const input = f.property === undefined ? ctx.zoom : ctx.properties[f.property];
|
|
47
56
|
const stops = f.stops;
|
|
48
57
|
const type = f.type ?? (f.property === undefined || typeof stops[0]?.[0] === 'number' ? 'exponential' : 'categorical');
|
|
@@ -53,30 +62,45 @@ function legacy(f, ctx) {
|
|
|
53
62
|
if (typeof input !== 'number' || !stops.length)
|
|
54
63
|
return f.default ?? stops[0]?.[1];
|
|
55
64
|
// Zoom-and-property stops ({ zoom, value } keys) are taken at their zoom only
|
|
56
|
-
const key = (
|
|
65
|
+
const key = ([k]) => {
|
|
66
|
+
if (Array.isArray(k))
|
|
67
|
+
return Number.NaN;
|
|
68
|
+
return isRecord(k) ? Number(k.zoom) : Number(k);
|
|
69
|
+
};
|
|
57
70
|
const first = stops[0];
|
|
58
71
|
if (!first)
|
|
59
72
|
return f.default;
|
|
60
73
|
if (input <= key(first))
|
|
61
74
|
return first[1];
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return stops.at(-1)?.[1];
|
|
73
|
-
}
|
|
75
|
+
const at = stops.findIndex((s1, i) => i > 0 && Boolean(stops[i - 1]) && Boolean(s1) && input < key(s1));
|
|
76
|
+
const [s0, s1] = [stops[at - 1], stops[at]];
|
|
77
|
+
if (at < 0 || !s0 || !s1)
|
|
78
|
+
return stops.at(-1)?.[1];
|
|
79
|
+
if (type === 'interval')
|
|
80
|
+
return s0[1];
|
|
81
|
+
return mix(s0[1], s1[1], factor(input, key(s0), key(s1), f.base ?? 1));
|
|
82
|
+
};
|
|
74
83
|
// ── Expressions ──
|
|
75
|
-
|
|
84
|
+
/** A list of values to look a value up in (any value: `includes` compares with `===`) */
|
|
85
|
+
const labels = (values) => values;
|
|
86
|
+
const ORDERS = {
|
|
87
|
+
'<': (a, b) => a < b,
|
|
88
|
+
'<=': (a, b) => a <= b,
|
|
89
|
+
'>': (a, b) => a > b,
|
|
90
|
+
'>=': (a, b) => a >= b,
|
|
91
|
+
};
|
|
92
|
+
/** A comparison of any two values the way JavaScript's operators make it: two strings (lists and objects as their
|
|
93
|
+
* text) in text order, anything else as numbers */
|
|
94
|
+
const compare = (op, a, b) => {
|
|
95
|
+
const text = (v) => (typeof v === 'object' && v !== null ? String(v) : v);
|
|
96
|
+
const [x, y] = [text(a), text(b)];
|
|
97
|
+
return typeof x === 'string' && typeof y === 'string' ? ORDERS[op](x, y) : ORDERS[op](Number(x), Number(y));
|
|
98
|
+
};
|
|
99
|
+
const get = (ctx, key) => {
|
|
76
100
|
if (key === '$type')
|
|
77
101
|
return ctx.type;
|
|
78
102
|
return typeof key === 'string' ? ctx.properties[key] : undefined;
|
|
79
|
-
}
|
|
103
|
+
};
|
|
80
104
|
/** The operators `evaluate` knows */
|
|
81
105
|
const OPERATORS = new Set([
|
|
82
106
|
'literal',
|
|
@@ -142,13 +166,13 @@ const OPERATORS = new Set([
|
|
|
142
166
|
'e',
|
|
143
167
|
]);
|
|
144
168
|
/** Whether a value is an expression (an array starting with a known operator), not a literal array */
|
|
145
|
-
export
|
|
169
|
+
export const isExpression = (e) => {
|
|
146
170
|
return Array.isArray(e) && typeof e[0] === 'string' && OPERATORS.has(e[0]);
|
|
147
|
-
}
|
|
171
|
+
};
|
|
148
172
|
/** Operators already warned about */
|
|
149
173
|
const warned = new Set();
|
|
150
174
|
const str = (v) => (v === undefined || v === null ? '' : String(v));
|
|
151
|
-
export
|
|
175
|
+
export const evaluate = (e, ctx) => {
|
|
152
176
|
if (isFunction(e))
|
|
153
177
|
return legacy(e, ctx);
|
|
154
178
|
if (!Array.isArray(e))
|
|
@@ -184,13 +208,17 @@ export function evaluate(e, ctx) {
|
|
|
184
208
|
case 'image':
|
|
185
209
|
return ev(0);
|
|
186
210
|
case 'number-format': {
|
|
187
|
-
const options = (args[1]
|
|
211
|
+
const options = isRecord(args[1]) ? args[1] : {};
|
|
212
|
+
const option = (key) => {
|
|
213
|
+
const v = options[key];
|
|
214
|
+
return typeof v === 'number' ? v : undefined;
|
|
215
|
+
};
|
|
188
216
|
const n = num(0);
|
|
189
217
|
if (!Number.isFinite(n))
|
|
190
218
|
return '';
|
|
191
|
-
return n.toLocaleString(options.locale, {
|
|
192
|
-
minimumFractionDigits:
|
|
193
|
-
maximumFractionDigits:
|
|
219
|
+
return n.toLocaleString(typeof options.locale === 'string' ? options.locale : undefined, {
|
|
220
|
+
minimumFractionDigits: option('min-fraction-digits'),
|
|
221
|
+
maximumFractionDigits: option('max-fraction-digits'),
|
|
194
222
|
});
|
|
195
223
|
}
|
|
196
224
|
case 'to-number': {
|
|
@@ -262,13 +290,10 @@ export function evaluate(e, ctx) {
|
|
|
262
290
|
case '!=':
|
|
263
291
|
return ev(0) !== ev(1);
|
|
264
292
|
case '<':
|
|
265
|
-
return ev(0) < ev(1);
|
|
266
293
|
case '<=':
|
|
267
|
-
return ev(0) <= ev(1);
|
|
268
294
|
case '>':
|
|
269
|
-
return ev(0) > ev(1);
|
|
270
295
|
case '>=':
|
|
271
|
-
return ev(0)
|
|
296
|
+
return compare(op, ev(0), ev(1));
|
|
272
297
|
case 'in': {
|
|
273
298
|
const haystack = ev(1);
|
|
274
299
|
const needle = ev(0);
|
|
@@ -277,19 +302,15 @@ export function evaluate(e, ctx) {
|
|
|
277
302
|
return Array.isArray(haystack) && haystack.includes(needle);
|
|
278
303
|
}
|
|
279
304
|
case 'case': {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
return ev(i + 1);
|
|
283
|
-
return ev(args.length - 1);
|
|
305
|
+
const hit = args.findIndex((_, i) => i % 2 === 0 && i + 1 < args.length && Boolean(ev(i)));
|
|
306
|
+
return hit < 0 ? ev(args.length - 1) : ev(hit + 1);
|
|
284
307
|
}
|
|
285
308
|
case 'match': {
|
|
286
309
|
const input = ev(0);
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
292
|
-
return ev(args.length - 1);
|
|
310
|
+
const hit = args.findIndex((label, i) => i % 2 === 1 &&
|
|
311
|
+
i + 1 < args.length &&
|
|
312
|
+
(Array.isArray(label) ? labels(label).includes(input) : label === input));
|
|
313
|
+
return hit < 0 ? ev(args.length - 1) : ev(hit + 1);
|
|
293
314
|
}
|
|
294
315
|
case 'step': {
|
|
295
316
|
const input = num(0);
|
|
@@ -308,20 +329,20 @@ export function evaluate(e, ctx) {
|
|
|
308
329
|
const kind = args[0];
|
|
309
330
|
const input = num(1);
|
|
310
331
|
const base = Array.isArray(kind) && kind[0] === 'exponential' ? Number(kind[1]) : 1;
|
|
311
|
-
const stops = [
|
|
312
|
-
|
|
313
|
-
|
|
332
|
+
const stops = Array.from({ length: Math.floor((args.length - 2) / 2) }, (_, k) => [
|
|
333
|
+
Number(args[2 + 2 * k]),
|
|
334
|
+
args[3 + 2 * k] ?? null,
|
|
335
|
+
]);
|
|
314
336
|
const first = stops[0];
|
|
315
337
|
if (!first)
|
|
316
338
|
return null;
|
|
317
339
|
if (input <= first[0])
|
|
318
340
|
return evaluate(first[1], ctx);
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
return evaluate(stops.at(-1)?.[1] ?? null, ctx);
|
|
341
|
+
const at = stops.findIndex((s1, i) => i > 0 && input < s1[0]);
|
|
342
|
+
const [s0, s1] = [stops[at - 1], stops[at]];
|
|
343
|
+
if (at < 0 || !s0 || !s1)
|
|
344
|
+
return evaluate(stops.at(-1)?.[1] ?? null, ctx);
|
|
345
|
+
return mix(evaluate(s0[1], ctx), evaluate(s1[1], ctx), factor(input, s0[0], s1[0], base));
|
|
325
346
|
}
|
|
326
347
|
case 'rgb':
|
|
327
348
|
case 'rgba':
|
|
@@ -371,12 +392,12 @@ export function evaluate(e, ctx) {
|
|
|
371
392
|
}
|
|
372
393
|
return null;
|
|
373
394
|
}
|
|
374
|
-
}
|
|
395
|
+
};
|
|
375
396
|
// ── Filters ──
|
|
376
397
|
const LEGACY_COMPARISONS = new Set(['==', '!=', '<', '<=', '>', '>=']);
|
|
377
398
|
/** Whether a filter (not `all`, `any`, `none`) is in the legacy form: `["==", "key", value]`, `["in", "key", a, b]`,
|
|
378
399
|
* `["has", "key"]`; a key and literal values, as MapLibre tells them from expressions */
|
|
379
|
-
|
|
400
|
+
const isLegacyLeaf = (f) => {
|
|
380
401
|
const [op, a, ...rest] = f;
|
|
381
402
|
if (typeof op !== 'string' || typeof a !== 'string' || rest.some(Array.isArray))
|
|
382
403
|
return false;
|
|
@@ -385,8 +406,8 @@ function isLegacyLeaf(f) {
|
|
|
385
406
|
if (op === 'in')
|
|
386
407
|
return f.length !== 3 || !Array.isArray(f[2]);
|
|
387
408
|
return op === '!in' || op === 'has' || op === '!has';
|
|
388
|
-
}
|
|
389
|
-
|
|
409
|
+
};
|
|
410
|
+
const legacyFilter = (f, ctx) => {
|
|
390
411
|
const [op, key, ...rest] = f;
|
|
391
412
|
const v = get(ctx, key);
|
|
392
413
|
switch (op) {
|
|
@@ -395,17 +416,14 @@ function legacyFilter(f, ctx) {
|
|
|
395
416
|
case '!=':
|
|
396
417
|
return v !== rest[0];
|
|
397
418
|
case '<':
|
|
398
|
-
return v < rest[0];
|
|
399
419
|
case '<=':
|
|
400
|
-
return v <= rest[0];
|
|
401
420
|
case '>':
|
|
402
|
-
return v > rest[0];
|
|
403
421
|
case '>=':
|
|
404
|
-
return v
|
|
422
|
+
return compare(op, v, rest[0]);
|
|
405
423
|
case 'in':
|
|
406
|
-
return rest.includes(v);
|
|
424
|
+
return labels(rest).includes(v);
|
|
407
425
|
case '!in':
|
|
408
|
-
return !rest.includes(v);
|
|
426
|
+
return !labels(rest).includes(v);
|
|
409
427
|
case 'has':
|
|
410
428
|
return v !== undefined;
|
|
411
429
|
case '!has':
|
|
@@ -413,53 +431,53 @@ function legacyFilter(f, ctx) {
|
|
|
413
431
|
default:
|
|
414
432
|
return true;
|
|
415
433
|
}
|
|
416
|
-
}
|
|
434
|
+
};
|
|
417
435
|
/** Compiled filters, by filter object */
|
|
418
436
|
const compiled = new WeakMap();
|
|
419
437
|
/** A filter as a function: `all`, `any`, `none` of their parts, each part legacy or an expression (they may mix) */
|
|
420
|
-
|
|
438
|
+
const compile = (f) => {
|
|
421
439
|
if (!Array.isArray(f))
|
|
422
440
|
return () => Boolean(f);
|
|
423
441
|
const hit = compiled.get(f);
|
|
424
442
|
if (hit)
|
|
425
443
|
return hit;
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
test = (ctx) => Boolean(evaluate(f, ctx));
|
|
442
|
-
}
|
|
444
|
+
const make = () => {
|
|
445
|
+
const op = f[0];
|
|
446
|
+
if (op === 'all' || op === 'any' || op === 'none') {
|
|
447
|
+
const parts = f.slice(1).map(compile);
|
|
448
|
+
if (op === 'all')
|
|
449
|
+
return (ctx) => parts.every((p) => p(ctx));
|
|
450
|
+
if (op === 'any')
|
|
451
|
+
return (ctx) => parts.some((p) => p(ctx));
|
|
452
|
+
return (ctx) => !parts.some((p) => p(ctx));
|
|
453
|
+
}
|
|
454
|
+
if (isLegacyLeaf(f))
|
|
455
|
+
return (ctx) => legacyFilter(f, ctx);
|
|
456
|
+
return (ctx) => Boolean(evaluate(f, ctx));
|
|
457
|
+
};
|
|
458
|
+
const test = make();
|
|
443
459
|
compiled.set(f, test);
|
|
444
460
|
return test;
|
|
445
|
-
}
|
|
446
|
-
export
|
|
461
|
+
};
|
|
462
|
+
export const filter = (f, ctx) => {
|
|
447
463
|
if (f === undefined || f === null)
|
|
448
464
|
return true;
|
|
449
465
|
return compile(f)(ctx);
|
|
450
|
-
}
|
|
466
|
+
};
|
|
467
|
+
/** The operators that read the feature */
|
|
468
|
+
const FEATURE_OPERATORS = new Set(['get', 'has', '!has', 'geometry-type', 'properties', 'id']);
|
|
451
469
|
/** Whether a value depends on the feature (else only on the zoom, evaluated once per tile) */
|
|
452
|
-
export
|
|
470
|
+
export const isFeatureDependent = (e) => {
|
|
453
471
|
if (e !== undefined && isFunction(e))
|
|
454
472
|
return e.property !== undefined;
|
|
455
473
|
if (!Array.isArray(e))
|
|
456
474
|
return false;
|
|
457
|
-
if (
|
|
475
|
+
if (FEATURE_OPERATORS.has(e[0]))
|
|
458
476
|
return true;
|
|
459
477
|
return e.some((x) => isFeatureDependent(x));
|
|
460
|
-
}
|
|
478
|
+
};
|
|
461
479
|
/** A `{token}` text field (or an expression) to the text of a feature */
|
|
462
|
-
export
|
|
480
|
+
export const text = (field, ctx) => {
|
|
463
481
|
if (field === undefined || field === null)
|
|
464
482
|
return '';
|
|
465
483
|
if (typeof field === 'string') {
|
|
@@ -474,45 +492,45 @@ export function text(field, ctx) {
|
|
|
474
492
|
return v.filter((x) => typeof x === 'string').join('');
|
|
475
493
|
}
|
|
476
494
|
return v === undefined || v === null ? '' : String(v);
|
|
477
|
-
}
|
|
495
|
+
};
|
|
478
496
|
/** The font of a label from the first of its `text-font`: a family without its weight takes the regular one */
|
|
479
|
-
export
|
|
497
|
+
export const labelFont = (font) => {
|
|
480
498
|
return /Regular|Bold|Italic|Semibold|Light|Medium|Black/.test(font) ? font : `${font} Regular`;
|
|
481
|
-
}
|
|
499
|
+
};
|
|
482
500
|
/**
|
|
483
501
|
* A value of the zoom only (an expression: `interpolate`, `step` of `["zoom"]`) as stops `[[zoom, value], …]` for the
|
|
484
502
|
* engine, which interpolates them linearly: evaluated at its own stops and at the whole zooms between (an exponential
|
|
485
503
|
* curve followed closely), a step kept sharp just before its threshold
|
|
486
504
|
*/
|
|
487
|
-
export
|
|
505
|
+
export const zoomStops = (e) => {
|
|
488
506
|
const zooms = new Set();
|
|
507
|
+
// The inputs of the stops of an `interpolate` or a `step` (from its fourth argument, one in two)
|
|
508
|
+
const stopInputs = (x) => x.filter((_, i) => i >= 3 && i % 2 === 1).map(Number);
|
|
489
509
|
const walk = (x) => {
|
|
490
510
|
if (!Array.isArray(x))
|
|
491
511
|
return;
|
|
492
512
|
const zoomInput = (input) => Array.isArray(input) && input[0] === 'zoom';
|
|
493
513
|
if ((x[0] === 'interpolate' || x[0] === 'interpolate-hcl' || x[0] === 'interpolate-lab') && zoomInput(x[2])) {
|
|
494
|
-
|
|
495
|
-
zooms.add(
|
|
514
|
+
stopInputs(x).forEach((t) => {
|
|
515
|
+
zooms.add(t);
|
|
516
|
+
});
|
|
496
517
|
}
|
|
497
518
|
else if (x[0] === 'step' && zoomInput(x[1])) {
|
|
498
|
-
|
|
499
|
-
const t = Number(x[i]);
|
|
519
|
+
stopInputs(x).forEach((t) => {
|
|
500
520
|
zooms.add(t);
|
|
501
521
|
zooms.add(t - 0.01);
|
|
502
|
-
}
|
|
522
|
+
});
|
|
503
523
|
}
|
|
504
|
-
|
|
505
|
-
walk(y);
|
|
524
|
+
x.forEach(walk);
|
|
506
525
|
};
|
|
507
526
|
walk(e);
|
|
508
527
|
const finite = [...zooms].filter(Number.isFinite);
|
|
509
528
|
if (finite.length === 0)
|
|
510
529
|
finite.push(0);
|
|
511
530
|
const [lo, hi] = [Math.min(...finite), Math.max(...finite)];
|
|
512
|
-
|
|
513
|
-
finite.push(z);
|
|
531
|
+
finite.push(...Array.from({ length: Math.floor(hi) - Math.ceil(lo) + 1 }, (_, i) => Math.ceil(lo) + i));
|
|
514
532
|
return [...new Set(finite)]
|
|
515
533
|
.sort((a, b) => a - b)
|
|
516
534
|
.map((zoom) => [zoom, Number(evaluate(e, { zoom, properties: {}, type: 'Unknown' }))]);
|
|
517
|
-
}
|
|
535
|
+
};
|
|
518
536
|
//# sourceMappingURL=vectorstyle.js.map
|