isard 0.2.1 → 0.4.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 (93) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/README.md +8 -4
  3. package/dist/animation.d.ts +18 -0
  4. package/dist/animation.js +84 -0
  5. package/dist/animation.js.map +1 -0
  6. package/dist/basemap.worker.d.ts +26 -4
  7. package/dist/basemap.worker.js +2 -2
  8. package/dist/basemap.worker.js.map +9 -5
  9. package/dist/crs.d.ts +72 -0
  10. package/dist/crs.js +243 -0
  11. package/dist/crs.js.map +1 -0
  12. package/dist/decoder.worker.js +4 -4
  13. package/dist/decoder.worker.js.map +4 -4
  14. package/dist/engine-loader.d.ts +28 -0
  15. package/dist/engine-loader.js +112 -0
  16. package/dist/engine-loader.js.map +1 -0
  17. package/dist/features.d.ts +8 -0
  18. package/dist/features.js +17 -10
  19. package/dist/features.js.map +1 -1
  20. package/dist/geo.d.ts +16 -0
  21. package/dist/geo.js +32 -0
  22. package/dist/geo.js.map +1 -0
  23. package/dist/geoplateforme.d.ts +21 -5
  24. package/dist/geoplateforme.js +47 -12
  25. package/dist/geoplateforme.js.map +1 -1
  26. package/dist/glyphs.d.ts +13 -3
  27. package/dist/glyphs.js +26 -4
  28. package/dist/glyphs.js.map +1 -1
  29. package/dist/gpx.d.ts +11 -0
  30. package/dist/gpx.js +74 -0
  31. package/dist/gpx.js.map +1 -0
  32. package/dist/grid.d.ts +81 -0
  33. package/dist/grid.js +270 -0
  34. package/dist/grid.js.map +1 -0
  35. package/dist/icons.d.ts +146 -0
  36. package/dist/icons.js +333 -0
  37. package/dist/icons.js.map +1 -0
  38. package/dist/index.d.ts +11 -4
  39. package/dist/index.js +6 -1
  40. package/dist/index.js.map +1 -1
  41. package/dist/interaction.d.ts +0 -4
  42. package/dist/interaction.js +8 -4
  43. package/dist/interaction.js.map +1 -1
  44. package/dist/isard_bg.wasm +0 -0
  45. package/dist/isard_core_bg.wasm +0 -0
  46. package/dist/kml.d.ts +12 -0
  47. package/dist/kml.js +159 -0
  48. package/dist/kml.js.map +1 -0
  49. package/dist/layers.d.ts +89 -2
  50. package/dist/layers.js +171 -15
  51. package/dist/layers.js.map +1 -1
  52. package/dist/lru.d.ts +22 -0
  53. package/dist/lru.js +52 -0
  54. package/dist/lru.js.map +1 -0
  55. package/dist/map.d.ts +45 -7
  56. package/dist/map.js +138 -310
  57. package/dist/map.js.map +1 -1
  58. package/dist/resample.d.ts +41 -0
  59. package/dist/resample.js +164 -0
  60. package/dist/resample.js.map +1 -0
  61. package/dist/settings.d.ts +39 -0
  62. package/dist/settings.js +104 -0
  63. package/dist/settings.js.map +1 -0
  64. package/dist/symbols.d.ts +54 -9
  65. package/dist/symbols.js +278 -55
  66. package/dist/symbols.js.map +1 -1
  67. package/dist/terrain.d.ts +19 -7
  68. package/dist/terrain.js +40 -28
  69. package/dist/terrain.js.map +1 -1
  70. package/dist/topojson.d.ts +29 -0
  71. package/dist/topojson.js +66 -0
  72. package/dist/topojson.js.map +1 -0
  73. package/dist/types.d.ts +14 -6
  74. package/dist/types.js.map +1 -1
  75. package/dist/vectorstyle.d.ts +32 -3
  76. package/dist/vectorstyle.js.map +1 -1
  77. package/dist/vectortiles.d.ts +19 -7
  78. package/dist/vectortiles.js +117 -69
  79. package/dist/vectortiles.js.map +1 -1
  80. package/dist/wasm/isard.d.ts +55 -7
  81. package/dist/wasm/isard.js +117 -6
  82. package/dist/wasm/isard_core.d.ts +29 -4
  83. package/dist/wasm/isard_core.js +84 -5
  84. package/dist/wmts.d.ts +14 -0
  85. package/dist/wmts.js +76 -0
  86. package/dist/wmts.js.map +1 -0
  87. package/dist/xml.d.ts +26 -0
  88. package/dist/xml.js +109 -0
  89. package/dist/xml.js.map +1 -0
  90. package/package.json +1 -1
  91. package/dist/equirectangular.d.ts +0 -35
  92. package/dist/equirectangular.js +0 -143
  93. package/dist/equirectangular.js.map +0 -1
