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.
- package/CHANGELOG.md +93 -0
- package/README.md +8 -4
- package/dist/animation.d.ts +18 -0
- package/dist/animation.js +84 -0
- package/dist/animation.js.map +1 -0
- package/dist/basemap.worker.d.ts +26 -4
- package/dist/basemap.worker.js +2 -2
- package/dist/basemap.worker.js.map +9 -5
- package/dist/crs.d.ts +72 -0
- package/dist/crs.js +243 -0
- package/dist/crs.js.map +1 -0
- package/dist/decoder.worker.js +4 -4
- package/dist/decoder.worker.js.map +4 -4
- package/dist/engine-loader.d.ts +28 -0
- package/dist/engine-loader.js +112 -0
- package/dist/engine-loader.js.map +1 -0
- package/dist/features.d.ts +8 -0
- package/dist/features.js +17 -10
- package/dist/features.js.map +1 -1
- package/dist/geo.d.ts +16 -0
- package/dist/geo.js +32 -0
- package/dist/geo.js.map +1 -0
- package/dist/geoplateforme.d.ts +21 -5
- package/dist/geoplateforme.js +47 -12
- package/dist/geoplateforme.js.map +1 -1
- package/dist/glyphs.d.ts +13 -3
- package/dist/glyphs.js +26 -4
- package/dist/glyphs.js.map +1 -1
- package/dist/gpx.d.ts +11 -0
- package/dist/gpx.js +74 -0
- package/dist/gpx.js.map +1 -0
- package/dist/grid.d.ts +81 -0
- package/dist/grid.js +270 -0
- package/dist/grid.js.map +1 -0
- package/dist/icons.d.ts +146 -0
- package/dist/icons.js +333 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.d.ts +11 -4
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/interaction.d.ts +0 -4
- package/dist/interaction.js +8 -4
- package/dist/interaction.js.map +1 -1
- package/dist/isard_bg.wasm +0 -0
- package/dist/isard_core_bg.wasm +0 -0
- package/dist/kml.d.ts +12 -0
- package/dist/kml.js +159 -0
- package/dist/kml.js.map +1 -0
- package/dist/layers.d.ts +89 -2
- package/dist/layers.js +171 -15
- package/dist/layers.js.map +1 -1
- package/dist/lru.d.ts +22 -0
- package/dist/lru.js +52 -0
- package/dist/lru.js.map +1 -0
- package/dist/map.d.ts +45 -7
- package/dist/map.js +138 -310
- package/dist/map.js.map +1 -1
- package/dist/resample.d.ts +41 -0
- package/dist/resample.js +164 -0
- package/dist/resample.js.map +1 -0
- package/dist/settings.d.ts +39 -0
- package/dist/settings.js +104 -0
- package/dist/settings.js.map +1 -0
- package/dist/symbols.d.ts +54 -9
- package/dist/symbols.js +278 -55
- package/dist/symbols.js.map +1 -1
- package/dist/terrain.d.ts +19 -7
- package/dist/terrain.js +40 -28
- package/dist/terrain.js.map +1 -1
- package/dist/topojson.d.ts +29 -0
- package/dist/topojson.js +66 -0
- package/dist/topojson.js.map +1 -0
- package/dist/types.d.ts +14 -6
- package/dist/types.js.map +1 -1
- package/dist/vectorstyle.d.ts +32 -3
- package/dist/vectorstyle.js.map +1 -1
- package/dist/vectortiles.d.ts +19 -7
- package/dist/vectortiles.js +117 -69
- package/dist/vectortiles.js.map +1 -1
- package/dist/wasm/isard.d.ts +55 -7
- package/dist/wasm/isard.js +117 -6
- package/dist/wasm/isard_core.d.ts +29 -4
- package/dist/wasm/isard_core.js +84 -5
- package/dist/wmts.d.ts +14 -0
- package/dist/wmts.js +76 -0
- package/dist/wmts.js.map +1 -0
- package/dist/xml.d.ts +26 -0
- package/dist/xml.js +109 -0
- package/dist/xml.js.map +1 -0
- package/package.json +1 -1
- package/dist/equirectangular.d.ts +0 -35
- package/dist/equirectangular.js +0 -143
- package/dist/equirectangular.js.map +0 -1
package/dist/geoplateforme.js
CHANGED
|
@@ -1,39 +1,74 @@
|
|
|
1
1
|
/** Credits of the Géoplateforme's data: its basemaps, hillshade, terrain model, rasters and features */
|
|
2
2
|
export const IGN_ATTRIBUTION = '<a href="https://www.ign.fr/">© IGN</a> – <a href="https://geoservices.ign.fr/">Géoplateforme</a>';
|
|
3
|
+
/** France (metropolitan, Corsica included) in longitudes and latitudes, where the Géoplateforme's Lambert-93 layers
|
|
4
|
+
* lie */
|
|
5
|
+
const FRANCE = [-5.5, 41, 10, 51.5];
|
|
3
6
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
+
* The Géoplateforme's Lambert-93 tile matrix sets of 5 and 10 cm (`2154_10cm_6_20`, `2154_5cm_6_22`…: one pyramid,
|
|
8
|
+
* 209 715.2 m per pixel at level 0, halved at each level, from the corner (0, 12 000 000)), levels `min` to `max`, over
|
|
9
|
+
* France
|
|
10
|
+
*/
|
|
11
|
+
export function lambert93Grid(name, min, max) {
|
|
12
|
+
const matrices = [];
|
|
13
|
+
for (let level = min; level <= max; level += 1) {
|
|
14
|
+
matrices.push({ id: level, resolution: 209715.2 / 2 ** level, origin: [0, 12000000] });
|
|
15
|
+
}
|
|
16
|
+
return { crs: 'EPSG:2154', matrices, bounds: FRANCE, name };
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A layer of the Géoplateforme's WMTS as raster options for `addRaster`, crediting the IGN:
|
|
20
|
+
* `geoplateformeWmts('ORTHOIMAGERY.ORTHOPHOTOS', { format: 'image/jpeg' })`. The layer names are those of its
|
|
21
|
+
* capabilities (https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetCapabilities). In its Web Mercator grid (`PM`) by
|
|
22
|
+
* default; a Lambert-93 layer in its matrix set (`matrixSet: '2154_10cm_6_20'`, a set of 5 or 10 cm, read from the
|
|
23
|
+
* capabilities) or another `grid` (from `wmtsGrid`, its set named) is reprojected by the map
|
|
7
24
|
*/
|
|
8
25
|
export function geoplateformeWmts(layer, options = {}) {
|
|
9
|
-
const { format = 'image/png', style = 'normal', ...raster } = options;
|
|
26
|
+
const { format = 'image/png', style = 'normal', matrixSet, ...raster } = options;
|
|
27
|
+
const set = (typeof raster.grid === 'object' ? raster.grid.name : undefined) ?? matrixSet ?? 'PM';
|
|
28
|
+
const lambert = /^2154_(?:5|10)cm_(\d+)_(\d+)$/.exec(set);
|
|
29
|
+
if (lambert && raster.grid === undefined)
|
|
30
|
+
raster.grid = lambert93Grid(set, Number(lambert[1]), Number(lambert[2]));
|
|
31
|
+
else if (set !== 'PM' && raster.grid === undefined) {
|
|
32
|
+
throw new Error(`isard: the grid of the matrix set ${set}: wmtsGrid(capabilities, '${layer}', '${set}')`);
|
|
33
|
+
}
|
|
10
34
|
return {
|
|
11
|
-
maxZoom: 19,
|
|
35
|
+
...(raster.grid === undefined ? { maxZoom: 19 } : {}),
|
|
12
36
|
attribution: IGN_ATTRIBUTION,
|
|
13
37
|
...raster,
|
|
14
38
|
url: `https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&STYLE=${encodeURIComponent(style)}` +
|
|
15
|
-
`&TILEMATRIXSET
|
|
39
|
+
`&TILEMATRIXSET=${encodeURIComponent(set)}&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}` +
|
|
40
|
+
`&LAYER=${encodeURIComponent(layer)}&FORMAT=${format}`,
|
|
16
41
|
};
|
|
17
42
|
}
|
|
18
43
|
/**
|
|
19
44
|
* Layers of the Géoplateforme's WMS (raster, `wms-r`) as raster options for `addRaster`, crediting the IGN: 256 px
|
|
20
|
-
* images of each tile
|
|
45
|
+
* images of each tile, transparent where empty. `geoplateformeWms('CADASTRALPARCELS.PARCELLAIRE_EXPRESS')`. Asked for
|
|
46
|
+
* in EPSG:3857, or in `crs` (`'EPSG:2154'`: the box of each tile in Lambert-93, at the tile's `size`, reprojected by
|
|
47
|
+
* the map; `'EPSG:4326'` is asked for as CRS:84, longitude first)
|
|
21
48
|
*/
|
|
22
49
|
export function geoplateformeWms(layers, options = {}) {
|
|
23
|
-
const { format = 'image/png', styles = '', ...raster } = options;
|
|
50
|
+
const { format = 'image/png', styles = '', crs = 'EPSG:3857', ...raster } = options;
|
|
51
|
+
const projected = crs !== 'EPSG:3857';
|
|
52
|
+
// WMS 1.3 puts the latitude first in EPSG:4326; {bbox} is x, y
|
|
53
|
+
const asked = crs === 'EPSG:4326' ? 'CRS:84' : crs;
|
|
24
54
|
return {
|
|
25
55
|
maxZoom: 20,
|
|
26
56
|
attribution: IGN_ATTRIBUTION,
|
|
57
|
+
...(projected ? { grid: { crs, ...(crs === 'EPSG:2154' ? { bounds: FRANCE } : {}) } } : {}),
|
|
27
58
|
...raster,
|
|
28
|
-
url:
|
|
29
|
-
|
|
59
|
+
url: `https://data.geopf.fr/wms-r/wms?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=${asked}&BBOX={bbox}` +
|
|
60
|
+
// Reprojected, the image of each tile at its size
|
|
61
|
+
`&${projected ? 'WIDTH={width}&HEIGHT={height}' : 'WIDTH=256&HEIGHT=256'}&TRANSPARENT=TRUE` +
|
|
62
|
+
`&LAYERS=${encodeURIComponent(layers)}` +
|
|
30
63
|
`&STYLES=${encodeURIComponent(styles)}&FORMAT=${format}`,
|
|
31
64
|
};
|
|
32
65
|
}
|
|
33
66
|
/**
|
|
34
67
|
* Features of the Géoplateforme's WFS in a box (west, south, east, north, degrees), as GeoJSON in longitudes and
|
|
35
68
|
* latitudes: `await geoplateformeWfs('BDTOPO_V3:batiment', [2.41, 48.84, 2.43, 48.85])`. At most `count` features
|
|
36
|
-
* (default 5000). The type names are those of its capabilities (BD TOPO, ADMIN EXPRESS…)
|
|
69
|
+
* (default 5000). The type names are those of its capabilities (BD TOPO, ADMIN EXPRESS…). With `srsName`
|
|
70
|
+
* (`'EPSG:2154'`), the features come in that CRS (the box stays in degrees), the collection naming it in its `crs`
|
|
71
|
+
* member: the feature layers reproject it by themselves
|
|
37
72
|
*/
|
|
38
73
|
export async function geoplateformeWfs(typeName, [west, south, east, north], options = {}) {
|
|
39
74
|
const url = new URL('https://data.geopf.fr/wfs/ows');
|
|
@@ -43,7 +78,7 @@ export async function geoplateformeWfs(typeName, [west, south, east, north], opt
|
|
|
43
78
|
REQUEST: 'GetFeature',
|
|
44
79
|
TYPENAMES: typeName,
|
|
45
80
|
OUTPUTFORMAT: 'application/json',
|
|
46
|
-
SRSNAME: 'EPSG:4326',
|
|
81
|
+
SRSNAME: options.srsName ?? 'EPSG:4326',
|
|
47
82
|
// WFS 2.0 in EPSG:4326: latitude first
|
|
48
83
|
BBOX: `${south},${west},${north},${east},urn:ogc:def:crs:EPSG::4326`,
|
|
49
84
|
COUNT: String(options.count ?? 5000),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geoplateforme.js","sourceRoot":"","sources":["../src/geoplateforme.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"geoplateforme.js","sourceRoot":"","sources":["../src/geoplateforme.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Géoplateforme's data (IGN, France; open, no key): its WMTS and WMS rasters as raster layers, its WFS features as\n * GeoJSON. Its basemaps, hillshade, terrain model and vector styles are named options of the map (`'ign-plan'`,\n * `hillshade`, `terrain: 'ign'`, `PLAN_STYLES`); the rasters credit the IGN by themselves.\n */\nimport type { FeatureCollection, Properties } from './features.ts';\nimport type { TileGrid, TileMatrix } from './grid.ts';\nimport type { RasterOptions } from './types.ts';\n\n/** Credits of the Géoplateforme's data: its basemaps, hillshade, terrain model, rasters and features */\nexport const IGN_ATTRIBUTION =\n '<a href=\"https://www.ign.fr/\">© IGN</a> – <a href=\"https://geoservices.ign.fr/\">Géoplateforme</a>';\n\n/** France (metropolitan, Corsica included) in longitudes and latitudes, where the Géoplateforme's Lambert-93 layers\n * lie */\nconst FRANCE: [number, number, number, number] = [-5.5, 41, 10, 51.5];\n\n/**\n * The Géoplateforme's Lambert-93 tile matrix sets of 5 and 10 cm (`2154_10cm_6_20`, `2154_5cm_6_22`…: one pyramid,\n * 209 715.2 m per pixel at level 0, halved at each level, from the corner (0, 12 000 000)), levels `min` to `max`, over\n * France\n */\nexport function lambert93Grid(name: string, min: number, max: number): TileGrid {\n const matrices: TileMatrix[] = [];\n for (let level = min; level <= max; level += 1) {\n matrices.push({ id: level, resolution: 209715.2 / 2 ** level, origin: [0, 12000000] });\n }\n return { crs: 'EPSG:2154', matrices, bounds: FRANCE, name };\n}\n\n/**\n * A layer of the Géoplateforme's WMTS as raster options for `addRaster`, crediting the IGN:\n * `geoplateformeWmts('ORTHOIMAGERY.ORTHOPHOTOS', { format: 'image/jpeg' })`. The layer names are those of its\n * capabilities (https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetCapabilities). In its Web Mercator grid (`PM`) by\n * default; a Lambert-93 layer in its matrix set (`matrixSet: '2154_10cm_6_20'`, a set of 5 or 10 cm, read from the\n * capabilities) or another `grid` (from `wmtsGrid`, its set named) is reprojected by the map\n */\nexport function geoplateformeWmts(\n layer: string,\n options: { format?: string; style?: string; matrixSet?: string } & Omit<RasterOptions, 'url'> = {},\n): RasterOptions {\n const { format = 'image/png', style = 'normal', matrixSet, ...raster } = options;\n const set = (typeof raster.grid === 'object' ? raster.grid.name : undefined) ?? matrixSet ?? 'PM';\n const lambert = /^2154_(?:5|10)cm_(\\d+)_(\\d+)$/.exec(set);\n if (lambert && raster.grid === undefined) raster.grid = lambert93Grid(set, Number(lambert[1]), Number(lambert[2]));\n else if (set !== 'PM' && raster.grid === undefined) {\n throw new Error(`isard: the grid of the matrix set ${set}: wmtsGrid(capabilities, '${layer}', '${set}')`);\n }\n return {\n ...(raster.grid === undefined ? { maxZoom: 19 } : {}),\n attribution: IGN_ATTRIBUTION,\n ...raster,\n url:\n `https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&STYLE=${encodeURIComponent(style)}` +\n `&TILEMATRIXSET=${encodeURIComponent(set)}&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}` +\n `&LAYER=${encodeURIComponent(layer)}&FORMAT=${format}`,\n };\n}\n\n/**\n * Layers of the Géoplateforme's WMS (raster, `wms-r`) as raster options for `addRaster`, crediting the IGN: 256 px\n * images of each tile, transparent where empty. `geoplateformeWms('CADASTRALPARCELS.PARCELLAIRE_EXPRESS')`. Asked for\n * in EPSG:3857, or in `crs` (`'EPSG:2154'`: the box of each tile in Lambert-93, at the tile's `size`, reprojected by\n * the map; `'EPSG:4326'` is asked for as CRS:84, longitude first)\n */\nexport function geoplateformeWms(\n layers: string,\n options: { format?: string; styles?: string; crs?: string } & Omit<RasterOptions, 'url'> = {},\n): RasterOptions {\n const { format = 'image/png', styles = '', crs = 'EPSG:3857', ...raster } = options;\n const projected = crs !== 'EPSG:3857';\n // WMS 1.3 puts the latitude first in EPSG:4326; {bbox} is x, y\n const asked = crs === 'EPSG:4326' ? 'CRS:84' : crs;\n return {\n maxZoom: 20,\n attribution: IGN_ATTRIBUTION,\n ...(projected ? { grid: { crs, ...(crs === 'EPSG:2154' ? { bounds: FRANCE } : {}) } } : {}),\n ...raster,\n url:\n `https://data.geopf.fr/wms-r/wms?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=${asked}&BBOX={bbox}` +\n // Reprojected, the image of each tile at its size\n `&${projected ? 'WIDTH={width}&HEIGHT={height}' : 'WIDTH=256&HEIGHT=256'}&TRANSPARENT=TRUE` +\n `&LAYERS=${encodeURIComponent(layers)}` +\n `&STYLES=${encodeURIComponent(styles)}&FORMAT=${format}`,\n };\n}\n\n/**\n * Features of the Géoplateforme's WFS in a box (west, south, east, north, degrees), as GeoJSON in longitudes and\n * latitudes: `await geoplateformeWfs('BDTOPO_V3:batiment', [2.41, 48.84, 2.43, 48.85])`. At most `count` features\n * (default 5000). The type names are those of its capabilities (BD TOPO, ADMIN EXPRESS…). With `srsName`\n * (`'EPSG:2154'`), the features come in that CRS (the box stays in degrees), the collection naming it in its `crs`\n * member: the feature layers reproject it by themselves\n */\nexport async function geoplateformeWfs<P = Properties>(\n typeName: string,\n [west, south, east, north]: [number, number, number, number],\n options: { count?: number; signal?: AbortSignal; srsName?: string } = {},\n): Promise<FeatureCollection<P>> {\n const url = new URL('https://data.geopf.fr/wfs/ows');\n url.search = new URLSearchParams({\n SERVICE: 'WFS',\n VERSION: '2.0.0',\n REQUEST: 'GetFeature',\n TYPENAMES: typeName,\n OUTPUTFORMAT: 'application/json',\n SRSNAME: options.srsName ?? 'EPSG:4326',\n // WFS 2.0 in EPSG:4326: latitude first\n BBOX: `${south},${west},${north},${east},urn:ogc:def:crs:EPSG::4326`,\n COUNT: String(options.count ?? 5000),\n }).toString();\n const response = await fetch(url, options.signal ? { signal: options.signal } : {});\n if (!response.ok) throw new Error(`isard: ${typeName}: ${response.status}`);\n return response.json() as Promise<FeatureCollection<P>>;\n}\n"]}
|
package/dist/glyphs.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Glyphs for the symbol layers: signed distance fields in MapLibre's glyph format (ranges of 256 code points per
|
|
3
3
|
* protobuf file, 24 px glyphs with a 3 px buffer), loaded on first use (from OpenFreeMap's fonts by default, a vector
|
|
4
|
-
* basemap's labels from the glyphs of its style), packed into an atlas the engine samples; and the shaping of a label:
|
|
5
|
-
* the anchor.
|
|
4
|
+
* basemap's labels from the glyphs of its style), packed into an atlas the engine samples; and the shaping of a label:
|
|
5
|
+
* its lines (explicit and wrapped), their glyphs placed around the anchor.
|
|
6
6
|
*
|
|
7
7
|
* The atlas has pages of one size: the first one grows up to the page size limit, then pages are added, so it never
|
|
8
8
|
* runs out. A glyph's atlas row counts the rows of the pages before its own (`y + page × size`, the pages stacked):
|
|
@@ -38,6 +38,8 @@ export declare class Glyphs {
|
|
|
38
38
|
/** Pages allocated in the engine (doubled when more are needed: fewer reallocations) */
|
|
39
39
|
private capacity;
|
|
40
40
|
private shelves;
|
|
41
|
+
/** Rows of each page holding glyphs (from its top): the rest is blank, never sent */
|
|
42
|
+
private readonly used;
|
|
41
43
|
private readonly fonts;
|
|
42
44
|
private readonly ranges;
|
|
43
45
|
/** Glyph URLs of fonts other than the map's (those of a vector basemap's style) */
|
|
@@ -49,6 +51,8 @@ export declare class Glyphs {
|
|
|
49
51
|
private full;
|
|
50
52
|
/** Largest side of a page */
|
|
51
53
|
private readonly maxSize;
|
|
54
|
+
/** Bumped each time glyphs are added: labels shaped while some of theirs were missing are shaped again */
|
|
55
|
+
version: number;
|
|
52
56
|
/** `maxSize`: the GPU's texture size limit if known (the pages are at most 2048 × 2048) */
|
|
53
57
|
constructor(url?: string, maxSize?: number);
|
|
54
58
|
/** Sends the whole atlas to an engine (a new one after a context loss) */
|
|
@@ -61,7 +65,10 @@ export declare class Glyphs {
|
|
|
61
65
|
/** Loads the glyphs of these code points in a font */
|
|
62
66
|
load(font: string, codes: Iterable<number>): Promise<Map<number, Glyph>>;
|
|
63
67
|
private range;
|
|
64
|
-
/**
|
|
68
|
+
/**
|
|
69
|
+
* Allocates the pages in the engine and sends what they hold (their rows with glyphs). The engine allocates its
|
|
70
|
+
* pages again empty: everything is sent each time, the pages doubled to make it rare
|
|
71
|
+
*/
|
|
65
72
|
private upload;
|
|
66
73
|
/** Sends the rows changed since the last upload to the engine */
|
|
67
74
|
private flush;
|
|
@@ -87,6 +94,9 @@ export interface Shaping {
|
|
|
87
94
|
quads: number[][];
|
|
88
95
|
/** Ink box from the anchor: min x, min y, max x, max y */
|
|
89
96
|
box: [number, number, number, number];
|
|
97
|
+
/** Layout box from the anchor, what an icon fitted to the text frames: the advances of its widest line across, its
|
|
98
|
+
* lines' height (`lineHeight` each) down, centered on the ink */
|
|
99
|
+
layout: [number, number, number, number];
|
|
90
100
|
}
|
|
91
101
|
/** Code points of a text, for loading */
|
|
92
102
|
export declare function codes(parts: readonly TextPart[]): Set<number>;
|
package/dist/glyphs.js
CHANGED
|
@@ -114,6 +114,8 @@ export class Glyphs {
|
|
|
114
114
|
/** Pages allocated in the engine (doubled when more are needed: fewer reallocations) */
|
|
115
115
|
capacity = 1;
|
|
116
116
|
shelves = [];
|
|
117
|
+
/** Rows of each page holding glyphs (from its top): the rest is blank, never sent */
|
|
118
|
+
used = [0];
|
|
117
119
|
fonts = new Map();
|
|
118
120
|
ranges = new Map();
|
|
119
121
|
/** Glyph URLs of fonts other than the map's (those of a vector basemap's style) */
|
|
@@ -125,6 +127,8 @@ export class Glyphs {
|
|
|
125
127
|
full = false;
|
|
126
128
|
/** Largest side of a page */
|
|
127
129
|
maxSize;
|
|
130
|
+
/** Bumped each time glyphs are added: labels shaped while some of theirs were missing are shaped again */
|
|
131
|
+
version = 0;
|
|
128
132
|
/** `maxSize`: the GPU's texture size limit if known (the pages are at most 2048 × 2048) */
|
|
129
133
|
constructor(url = GLYPHS_URL, maxSize = 4096) {
|
|
130
134
|
this.url = url;
|
|
@@ -176,6 +180,7 @@ export class Glyphs {
|
|
|
176
180
|
}
|
|
177
181
|
glyphs.set(id, glyph);
|
|
178
182
|
}
|
|
183
|
+
this.version += 1;
|
|
179
184
|
// One upload for the range
|
|
180
185
|
this.flush();
|
|
181
186
|
})
|
|
@@ -187,14 +192,19 @@ export class Glyphs {
|
|
|
187
192
|
}
|
|
188
193
|
return pending;
|
|
189
194
|
}
|
|
190
|
-
/**
|
|
195
|
+
/**
|
|
196
|
+
* Allocates the pages in the engine and sends what they hold (their rows with glyphs). The engine allocates its
|
|
197
|
+
* pages again empty: everything is sent each time, the pages doubled to make it rare
|
|
198
|
+
*/
|
|
191
199
|
upload() {
|
|
192
200
|
const engine = this.engine;
|
|
193
201
|
if (!engine)
|
|
194
202
|
return;
|
|
195
203
|
engine.setGlyphPages(this.size, this.size, this.capacity);
|
|
196
204
|
this.pages.forEach((page, i) => {
|
|
197
|
-
|
|
205
|
+
const rows = this.used[i] ?? 0;
|
|
206
|
+
if (rows > 0)
|
|
207
|
+
engine.updateGlyphPage(i, 0, 0, this.size, rows, page.subarray(0, rows * this.size));
|
|
198
208
|
});
|
|
199
209
|
}
|
|
200
210
|
/** Sends the rows changed since the last upload to the engine */
|
|
@@ -248,6 +258,7 @@ export class Glyphs {
|
|
|
248
258
|
for (let row = 0; row < h; row += 1) {
|
|
249
259
|
data.set(bitmap.subarray(row * w, row * w + w), (shelf.y + row) * this.size + glyph.x);
|
|
250
260
|
}
|
|
261
|
+
this.used[shelf.page] = Math.max(this.used[shelf.page] ?? 0, shelf.y + h);
|
|
251
262
|
const dirty = this.dirty.get(shelf.page);
|
|
252
263
|
this.dirty.set(shelf.page, [Math.min(dirty?.[0] ?? shelf.y, shelf.y), Math.max(dirty?.[1] ?? 0, shelf.y + h)]);
|
|
253
264
|
}
|
|
@@ -268,6 +279,7 @@ export class Glyphs {
|
|
|
268
279
|
/** A new empty page, after the others; the engine's pages are allocated again only past its capacity */
|
|
269
280
|
addPage() {
|
|
270
281
|
this.pages.push(new Uint8Array(this.size * this.size));
|
|
282
|
+
this.used.push(0);
|
|
271
283
|
if (this.pages.length > this.capacity) {
|
|
272
284
|
this.capacity = Math.min(MAX_PAGES, this.capacity * 2);
|
|
273
285
|
// The pages are allocated again: everything is sent, pending changes included
|
|
@@ -334,11 +346,15 @@ export function shape(parts, glyphsOf, options) {
|
|
|
334
346
|
Number.NEGATIVE_INFINITY,
|
|
335
347
|
];
|
|
336
348
|
let baseline = 0;
|
|
349
|
+
let widest = 0;
|
|
350
|
+
let height = 0;
|
|
337
351
|
wrapped.forEach((line, i) => {
|
|
338
352
|
const scale = Math.max(1, ...line.map((c) => c.scale));
|
|
339
353
|
if (i > 0)
|
|
340
354
|
baseline += lineHeight * EM * scale;
|
|
355
|
+
height += lineHeight * EM * scale;
|
|
341
356
|
const width = line.reduce((s, c) => s + advance(c), 0);
|
|
357
|
+
widest = Math.max(widest, width);
|
|
342
358
|
let pen = -width / 2;
|
|
343
359
|
for (const c of line) {
|
|
344
360
|
const g = c.glyph;
|
|
@@ -357,7 +373,7 @@ export function shape(parts, glyphsOf, options) {
|
|
|
357
373
|
}
|
|
358
374
|
});
|
|
359
375
|
if (!quads.length)
|
|
360
|
-
return { quads, box: [0, 0, 0, 0] };
|
|
376
|
+
return { quads, box: [0, 0, 0, 0], layout: [0, 0, 0, 0] };
|
|
361
377
|
// The block placed around the anchor by its ink box
|
|
362
378
|
// The side of the box at the anchor: its start, its end, or its middle
|
|
363
379
|
const side = (start, end, lo, hi) => {
|
|
@@ -378,6 +394,12 @@ export function shape(parts, glyphsOf, options) {
|
|
|
378
394
|
q[3] = (q[3] ?? 0) * k;
|
|
379
395
|
q[8] = (q[8] ?? 1) * k;
|
|
380
396
|
}
|
|
381
|
-
|
|
397
|
+
const middle = (y0 + y1) / 2 + dy;
|
|
398
|
+
height = Math.max(height, y1 - y0);
|
|
399
|
+
return {
|
|
400
|
+
quads,
|
|
401
|
+
box: [(x0 + dx) * k, (y0 + dy) * k, (x1 + dx) * k, (y1 + dy) * k],
|
|
402
|
+
layout: [(dx - widest / 2) * k, (middle - height / 2) * k, (dx + widest / 2) * k, (middle + height / 2) * k],
|
|
403
|
+
};
|
|
382
404
|
}
|
|
383
405
|
//# sourceMappingURL=glyphs.js.map
|
package/dist/glyphs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glyphs.js","sourceRoot":"","sources":["../src/glyphs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Glyphs for the symbol layers: signed distance fields in MapLibre's glyph format (ranges of 256 code points per\n * protobuf file, 24 px glyphs with a 3 px buffer), loaded on first use (from OpenFreeMap's fonts by default, a vector\n * basemap's labels from the glyphs of its style), packed into an atlas the engine samples; and the shaping of a label: its lines (explicit and wrapped), their glyphs placed around\n * the anchor.\n *\n * The atlas has pages of one size: the first one grows up to the page size limit, then pages are added, so it never\n * runs out. A glyph's atlas row counts the rows of the pages before its own (`y + page × size`, the pages stacked):\n * the coordinates of the glyphs placed so far stay valid as the atlas grows.\n */\nimport type { Anchor } from './overlay.ts';\nimport type { Engine } from './wasm/isard.js';\n\n/** OpenFreeMap's fonts, those of its styles (Noto Sans Regular, Bold, Italic) */\nexport const GLYPHS_URL = 'https://tiles.openfreemap.org/fonts/{fontstack}/{range}.pbf';\n\n/** The font of labels that name none */\nexport const DEFAULT_FONT = 'Noto Sans Regular';\n\n/** Size the glyphs are drawn at in the files, and their buffer */\nconst EM = 24;\nconst BUFFER = 3;\n\nexport interface Glyph {\n width: number;\n height: number;\n left: number;\n top: number;\n advance: number;\n /**\n * Place of its bitmap ((width + 6) × (height + 6)) in the atlas, `y` counting the rows of the pages before its\n * own; undefined for an empty one (a space)\n */\n x?: number;\n y?: number;\n /** Its page of the atlas */\n page?: number;\n}\n\n/** Largest side of a page of the atlas, and most pages (WebGL2 guarantees 256 layers of a texture array) */\nconst PAGE_MAX = 2048;\nconst MAX_PAGES = 256;\n\n/** A protobuf reader, enough for the glyph files */\nclass Reader {\n pos = 0;\n constructor(private readonly buf: Uint8Array) {}\n get done(): boolean {\n return this.pos >= this.buf.length;\n }\n varint(): number {\n let value = 0;\n let shift = 0;\n for (;;) {\n const b = this.buf[this.pos++] ?? 0;\n value += (b & 0x7f) * 2 ** shift;\n if (b < 0x80) return value;\n shift += 7;\n }\n }\n sint(): number {\n const v = this.varint();\n return v % 2 === 1 ? -(v + 1) / 2 : v / 2;\n }\n bytes(): Uint8Array {\n const n = this.varint();\n const out = this.buf.subarray(this.pos, this.pos + n);\n this.pos += n;\n return out;\n }\n skip(wire: number): void {\n if (wire === 0) this.varint();\n else if (wire === 2) this.pos += this.varint();\n else if (wire === 5) this.pos += 4;\n else if (wire === 1) this.pos += 8;\n }\n}\n\n/** Glyphs of a range file: id → metrics and bitmap */\nfunction parse(buffer: ArrayBuffer): Map<number, { glyph: Glyph; bitmap: Uint8Array }> {\n const out = new Map<number, { glyph: Glyph; bitmap: Uint8Array }>();\n const root = new Reader(new Uint8Array(buffer));\n while (!root.done) {\n const tag = root.varint();\n if (tag >> 3 !== 1) {\n root.skip(tag & 7);\n continue;\n }\n // A fontstack\n const stack = new Reader(root.bytes());\n while (!stack.done) {\n const t = stack.varint();\n if (t >> 3 !== 3) {\n stack.skip(t & 7);\n continue;\n }\n const g = new Reader(stack.bytes());\n let id = 0;\n let bitmap: Uint8Array = new Uint8Array(0);\n const glyph: Glyph = { width: 0, height: 0, left: 0, top: 0, advance: 0 };\n while (!g.done) {\n const f = g.varint();\n switch (f >> 3) {\n case 1:\n id = g.varint();\n break;\n case 2:\n bitmap = g.bytes();\n break;\n case 3:\n glyph.width = g.varint();\n break;\n case 4:\n glyph.height = g.varint();\n break;\n case 5:\n glyph.left = g.sint();\n break;\n case 6:\n glyph.top = g.sint();\n break;\n case 7:\n glyph.advance = g.varint();\n break;\n default:\n g.skip(f & 7);\n }\n }\n out.set(id, { glyph, bitmap });\n }\n }\n return out;\n}\n\n/** A shelf of the packer: its page, y, height, and the x of the next free place */\ninterface Shelf {\n page: number;\n y: number;\n height: number;\n x: number;\n}\n\n/** The glyphs of a map and their atlas */\nexport class Glyphs {\n /** Side of the pages */\n private size = 512;\n private pages: Uint8Array[] = [new Uint8Array(512 * 512)];\n /** Pages allocated in the engine (doubled when more are needed: fewer reallocations) */\n private capacity = 1;\n private shelves: Shelf[] = [];\n private readonly fonts = new Map<string, Map<number, Glyph>>();\n private readonly ranges = new Map<string, Promise<void>>();\n /** Glyph URLs of fonts other than the map's (those of a vector basemap's style) */\n private readonly sources = new Map<string, string>();\n private engine: Engine | undefined;\n /** Rows of each page changed since the last upload: first, end */\n private readonly dirty = new Map<number, [number, number]>();\n /** The atlas has its most pages: new glyphs stay blank */\n private full = false;\n /** Largest side of a page */\n private readonly maxSize: number;\n\n /** `maxSize`: the GPU's texture size limit if known (the pages are at most 2048 × 2048) */\n constructor(\n private readonly url = GLYPHS_URL,\n maxSize = 4096,\n ) {\n this.maxSize = Math.max(512, Math.min(PAGE_MAX, maxSize));\n }\n\n /** Sends the whole atlas to an engine (a new one after a context loss) */\n attach(engine: Engine): void {\n this.engine = engine;\n this.dirty.clear();\n this.upload();\n }\n\n /** Side of the pages of the atlas */\n get atlasSize(): number {\n return this.size;\n }\n\n get pageCount(): number {\n return this.pages.length;\n }\n\n /** Loads these fonts from another glyph URL (a style's `glyphs`); a font keeps the first URL given for it */\n register(url: string, fonts: Iterable<string>): void {\n for (const font of fonts) if (!this.sources.has(font)) this.sources.set(font, url);\n }\n\n /** Loads the glyphs of these code points in a font */\n async load(font: string, codes: Iterable<number>): Promise<Map<number, Glyph>> {\n const glyphs = this.fonts.get(font) ?? new Map<number, Glyph>();\n this.fonts.set(font, glyphs);\n const starts = new Set<number>();\n for (const code of codes) if (!glyphs.has(code)) starts.add(Math.floor(code / 256) * 256);\n await Promise.all([...starts].map((start) => this.range(font, start, glyphs)));\n return glyphs;\n }\n\n private range(font: string, start: number, glyphs: Map<number, Glyph>): Promise<void> {\n const key = `${font}/${start}`;\n let pending = this.ranges.get(key);\n if (!pending) {\n const url = (this.sources.get(font) ?? this.url)\n .replace('{fontstack}', encodeURIComponent(font))\n .replace('{range}', `${start}-${start + 255}`);\n pending = fetch(url)\n .then((r) => (r.ok ? r.arrayBuffer() : Promise.reject(new Error(`${url}: ${r.status}`))))\n .then((buffer) => {\n for (const [id, { glyph, bitmap }] of parse(buffer)) {\n if (glyph.width > 0 && bitmap.length >= (glyph.width + 2 * BUFFER) * (glyph.height + 2 * BUFFER)) {\n this.pack(glyph, bitmap);\n }\n glyphs.set(id, glyph);\n }\n // One upload for the range\n this.flush();\n })\n .catch((error: unknown) => {\n // A missing range is not retried this session; its characters stay blank\n console.warn('isard: glyphs', error);\n });\n this.ranges.set(key, pending);\n }\n return pending;\n }\n\n /** Allocates the pages in the engine and sends them all */\n private upload(): void {\n const engine = this.engine;\n if (!engine) return;\n engine.setGlyphPages(this.size, this.size, this.capacity);\n this.pages.forEach((page, i) => {\n engine.updateGlyphPage(i, 0, 0, this.size, this.size, page);\n });\n }\n\n /** Sends the rows changed since the last upload to the engine */\n private flush(): void {\n for (const [page, [y0, y1]] of this.dirty) {\n const data = this.pages[page];\n if (data)\n this.engine?.updateGlyphPage(page, 0, y0, this.size, y1 - y0, data.subarray(y0 * this.size, y1 * this.size));\n }\n this.dirty.clear();\n }\n\n /**\n * Places a bitmap in the atlas (growing the first page, then adding pages when full); `flush` sends it to the\n * engine\n */\n private pack(glyph: Glyph, bitmap: Uint8Array): void {\n const w = glyph.width + 2 * BUFFER;\n const h = glyph.height + 2 * BUFFER;\n // One texel of padding between bitmaps: linear filtering never reads a neighbour\n let shelf = this.shelves.find((s) => s.height >= h && s.height <= h + 4 && s.x + w + 1 <= this.size);\n if (!shelf) {\n const page = this.pages.length - 1;\n // New shelves go on the last page only: the last shelf is on it, unless the page is new\n const last = this.shelves.at(-1);\n const y = last && last.page === page ? last.y + last.height + 1 : 0;\n if (y + h > this.size) {\n if (this.pages.length === 1 && this.size * 2 <= this.maxSize) this.grow();\n else if (this.pages.length < MAX_PAGES) this.addPage();\n else {\n // Full: the glyph takes its room in the text but is not drawn\n if (!this.full) console.warn(`isard: the glyph atlas is full (${MAX_PAGES} pages)`);\n this.full = true;\n return;\n }\n this.pack(glyph, bitmap);\n return;\n }\n shelf = { page, y, height: h, x: 0 };\n this.shelves.push(shelf);\n }\n const data = this.pages[shelf.page];\n if (!data) return;\n glyph.x = shelf.x;\n glyph.y = shelf.page * this.size + shelf.y;\n glyph.page = shelf.page;\n shelf.x += w + 1;\n for (let row = 0; row < h; row += 1) {\n data.set(bitmap.subarray(row * w, row * w + w), (shelf.y + row) * this.size + glyph.x);\n }\n const dirty = this.dirty.get(shelf.page);\n this.dirty.set(shelf.page, [Math.min(dirty?.[0] ?? shelf.y, shelf.y), Math.max(dirty?.[1] ?? 0, shelf.y + h)]);\n }\n\n /** Doubles the only page; the glyphs keep their places (texel coordinates) */\n private grow(): void {\n const size = this.size * 2;\n const old = this.pages[0] ?? new Uint8Array(this.size * this.size);\n const page = new Uint8Array(size * size);\n for (let row = 0; row < this.size; row += 1) {\n page.set(old.subarray(row * this.size, (row + 1) * this.size), row * size);\n }\n this.size = size;\n this.pages = [page];\n // The whole atlas is sent with what it holds so far\n this.dirty.clear();\n this.upload();\n }\n\n /** A new empty page, after the others; the engine's pages are allocated again only past its capacity */\n private addPage(): void {\n this.pages.push(new Uint8Array(this.size * this.size));\n if (this.pages.length > this.capacity) {\n this.capacity = Math.min(MAX_PAGES, this.capacity * 2);\n // The pages are allocated again: everything is sent, pending changes included\n this.dirty.clear();\n this.upload();\n }\n }\n}\n\n/** A run of text with its own scale (MapLibre's `format` with `font-scale`) and font */\nexport interface TextPart {\n text: string;\n scale?: number;\n font?: string;\n}\n\nexport type { Anchor } from './overlay.ts';\n\nexport interface Shaping {\n /** Glyph quads: x, y, width, height (CSS pixels from the anchor), atlas u0, v0, u1, v1, font scale */\n quads: number[][];\n /** Ink box from the anchor: min x, min y, max x, max y */\n box: [number, number, number, number];\n}\n\n/** Code points of a text, for loading */\nexport function codes(parts: readonly TextPart[]): Set<number> {\n const out = new Set<number>();\n for (const p of parts) for (const ch of p.text) out.add(ch.codePointAt(0) ?? 32);\n return out;\n}\n\n/**\n * Lays out a label: lines split at `\\n` and wrapped at `maxWidth` ems, centered, the block placed by `anchor` around\n * the anchor point and moved by `offset` (ems); `size` in CSS pixels. Glyphs not loaded take no room.\n */\nexport function shape(\n parts: readonly TextPart[],\n glyphsOf: (font: string) => Map<number, Glyph> | undefined,\n options: {\n font: string;\n size: number;\n maxWidth: number;\n lineHeight: number;\n anchor: Anchor;\n offset: [number, number];\n },\n): Shaping {\n const { size, maxWidth, lineHeight, anchor, offset } = options;\n const k = size / EM;\n // Characters with their glyph and scale, split into lines\n type Char = { glyph: Glyph | undefined; scale: number; space: boolean };\n const lines: Char[][] = [[]];\n for (const part of parts) {\n const glyphs = glyphsOf(part.font ?? options.font);\n for (const ch of part.text) {\n if (ch === '\\n') {\n lines.push([]);\n continue;\n }\n const code = ch.codePointAt(0) ?? 32;\n lines.at(-1)?.push({ glyph: glyphs?.get(code), scale: part.scale ?? 1, space: /\\s/.test(ch) });\n }\n }\n const advance = (c: Char) => (c.glyph?.advance ?? (c.space ? EM / 4 : 0)) * c.scale;\n // Wrapping at spaces, greedy\n const limit = maxWidth * EM;\n const wrapped: Char[][] = [];\n for (const line of lines) {\n let current: Char[] = [];\n let width = 0;\n let lastSpace = -1;\n for (const c of line) {\n current.push(c);\n width += advance(c);\n if (c.space) lastSpace = current.length - 1;\n if (width > limit && lastSpace > 0) {\n wrapped.push(current.slice(0, lastSpace));\n current = current.slice(lastSpace + 1);\n width = current.reduce((s, x) => s + advance(x), 0);\n lastSpace = -1;\n }\n }\n wrapped.push(current);\n }\n // Glyphs on their lines, each line centered on x = 0, in units of the 24 px font\n const quads: number[][] = [];\n let [x0, y0, x1, y1] = [\n Number.POSITIVE_INFINITY,\n Number.POSITIVE_INFINITY,\n Number.NEGATIVE_INFINITY,\n Number.NEGATIVE_INFINITY,\n ];\n let baseline = 0;\n wrapped.forEach((line, i) => {\n const scale = Math.max(1, ...line.map((c) => c.scale));\n if (i > 0) baseline += lineHeight * EM * scale;\n const width = line.reduce((s, c) => s + advance(c), 0);\n let pen = -width / 2;\n for (const c of line) {\n const g = c.glyph;\n if (g && g.x !== undefined && g.y !== undefined && g.width > 0) {\n const qx = pen + (g.left - BUFFER) * c.scale;\n const qy = baseline - (g.top + BUFFER) * c.scale;\n const qw = (g.width + 2 * BUFFER) * c.scale;\n const qh = (g.height + 2 * BUFFER) * c.scale;\n quads.push([qx, qy, qw, qh, g.x, g.y, g.x + g.width + 2 * BUFFER, g.y + g.height + 2 * BUFFER, c.scale]);\n x0 = Math.min(x0, qx + BUFFER * c.scale);\n y0 = Math.min(y0, qy + BUFFER * c.scale);\n x1 = Math.max(x1, qx + qw - BUFFER * c.scale);\n y1 = Math.max(y1, qy + qh - BUFFER * c.scale);\n }\n pen += advance(c);\n }\n });\n if (!quads.length) return { quads, box: [0, 0, 0, 0] };\n // The block placed around the anchor by its ink box\n // The side of the box at the anchor: its start, its end, or its middle\n const side = (start: boolean, end: boolean, lo: number, hi: number) => {\n if (start) return -lo;\n if (end) return -hi;\n return -(lo + hi) / 2;\n };\n const horizontal = side(anchor.includes('left'), anchor.includes('right'), x0, x1);\n const vertical = side(anchor.startsWith('top'), anchor.startsWith('bottom'), y0, y1);\n const dx = horizontal + offset[0] * EM;\n const dy = vertical + offset[1] * EM;\n for (const q of quads) {\n q[0] = ((q[0] ?? 0) + dx) * k;\n q[1] = ((q[1] ?? 0) + dy) * k;\n q[2] = (q[2] ?? 0) * k;\n q[3] = (q[3] ?? 0) * k;\n q[8] = (q[8] ?? 1) * k;\n }\n return { quads, box: [(x0 + dx) * k, (y0 + dy) * k, (x1 + dx) * k, (y1 + dy) * k] };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"glyphs.js","sourceRoot":"","sources":["../src/glyphs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Glyphs for the symbol layers: signed distance fields in MapLibre's glyph format (ranges of 256 code points per\n * protobuf file, 24 px glyphs with a 3 px buffer), loaded on first use (from OpenFreeMap's fonts by default, a vector\n * basemap's labels from the glyphs of its style), packed into an atlas the engine samples; and the shaping of a label:\n * its lines (explicit and wrapped), their glyphs placed around the anchor.\n *\n * The atlas has pages of one size: the first one grows up to the page size limit, then pages are added, so it never\n * runs out. A glyph's atlas row counts the rows of the pages before its own (`y + page × size`, the pages stacked):\n * the coordinates of the glyphs placed so far stay valid as the atlas grows.\n */\nimport type { Anchor } from './overlay.ts';\nimport type { Engine } from './wasm/isard.js';\n\n/** OpenFreeMap's fonts, those of its styles (Noto Sans Regular, Bold, Italic) */\nexport const GLYPHS_URL = 'https://tiles.openfreemap.org/fonts/{fontstack}/{range}.pbf';\n\n/** The font of labels that name none */\nexport const DEFAULT_FONT = 'Noto Sans Regular';\n\n/** Size the glyphs are drawn at in the files, and their buffer */\nconst EM = 24;\nconst BUFFER = 3;\n\nexport interface Glyph {\n width: number;\n height: number;\n left: number;\n top: number;\n advance: number;\n /**\n * Place of its bitmap ((width + 6) × (height + 6)) in the atlas, `y` counting the rows of the pages before its\n * own; undefined for an empty one (a space)\n */\n x?: number;\n y?: number;\n /** Its page of the atlas */\n page?: number;\n}\n\n/** Largest side of a page of the atlas, and most pages (WebGL2 guarantees 256 layers of a texture array) */\nconst PAGE_MAX = 2048;\nconst MAX_PAGES = 256;\n\n/** A protobuf reader, enough for the glyph files */\nclass Reader {\n pos = 0;\n constructor(private readonly buf: Uint8Array) {}\n get done(): boolean {\n return this.pos >= this.buf.length;\n }\n varint(): number {\n let value = 0;\n let shift = 0;\n for (;;) {\n const b = this.buf[this.pos++] ?? 0;\n value += (b & 0x7f) * 2 ** shift;\n if (b < 0x80) return value;\n shift += 7;\n }\n }\n sint(): number {\n const v = this.varint();\n return v % 2 === 1 ? -(v + 1) / 2 : v / 2;\n }\n bytes(): Uint8Array {\n const n = this.varint();\n const out = this.buf.subarray(this.pos, this.pos + n);\n this.pos += n;\n return out;\n }\n skip(wire: number): void {\n if (wire === 0) this.varint();\n else if (wire === 2) this.pos += this.varint();\n else if (wire === 5) this.pos += 4;\n else if (wire === 1) this.pos += 8;\n }\n}\n\n/** Glyphs of a range file: id → metrics and bitmap */\nfunction parse(buffer: ArrayBuffer): Map<number, { glyph: Glyph; bitmap: Uint8Array }> {\n const out = new Map<number, { glyph: Glyph; bitmap: Uint8Array }>();\n const root = new Reader(new Uint8Array(buffer));\n while (!root.done) {\n const tag = root.varint();\n if (tag >> 3 !== 1) {\n root.skip(tag & 7);\n continue;\n }\n // A fontstack\n const stack = new Reader(root.bytes());\n while (!stack.done) {\n const t = stack.varint();\n if (t >> 3 !== 3) {\n stack.skip(t & 7);\n continue;\n }\n const g = new Reader(stack.bytes());\n let id = 0;\n let bitmap: Uint8Array = new Uint8Array(0);\n const glyph: Glyph = { width: 0, height: 0, left: 0, top: 0, advance: 0 };\n while (!g.done) {\n const f = g.varint();\n switch (f >> 3) {\n case 1:\n id = g.varint();\n break;\n case 2:\n bitmap = g.bytes();\n break;\n case 3:\n glyph.width = g.varint();\n break;\n case 4:\n glyph.height = g.varint();\n break;\n case 5:\n glyph.left = g.sint();\n break;\n case 6:\n glyph.top = g.sint();\n break;\n case 7:\n glyph.advance = g.varint();\n break;\n default:\n g.skip(f & 7);\n }\n }\n out.set(id, { glyph, bitmap });\n }\n }\n return out;\n}\n\n/** A shelf of the packer: its page, y, height, and the x of the next free place */\ninterface Shelf {\n page: number;\n y: number;\n height: number;\n x: number;\n}\n\n/** The glyphs of a map and their atlas */\nexport class Glyphs {\n /** Side of the pages */\n private size = 512;\n private pages: Uint8Array[] = [new Uint8Array(512 * 512)];\n /** Pages allocated in the engine (doubled when more are needed: fewer reallocations) */\n private capacity = 1;\n private shelves: Shelf[] = [];\n /** Rows of each page holding glyphs (from its top): the rest is blank, never sent */\n private readonly used: number[] = [0];\n private readonly fonts = new Map<string, Map<number, Glyph>>();\n private readonly ranges = new Map<string, Promise<void>>();\n /** Glyph URLs of fonts other than the map's (those of a vector basemap's style) */\n private readonly sources = new Map<string, string>();\n private engine: Engine | undefined;\n /** Rows of each page changed since the last upload: first, end */\n private readonly dirty = new Map<number, [number, number]>();\n /** The atlas has its most pages: new glyphs stay blank */\n private full = false;\n /** Largest side of a page */\n private readonly maxSize: number;\n /** Bumped each time glyphs are added: labels shaped while some of theirs were missing are shaped again */\n version = 0;\n\n /** `maxSize`: the GPU's texture size limit if known (the pages are at most 2048 × 2048) */\n constructor(\n private readonly url = GLYPHS_URL,\n maxSize = 4096,\n ) {\n this.maxSize = Math.max(512, Math.min(PAGE_MAX, maxSize));\n }\n\n /** Sends the whole atlas to an engine (a new one after a context loss) */\n attach(engine: Engine): void {\n this.engine = engine;\n this.dirty.clear();\n this.upload();\n }\n\n /** Side of the pages of the atlas */\n get atlasSize(): number {\n return this.size;\n }\n\n get pageCount(): number {\n return this.pages.length;\n }\n\n /** Loads these fonts from another glyph URL (a style's `glyphs`); a font keeps the first URL given for it */\n register(url: string, fonts: Iterable<string>): void {\n for (const font of fonts) if (!this.sources.has(font)) this.sources.set(font, url);\n }\n\n /** Loads the glyphs of these code points in a font */\n async load(font: string, codes: Iterable<number>): Promise<Map<number, Glyph>> {\n const glyphs = this.fonts.get(font) ?? new Map<number, Glyph>();\n this.fonts.set(font, glyphs);\n const starts = new Set<number>();\n for (const code of codes) if (!glyphs.has(code)) starts.add(Math.floor(code / 256) * 256);\n await Promise.all([...starts].map((start) => this.range(font, start, glyphs)));\n return glyphs;\n }\n\n private range(font: string, start: number, glyphs: Map<number, Glyph>): Promise<void> {\n const key = `${font}/${start}`;\n let pending = this.ranges.get(key);\n if (!pending) {\n const url = (this.sources.get(font) ?? this.url)\n .replace('{fontstack}', encodeURIComponent(font))\n .replace('{range}', `${start}-${start + 255}`);\n pending = fetch(url)\n .then((r) => (r.ok ? r.arrayBuffer() : Promise.reject(new Error(`${url}: ${r.status}`))))\n .then((buffer) => {\n for (const [id, { glyph, bitmap }] of parse(buffer)) {\n if (glyph.width > 0 && bitmap.length >= (glyph.width + 2 * BUFFER) * (glyph.height + 2 * BUFFER)) {\n this.pack(glyph, bitmap);\n }\n glyphs.set(id, glyph);\n }\n this.version += 1;\n // One upload for the range\n this.flush();\n })\n .catch((error: unknown) => {\n // A missing range is not retried this session; its characters stay blank\n console.warn('isard: glyphs', error);\n });\n this.ranges.set(key, pending);\n }\n return pending;\n }\n\n /**\n * Allocates the pages in the engine and sends what they hold (their rows with glyphs). The engine allocates its\n * pages again empty: everything is sent each time, the pages doubled to make it rare\n */\n private upload(): void {\n const engine = this.engine;\n if (!engine) return;\n engine.setGlyphPages(this.size, this.size, this.capacity);\n this.pages.forEach((page, i) => {\n const rows = this.used[i] ?? 0;\n if (rows > 0) engine.updateGlyphPage(i, 0, 0, this.size, rows, page.subarray(0, rows * this.size));\n });\n }\n\n /** Sends the rows changed since the last upload to the engine */\n private flush(): void {\n for (const [page, [y0, y1]] of this.dirty) {\n const data = this.pages[page];\n if (data)\n this.engine?.updateGlyphPage(page, 0, y0, this.size, y1 - y0, data.subarray(y0 * this.size, y1 * this.size));\n }\n this.dirty.clear();\n }\n\n /**\n * Places a bitmap in the atlas (growing the first page, then adding pages when full); `flush` sends it to the\n * engine\n */\n private pack(glyph: Glyph, bitmap: Uint8Array): void {\n const w = glyph.width + 2 * BUFFER;\n const h = glyph.height + 2 * BUFFER;\n // One texel of padding between bitmaps: linear filtering never reads a neighbour\n let shelf = this.shelves.find((s) => s.height >= h && s.height <= h + 4 && s.x + w + 1 <= this.size);\n if (!shelf) {\n const page = this.pages.length - 1;\n // New shelves go on the last page only: the last shelf is on it, unless the page is new\n const last = this.shelves.at(-1);\n const y = last && last.page === page ? last.y + last.height + 1 : 0;\n if (y + h > this.size) {\n if (this.pages.length === 1 && this.size * 2 <= this.maxSize) this.grow();\n else if (this.pages.length < MAX_PAGES) this.addPage();\n else {\n // Full: the glyph takes its room in the text but is not drawn\n if (!this.full) console.warn(`isard: the glyph atlas is full (${MAX_PAGES} pages)`);\n this.full = true;\n return;\n }\n this.pack(glyph, bitmap);\n return;\n }\n shelf = { page, y, height: h, x: 0 };\n this.shelves.push(shelf);\n }\n const data = this.pages[shelf.page];\n if (!data) return;\n glyph.x = shelf.x;\n glyph.y = shelf.page * this.size + shelf.y;\n glyph.page = shelf.page;\n shelf.x += w + 1;\n for (let row = 0; row < h; row += 1) {\n data.set(bitmap.subarray(row * w, row * w + w), (shelf.y + row) * this.size + glyph.x);\n }\n this.used[shelf.page] = Math.max(this.used[shelf.page] ?? 0, shelf.y + h);\n const dirty = this.dirty.get(shelf.page);\n this.dirty.set(shelf.page, [Math.min(dirty?.[0] ?? shelf.y, shelf.y), Math.max(dirty?.[1] ?? 0, shelf.y + h)]);\n }\n\n /** Doubles the only page; the glyphs keep their places (texel coordinates) */\n private grow(): void {\n const size = this.size * 2;\n const old = this.pages[0] ?? new Uint8Array(this.size * this.size);\n const page = new Uint8Array(size * size);\n for (let row = 0; row < this.size; row += 1) {\n page.set(old.subarray(row * this.size, (row + 1) * this.size), row * size);\n }\n this.size = size;\n this.pages = [page];\n // The whole atlas is sent with what it holds so far\n this.dirty.clear();\n this.upload();\n }\n\n /** A new empty page, after the others; the engine's pages are allocated again only past its capacity */\n private addPage(): void {\n this.pages.push(new Uint8Array(this.size * this.size));\n this.used.push(0);\n if (this.pages.length > this.capacity) {\n this.capacity = Math.min(MAX_PAGES, this.capacity * 2);\n // The pages are allocated again: everything is sent, pending changes included\n this.dirty.clear();\n this.upload();\n }\n }\n}\n\n/** A run of text with its own scale (MapLibre's `format` with `font-scale`) and font */\nexport interface TextPart {\n text: string;\n scale?: number;\n font?: string;\n}\n\nexport type { Anchor } from './overlay.ts';\n\nexport interface Shaping {\n /** Glyph quads: x, y, width, height (CSS pixels from the anchor), atlas u0, v0, u1, v1, font scale */\n quads: number[][];\n /** Ink box from the anchor: min x, min y, max x, max y */\n box: [number, number, number, number];\n /** Layout box from the anchor, what an icon fitted to the text frames: the advances of its widest line across, its\n * lines' height (`lineHeight` each) down, centered on the ink */\n layout: [number, number, number, number];\n}\n\n/** Code points of a text, for loading */\nexport function codes(parts: readonly TextPart[]): Set<number> {\n const out = new Set<number>();\n for (const p of parts) for (const ch of p.text) out.add(ch.codePointAt(0) ?? 32);\n return out;\n}\n\n/**\n * Lays out a label: lines split at `\\n` and wrapped at `maxWidth` ems, centered, the block placed by `anchor` around\n * the anchor point and moved by `offset` (ems); `size` in CSS pixels. Glyphs not loaded take no room.\n */\nexport function shape(\n parts: readonly TextPart[],\n glyphsOf: (font: string) => Map<number, Glyph> | undefined,\n options: {\n font: string;\n size: number;\n maxWidth: number;\n lineHeight: number;\n anchor: Anchor;\n offset: [number, number];\n },\n): Shaping {\n const { size, maxWidth, lineHeight, anchor, offset } = options;\n const k = size / EM;\n // Characters with their glyph and scale, split into lines\n type Char = { glyph: Glyph | undefined; scale: number; space: boolean };\n const lines: Char[][] = [[]];\n for (const part of parts) {\n const glyphs = glyphsOf(part.font ?? options.font);\n for (const ch of part.text) {\n if (ch === '\\n') {\n lines.push([]);\n continue;\n }\n const code = ch.codePointAt(0) ?? 32;\n lines.at(-1)?.push({ glyph: glyphs?.get(code), scale: part.scale ?? 1, space: /\\s/.test(ch) });\n }\n }\n const advance = (c: Char) => (c.glyph?.advance ?? (c.space ? EM / 4 : 0)) * c.scale;\n // Wrapping at spaces, greedy\n const limit = maxWidth * EM;\n const wrapped: Char[][] = [];\n for (const line of lines) {\n let current: Char[] = [];\n let width = 0;\n let lastSpace = -1;\n for (const c of line) {\n current.push(c);\n width += advance(c);\n if (c.space) lastSpace = current.length - 1;\n if (width > limit && lastSpace > 0) {\n wrapped.push(current.slice(0, lastSpace));\n current = current.slice(lastSpace + 1);\n width = current.reduce((s, x) => s + advance(x), 0);\n lastSpace = -1;\n }\n }\n wrapped.push(current);\n }\n // Glyphs on their lines, each line centered on x = 0, in units of the 24 px font\n const quads: number[][] = [];\n let [x0, y0, x1, y1] = [\n Number.POSITIVE_INFINITY,\n Number.POSITIVE_INFINITY,\n Number.NEGATIVE_INFINITY,\n Number.NEGATIVE_INFINITY,\n ];\n let baseline = 0;\n let widest = 0;\n let height = 0;\n wrapped.forEach((line, i) => {\n const scale = Math.max(1, ...line.map((c) => c.scale));\n if (i > 0) baseline += lineHeight * EM * scale;\n height += lineHeight * EM * scale;\n const width = line.reduce((s, c) => s + advance(c), 0);\n widest = Math.max(widest, width);\n let pen = -width / 2;\n for (const c of line) {\n const g = c.glyph;\n if (g && g.x !== undefined && g.y !== undefined && g.width > 0) {\n const qx = pen + (g.left - BUFFER) * c.scale;\n const qy = baseline - (g.top + BUFFER) * c.scale;\n const qw = (g.width + 2 * BUFFER) * c.scale;\n const qh = (g.height + 2 * BUFFER) * c.scale;\n quads.push([qx, qy, qw, qh, g.x, g.y, g.x + g.width + 2 * BUFFER, g.y + g.height + 2 * BUFFER, c.scale]);\n x0 = Math.min(x0, qx + BUFFER * c.scale);\n y0 = Math.min(y0, qy + BUFFER * c.scale);\n x1 = Math.max(x1, qx + qw - BUFFER * c.scale);\n y1 = Math.max(y1, qy + qh - BUFFER * c.scale);\n }\n pen += advance(c);\n }\n });\n if (!quads.length) return { quads, box: [0, 0, 0, 0], layout: [0, 0, 0, 0] };\n // The block placed around the anchor by its ink box\n // The side of the box at the anchor: its start, its end, or its middle\n const side = (start: boolean, end: boolean, lo: number, hi: number) => {\n if (start) return -lo;\n if (end) return -hi;\n return -(lo + hi) / 2;\n };\n const horizontal = side(anchor.includes('left'), anchor.includes('right'), x0, x1);\n const vertical = side(anchor.startsWith('top'), anchor.startsWith('bottom'), y0, y1);\n const dx = horizontal + offset[0] * EM;\n const dy = vertical + offset[1] * EM;\n for (const q of quads) {\n q[0] = ((q[0] ?? 0) + dx) * k;\n q[1] = ((q[1] ?? 0) + dy) * k;\n q[2] = (q[2] ?? 0) * k;\n q[3] = (q[3] ?? 0) * k;\n q[8] = (q[8] ?? 1) * k;\n }\n const middle = (y0 + y1) / 2 + dy;\n height = Math.max(height, y1 - y0);\n return {\n quads,\n box: [(x0 + dx) * k, (y0 + dy) * k, (x1 + dx) * k, (y1 + dy) * k],\n layout: [(dx - widest / 2) * k, (middle - height / 2) * k, (dx + widest / 2) * k, (middle + height / 2) * k],\n };\n}\n"]}
|
package/dist/gpx.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GPX to GeoJSON, for the feature layers: `map.addLines({ data: parseGpx(await (await fetch(url)).text()) })`.
|
|
3
|
+
*/
|
|
4
|
+
import type { FeatureCollection, Properties } from './features.ts';
|
|
5
|
+
/**
|
|
6
|
+
* The waypoints, routes and tracks of a GPX file as GeoJSON features: a waypoint as a point (its `time` a property),
|
|
7
|
+
* a route as a line, a track as a line or, of several segments, a multi-line; altitudes (`ele`) as the third
|
|
8
|
+
* coordinate; `name`, `desc`, `cmt`, `type`… as properties, and the times of the points as `times` (one list, or one
|
|
9
|
+
* per segment) when they all have one
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseGpx<P = Properties>(text: string): FeatureCollection<P>;
|
package/dist/gpx.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { child, children, childText, parseXml } from "./xml.js";
|
|
2
|
+
/** The fields of a waypoint, route or track kept as properties when present */
|
|
3
|
+
const FIELDS = ['name', 'cmt', 'desc', 'src', 'sym', 'type', 'number'];
|
|
4
|
+
function properties(element) {
|
|
5
|
+
const out = {};
|
|
6
|
+
for (const key of FIELDS) {
|
|
7
|
+
const value = childText(element, key);
|
|
8
|
+
if (value !== undefined)
|
|
9
|
+
out[key] = key === 'number' ? Number(value) : value;
|
|
10
|
+
}
|
|
11
|
+
const link = child(element, 'link')?.attributes.href;
|
|
12
|
+
if (link !== undefined)
|
|
13
|
+
out.link = link;
|
|
14
|
+
return out;
|
|
15
|
+
}
|
|
16
|
+
/** A point of a GPX file (wpt, rtept, trkpt): its position, its altitude third if any, and its time */
|
|
17
|
+
function point(element) {
|
|
18
|
+
const lon = Number(element.attributes.lon);
|
|
19
|
+
const lat = Number(element.attributes.lat);
|
|
20
|
+
if (!Number.isFinite(lon) || !Number.isFinite(lat) || element.attributes.lon === undefined)
|
|
21
|
+
return undefined;
|
|
22
|
+
const ele = childText(element, 'ele');
|
|
23
|
+
const position = ele !== undefined && Number.isFinite(Number(ele)) ? [lon, lat, Number(ele)] : [lon, lat];
|
|
24
|
+
return { position, time: childText(element, 'time') };
|
|
25
|
+
}
|
|
26
|
+
/** The positions of a line of points, and their times when every point has one */
|
|
27
|
+
function line(points) {
|
|
28
|
+
const read = points.map(point).filter((p) => p !== undefined);
|
|
29
|
+
const times = read.map((p) => p.time);
|
|
30
|
+
return {
|
|
31
|
+
coordinates: read.map((p) => p.position),
|
|
32
|
+
times: read.length > 0 && times.every((t) => t !== undefined) ? times : undefined,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The waypoints, routes and tracks of a GPX file as GeoJSON features: a waypoint as a point (its `time` a property),
|
|
37
|
+
* a route as a line, a track as a line or, of several segments, a multi-line; altitudes (`ele`) as the third
|
|
38
|
+
* coordinate; `name`, `desc`, `cmt`, `type`… as properties, and the times of the points as `times` (one list, or one
|
|
39
|
+
* per segment) when they all have one
|
|
40
|
+
*/
|
|
41
|
+
export function parseGpx(text) {
|
|
42
|
+
const root = parseXml(text);
|
|
43
|
+
const features = [];
|
|
44
|
+
const add = (geometry, props) => features.push({ type: 'Feature', geometry, properties: props });
|
|
45
|
+
for (const wpt of children(root, 'wpt')) {
|
|
46
|
+
const p = point(wpt);
|
|
47
|
+
if (!p)
|
|
48
|
+
continue;
|
|
49
|
+
add({ type: 'Point', coordinates: p.position }, { ...properties(wpt), ...(p.time ? { time: p.time } : {}) });
|
|
50
|
+
}
|
|
51
|
+
for (const rte of children(root, 'rte')) {
|
|
52
|
+
const { coordinates, times } = line(children(rte, 'rtept'));
|
|
53
|
+
if (coordinates.length >= 2)
|
|
54
|
+
add({ type: 'LineString', coordinates }, { ...properties(rte), ...(times ? { times } : {}) });
|
|
55
|
+
}
|
|
56
|
+
for (const trk of children(root, 'trk')) {
|
|
57
|
+
const segments = children(trk, 'trkseg')
|
|
58
|
+
.map((s) => line(children(s, 'trkpt')))
|
|
59
|
+
.filter((s) => s.coordinates.length >= 2);
|
|
60
|
+
const [first] = segments;
|
|
61
|
+
if (!first)
|
|
62
|
+
continue;
|
|
63
|
+
const props = properties(trk);
|
|
64
|
+
if (segments.length === 1) {
|
|
65
|
+
add({ type: 'LineString', coordinates: first.coordinates }, { ...props, ...(first.times ? { times: first.times } : {}) });
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
const times = segments.every((s) => s.times) ? { times: segments.map((s) => s.times) } : {};
|
|
69
|
+
add({ type: 'MultiLineString', coordinates: segments.map((s) => s.coordinates) }, { ...props, ...times });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return { type: 'FeatureCollection', features };
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=gpx.js.map
|
package/dist/gpx.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gpx.js","sourceRoot":"","sources":["../src/gpx.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * GPX to GeoJSON, for the feature layers: `map.addLines({ data: parseGpx(await (await fetch(url)).text()) })`.\n */\nimport type { Feature, FeatureCollection, Geometry, Position, Properties } from './features.ts';\nimport { child, children, childText, parseXml, type XmlElement } from './xml.ts';\n\n/** The fields of a waypoint, route or track kept as properties when present */\nconst FIELDS = ['name', 'cmt', 'desc', 'src', 'sym', 'type', 'number'];\n\nfunction properties(element: XmlElement): Properties {\n const out: Properties = {};\n for (const key of FIELDS) {\n const value = childText(element, key);\n if (value !== undefined) out[key] = key === 'number' ? Number(value) : value;\n }\n const link = child(element, 'link')?.attributes.href;\n if (link !== undefined) out.link = link;\n return out;\n}\n\n/** A point of a GPX file (wpt, rtept, trkpt): its position, its altitude third if any, and its time */\nfunction point(element: XmlElement): { position: Position; time: string | undefined } | undefined {\n const lon = Number(element.attributes.lon);\n const lat = Number(element.attributes.lat);\n if (!Number.isFinite(lon) || !Number.isFinite(lat) || element.attributes.lon === undefined) return undefined;\n const ele = childText(element, 'ele');\n const position: Position = ele !== undefined && Number.isFinite(Number(ele)) ? [lon, lat, Number(ele)] : [lon, lat];\n return { position, time: childText(element, 'time') };\n}\n\n/** The positions of a line of points, and their times when every point has one */\nfunction line(points: XmlElement[]): { coordinates: Position[]; times: string[] | undefined } {\n const read = points.map(point).filter((p) => p !== undefined);\n const times = read.map((p) => p.time);\n return {\n coordinates: read.map((p) => p.position),\n times: read.length > 0 && times.every((t) => t !== undefined) ? (times as string[]) : undefined,\n };\n}\n\n/**\n * The waypoints, routes and tracks of a GPX file as GeoJSON features: a waypoint as a point (its `time` a property),\n * a route as a line, a track as a line or, of several segments, a multi-line; altitudes (`ele`) as the third\n * coordinate; `name`, `desc`, `cmt`, `type`… as properties, and the times of the points as `times` (one list, or one\n * per segment) when they all have one\n */\nexport function parseGpx<P = Properties>(text: string): FeatureCollection<P> {\n const root = parseXml(text);\n const features: Feature<P>[] = [];\n const add = (geometry: Geometry, props: Properties) =>\n features.push({ type: 'Feature', geometry, properties: props as P });\n for (const wpt of children(root, 'wpt')) {\n const p = point(wpt);\n if (!p) continue;\n add({ type: 'Point', coordinates: p.position }, { ...properties(wpt), ...(p.time ? { time: p.time } : {}) });\n }\n for (const rte of children(root, 'rte')) {\n const { coordinates, times } = line(children(rte, 'rtept'));\n if (coordinates.length >= 2)\n add({ type: 'LineString', coordinates }, { ...properties(rte), ...(times ? { times } : {}) });\n }\n for (const trk of children(root, 'trk')) {\n const segments = children(trk, 'trkseg')\n .map((s) => line(children(s, 'trkpt')))\n .filter((s) => s.coordinates.length >= 2);\n const [first] = segments;\n if (!first) continue;\n const props = properties(trk);\n if (segments.length === 1) {\n add(\n { type: 'LineString', coordinates: first.coordinates },\n { ...props, ...(first.times ? { times: first.times } : {}) },\n );\n } else {\n const times = segments.every((s) => s.times) ? { times: segments.map((s) => s.times) } : {};\n add({ type: 'MultiLineString', coordinates: segments.map((s) => s.coordinates) }, { ...props, ...times });\n }\n }\n return { type: 'FeatureCollection', features };\n}\n"]}
|