isard 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. package/CHANGELOG.md +121 -0
  2. package/README.md +44 -39
  3. package/dist/basemap/basemaps.d.ts +1 -1
  4. package/dist/basemap/basemaps.js +2 -2
  5. package/dist/basemap/basemaps.js.map +1 -1
  6. package/dist/basemap/grid.d.ts +5 -5
  7. package/dist/basemap/grid.js +59 -65
  8. package/dist/basemap/grid.js.map +1 -1
  9. package/dist/basemap/mvt.d.ts +1 -1
  10. package/dist/basemap/mvt.js +6 -6
  11. package/dist/basemap/mvt.js.map +1 -1
  12. package/dist/basemap/pmtiles.d.ts +10 -10
  13. package/dist/basemap/pmtiles.js +39 -31
  14. package/dist/basemap/pmtiles.js.map +1 -1
  15. package/dist/basemap/pmtileslayer.d.ts +33 -0
  16. package/dist/basemap/pmtileslayer.js +97 -0
  17. package/dist/basemap/pmtileslayer.js.map +1 -0
  18. package/dist/basemap/resample.d.ts +2 -2
  19. package/dist/basemap/resample.js +16 -14
  20. package/dist/basemap/resample.js.map +1 -1
  21. package/dist/basemap/terrain.d.ts +3 -3
  22. package/dist/basemap/terrain.js +6 -6
  23. package/dist/basemap/terrain.js.map +1 -1
  24. package/dist/basemap/trees.d.ts +26 -0
  25. package/dist/basemap/trees.js +141 -0
  26. package/dist/basemap/trees.js.map +1 -0
  27. package/dist/basemap/vectorstyle.d.ts +22 -10
  28. package/dist/basemap/vectorstyle.js +163 -110
  29. package/dist/basemap/vectorstyle.js.map +1 -1
  30. package/dist/basemap/vectortiles.d.ts +70 -47
  31. package/dist/basemap/vectortiles.js +480 -358
  32. package/dist/basemap/vectortiles.js.map +1 -1
  33. package/dist/basemap/wmts.d.ts +3 -3
  34. package/dist/basemap/wmts.js +16 -11
  35. package/dist/basemap/wmts.js.map +1 -1
  36. package/dist/basemap/workerpool.d.ts +17 -0
  37. package/dist/basemap/workerpool.js +194 -0
  38. package/dist/basemap/workerpool.js.map +1 -0
  39. package/dist/basemap.worker.js +2 -2
  40. package/dist/basemap.worker.js.map +21 -13
  41. package/dist/bind/layers.d.ts +13 -4
  42. package/dist/bind/layers.js +64 -40
  43. package/dist/bind/layers.js.map +1 -1
  44. package/dist/data/crs.d.ts +10 -10
  45. package/dist/data/crs.js +38 -34
  46. package/dist/data/crs.js.map +1 -1
  47. package/dist/data/gpx.d.ts +1 -1
  48. package/dist/data/gpx.js +20 -20
  49. package/dist/data/gpx.js.map +1 -1
  50. package/dist/data/kml.d.ts +1 -1
  51. package/dist/data/kml.js +42 -39
  52. package/dist/data/kml.js.map +1 -1
  53. package/dist/data/topojson.d.ts +1 -1
  54. package/dist/data/topojson.js +15 -10
  55. package/dist/data/topojson.js.map +1 -1
  56. package/dist/data/xml.d.ts +5 -5
  57. package/dist/data/xml.js +19 -18
  58. package/dist/data/xml.js.map +1 -1
  59. package/dist/decoder.worker.js +4 -4
  60. package/dist/decoder.worker.js.map +6 -6
  61. package/dist/engine/decoders.d.ts +2 -2
  62. package/dist/engine/decoders.js +28 -25
  63. package/dist/engine/decoders.js.map +1 -1
  64. package/dist/engine/loader.js +13 -14
  65. package/dist/engine/loader.js.map +1 -1
  66. package/dist/engine/requests.d.ts +1 -1
  67. package/dist/engine/requests.js +19 -16
  68. package/dist/engine/requests.js.map +1 -1
  69. package/dist/engine-loader.d.ts +13 -9
  70. package/dist/engine-loader.js +38 -28
  71. package/dist/engine-loader.js.map +1 -1
  72. package/dist/geoplateforme.d.ts +26 -10
  73. package/dist/geoplateforme.js +45 -20
  74. package/dist/geoplateforme.js.map +1 -1
  75. package/dist/index.d.ts +12 -4
  76. package/dist/index.js +9 -2
  77. package/dist/index.js.map +1 -1
  78. package/dist/isard_bg.wasm +0 -0
  79. package/dist/isard_core_bg.wasm +0 -0
  80. package/dist/isard_points_bg.wasm +0 -0
  81. package/dist/isard_tess_bg.wasm +0 -0
  82. package/dist/layers/extrusions.d.ts +1 -1
  83. package/dist/layers/extrusions.js +10 -5
  84. package/dist/layers/extrusions.js.map +1 -1
  85. package/dist/layers/features.d.ts +10 -10
  86. package/dist/layers/features.js +41 -42
  87. package/dist/layers/features.js.map +1 -1
  88. package/dist/layers/glyphs.d.ts +3 -3
  89. package/dist/layers/glyphs.js +34 -40
  90. package/dist/layers/glyphs.js.map +1 -1
  91. package/dist/layers/icons.d.ts +8 -8
  92. package/dist/layers/icons.js +76 -68
  93. package/dist/layers/icons.js.map +1 -1
  94. package/dist/layers/layers.d.ts +1 -1
  95. package/dist/layers/layers.js +42 -29
  96. package/dist/layers/layers.js.map +1 -1
  97. package/dist/layers/panoramas.d.ts +2 -2
  98. package/dist/layers/panoramas.js +52 -41
  99. package/dist/layers/panoramas.js.map +1 -1
  100. package/dist/layers/pointclouds.d.ts +3 -3
  101. package/dist/layers/pointclouds.js +25 -33
  102. package/dist/layers/pointclouds.js.map +1 -1
  103. package/dist/layers/symbols.d.ts +1 -1
  104. package/dist/layers/symbols.js +68 -71
  105. package/dist/layers/symbols.js.map +1 -1
  106. package/dist/layers/vectors.d.ts +60 -0
  107. package/dist/layers/vectors.js +130 -0
  108. package/dist/layers/vectors.js.map +1 -0
  109. package/dist/map/basemap-layers.d.ts +26 -0
  110. package/dist/map/basemap-layers.js +61 -0
  111. package/dist/map/basemap-layers.js.map +1 -0
  112. package/dist/map/canvas.d.ts +17 -0
  113. package/dist/map/canvas.js +56 -0
  114. package/dist/map/canvas.js.map +1 -0
  115. package/dist/map/checks.d.ts +11 -0
  116. package/dist/map/checks.js +39 -0
  117. package/dist/map/checks.js.map +1 -0
  118. package/dist/map/credits.d.ts +17 -0
  119. package/dist/map/credits.js +34 -0
  120. package/dist/map/credits.js.map +1 -0
  121. package/dist/map/engine-settings.d.ts +15 -0
  122. package/dist/map/engine-settings.js +45 -0
  123. package/dist/map/engine-settings.js.map +1 -0
  124. package/dist/map/engines.d.ts +41 -0
  125. package/dist/map/engines.js +77 -0
  126. package/dist/map/engines.js.map +1 -0
  127. package/dist/map/events.d.ts +14 -0
  128. package/dist/map/events.js +46 -0
  129. package/dist/map/events.js.map +1 -0
  130. package/dist/map/frame-loop.d.ts +64 -0
  131. package/dist/map/frame-loop.js +145 -0
  132. package/dist/map/frame-loop.js.map +1 -0
  133. package/dist/map/hover-pick.d.ts +30 -0
  134. package/dist/map/hover-pick.js +56 -0
  135. package/dist/map/hover-pick.js.map +1 -0
  136. package/dist/map/layer-spec.d.ts +42 -0
  137. package/dist/map/layer-spec.js +34 -0
  138. package/dist/map/layer-spec.js.map +1 -0
  139. package/dist/map/layer-stack.d.ts +36 -0
  140. package/dist/map/layer-stack.js +101 -0
  141. package/dist/map/layer-stack.js.map +1 -0
  142. package/dist/map/overlay-host.d.ts +36 -0
  143. package/dist/map/overlay-host.js +101 -0
  144. package/dist/map/overlay-host.js.map +1 -0
  145. package/dist/map/panorama-host.d.ts +5 -0
  146. package/dist/map/panorama-host.js +32 -0
  147. package/dist/map/panorama-host.js.map +1 -0
  148. package/dist/map/raster-source.d.ts +11 -0
  149. package/dist/map/raster-source.js +26 -0
  150. package/dist/map/raster-source.js.map +1 -0
  151. package/dist/map/symbol-atlases.d.ts +26 -0
  152. package/dist/map/symbol-atlases.js +59 -0
  153. package/dist/map/symbol-atlases.js.map +1 -0
  154. package/dist/map/viewshed.d.ts +5 -0
  155. package/dist/map/viewshed.js +28 -0
  156. package/dist/map/viewshed.js.map +1 -0
  157. package/dist/map/workers.d.ts +46 -0
  158. package/dist/map/workers.js +73 -0
  159. package/dist/map/workers.js.map +1 -0
  160. package/dist/map.d.ts +54 -126
  161. package/dist/map.js +227 -698
  162. package/dist/map.js.map +1 -1
  163. package/dist/react/Control.d.ts +11 -0
  164. package/dist/react/Control.js +18 -0
  165. package/dist/react/Control.js.map +1 -0
  166. package/dist/react/CustomLayer.d.ts +11 -0
  167. package/dist/react/CustomLayer.js +30 -0
  168. package/dist/react/CustomLayer.js.map +1 -0
  169. package/dist/react/IsardMap.d.ts +43 -0
  170. package/dist/react/IsardMap.js +147 -0
  171. package/dist/react/IsardMap.js.map +1 -0
  172. package/dist/react/Layer.d.ts +42 -0
  173. package/dist/react/Layer.js +74 -0
  174. package/dist/react/Layer.js.map +1 -0
  175. package/dist/react/Marker.d.ts +24 -0
  176. package/dist/react/Marker.js +53 -0
  177. package/dist/react/Marker.js.map +1 -0
  178. package/dist/react/Panel.d.ts +11 -0
  179. package/dist/react/Panel.js +37 -0
  180. package/dist/react/Panel.js.map +1 -0
  181. package/dist/react/Popup.d.ts +18 -0
  182. package/dist/react/Popup.js +60 -0
  183. package/dist/react/Popup.js.map +1 -0
  184. package/dist/react/Swipe.d.ts +16 -0
  185. package/dist/react/Swipe.js +52 -0
  186. package/dist/react/Swipe.js.map +1 -0
  187. package/dist/react/VectorGeometry.d.ts +35 -0
  188. package/dist/react/VectorGeometry.js +82 -0
  189. package/dist/react/VectorGeometry.js.map +1 -0
  190. package/dist/react/Viewshed.d.ts +5 -0
  191. package/dist/react/Viewshed.js +28 -0
  192. package/dist/react/Viewshed.js.map +1 -0
  193. package/dist/react/context.d.ts +33 -0
  194. package/dist/react/context.js +20 -0
  195. package/dist/react/context.js.map +1 -0
  196. package/dist/react/index.d.ts +16 -108
  197. package/dist/react/index.js +11 -397
  198. package/dist/react/index.js.map +1 -1
  199. package/dist/settings.d.ts +5 -9
  200. package/dist/settings.js +17 -15
  201. package/dist/settings.js.map +1 -1
  202. package/dist/types.d.ts +27 -4
  203. package/dist/types.js.map +1 -1
  204. package/dist/ui/controls.js +6 -4
  205. package/dist/ui/controls.js.map +1 -1
  206. package/dist/ui/interaction.d.ts +2 -2
  207. package/dist/ui/interaction.js +8 -7
  208. package/dist/ui/interaction.js.map +1 -1
  209. package/dist/ui/minimap.d.ts +25 -0
  210. package/dist/ui/minimap.js +90 -0
  211. package/dist/ui/minimap.js.map +1 -0
  212. package/dist/ui/overlay.js +18 -20
  213. package/dist/ui/overlay.js.map +1 -1
  214. package/dist/ui/scale.d.ts +19 -0
  215. package/dist/ui/scale.js +44 -0
  216. package/dist/ui/scale.js.map +1 -0
  217. package/dist/ui/search.d.ts +25 -0
  218. package/dist/ui/search.js +119 -0
  219. package/dist/ui/search.js.map +1 -0
  220. package/dist/ui/style.d.ts +1 -1
  221. package/dist/ui/style.js +19 -2
  222. package/dist/ui/style.js.map +1 -1
  223. package/dist/util/animation.d.ts +3 -3
  224. package/dist/util/animation.js +6 -6
  225. package/dist/util/animation.js.map +1 -1
  226. package/dist/util/color.d.ts +1 -1
  227. package/dist/util/color.js +14 -16
  228. package/dist/util/color.js.map +1 -1
  229. package/dist/util/geo.d.ts +6 -6
  230. package/dist/util/geo.js +12 -12
  231. package/dist/util/geo.js.map +1 -1
  232. package/dist/util/guards.d.ts +7 -0
  233. package/dist/util/guards.js +8 -0
  234. package/dist/util/guards.js.map +1 -0
  235. package/dist/util/lru.js.map +1 -1
  236. package/dist/util/sun.d.ts +11 -0
  237. package/dist/util/sun.js +26 -0
  238. package/dist/util/sun.js.map +1 -0
  239. package/dist/wasm/isard.d.ts +250 -7
  240. package/dist/wasm/isard.js +375 -8
  241. package/dist/wasm/isard_core.d.ts +226 -7
  242. package/dist/wasm/isard_core.js +351 -8
  243. package/dist/wasm/isard_tess.d.ts +109 -0
  244. package/dist/wasm/isard_tess.js +398 -0
  245. package/dist/workers/basemap/geometry.d.ts +72 -0
  246. package/dist/workers/basemap/labels.d.ts +8 -0
  247. package/dist/workers/basemap/raster.d.ts +10 -0
  248. package/dist/workers/basemap/tiles.d.ts +65 -0
  249. package/dist/workers/basemap/trees.d.ts +19 -0
  250. package/dist/workers/basemap.worker.d.ts +126 -22
  251. package/dist/workers/basemap.worker.js +76 -544
  252. package/dist/workers/basemap.worker.js.map +1 -1
  253. package/package.json +5 -4
  254. package/vite.js +10 -2