package/dist/grid.d.ts ADDED
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Rasters in another tile grid, the planning half: a WMTS-like tile matrix set in any CRS (Lambert-93, UTM, longitudes
3
+ * and latitudes…), or a WMS asked for a box in that CRS, reprojected into the Web Mercator tiles the engine draws. For
4
+ * each Mercator tile the page projects a mesh of 17 × 17 points of the tile into the source CRS (the only projection
5
+ * work: 289 points a tile, whatever its size), picks the source level of the same pixel size, and lists the source
6
+ * images the tile spans; the drawing (`resample.ts`) is done by a worker of the map, or in the page without workers.
7
+ */
8
+ import { type Crs, type CrsLike } from './crs.ts';
9
+ import { type Job } from './resample.ts';
10
+ /** One level of a tile grid, as a `TileMatrix` of WMTS */
11
+ export interface TileMatrix {
12
+ /** What replaces {z} in the URL (the `TILEMATRIX` of a WMTS; default the index of the matrix in the grid) */
13
+ id?: string | number;
14
+ /** Size of a pixel, CRS units (WMTS: its `ScaleDenominator` × 0.00028 m, in CRS units) */
15
+ resolution: number;
16
+ /** Top-left corner of the tile (0, 0), CRS units (x east, y north) */
17
+ origin: [x: number, y: number];
18
+ /** Size of a tile, pixels (default 256) */
19
+ tileWidth?: number;
20
+ tileHeight?: number;
21
+ /** Tiles across and down (default unbounded) */
22
+ matrixWidth?: number;
23
+ matrixHeight?: number;
24
+ /** The tiles the source has (a WMTS's `TileMatrixLimits`), inclusive: none is asked for outside */
25
+ limits?: [minCol: number, minRow: number, maxCol: number, maxRow: number];
26
+ }
27
+ /**
28
+ * A raster's tile grid in a CRS of its own, reprojected into Web Mercator by the map: `matrices` for tiles ({z}, {x},
29
+ * {y} in the URL: matrix, column, row, rows from the north), none for a WMS whose URL has `{bbox}` (the box of each
30
+ * Mercator tile in that CRS: minimum x, minimum y, maximum x, maximum y, asked for at the tile's size)
31
+ */
32
+ export interface TileGrid {
33
+ /** `'EPSG:2154'`, another built-in or registered name, or an object with `forward` and `inverse` (proj4's) */
34
+ crs: CrsLike;
35
+ /** The levels of the grid, in any order */
36
+ matrices?: TileMatrix[];
37
+ /** Longitudes and latitudes the source covers (west, south, east, north): nothing is asked for outside */
38
+ bounds?: [west: number, south: number, east: number, north: number];
39
+ /** Identifier of the tile matrix set (a WMTS's `TILEMATRIXSET`), for the helpers that write the URL */
40
+ name?: string;
41
+ }
42
+ interface Matrix extends Required<Omit<TileMatrix, 'limits' | 'id'>> {
43
+ id: string | number;
44
+ limits: [number, number, number, number] | undefined;
45
+ }
46
+ interface Resolved {
47
+ crs: Crs;
48
+ /** Coarsest first */
49
+ matrices: Matrix[];
50
+ bounds: [number, number, number, number] | undefined;
51
+ /** The bounds in the CRS: minimum x, minimum y, maximum x, maximum y */
52
+ extent: [number, number, number, number] | undefined;
53
+ }
54
+ /** A tile grid ready to plan tiles: its CRS found, its matrices completed, its bounds projected */
55
+ export declare function resolveGrid(grid: TileGrid): Resolved;
56
+ /** The longitudes and latitudes of tiles in longitudes and latitudes, two 256 px tiles side by side at level 0, rows
57
+ * from the north (NASA's Trek, WorldCRS84Quad), levels `minLevel` to `maxLevel` ({z} is the level) */
58
+ export declare function equirectangularGrid(minLevel: number, maxLevel: number): TileGrid;
59
+ /**
60
+ * The plan of Mercator tile `z`/`x`/`y` (`size` pixels a side) from a source of URL template `url` in grid `g`; null
61
+ * where the source has nothing
62
+ */
63
+ export declare function planTile(g: Resolved, url: string, z: number, x: number, y: number, size: number): Job | null;
64
+ /**
65
+ * The map zooms a grid's matrices span (the pixel size of the finest and of the coarsest, two levels coarser, where
66
+ * the tiles still fit a mosaic), measured at the middle of its bounds, or of its coarsest matrix
67
+ */
68
+ export declare function gridZooms(g: Resolved): {
69
+ minZoom: number;
70
+ maxZoom: number;
71
+ };
72
+ /** Draws a Mercator tile `z`/`x`/`y`: its image, null where the source has nothing; rejects on errors */
73
+ type Draw = (z: number, x: number, y: number, signal: AbortSignal) => Promise<ImageBitmap | null>;
74
+ /** A planned tile drawn in a worker; undefined when the map has no workers (drawn in the page) */
75
+ export type RemoteReprojection = (job: Job, tile: [z: number, x: number, y: number], signal: AbortSignal) => Promise<ImageBitmap | null> | undefined;
76
+ /**
77
+ * A raster loader drawing Web Mercator tiles of `size` pixels from a source of URL template `url` in tile grid `grid`:
78
+ * planned here, drawn in a worker of the map through `remote` when it can, else in the page
79
+ */
80
+ export declare function gridLoader(url: string, grid: Resolved, size: number, remote?: RemoteReprojection): Draw;
81
+ export {};
package/dist/grid.js ADDED
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Rasters in another tile grid, the planning half: a WMTS-like tile matrix set in any CRS (Lambert-93, UTM, longitudes
3
+ * and latitudes…), or a WMS asked for a box in that CRS, reprojected into the Web Mercator tiles the engine draws. For
4
+ * each Mercator tile the page projects a mesh of 17 × 17 points of the tile into the source CRS (the only projection
5
+ * work: 289 points a tile, whatever its size), picks the source level of the same pixel size, and lists the source
6
+ * images the tile spans; the drawing (`resample.ts`) is done by a worker of the map, or in the page without workers.
7
+ */
8
+ import { getCrs } from "./crs.js";
9
+ import { latitude, longitude, mercatorX, mercatorY } from "./geo.js";
10
+ import { resampler } from "./resample.js";
11
+ /** Cells of the mesh along each side of a tile */
12
+ const N = 16;
13
+ /** Source levels finer at most than the pixel size across, where the grid stretches one axis (towards the poles in
14
+ * longitudes and latitudes) */
15
+ const MAX_BOOST = 3;
16
+ /** Pixels of a mosaic at most: coarser levels beyond, nothing if even the coarsest is larger */
17
+ const MAX_MOSAIC = 2048 * 2048;
18
+ /** A box of the CRS around points of it (x, y, x, y…), NaN ignored; undefined without any */
19
+ function box(points) {
20
+ let [x0, y0, x1, y1] = [Infinity, Infinity, -Infinity, -Infinity];
21
+ for (let k = 0; k + 1 < points.length; k += 2) {
22
+ const [x, y] = [points[k], points[k + 1]];
23
+ if (!Number.isFinite(x) || !Number.isFinite(y))
24
+ continue;
25
+ x0 = Math.min(x0, x);
26
+ y0 = Math.min(y0, y);
27
+ x1 = Math.max(x1, x);
28
+ y1 = Math.max(y1, y);
29
+ }
30
+ return x0 <= x1 ? [x0, y0, x1, y1] : undefined;
31
+ }
32
+ /** A tile grid ready to plan tiles: its CRS found, its matrices completed, its bounds projected */
33
+ export function resolveGrid(grid) {
34
+ const crs = getCrs(grid.crs);
35
+ const matrices = (grid.matrices ?? [])
36
+ .map((m, i) => ({
37
+ id: m.id ?? i,
38
+ resolution: m.resolution,
39
+ origin: m.origin,
40
+ tileWidth: m.tileWidth ?? 256,
41
+ tileHeight: m.tileHeight ?? 256,
42
+ matrixWidth: m.matrixWidth ?? Infinity,
43
+ matrixHeight: m.matrixHeight ?? Infinity,
44
+ limits: m.limits,
45
+ }))
46
+ .sort((a, b) => b.resolution - a.resolution);
47
+ let extent;
48
+ if (grid.bounds) {
49
+ // Its outline and inside, projected: the box of the CRS around them, a little larger (curved edges)
50
+ const [w, s, e, n] = grid.bounds;
51
+ const points = [];
52
+ for (let i = 0; i <= 8; i += 1) {
53
+ for (let j = 0; j <= 8; j += 1)
54
+ points.push(...crs.forward([w + ((e - w) * i) / 8, s + ((n - s) * j) / 8]));
55
+ }
56
+ const b = box(points);
57
+ if (b) {
58
+ const margin = 0.01 * Math.max(b[2] - b[0], b[3] - b[1]);
59
+ extent = [b[0] - margin, b[1] - margin, b[2] + margin, b[3] + margin];
60
+ }
61
+ }
62
+ return { crs, matrices, bounds: grid.bounds, extent };
63
+ }
64
+ /** The longitudes and latitudes of tiles in longitudes and latitudes, two 256 px tiles side by side at level 0, rows
65
+ * from the north (NASA's Trek, WorldCRS84Quad), levels `minLevel` to `maxLevel` ({z} is the level) */
66
+ export function equirectangularGrid(minLevel, maxLevel) {
67
+ const matrices = [];
68
+ for (let level = minLevel; level <= maxLevel; level += 1) {
69
+ const n = 2 ** level;
70
+ matrices.push({ id: level, resolution: 180 / 256 / n, origin: [-180, 90], matrixWidth: 2 * n, matrixHeight: n });
71
+ }
72
+ return { crs: 'EPSG:4326', matrices };
73
+ }
74
+ /** A URL of the source: {z}, {x}, {y}, {bbox}, {width} and {height} replaced */
75
+ function sourceUrl(template, z, x, y, bbox, w, h) {
76
+ return template
77
+ .replaceAll('{z}', String(z))
78
+ .replaceAll('{x}', String(x))
79
+ .replaceAll('{y}', String(y))
80
+ .replaceAll('{bbox}', bbox.join(','))
81
+ .replaceAll('{width}', String(w))
82
+ .replaceAll('{height}', String(h));
83
+ }
84
+ /** CRS units per pixel along the mesh's x and y around its middle (NaN where the CRS has nothing there) */
85
+ function pixelSize(points, size) {
86
+ const c = N / 2;
87
+ const at = (i, j) => 2 * (j * (N + 1) + i);
88
+ const d = (p, q) => Math.hypot(points[q] - points[p], points[q + 1] - points[p + 1]);
89
+ const step = (2 * size) / N;
90
+ return [d(at(c - 1, c), at(c + 1, c)) / step, d(at(c, c - 1), at(c, c + 1)) / step];
91
+ }
92
+ /**
93
+ * The box (CRS) of the points a tile samples: the centers of its edge pixels, interpolated in the mesh as `resample`
94
+ * does, and the inner points of the mesh (should the projection bend); within `clip`. Undefined if none is
95
+ */
96
+ function sampled(points, size, clip) {
97
+ const at = (i, j, k) => points[2 * (j * (N + 1) + i) + k];
98
+ const centers = [];
99
+ for (let j = 1; j < N; j += 1)
100
+ for (let i = 1; i < N; i += 1)
101
+ centers.push(at(i, j, 0), at(i, j, 1));
102
+ const cell = size / N;
103
+ const add = (px, py) => {
104
+ const [fx, fy] = [px / cell, py / cell];
105
+ const [i, j] = [Math.min(N - 1, Math.floor(fx)), Math.min(N - 1, Math.floor(fy))];
106
+ const [tx, ty] = [fx - i, fy - j];
107
+ for (const k of [0, 1]) {
108
+ const top = at(i, j, k) + (at(i + 1, j, k) - at(i, j, k)) * tx;
109
+ const bottom = at(i, j + 1, k) + (at(i + 1, j + 1, k) - at(i, j + 1, k)) * tx;
110
+ centers.push(top + (bottom - top) * ty);
111
+ }
112
+ };
113
+ for (let p = 0.5; p < size; p += 1) {
114
+ add(p, 0.5);
115
+ add(p, size - 0.5);
116
+ add(0.5, p);
117
+ add(size - 0.5, p);
118
+ }
119
+ const b = box(centers);
120
+ if (!b)
121
+ return undefined;
122
+ const out = [
123
+ Math.max(b[0], clip[0]),
124
+ Math.max(b[1], clip[1]),
125
+ Math.min(b[2], clip[2]),
126
+ Math.min(b[3], clip[3]),
127
+ ];
128
+ return out[0] <= out[2] && out[1] <= out[3] ? out : undefined;
129
+ }
130
+ /**
131
+ * The plan of Mercator tile `z`/`x`/`y` (`size` pixels a side) from a source of URL template `url` in grid `g`; null
132
+ * where the source has nothing
133
+ */
134
+ export function planTile(g, url, z, x, y, size) {
135
+ const tiles = 2 ** z;
136
+ if (g.bounds) {
137
+ const [w, s, e, n] = g.bounds;
138
+ if (longitude((x + 1) / tiles) <= w || longitude(x / tiles) >= e)
139
+ return null;
140
+ if (latitude(y / tiles) <= s || latitude((y + 1) / tiles) >= n)
141
+ return null;
142
+ }
143
+ // The mesh in the source CRS
144
+ const points = new Float64Array(2 * (N + 1) ** 2);
145
+ for (let j = 0; j <= N; j += 1) {
146
+ const lat = latitude((y + j / N) / tiles);
147
+ for (let i = 0; i <= N; i += 1) {
148
+ const [px = Number.NaN, py = Number.NaN] = g.crs.forward([longitude((x + i / N) / tiles), lat]);
149
+ points[2 * (j * (N + 1) + i)] = px;
150
+ points[2 * (j * (N + 1) + i) + 1] = py;
151
+ }
152
+ }
153
+ let b = box(points);
154
+ if (!b)
155
+ return null;
156
+ if (g.extent) {
157
+ const e = g.extent;
158
+ b = [Math.max(b[0], e[0]), Math.max(b[1], e[1]), Math.min(b[2], e[2]), Math.min(b[3], e[3])];
159
+ if (b[0] >= b[2] || b[1] >= b[3])
160
+ return null;
161
+ }
162
+ const mesh = new Float32Array(points.length);
163
+ if (g.matrices.length === 0) {
164
+ // One image of the tile's box, a pixel larger on each side
165
+ const [sx, sy] = pixelSize(points, size);
166
+ const m = Number.isFinite(sx + sy) ? Math.max(sx, sy) : 0;
167
+ const [x0, y0, x1, y1] = [b[0] - m, b[1] - m, b[2] + m, b[3] + m];
168
+ for (let k = 0; k < points.length; k += 2) {
169
+ mesh[k] = ((points[k] - x0) / (x1 - x0)) * size;
170
+ mesh[k + 1] = ((y1 - points[k + 1]) / (y1 - y0)) * size;
171
+ }
172
+ const source = { url: sourceUrl(url, z, x, y, [x0, y0, x1, y1], size, size), x: 0, y: 0, w: size, h: size };
173
+ return { size, width: size, height: size, sources: [source], n: N, mesh };
174
+ }
175
+ // The level of the same pixel size, along the axis the grid stretches least (up to MAX_BOOST levels finer)
176
+ const [sx, sy] = pixelSize(points, size);
177
+ const across = Math.max(sx, sy);
178
+ const target = Number.isFinite(across) ? Math.max(Math.min(sx, sy), across / 2 ** MAX_BOOST) : (b[2] - b[0]) / size;
179
+ // Where the pixels of the tile are sampled: the centers of its edge pixels and the mesh, within the source's extent
180
+ const centers = sampled(points, size, b);
181
+ if (!centers)
182
+ return null;
183
+ let best = 0;
184
+ g.matrices.forEach((m, i) => {
185
+ const r = g.matrices[best]?.resolution ?? m.resolution;
186
+ if (Math.abs(Math.log2(m.resolution / target)) < Math.abs(Math.log2(r / target)))
187
+ best = i;
188
+ });
189
+ for (let level = best; level >= 0; level -= 1) {
190
+ const m = g.matrices[level];
191
+ const [ox, oy] = m.origin;
192
+ const [tw, th, res] = [m.tileWidth, m.tileHeight, m.resolution];
193
+ const [l0, r0, l1, r1] = m.limits ?? [0, 0, Infinity, Infinity];
194
+ // The tiles of the source pixels sampled (those of a weight over a thousandth: a tile edge on a source tile edge
195
+ // does not fetch the next source tile for nothing)
196
+ const c0 = Math.max(0, l0, Math.floor(((centers[0] - ox) / res - 0.5 + 1e-3) / tw));
197
+ const c1 = Math.min(m.matrixWidth - 1, l1, Math.floor(((centers[2] - ox) / res + 0.5 - 1e-3) / tw));
198
+ const t0 = Math.max(0, r0, Math.floor(((oy - centers[3]) / res - 0.5 + 1e-3) / th));
199
+ const t1 = Math.min(m.matrixHeight - 1, r1, Math.floor(((oy - centers[1]) / res + 0.5 - 1e-3) / th));
200
+ if (c0 > c1 || t0 > t1)
201
+ return null;
202
+ const [width, height] = [(c1 - c0 + 1) * tw, (t1 - t0 + 1) * th];
203
+ if (width * height > MAX_MOSAIC)
204
+ continue;
205
+ const sources = [];
206
+ for (let row = t0; row <= t1; row += 1) {
207
+ for (let col = c0; col <= c1; col += 1) {
208
+ const bbox = [ox + col * tw * res, oy - (row + 1) * th * res, ox + (col + 1) * tw * res, oy - row * th * res];
209
+ const placed = { x: (col - c0) * tw, y: (row - t0) * th, w: tw, h: th };
210
+ sources.push({ url: sourceUrl(url, m.id, col, row, bbox, tw, th), ...placed });
211
+ }
212
+ }
213
+ for (let k = 0; k < points.length; k += 2) {
214
+ mesh[k] = (points[k] - ox) / res - c0 * tw;
215
+ mesh[k + 1] = (oy - points[k + 1]) / res - t0 * th;
216
+ }
217
+ return { size, width, height, sources, n: N, mesh };
218
+ }
219
+ return null;
220
+ }
221
+ /**
222
+ * The map zooms a grid's matrices span (the pixel size of the finest and of the coarsest, two levels coarser, where
223
+ * the tiles still fit a mosaic), measured at the middle of its bounds, or of its coarsest matrix
224
+ */
225
+ export function gridZooms(g) {
226
+ const coarse = g.matrices[0];
227
+ const fine = g.matrices.at(-1);
228
+ if (!coarse || !fine)
229
+ return { minZoom: 0, maxZoom: 19 };
230
+ let lonLat = [0, 0];
231
+ if (g.bounds)
232
+ lonLat = [(g.bounds[0] + g.bounds[2]) / 2, (g.bounds[1] + g.bounds[3]) / 2];
233
+ else {
234
+ const [l0, r0, l1, r1] = coarse.limits ?? [0, 0, coarse.matrixWidth - 1, coarse.matrixHeight - 1];
235
+ const span = coarse.resolution * coarse.tileWidth;
236
+ const [cx, cy] = [(l0 + l1 + 1) / 2, (r0 + r1 + 1) / 2];
237
+ if (Number.isFinite(cx + cy))
238
+ lonLat = g.crs.inverse([coarse.origin[0] + cx * span, coarse.origin[1] - cy * span]);
239
+ }
240
+ // CRS units per pixel of a 256 px tile at zoom 0 there
241
+ const [mx, my] = [mercatorX(lonLat[0] ?? 0), mercatorY(lonLat[1] ?? 0)];
242
+ const d = 1e-7;
243
+ const p = g.crs.forward([longitude(mx), latitude(my)]);
244
+ const q = g.crs.forward([longitude(mx + d), latitude(my)]);
245
+ const zero = Math.hypot((q[0] ?? 0) - (p[0] ?? 0), (q[1] ?? 0) - (p[1] ?? 0)) / (d * 256);
246
+ if (!(zero > 0))
247
+ return { minZoom: 0, maxZoom: 19 };
248
+ return {
249
+ minZoom: Math.max(0, Math.floor(Math.log2(zero / coarse.resolution)) - 2),
250
+ maxZoom: Math.max(0, Math.round(Math.log2(zero / fine.resolution))),
251
+ };
252
+ }
253
+ /**
254
+ * A raster loader drawing Web Mercator tiles of `size` pixels from a source of URL template `url` in tile grid `grid`:
255
+ * planned here, drawn in a worker of the map through `remote` when it can, else in the page
256
+ */
257
+ export function gridLoader(url, grid, size, remote) {
258
+ let local;
259
+ return async (z, x, y, signal) => {
260
+ const job = planTile(grid, url, z, x, y, size);
261
+ if (!job)
262
+ return null;
263
+ const drawn = remote?.(job, [z, x, y], signal);
264
+ if (drawn)
265
+ return drawn;
266
+ local ??= resampler().draw;
267
+ return local(job, signal);
268
+ };
269
+ }
270
+ //# sourceMappingURL=grid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid.js","sourceRoot":"","sources":["../src/grid.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Rasters in another tile grid, the planning half: a WMTS-like tile matrix set in any CRS (Lambert-93, UTM, longitudes\n * and latitudes…), or a WMS asked for a box in that CRS, reprojected into the Web Mercator tiles the engine draws. For\n * each Mercator tile the page projects a mesh of 17 × 17 points of the tile into the source CRS (the only projection\n * work: 289 points a tile, whatever its size), picks the source level of the same pixel size, and lists the source\n * images the tile spans; the drawing (`resample.ts`) is done by a worker of the map, or in the page without workers.\n */\nimport { type Crs, type CrsLike, getCrs } from './crs.ts';\nimport { latitude, longitude, mercatorX, mercatorY } from './geo.ts';\nimport { type Job, type Placed, resampler } from './resample.ts';\n\n/** One level of a tile grid, as a `TileMatrix` of WMTS */\nexport interface TileMatrix {\n /** What replaces {z} in the URL (the `TILEMATRIX` of a WMTS; default the index of the matrix in the grid) */\n id?: string | number;\n /** Size of a pixel, CRS units (WMTS: its `ScaleDenominator` × 0.00028 m, in CRS units) */\n resolution: number;\n /** Top-left corner of the tile (0, 0), CRS units (x east, y north) */\n origin: [x: number, y: number];\n /** Size of a tile, pixels (default 256) */\n tileWidth?: number;\n tileHeight?: number;\n /** Tiles across and down (default unbounded) */\n matrixWidth?: number;\n matrixHeight?: number;\n /** The tiles the source has (a WMTS's `TileMatrixLimits`), inclusive: none is asked for outside */\n limits?: [minCol: number, minRow: number, maxCol: number, maxRow: number];\n}\n\n/**\n * A raster's tile grid in a CRS of its own, reprojected into Web Mercator by the map: `matrices` for tiles ({z}, {x},\n * {y} in the URL: matrix, column, row, rows from the north), none for a WMS whose URL has `{bbox}` (the box of each\n * Mercator tile in that CRS: minimum x, minimum y, maximum x, maximum y, asked for at the tile's size)\n */\nexport interface TileGrid {\n /** `'EPSG:2154'`, another built-in or registered name, or an object with `forward` and `inverse` (proj4's) */\n crs: CrsLike;\n /** The levels of the grid, in any order */\n matrices?: TileMatrix[];\n /** Longitudes and latitudes the source covers (west, south, east, north): nothing is asked for outside */\n bounds?: [west: number, south: number, east: number, north: number];\n /** Identifier of the tile matrix set (a WMTS's `TILEMATRIXSET`), for the helpers that write the URL */\n name?: string;\n}\n\n/** Cells of the mesh along each side of a tile */\nconst N = 16;\n/** Source levels finer at most than the pixel size across, where the grid stretches one axis (towards the poles in\n * longitudes and latitudes) */\nconst MAX_BOOST = 3;\n/** Pixels of a mosaic at most: coarser levels beyond, nothing if even the coarsest is larger */\nconst MAX_MOSAIC = 2048 * 2048;\n\ninterface Matrix extends Required<Omit<TileMatrix, 'limits' | 'id'>> {\n id: string | number;\n limits: [number, number, number, number] | undefined;\n}\n\ninterface Resolved {\n crs: Crs;\n /** Coarsest first */\n matrices: Matrix[];\n bounds: [number, number, number, number] | undefined;\n /** The bounds in the CRS: minimum x, minimum y, maximum x, maximum y */\n extent: [number, number, number, number] | undefined;\n}\n\n/** A box of the CRS around points of it (x, y, x, y…), NaN ignored; undefined without any */\nfunction box(points: ArrayLike<number>): [number, number, number, number] | undefined {\n let [x0, y0, x1, y1] = [Infinity, Infinity, -Infinity, -Infinity];\n for (let k = 0; k + 1 < points.length; k += 2) {\n const [x, y] = [points[k] as number, points[k + 1] as number];\n if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n x0 = Math.min(x0, x);\n y0 = Math.min(y0, y);\n x1 = Math.max(x1, x);\n y1 = Math.max(y1, y);\n }\n return x0 <= x1 ? [x0, y0, x1, y1] : undefined;\n}\n\n/** A tile grid ready to plan tiles: its CRS found, its matrices completed, its bounds projected */\nexport function resolveGrid(grid: TileGrid): Resolved {\n const crs = getCrs(grid.crs);\n const matrices = (grid.matrices ?? [])\n .map(\n (m, i): Matrix => ({\n id: m.id ?? i,\n resolution: m.resolution,\n origin: m.origin,\n tileWidth: m.tileWidth ?? 256,\n tileHeight: m.tileHeight ?? 256,\n matrixWidth: m.matrixWidth ?? Infinity,\n matrixHeight: m.matrixHeight ?? Infinity,\n limits: m.limits,\n }),\n )\n .sort((a, b) => b.resolution - a.resolution);\n let extent: Resolved['extent'];\n if (grid.bounds) {\n // Its outline and inside, projected: the box of the CRS around them, a little larger (curved edges)\n const [w, s, e, n] = grid.bounds;\n const points: number[] = [];\n for (let i = 0; i <= 8; i += 1) {\n for (let j = 0; j <= 8; j += 1) points.push(...crs.forward([w + ((e - w) * i) / 8, s + ((n - s) * j) / 8]));\n }\n const b = box(points);\n if (b) {\n const margin = 0.01 * Math.max(b[2] - b[0], b[3] - b[1]);\n extent = [b[0] - margin, b[1] - margin, b[2] + margin, b[3] + margin];\n }\n }\n return { crs, matrices, bounds: grid.bounds, extent };\n}\n\n/** The longitudes and latitudes of tiles in longitudes and latitudes, two 256 px tiles side by side at level 0, rows\n * from the north (NASA's Trek, WorldCRS84Quad), levels `minLevel` to `maxLevel` ({z} is the level) */\nexport function equirectangularGrid(minLevel: number, maxLevel: number): TileGrid {\n const matrices: TileMatrix[] = [];\n for (let level = minLevel; level <= maxLevel; level += 1) {\n const n = 2 ** level;\n matrices.push({ id: level, resolution: 180 / 256 / n, origin: [-180, 90], matrixWidth: 2 * n, matrixHeight: n });\n }\n return { crs: 'EPSG:4326', matrices };\n}\n\n/** A URL of the source: {z}, {x}, {y}, {bbox}, {width} and {height} replaced */\nfunction sourceUrl(template: string, z: string | number, x: number, y: number, bbox: number[], w: number, h: number) {\n return template\n .replaceAll('{z}', String(z))\n .replaceAll('{x}', String(x))\n .replaceAll('{y}', String(y))\n .replaceAll('{bbox}', bbox.join(','))\n .replaceAll('{width}', String(w))\n .replaceAll('{height}', String(h));\n}\n\n/** CRS units per pixel along the mesh's x and y around its middle (NaN where the CRS has nothing there) */\nfunction pixelSize(points: Float64Array, size: number): [number, number] {\n const c = N / 2;\n const at = (i: number, j: number) => 2 * (j * (N + 1) + i);\n const d = (p: number, q: number) =>\n Math.hypot((points[q] as number) - (points[p] as number), (points[q + 1] as number) - (points[p + 1] as number));\n const step = (2 * size) / N;\n return [d(at(c - 1, c), at(c + 1, c)) / step, d(at(c, c - 1), at(c, c + 1)) / step];\n}\n\n/**\n * The box (CRS) of the points a tile samples: the centers of its edge pixels, interpolated in the mesh as `resample`\n * does, and the inner points of the mesh (should the projection bend); within `clip`. Undefined if none is\n */\nfunction sampled(points: Float64Array, size: number, clip: number[]): [number, number, number, number] | undefined {\n const at = (i: number, j: number, k: number) => points[2 * (j * (N + 1) + i) + k] as number;\n const centers: number[] = [];\n for (let j = 1; j < N; j += 1) for (let i = 1; i < N; i += 1) centers.push(at(i, j, 0), at(i, j, 1));\n const cell = size / N;\n const add = (px: number, py: number) => {\n const [fx, fy] = [px / cell, py / cell];\n const [i, j] = [Math.min(N - 1, Math.floor(fx)), Math.min(N - 1, Math.floor(fy))];\n const [tx, ty] = [fx - i, fy - j];\n for (const k of [0, 1]) {\n const top = at(i, j, k) + (at(i + 1, j, k) - at(i, j, k)) * tx;\n const bottom = at(i, j + 1, k) + (at(i + 1, j + 1, k) - at(i, j + 1, k)) * tx;\n centers.push(top + (bottom - top) * ty);\n }\n };\n for (let p = 0.5; p < size; p += 1) {\n add(p, 0.5);\n add(p, size - 0.5);\n add(0.5, p);\n add(size - 0.5, p);\n }\n const b = box(centers);\n if (!b) return undefined;\n const out: [number, number, number, number] = [\n Math.max(b[0], clip[0] as number),\n Math.max(b[1], clip[1] as number),\n Math.min(b[2], clip[2] as number),\n Math.min(b[3], clip[3] as number),\n ];\n return out[0] <= out[2] && out[1] <= out[3] ? out : undefined;\n}\n\n/**\n * The plan of Mercator tile `z`/`x`/`y` (`size` pixels a side) from a source of URL template `url` in grid `g`; null\n * where the source has nothing\n */\nexport function planTile(g: Resolved, url: string, z: number, x: number, y: number, size: number): Job | null {\n const tiles = 2 ** z;\n if (g.bounds) {\n const [w, s, e, n] = g.bounds;\n if (longitude((x + 1) / tiles) <= w || longitude(x / tiles) >= e) return null;\n if (latitude(y / tiles) <= s || latitude((y + 1) / tiles) >= n) return null;\n }\n // The mesh in the source CRS\n const points = new Float64Array(2 * (N + 1) ** 2);\n for (let j = 0; j <= N; j += 1) {\n const lat = latitude((y + j / N) / tiles);\n for (let i = 0; i <= N; i += 1) {\n const [px = Number.NaN, py = Number.NaN] = g.crs.forward([longitude((x + i / N) / tiles), lat]);\n points[2 * (j * (N + 1) + i)] = px;\n points[2 * (j * (N + 1) + i) + 1] = py;\n }\n }\n let b = box(points);\n if (!b) return null;\n if (g.extent) {\n const e = g.extent;\n b = [Math.max(b[0], e[0]), Math.max(b[1], e[1]), Math.min(b[2], e[2]), Math.min(b[3], e[3])];\n if (b[0] >= b[2] || b[1] >= b[3]) return null;\n }\n const mesh = new Float32Array(points.length);\n if (g.matrices.length === 0) {\n // One image of the tile's box, a pixel larger on each side\n const [sx, sy] = pixelSize(points, size);\n const m = Number.isFinite(sx + sy) ? Math.max(sx, sy) : 0;\n const [x0, y0, x1, y1] = [b[0] - m, b[1] - m, b[2] + m, b[3] + m];\n for (let k = 0; k < points.length; k += 2) {\n mesh[k] = (((points[k] as number) - x0) / (x1 - x0)) * size;\n mesh[k + 1] = ((y1 - (points[k + 1] as number)) / (y1 - y0)) * size;\n }\n const source = { url: sourceUrl(url, z, x, y, [x0, y0, x1, y1], size, size), x: 0, y: 0, w: size, h: size };\n return { size, width: size, height: size, sources: [source], n: N, mesh };\n }\n // The level of the same pixel size, along the axis the grid stretches least (up to MAX_BOOST levels finer)\n const [sx, sy] = pixelSize(points, size);\n const across = Math.max(sx, sy);\n const target = Number.isFinite(across) ? Math.max(Math.min(sx, sy), across / 2 ** MAX_BOOST) : (b[2] - b[0]) / size;\n // Where the pixels of the tile are sampled: the centers of its edge pixels and the mesh, within the source's extent\n const centers = sampled(points, size, b);\n if (!centers) return null;\n let best = 0;\n g.matrices.forEach((m, i) => {\n const r = g.matrices[best]?.resolution ?? m.resolution;\n if (Math.abs(Math.log2(m.resolution / target)) < Math.abs(Math.log2(r / target))) best = i;\n });\n for (let level = best; level >= 0; level -= 1) {\n const m = g.matrices[level] as Matrix;\n const [ox, oy] = m.origin;\n const [tw, th, res] = [m.tileWidth, m.tileHeight, m.resolution];\n const [l0, r0, l1, r1] = m.limits ?? [0, 0, Infinity, Infinity];\n // The tiles of the source pixels sampled (those of a weight over a thousandth: a tile edge on a source tile edge\n // does not fetch the next source tile for nothing)\n const c0 = Math.max(0, l0, Math.floor(((centers[0] - ox) / res - 0.5 + 1e-3) / tw));\n const c1 = Math.min(m.matrixWidth - 1, l1, Math.floor(((centers[2] - ox) / res + 0.5 - 1e-3) / tw));\n const t0 = Math.max(0, r0, Math.floor(((oy - centers[3]) / res - 0.5 + 1e-3) / th));\n const t1 = Math.min(m.matrixHeight - 1, r1, Math.floor(((oy - centers[1]) / res + 0.5 - 1e-3) / th));\n if (c0 > c1 || t0 > t1) return null;\n const [width, height] = [(c1 - c0 + 1) * tw, (t1 - t0 + 1) * th];\n if (width * height > MAX_MOSAIC) continue;\n const sources: Placed[] = [];\n for (let row = t0; row <= t1; row += 1) {\n for (let col = c0; col <= c1; col += 1) {\n const bbox = [ox + col * tw * res, oy - (row + 1) * th * res, ox + (col + 1) * tw * res, oy - row * th * res];\n const placed = { x: (col - c0) * tw, y: (row - t0) * th, w: tw, h: th };\n sources.push({ url: sourceUrl(url, m.id, col, row, bbox, tw, th), ...placed });\n }\n }\n for (let k = 0; k < points.length; k += 2) {\n mesh[k] = ((points[k] as number) - ox) / res - c0 * tw;\n mesh[k + 1] = (oy - (points[k + 1] as number)) / res - t0 * th;\n }\n return { size, width, height, sources, n: N, mesh };\n }\n return null;\n}\n\n/**\n * The map zooms a grid's matrices span (the pixel size of the finest and of the coarsest, two levels coarser, where\n * the tiles still fit a mosaic), measured at the middle of its bounds, or of its coarsest matrix\n */\nexport function gridZooms(g: Resolved): { minZoom: number; maxZoom: number } {\n const coarse = g.matrices[0];\n const fine = g.matrices.at(-1);\n if (!coarse || !fine) return { minZoom: 0, maxZoom: 19 };\n let lonLat: readonly number[] = [0, 0];\n if (g.bounds) lonLat = [(g.bounds[0] + g.bounds[2]) / 2, (g.bounds[1] + g.bounds[3]) / 2];\n else {\n const [l0, r0, l1, r1] = coarse.limits ?? [0, 0, coarse.matrixWidth - 1, coarse.matrixHeight - 1];\n const span = coarse.resolution * coarse.tileWidth;\n const [cx, cy] = [(l0 + l1 + 1) / 2, (r0 + r1 + 1) / 2];\n if (Number.isFinite(cx + cy)) lonLat = g.crs.inverse([coarse.origin[0] + cx * span, coarse.origin[1] - cy * span]);\n }\n // CRS units per pixel of a 256 px tile at zoom 0 there\n const [mx, my] = [mercatorX(lonLat[0] ?? 0), mercatorY(lonLat[1] ?? 0)];\n const d = 1e-7;\n const p = g.crs.forward([longitude(mx), latitude(my)]);\n const q = g.crs.forward([longitude(mx + d), latitude(my)]);\n const zero = Math.hypot((q[0] ?? 0) - (p[0] ?? 0), (q[1] ?? 0) - (p[1] ?? 0)) / (d * 256);\n if (!(zero > 0)) return { minZoom: 0, maxZoom: 19 };\n return {\n minZoom: Math.max(0, Math.floor(Math.log2(zero / coarse.resolution)) - 2),\n maxZoom: Math.max(0, Math.round(Math.log2(zero / fine.resolution))),\n };\n}\n\n/** Draws a Mercator tile `z`/`x`/`y`: its image, null where the source has nothing; rejects on errors */\ntype Draw = (z: number, x: number, y: number, signal: AbortSignal) => Promise<ImageBitmap | null>;\n\n/** A planned tile drawn in a worker; undefined when the map has no workers (drawn in the page) */\nexport type RemoteReprojection = (\n job: Job,\n tile: [z: number, x: number, y: number],\n signal: AbortSignal,\n) => Promise<ImageBitmap | null> | undefined;\n\n/**\n * A raster loader drawing Web Mercator tiles of `size` pixels from a source of URL template `url` in tile grid `grid`:\n * planned here, drawn in a worker of the map through `remote` when it can, else in the page\n */\nexport function gridLoader(url: string, grid: Resolved, size: number, remote?: RemoteReprojection): Draw {\n let local: ReturnType<typeof resampler>['draw'] | undefined;\n return async (z, x, y, signal) => {\n const job = planTile(grid, url, z, x, y, size);\n if (!job) return null;\n const drawn = remote?.(job, [z, x, y], signal);\n if (drawn) return drawn;\n local ??= resampler().draw;\n return local(job, signal);\n };\n}\n"]}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Icons for the symbol layers: the images of a style's sprite (MapLibre's sprite format: a JSON index and a PNG sheet,
3
+ * `@2x` on high-density screens, one sprite or several with their ids) and the application's own (`map.addImage`),
4
+ * packed on first use into an RGBA atlas the engine samples (premultiplied: no dark fringe where it is scaled); and the
5
+ * layout of an icon around its anchor: by its anchor and offset, or stretched around its text (`icon-text-fit`), by
6
+ * the stretchable zones and the content box of its image when it has them (`stretchX`, `stretchY`, `content`).
7
+ */
8
+ import type { Anchor } from './overlay.ts';
9
+ import type { Engine } from './wasm/isard.js';
10
+ /** An image of a sprite's index: its place in the sheet (pixels) and how it is drawn */
11
+ export interface SpriteIcon {
12
+ x: number;
13
+ y: number;
14
+ width: number;
15
+ height: number;
16
+ /** Image pixels per CSS pixel (default 1; 2 in an `@2x` sheet) */
17
+ pixelRatio?: number;
18
+ /** A signed distance field in alpha, drawn in the icon color */
19
+ sdf?: boolean;
20
+ /** Columns and rows that stretch when the icon is fitted to its text (image pixels): the others keep their size */
21
+ stretchX?: [number, number][];
22
+ stretchY?: [number, number][];
23
+ /** Where the text goes when the icon is fitted to it: left, top, right, bottom (image pixels) */
24
+ content?: [number, number, number, number];
25
+ }
26
+ export type SpriteIndex = Record<string, SpriteIcon>;
27
+ /** RGBA pixels, straight alpha, row after row */
28
+ export interface Pixels {
29
+ width: number;
30
+ height: number;
31
+ data: Uint8Array | Uint8ClampedArray;
32
+ }
33
+ /** How an image of the application is drawn (`map.addImage`): `SpriteIcon` without its place */
34
+ export type ImageOptions = Omit<SpriteIcon, 'x' | 'y' | 'width' | 'height'>;
35
+ /** An icon in the atlas: its place (texels) and how it is drawn */
36
+ export interface Icon {
37
+ x: number;
38
+ y: number;
39
+ width: number;
40
+ height: number;
41
+ pixelRatio: number;
42
+ sdf: boolean;
43
+ stretchX: [number, number][] | undefined;
44
+ stretchY: [number, number][] | undefined;
45
+ content: [number, number, number, number] | undefined;
46
+ }
47
+ /** A sprite of a style: its id (`default`: its images keep their names, else `id:name`) and its URL without
48
+ * extension */
49
+ export interface SpriteSource {
50
+ id: string;
51
+ url: string;
52
+ }
53
+ /** The sprites of a style's `sprite`: one URL, or several with their ids (MapLibre's style specification) */
54
+ export declare function spriteSources(sprite: string | readonly SpriteSource[] | undefined): SpriteSource[];
55
+ /** The name of an image of a sprite in the style: its own in the `default` sprite, `id:name` in another */
56
+ export declare function spriteName(id: string, name: string): string;
57
+ /** The URL of a sprite's index or sheet: `.json` or `.png`, `@2x` before it for high-density screens, before the
58
+ * query of the URL if it has one */
59
+ export declare function spriteFile(url: string, extension: 'json' | 'png', ratio: number): string;
60
+ /** A sprite loaded: its images by name (with the sprite's prefix) and its sheet */
61
+ export interface LoadedSprite {
62
+ icons: SpriteIndex;
63
+ image: ImageBitmap;
64
+ }
65
+ /** Loads a style's sprites (`@2x` above a device pixel ratio of 1, the 1x ones if a server has none); the sprites
66
+ * that fail are left out */
67
+ export declare function loadSprites(sprite: string | readonly SpriteSource[] | undefined, ratio?: number): Promise<LoadedSprite[]>;
68
+ /** The pixels of an image (read back through a canvas) */
69
+ export declare function readPixels(image: CanvasImageSource & {
70
+ width: number;
71
+ height: number;
72
+ }): Pixels | undefined;
73
+ /** The icons of a map and their atlas: a square that doubles as it fills, up to the texture size limit */
74
+ export declare class Icons {
75
+ private size;
76
+ private data;
77
+ private shelves;
78
+ private readonly sources;
79
+ /** Icons packed, null for those that cannot be (no pixels, the atlas full) */
80
+ private readonly packed;
81
+ private engine;
82
+ /** Rows changed since the last upload: first, end */
83
+ private dirty;
84
+ private full;
85
+ private readonly maxSize;
86
+ /** Bumped each time icons are added or removed: labels laid out without some of theirs are laid out again */
87
+ version: number;
88
+ /** `maxSize`: the GPU's texture size limit if known (the atlas is at most 4096 × 4096) */
89
+ constructor(maxSize?: number);
90
+ /** Sends the whole atlas to an engine (a new one after a context loss) */
91
+ attach(engine: Engine): void;
92
+ /** Side of the atlas */
93
+ get atlasSize(): number;
94
+ /** An image of the application under `name` (another image of that name is replaced) */
95
+ add(name: string, pixels: Pixels, options?: ImageOptions): void;
96
+ /** The images of a sprite's index, `prefix` before their names, their pixels read from the sheet on first use */
97
+ addSprite(prefix: string, index: SpriteIndex, sheet: () => Pixels | undefined): void;
98
+ private define;
99
+ has(name: string): boolean;
100
+ /** Forgets an image, or every image whose name starts with `prefix` (a sprite's) */
101
+ remove(name: string, prefix?: boolean): void;
102
+ /** The icon of this name, packed into the atlas on first use; undefined if there is none (`flush` uploads it) */
103
+ get(name: string): Icon | undefined;
104
+ /** Sends the rows changed since the last upload to the engine */
105
+ flush(): void;
106
+ private upload;
107
+ /** Copies an icon's pixels into the atlas, premultiplied, with a texel of room around it */
108
+ private pack;
109
+ /** A free place of `w` × `h` texels (shelves, the atlas doubled when full); undefined once it cannot grow */
110
+ private place;
111
+ /** Doubles the atlas; the icons keep their places (texels) */
112
+ private grow;
113
+ }
114
+ /** How an icon is laid out around its anchor */
115
+ export interface IconLayoutOptions {
116
+ /** Scale of the image (`icon-size`) */
117
+ size: number;
118
+ anchor: Anchor;
119
+ /** CSS pixels at size 1 */
120
+ offset: [number, number];
121
+ /** Degrees, clockwise */
122
+ rotate: number;
123
+ /** Stretched around the text: its width, its height, both (`icon-text-fit`) */
124
+ fit: 'none' | 'width' | 'height' | 'both';
125
+ /** Room around the text when fitted: top, right, bottom, left (CSS pixels) */
126
+ padding: [number, number, number, number];
127
+ /** The text's box around the anchor (CSS pixels), if it has one */
128
+ text?: [number, number, number, number] | undefined;
129
+ }
130
+ /** An icon laid out: its quads (x, y, width, height in CSS pixels from the anchor, atlas u0, v0, u1, v1 in texels, -1
131
+ * or -2 for a distance field, turn in radians) and its box from the anchor */
132
+ export interface IconLayout {
133
+ quads: number[][];
134
+ box: [number, number, number, number];
135
+ }
136
+ /** Pieces of an image along one axis: image start, end, laid out start, end */
137
+ type Pieces = [number, number, number, number][];
138
+ /**
139
+ * An axis of an icon fitted to `lo`…`hi` (CSS pixels): its content (the whole image by default) spans them, its
140
+ * stretchable zones (the whole image by default) taking the room the fixed parts (at `scale` CSS pixels per image
141
+ * pixel) leave
142
+ */
143
+ export declare function stretch(length: number, zones: readonly [number, number][] | undefined, content: [number, number] | undefined, lo: number, hi: number, scale: number): Pieces;
144
+ /** Lays an icon out around its anchor: placed by its anchor and offset, or fitted to its text */
145
+ export declare function layoutIcon(icon: Icon, options: IconLayoutOptions): IconLayout;
146
+ export {};