@@ -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 function context(feature, zoom) {
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 function color(value) {
23
+ export const color = (value) => {
17
24
  return parseCssColor(value);
18
- }
19
- export function css([r, g, b, a]) {
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
- function factor(x, x0, x1, base = 1) {
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
- function mix(a, b, t) {
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
- return css([0, 1, 2, 3].map((i) => (ca[i] ?? 0) + ((cb[i] ?? 0) - (ca[i] ?? 0)) * t));
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
- function isFunction(v) {
50
+ };
51
+ const isFunction = (v) => {
43
52
  return typeof v === 'object' && v !== null && !Array.isArray(v) && Array.isArray(v.stops);
44
- }
45
- function legacy(f, ctx) {
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 = (s) => typeof s[0] === 'object' && s[0] !== null ? Number(s[0].zoom) : Number(s[0]);
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
- for (let i = 1; i < stops.length; i += 1) {
63
- const [s0, s1] = [stops[i - 1], stops[i]];
64
- if (!s0 || !s1)
65
- continue;
66
- if (input < key(s1)) {
67
- if (type === 'interval')
68
- return s0[1];
69
- return mix(s0[1], s1[1], factor(input, key(s0), key(s1), f.base ?? 1));
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
- function get(ctx, key) {
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 function isExpression(e) {
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 function evaluate(e, ctx) {
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: options['min-fraction-digits'],
193
- maximumFractionDigits: options['max-fraction-digits'],
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) >= ev(1);
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
- for (let i = 0; i + 1 < args.length; i += 2)
281
- if (ev(i))
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
- for (let i = 1; i + 1 < args.length; i += 2) {
288
- const label = args[i];
289
- if (Array.isArray(label) ? label.includes(input) : label === input)
290
- return ev(i + 1);
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
- for (let i = 2; i + 1 < args.length; i += 2)
313
- stops.push([Number(args[i]), args[i + 1] ?? null]);
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
- for (let i = 1; i < stops.length; i += 1) {
320
- const [s0, s1] = [stops[i - 1], stops[i]];
321
- if (s0 && s1 && input < s1[0])
322
- return mix(evaluate(s0[1], ctx), evaluate(s1[1], ctx), factor(input, s0[0], s1[0], base));
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,26 @@ 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(['==', '!=', '<', '<=', '>', '>=']);
398
+ /** The kind of geometry a style layer is drawn with as vectors (`vectors()`: backgrounds as fills, extrusions raised
399
+ * into blocks); undefined for the others (symbols, circles, rasters) and for the layers drawn with a pattern (their
400
+ * images are the raster path's) */
401
+ export const vectorKind = (layer) => {
402
+ const paint = layer.paint ?? {};
403
+ if (['fill-pattern', 'line-pattern', 'fill-extrusion-pattern', 'background-pattern'].some((k) => k in paint)) {
404
+ return undefined;
405
+ }
406
+ if (layer.type === 'line')
407
+ return 'line';
408
+ if (layer.type === 'fill-extrusion')
409
+ return 'extrusion';
410
+ return layer.type === 'fill' || layer.type === 'background' ? 'fill' : undefined;
411
+ };
377
412
  /** Whether a filter (not `all`, `any`, `none`) is in the legacy form: `["==", "key", value]`, `["in", "key", a, b]`,
378
413
  * `["has", "key"]`; a key and literal values, as MapLibre tells them from expressions */
379
- function isLegacyLeaf(f) {
414
+ const isLegacyLeaf = (f) => {
380
415
  const [op, a, ...rest] = f;
381
416
  if (typeof op !== 'string' || typeof a !== 'string' || rest.some(Array.isArray))
382
417
  return false;
@@ -385,8 +420,8 @@ function isLegacyLeaf(f) {
385
420
  if (op === 'in')
386
421
  return f.length !== 3 || !Array.isArray(f[2]);
387
422
  return op === '!in' || op === 'has' || op === '!has';
388
- }
389
- function legacyFilter(f, ctx) {
423
+ };
424
+ const legacyFilter = (f, ctx) => {
390
425
  const [op, key, ...rest] = f;
391
426
  const v = get(ctx, key);
392
427
  switch (op) {
@@ -395,17 +430,14 @@ function legacyFilter(f, ctx) {
395
430
  case '!=':
396
431
  return v !== rest[0];
397
432
  case '<':
398
- return v < rest[0];
399
433
  case '<=':
400
- return v <= rest[0];
401
434
  case '>':
402
- return v > rest[0];
403
435
  case '>=':
404
- return v >= rest[0];
436
+ return compare(op, v, rest[0]);
405
437
  case 'in':
406
- return rest.includes(v);
438
+ return labels(rest).includes(v);
407
439
  case '!in':
408
- return !rest.includes(v);
440
+ return !labels(rest).includes(v);
409
441
  case 'has':
410
442
  return v !== undefined;
411
443
  case '!has':
@@ -413,53 +445,53 @@ function legacyFilter(f, ctx) {
413
445
  default:
414
446
  return true;
415
447
  }
416
- }
448
+ };
417
449
  /** Compiled filters, by filter object */
418
450
  const compiled = new WeakMap();
419
451
  /** A filter as a function: `all`, `any`, `none` of their parts, each part legacy or an expression (they may mix) */
420
- function compile(f) {
452
+ const compile = (f) => {
421
453
  if (!Array.isArray(f))
422
454
  return () => Boolean(f);
423
455
  const hit = compiled.get(f);
424
456
  if (hit)
425
457
  return hit;
426
- let test;
427
- const op = f[0];
428
- if (op === 'all' || op === 'any' || op === 'none') {
429
- const parts = f.slice(1).map(compile);
430
- if (op === 'all')
431
- test = (ctx) => parts.every((p) => p(ctx));
432
- else if (op === 'any')
433
- test = (ctx) => parts.some((p) => p(ctx));
434
- else
435
- test = (ctx) => !parts.some((p) => p(ctx));
436
- }
437
- else if (isLegacyLeaf(f)) {
438
- test = (ctx) => legacyFilter(f, ctx);
439
- }
440
- else {
441
- test = (ctx) => Boolean(evaluate(f, ctx));
442
- }
458
+ const make = () => {
459
+ const op = f[0];
460
+ if (op === 'all' || op === 'any' || op === 'none') {
461
+ const parts = f.slice(1).map(compile);
462
+ if (op === 'all')
463
+ return (ctx) => parts.every((p) => p(ctx));
464
+ if (op === 'any')
465
+ return (ctx) => parts.some((p) => p(ctx));
466
+ return (ctx) => !parts.some((p) => p(ctx));
467
+ }
468
+ if (isLegacyLeaf(f))
469
+ return (ctx) => legacyFilter(f, ctx);
470
+ return (ctx) => Boolean(evaluate(f, ctx));
471
+ };
472
+ const test = make();
443
473
  compiled.set(f, test);
444
474
  return test;
445
- }
446
- export function filter(f, ctx) {
475
+ };
476
+ export const filter = (f, ctx) => {
447
477
  if (f === undefined || f === null)
448
478
  return true;
449
479
  return compile(f)(ctx);
450
- }
480
+ };
481
+ /** The operators that read the feature */
482
+ const FEATURE_OPERATORS = new Set(['get', 'has', '!has', 'geometry-type', 'properties', 'id']);
451
483
  /** Whether a value depends on the feature (else only on the zoom, evaluated once per tile) */
452
- export function isFeatureDependent(e) {
484
+ export const isFeatureDependent = (e) => {
453
485
  if (e !== undefined && isFunction(e))
454
486
  return e.property !== undefined;
455
487
  if (!Array.isArray(e))
456
488
  return false;
457
- if (['get', 'has', '!has', 'geometry-type', 'properties', 'id'].includes(e[0]))
489
+ if (FEATURE_OPERATORS.has(e[0]))
458
490
  return true;
459
491
  return e.some((x) => isFeatureDependent(x));
460
- }
492
+ };
461
493
  /** A `{token}` text field (or an expression) to the text of a feature */
462
- export function text(field, ctx) {
494
+ export const text = (field, ctx) => {
463
495
  if (field === undefined || field === null)
464
496
  return '';
465
497
  if (typeof field === 'string') {
@@ -474,45 +506,66 @@ export function text(field, ctx) {
474
506
  return v.filter((x) => typeof x === 'string').join('');
475
507
  }
476
508
  return v === undefined || v === null ? '' : String(v);
477
- }
509
+ };
478
510
  /** The font of a label from the first of its `text-font`: a family without its weight takes the regular one */
479
- export function labelFont(font) {
511
+ export const labelFont = (font) => {
480
512
  return /Regular|Bold|Italic|Semibold|Light|Medium|Black/.test(font) ? font : `${font} Regular`;
481
- }
513
+ };
482
514
  /**
483
515
  * A value of the zoom only (an expression: `interpolate`, `step` of `["zoom"]`) as stops `[[zoom, value], …]` for the
484
516
  * engine, which interpolates them linearly: evaluated at its own stops and at the whole zooms between (an exponential
485
517
  * curve followed closely), a step kept sharp just before its threshold
486
518
  */
487
- export function zoomStops(e) {
519
+ export const zoomStops = (e) => {
488
520
  const zooms = new Set();
521
+ // The inputs of the stops of an `interpolate` or a `step` (from its fourth argument, one in two)
522
+ const stopInputs = (x) => x.filter((_, i) => i >= 3 && i % 2 === 1).map(Number);
489
523
  const walk = (x) => {
490
524
  if (!Array.isArray(x))
491
525
  return;
492
526
  const zoomInput = (input) => Array.isArray(input) && input[0] === 'zoom';
493
527
  if ((x[0] === 'interpolate' || x[0] === 'interpolate-hcl' || x[0] === 'interpolate-lab') && zoomInput(x[2])) {
494
- for (let i = 3; i < x.length; i += 2)
495
- zooms.add(Number(x[i]));
528
+ stopInputs(x).forEach((t) => {
529
+ zooms.add(t);
530
+ });
496
531
  }
497
532
  else if (x[0] === 'step' && zoomInput(x[1])) {
498
- for (let i = 3; i < x.length; i += 2) {
499
- const t = Number(x[i]);
533
+ stopInputs(x).forEach((t) => {
500
534
  zooms.add(t);
501
535
  zooms.add(t - 0.01);
502
- }
536
+ });
503
537
  }
504
- for (const y of x)
505
- walk(y);
538
+ x.forEach(walk);
506
539
  };
507
540
  walk(e);
508
541
  const finite = [...zooms].filter(Number.isFinite);
509
542
  if (finite.length === 0)
510
543
  finite.push(0);
511
544
  const [lo, hi] = [Math.min(...finite), Math.max(...finite)];
512
- for (let z = Math.ceil(lo); z <= Math.floor(hi); z += 1)
513
- finite.push(z);
545
+ finite.push(...Array.from({ length: Math.floor(hi) - Math.ceil(lo) + 1 }, (_, i) => Math.ceil(lo) + i));
514
546
  return [...new Set(finite)]
515
547
  .sort((a, b) => a - b)
516
548
  .map((zoom) => [zoom, Number(evaluate(e, { zoom, properties: {}, type: 'Unknown' }))]);
517
- }
549
+ };
550
+ /**
551
+ * A paint value as zoom stops when it depends on the zoom only (an expression as `zoomStops` samples it, a legacy zoom
552
+ * function at its stops and the whole zooms between), a number as it is, `fallback` when missing; undefined when it
553
+ * depends on the features
554
+ */
555
+ export const zoomOnly = (v, fallback) => {
556
+ if (v === undefined || v === null)
557
+ return fallback;
558
+ if (isFeatureDependent(v))
559
+ return undefined;
560
+ if (isExpression(v))
561
+ return zoomStops(v);
562
+ if (!isFunction(v))
563
+ return Number(v);
564
+ const zooms = v.stops.map(([z]) => Number(z)).filter(Number.isFinite);
565
+ const [lo, hi] = [Math.min(...zooms), Math.max(...zooms)];
566
+ const whole = Array.from({ length: Math.max(0, Math.floor(hi) - Math.ceil(lo) + 1) }, (_, i) => Math.ceil(lo) + i);
567
+ return [...new Set([...zooms, ...whole])]
568
+ .sort((a, b) => a - b)
569
+ .map((zoom) => [zoom, Number(evaluate(v, { zoom, properties: {}, type: 'Unknown' }))]);
570
+ };
518
571
  //# sourceMappingURL=vectorstyle.js.map