@maptiler/sdk 1.2.1 → 2.0.1
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/.eslintrc.cjs +1 -0
- package/dist/maptiler-sdk.css +1 -1
- package/dist/maptiler-sdk.d.ts +171 -240
- package/dist/maptiler-sdk.min.mjs +3 -3
- package/dist/maptiler-sdk.mjs +461 -458
- package/dist/maptiler-sdk.mjs.map +1 -1
- package/package.json +3 -3
- package/readme.md +16 -1
- package/CHANGELOG.md +0 -168
- package/colorramp.md +0 -93
- package/dist/maptiler-sdk.umd.js +0 -7702
- package/dist/maptiler-sdk.umd.js.map +0 -1
- package/dist/maptiler-sdk.umd.min.js +0 -582
- package/src/AttributionControl.ts +0 -13
- package/src/CanvasSource.ts +0 -13
- package/src/FullscreenControl.ts +0 -13
- package/src/GeoJSONSource.ts +0 -13
- package/src/GeolocateControl.ts +0 -13
- package/src/ImageSource.ts +0 -13
- package/src/LogoControl.ts +0 -13
- package/src/Map.ts +0 -1352
- package/src/MaptilerGeolocateControl.ts +0 -207
- package/src/MaptilerLogoControl.ts +0 -58
- package/src/MaptilerNavigationControl.ts +0 -69
- package/src/MaptilerTerrainControl.ts +0 -72
- package/src/Marker.ts +0 -13
- package/src/Minimap.ts +0 -373
- package/src/NavigationControl.ts +0 -13
- package/src/Point.ts +0 -334
- package/src/Popup.ts +0 -13
- package/src/RasterDEMTileSource.ts +0 -13
- package/src/RasterTileSource.ts +0 -13
- package/src/ScaleControl.ts +0 -13
- package/src/Style.ts +0 -13
- package/src/TerrainControl.ts +0 -13
- package/src/VectorTileSource.ts +0 -13
- package/src/VideoSource.ts +0 -13
- package/src/colorramp.ts +0 -1216
- package/src/config.ts +0 -96
- package/src/converters/index.ts +0 -1
- package/src/converters/xml.ts +0 -681
- package/src/defaults.ts +0 -20
- package/src/helpers/index.ts +0 -27
- package/src/helpers/stylehelper.ts +0 -395
- package/src/helpers/vectorlayerhelpers.ts +0 -1511
- package/src/index.ts +0 -201
- package/src/language.ts +0 -183
- package/src/mapstyle.ts +0 -46
- package/src/style/style_template.css +0 -146
- package/src/style/svg/v6-compass.svg +0 -12
- package/src/style/svg/v6-fullscreen-off.svg +0 -7
- package/src/style/svg/v6-fullscreen.svg +0 -7
- package/src/style/svg/v6-geolocate-active-error.svg +0 -10
- package/src/style/svg/v6-geolocate-active.svg +0 -7
- package/src/style/svg/v6-geolocate-background.svg +0 -8
- package/src/style/svg/v6-geolocate-disabled.svg +0 -10
- package/src/style/svg/v6-geolocate.svg +0 -7
- package/src/style/svg/v6-terrain-on.svg +0 -7
- package/src/style/svg/v6-terrain.svg +0 -7
- package/src/style/svg/v6-zoom-minus.svg +0 -7
- package/src/style/svg/v6-zoom-plus.svg +0 -7
- package/src/tools.ts +0 -171
- package/src/unit.ts +0 -1
package/src/converters/xml.ts
DELETED
|
@@ -1,681 +0,0 @@
|
|
|
1
|
-
// Typescript port of https://github.com/mapbox/togeojson/
|
|
2
|
-
// This includes KML and GPX parsing to GeoJSON
|
|
3
|
-
|
|
4
|
-
export interface Link {
|
|
5
|
-
href: string | null;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface XMLProperties {
|
|
9
|
-
links?: Link[];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface PlacemarkProperties {
|
|
13
|
-
name?: string;
|
|
14
|
-
address?: string;
|
|
15
|
-
styleUrl?: string;
|
|
16
|
-
description?: string;
|
|
17
|
-
styleHash?: string;
|
|
18
|
-
styleMapHash?: Record<string, string | null>;
|
|
19
|
-
timespan?: {
|
|
20
|
-
begin: string;
|
|
21
|
-
end: string;
|
|
22
|
-
};
|
|
23
|
-
timestamp?: string;
|
|
24
|
-
stroke?: string;
|
|
25
|
-
"stroke-opacity"?: number;
|
|
26
|
-
"stroke-width"?: number;
|
|
27
|
-
fill?: string;
|
|
28
|
-
"fill-opacity"?: number;
|
|
29
|
-
visibility?: string;
|
|
30
|
-
icon?: string;
|
|
31
|
-
coordTimes?: (string | null)[] | (string | null)[][];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* create a function that converts a string to XML
|
|
36
|
-
* https://developer.mozilla.org/en-US/docs/Web/API/DOMParser
|
|
37
|
-
*/
|
|
38
|
-
export function str2xml(str: string): Document {
|
|
39
|
-
if (typeof DOMParser !== "undefined") {
|
|
40
|
-
const doc = new DOMParser().parseFromString(str, "application/xml");
|
|
41
|
-
|
|
42
|
-
// If the input string was not valid XML
|
|
43
|
-
if (doc.querySelector("parsererror")) {
|
|
44
|
-
throw new Error("The provided string is not valid XML");
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return doc;
|
|
48
|
-
} else {
|
|
49
|
-
throw new Error("No XML parser found");
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Check one of the top level child node is of a given type ("gpx", "kml").
|
|
55
|
-
* The check is not case sensitive.
|
|
56
|
-
* @param doc
|
|
57
|
-
* @param nodeName
|
|
58
|
-
* @returns
|
|
59
|
-
*/
|
|
60
|
-
export function hasChildNodeWithName(doc: Document, nodeName: string): boolean {
|
|
61
|
-
if (!doc.hasChildNodes()) {
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
for (const childNode of Array.from(doc.childNodes)) {
|
|
66
|
-
const currentNodeName = childNode.nodeName;
|
|
67
|
-
if (
|
|
68
|
-
typeof currentNodeName === "string" &&
|
|
69
|
-
currentNodeName.trim().toLowerCase() === nodeName.toLowerCase()
|
|
70
|
-
) {
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* create a function that converts a XML to a string
|
|
80
|
-
* https://developer.mozilla.org/en-US/docs/Web/API/XMLSerializer
|
|
81
|
-
*/
|
|
82
|
-
export function xml2str(node: Node): string {
|
|
83
|
-
if (typeof XMLSerializer !== "undefined") {
|
|
84
|
-
return new XMLSerializer().serializeToString(node);
|
|
85
|
-
}
|
|
86
|
-
throw new Error("No XML serializer found");
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Given a XML document using the GPX spec, return GeoJSON
|
|
91
|
-
*/
|
|
92
|
-
export function gpx(doc: string | Document): GeoJSON.FeatureCollection {
|
|
93
|
-
if (typeof doc === "string") doc = str2xml(doc);
|
|
94
|
-
// doc.firstChild
|
|
95
|
-
// The document is valid XML but not valid GPX (at leas the first node is not)
|
|
96
|
-
if (!hasChildNodeWithName(doc, "gpx")) {
|
|
97
|
-
throw new Error("The XML document is not valid GPX");
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const tracks = get(doc, "trk");
|
|
101
|
-
const routes = get(doc, "rte");
|
|
102
|
-
const waypoints = get(doc, "wpt");
|
|
103
|
-
// a feature collection
|
|
104
|
-
const gj: GeoJSON.FeatureCollection = {
|
|
105
|
-
type: "FeatureCollection",
|
|
106
|
-
features: [],
|
|
107
|
-
};
|
|
108
|
-
for (const track of Array.from(tracks)) {
|
|
109
|
-
const feature = getTrack(track);
|
|
110
|
-
if (feature) gj.features.push(feature);
|
|
111
|
-
}
|
|
112
|
-
for (const route of Array.from(routes)) {
|
|
113
|
-
const feature = getRoute(route);
|
|
114
|
-
if (feature) gj.features.push(feature);
|
|
115
|
-
}
|
|
116
|
-
for (const waypoint of Array.from(waypoints)) {
|
|
117
|
-
gj.features.push(getPoint(waypoint));
|
|
118
|
-
}
|
|
119
|
-
return gj;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Given a XML document using the KML spec, return GeoJSON
|
|
124
|
-
*/
|
|
125
|
-
export function kml(
|
|
126
|
-
doc: string | Document,
|
|
127
|
-
xml2string?: (node: Node) => string,
|
|
128
|
-
): GeoJSON.FeatureCollection {
|
|
129
|
-
if (typeof doc === "string") doc = str2xml(doc);
|
|
130
|
-
|
|
131
|
-
// The document is valid XML but not valid KML (at leas the first node is not)
|
|
132
|
-
if (!hasChildNodeWithName(doc, "kml")) {
|
|
133
|
-
throw new Error("The XML document is not valid KML");
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const gj: GeoJSON.FeatureCollection = {
|
|
137
|
-
type: "FeatureCollection",
|
|
138
|
-
features: [],
|
|
139
|
-
};
|
|
140
|
-
// styleindex keeps track of hashed styles in order to match features
|
|
141
|
-
const styleIndex: Record<string, string> = {};
|
|
142
|
-
const styleByHash: Record<string, Element> = {};
|
|
143
|
-
// stylemapindex keeps track of style maps to expose in properties
|
|
144
|
-
const styleMapIndex: Record<string, Record<string, string | null>> = {};
|
|
145
|
-
// all root placemarks in the file
|
|
146
|
-
const placemarks = get(doc, "Placemark");
|
|
147
|
-
const styles = get(doc, "Style");
|
|
148
|
-
const styleMaps = get(doc, "StyleMap");
|
|
149
|
-
|
|
150
|
-
for (const style of Array.from(styles)) {
|
|
151
|
-
const hash = okhash(
|
|
152
|
-
xml2string !== undefined ? xml2string(style) : xml2str(style),
|
|
153
|
-
).toString(16);
|
|
154
|
-
styleIndex["#" + attr(style, "id")] = hash;
|
|
155
|
-
styleByHash[hash] = style;
|
|
156
|
-
}
|
|
157
|
-
for (const styleMap of Array.from(styleMaps)) {
|
|
158
|
-
styleIndex["#" + attr(styleMap, "id")] = okhash(
|
|
159
|
-
xml2string !== undefined ? xml2string(styleMap) : xml2str(styleMap),
|
|
160
|
-
).toString(16);
|
|
161
|
-
const pairs = get(styleMap, "Pair");
|
|
162
|
-
const pairsMap: Record<string, string | null> = {};
|
|
163
|
-
for (const pair of Array.from(pairs)) {
|
|
164
|
-
pairsMap[nodeVal(get1(pair, "key")) ?? ""] = nodeVal(
|
|
165
|
-
get1(pair, "styleUrl"),
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
styleMapIndex["#" + attr(styleMap, "id")] = pairsMap;
|
|
169
|
-
}
|
|
170
|
-
for (const placemark of Array.from(placemarks)) {
|
|
171
|
-
gj.features = gj.features.concat(
|
|
172
|
-
getPlacemark(placemark, styleIndex, styleByHash, styleMapIndex),
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
return gj;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// parse color string to hex string with opacity. black with 100% opacity will be returned if no data found
|
|
179
|
-
function kmlColor(v: string | null): [string, number] {
|
|
180
|
-
if (v === null) return ["#000000", 1];
|
|
181
|
-
let color = "";
|
|
182
|
-
let opacity = 1;
|
|
183
|
-
if (v.substring(0, 1) === "#") v = v.substring(1);
|
|
184
|
-
if (v.length === 6 || v.length === 3) color = v;
|
|
185
|
-
if (v.length === 8) {
|
|
186
|
-
opacity = parseInt(v.substring(0, 2), 16) / 255;
|
|
187
|
-
color = "#" + v.substring(6, 8) + v.substring(4, 6) + v.substring(2, 4);
|
|
188
|
-
}
|
|
189
|
-
return [color ?? "#000000", opacity ?? 1];
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function gxCoord(v: string): number[] {
|
|
193
|
-
return numarray(v.split(" "));
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// grab coordinates and timestamps (when available) from the gx:Track extension
|
|
197
|
-
function gxCoords(root: Document | Element): {
|
|
198
|
-
coords: number[][];
|
|
199
|
-
times: (string | null)[];
|
|
200
|
-
} {
|
|
201
|
-
let elems = get(root, "coord");
|
|
202
|
-
const coords: number[][] = [];
|
|
203
|
-
const times: (string | null)[] = [];
|
|
204
|
-
if (elems.length === 0) elems = get(root, "gx:coord");
|
|
205
|
-
for (const elem of Array.from(elems)) {
|
|
206
|
-
coords.push(gxCoord(nodeVal(elem) ?? ""));
|
|
207
|
-
}
|
|
208
|
-
const timeElems = get(root, "when");
|
|
209
|
-
for (const timeElem of Array.from(timeElems)) times.push(nodeVal(timeElem));
|
|
210
|
-
return {
|
|
211
|
-
coords: coords,
|
|
212
|
-
times,
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// get the geometry data and coordinate timestamps if available
|
|
217
|
-
function getGeometry(root: Element): {
|
|
218
|
-
geoms: GeoJSON.Geometry[];
|
|
219
|
-
coordTimes: (string | null)[][];
|
|
220
|
-
} {
|
|
221
|
-
// atomic geospatial types supported by KML - MultiGeometry is
|
|
222
|
-
// handled separately
|
|
223
|
-
const geotypes = ["Polygon", "LineString", "Point", "Track", "gx:Track"];
|
|
224
|
-
// setup variables
|
|
225
|
-
let geomNode, geomNodes, i, j, k;
|
|
226
|
-
const geoms: GeoJSON.Geometry[] = [];
|
|
227
|
-
const coordTimes: (string | null)[][] = [];
|
|
228
|
-
// simple cases
|
|
229
|
-
if (get1(root, "MultiGeometry") !== null) {
|
|
230
|
-
return getGeometry(get1(root, "MultiGeometry") as Element);
|
|
231
|
-
}
|
|
232
|
-
if (get1(root, "MultiTrack") !== null) {
|
|
233
|
-
return getGeometry(get1(root, "MultiTrack") as Element);
|
|
234
|
-
}
|
|
235
|
-
if (get1(root, "gx:MultiTrack") !== null) {
|
|
236
|
-
return getGeometry(get1(root, "gx:MultiTrack") as Element);
|
|
237
|
-
}
|
|
238
|
-
for (i = 0; i < geotypes.length; i++) {
|
|
239
|
-
geomNodes = get(root, geotypes[i]);
|
|
240
|
-
if (geomNodes) {
|
|
241
|
-
for (j = 0; j < geomNodes.length; j++) {
|
|
242
|
-
geomNode = geomNodes[j];
|
|
243
|
-
if (geotypes[i] === "Point") {
|
|
244
|
-
geoms.push({
|
|
245
|
-
type: "Point",
|
|
246
|
-
coordinates: coord1(nodeVal(get1(geomNode, "coordinates")) ?? ""),
|
|
247
|
-
});
|
|
248
|
-
} else if (geotypes[i] === "LineString") {
|
|
249
|
-
geoms.push({
|
|
250
|
-
type: "LineString",
|
|
251
|
-
coordinates: coord(nodeVal(get1(geomNode, "coordinates")) ?? ""),
|
|
252
|
-
});
|
|
253
|
-
} else if (geotypes[i] === "Polygon") {
|
|
254
|
-
const rings = get(geomNode, "LinearRing");
|
|
255
|
-
const coords = [];
|
|
256
|
-
for (k = 0; k < rings.length; k++) {
|
|
257
|
-
coords.push(coord(nodeVal(get1(rings[k], "coordinates")) ?? ""));
|
|
258
|
-
}
|
|
259
|
-
geoms.push({
|
|
260
|
-
type: "Polygon",
|
|
261
|
-
coordinates: coords,
|
|
262
|
-
});
|
|
263
|
-
} else if (geotypes[i] === "Track" || geotypes[i] === "gx:Track") {
|
|
264
|
-
const track = gxCoords(geomNode);
|
|
265
|
-
geoms.push({
|
|
266
|
-
type: "LineString",
|
|
267
|
-
coordinates: track.coords,
|
|
268
|
-
});
|
|
269
|
-
if (track.times.length) coordTimes.push(track.times);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
return { geoms, coordTimes };
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// build geojson feature sets with all their attributes and property data
|
|
278
|
-
function getPlacemark(
|
|
279
|
-
root: Element,
|
|
280
|
-
styleIndex: Record<string, string>,
|
|
281
|
-
styleByHash: Record<string, Element>,
|
|
282
|
-
styleMapIndex: Record<string, Record<string, string | null>>,
|
|
283
|
-
) {
|
|
284
|
-
const geomsAndTimes = getGeometry(root);
|
|
285
|
-
const properties: PlacemarkProperties & Record<string, string> = {};
|
|
286
|
-
const name = nodeVal(get1(root, "name"));
|
|
287
|
-
const address = nodeVal(get1(root, "address"));
|
|
288
|
-
const description = nodeVal(get1(root, "description"));
|
|
289
|
-
const timeSpan = get1(root, "TimeSpan");
|
|
290
|
-
const timeStamp = get1(root, "TimeStamp");
|
|
291
|
-
const extendedData = get1(root, "ExtendedData");
|
|
292
|
-
const visibility = get1(root, "visibility");
|
|
293
|
-
|
|
294
|
-
let i: number;
|
|
295
|
-
let styleUrl = nodeVal(get1(root, "styleUrl"));
|
|
296
|
-
let lineStyle = get1(root, "LineStyle");
|
|
297
|
-
let polyStyle = get1(root, "PolyStyle");
|
|
298
|
-
|
|
299
|
-
if (!geomsAndTimes.geoms.length) return [];
|
|
300
|
-
if (name) properties.name = name;
|
|
301
|
-
if (address) properties.address = address;
|
|
302
|
-
if (styleUrl) {
|
|
303
|
-
if (styleUrl[0] !== "#") styleUrl = "#" + styleUrl;
|
|
304
|
-
|
|
305
|
-
properties.styleUrl = styleUrl;
|
|
306
|
-
if (styleIndex[styleUrl]) {
|
|
307
|
-
properties.styleHash = styleIndex[styleUrl];
|
|
308
|
-
}
|
|
309
|
-
if (styleMapIndex[styleUrl]) {
|
|
310
|
-
properties.styleMapHash = styleMapIndex[styleUrl];
|
|
311
|
-
properties.styleHash = styleIndex[styleMapIndex[styleUrl].normal ?? ""];
|
|
312
|
-
}
|
|
313
|
-
// Try to populate the lineStyle or polyStyle since we got the style hash
|
|
314
|
-
const style = styleByHash[properties.styleHash ?? ""];
|
|
315
|
-
if (style) {
|
|
316
|
-
if (!lineStyle) lineStyle = get1(style, "LineStyle");
|
|
317
|
-
if (!polyStyle) polyStyle = get1(style, "PolyStyle");
|
|
318
|
-
const iconStyle = get1(style, "IconStyle");
|
|
319
|
-
if (iconStyle) {
|
|
320
|
-
const icon = get1(iconStyle, "Icon");
|
|
321
|
-
if (icon) {
|
|
322
|
-
const href = nodeVal(get1(icon, "href"));
|
|
323
|
-
if (href) properties.icon = href;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
if (description) properties.description = description;
|
|
329
|
-
if (timeSpan) {
|
|
330
|
-
const begin = nodeVal(get1(timeSpan, "begin"));
|
|
331
|
-
const end = nodeVal(get1(timeSpan, "end"));
|
|
332
|
-
if (begin && end) properties.timespan = { begin, end };
|
|
333
|
-
}
|
|
334
|
-
if (timeStamp !== null) {
|
|
335
|
-
properties.timestamp =
|
|
336
|
-
nodeVal(get1(timeStamp, "when")) ?? new Date().toISOString();
|
|
337
|
-
}
|
|
338
|
-
if (lineStyle !== null) {
|
|
339
|
-
const linestyles = kmlColor(nodeVal(get1(lineStyle, "color")));
|
|
340
|
-
const color = linestyles[0];
|
|
341
|
-
const opacity = linestyles[1];
|
|
342
|
-
const width = parseFloat(nodeVal(get1(lineStyle, "width")) ?? "");
|
|
343
|
-
if (color) properties.stroke = color;
|
|
344
|
-
if (!isNaN(opacity)) properties["stroke-opacity"] = opacity;
|
|
345
|
-
if (!isNaN(width)) properties["stroke-width"] = width;
|
|
346
|
-
}
|
|
347
|
-
if (polyStyle) {
|
|
348
|
-
const polystyles = kmlColor(nodeVal(get1(polyStyle, "color")));
|
|
349
|
-
const pcolor = polystyles[0];
|
|
350
|
-
const popacity = polystyles[1];
|
|
351
|
-
const fill = nodeVal(get1(polyStyle, "fill"));
|
|
352
|
-
const outline = nodeVal(get1(polyStyle, "outline"));
|
|
353
|
-
if (pcolor) properties.fill = pcolor;
|
|
354
|
-
if (!isNaN(popacity)) properties["fill-opacity"] = popacity;
|
|
355
|
-
if (fill)
|
|
356
|
-
properties["fill-opacity"] =
|
|
357
|
-
fill === "1" ? properties["fill-opacity"] || 1 : 0;
|
|
358
|
-
if (outline)
|
|
359
|
-
properties["stroke-opacity"] =
|
|
360
|
-
outline === "1" ? properties["stroke-opacity"] || 1 : 0;
|
|
361
|
-
}
|
|
362
|
-
if (extendedData) {
|
|
363
|
-
const datas = get(extendedData, "Data"),
|
|
364
|
-
simpleDatas = get(extendedData, "SimpleData");
|
|
365
|
-
|
|
366
|
-
for (i = 0; i < datas.length; i++) {
|
|
367
|
-
properties[datas[i].getAttribute("name") ?? ""] =
|
|
368
|
-
nodeVal(get1(datas[i], "value")) ?? "";
|
|
369
|
-
}
|
|
370
|
-
for (i = 0; i < simpleDatas.length; i++) {
|
|
371
|
-
properties[simpleDatas[i].getAttribute("name") ?? ""] =
|
|
372
|
-
nodeVal(simpleDatas[i]) ?? "";
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
if (visibility !== null) {
|
|
376
|
-
properties.visibility = nodeVal(visibility) ?? "";
|
|
377
|
-
}
|
|
378
|
-
if (geomsAndTimes.coordTimes.length !== 0) {
|
|
379
|
-
properties.coordTimes =
|
|
380
|
-
geomsAndTimes.coordTimes.length === 1
|
|
381
|
-
? geomsAndTimes.coordTimes[0]
|
|
382
|
-
: geomsAndTimes.coordTimes;
|
|
383
|
-
}
|
|
384
|
-
const feature: GeoJSON.Feature = {
|
|
385
|
-
type: "Feature",
|
|
386
|
-
geometry:
|
|
387
|
-
geomsAndTimes.geoms.length === 1
|
|
388
|
-
? geomsAndTimes.geoms[0]
|
|
389
|
-
: {
|
|
390
|
-
type: "GeometryCollection",
|
|
391
|
-
geometries: geomsAndTimes.geoms,
|
|
392
|
-
},
|
|
393
|
-
properties: properties,
|
|
394
|
-
};
|
|
395
|
-
if (attr(root, "id")) feature.id = attr(root, "id") ?? undefined;
|
|
396
|
-
return [feature];
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
function getPoints(
|
|
400
|
-
node: Element,
|
|
401
|
-
pointname: string,
|
|
402
|
-
):
|
|
403
|
-
| undefined
|
|
404
|
-
| {
|
|
405
|
-
line: number[][];
|
|
406
|
-
times: string[];
|
|
407
|
-
heartRates: (number | null)[];
|
|
408
|
-
} {
|
|
409
|
-
const pts = get(node, pointname);
|
|
410
|
-
const line: number[][] = [];
|
|
411
|
-
const times: string[] = [];
|
|
412
|
-
let heartRates: (number | null)[] = [];
|
|
413
|
-
const ptsLength = pts.length;
|
|
414
|
-
if (ptsLength < 2) return; // Invalid line in GeoJSON
|
|
415
|
-
for (let i = 0; i < ptsLength; i++) {
|
|
416
|
-
const cPair = coordPair(pts[i]);
|
|
417
|
-
line.push(cPair.coordinates);
|
|
418
|
-
if (cPair.time) times.push(cPair.time);
|
|
419
|
-
if (cPair.heartRate || heartRates.length) {
|
|
420
|
-
if (heartRates.length === 0) heartRates = new Array(i).fill(null);
|
|
421
|
-
heartRates.push(cPair.heartRate);
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
return {
|
|
425
|
-
line: line,
|
|
426
|
-
times: times,
|
|
427
|
-
heartRates,
|
|
428
|
-
};
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
function getTrack(node: Element): undefined | GeoJSON.Feature {
|
|
432
|
-
const segments = get(node, "trkseg");
|
|
433
|
-
const track = [];
|
|
434
|
-
const times = [];
|
|
435
|
-
const heartRates: (number | null)[][] = [];
|
|
436
|
-
let line;
|
|
437
|
-
for (let i = 0; i < segments.length; i++) {
|
|
438
|
-
line = getPoints(segments[i], "trkpt");
|
|
439
|
-
if (line !== undefined) {
|
|
440
|
-
if (line.line) track.push(line.line);
|
|
441
|
-
if (line.times && line.times.length) times.push(line.times);
|
|
442
|
-
if (heartRates.length || (line.heartRates && line.heartRates.length)) {
|
|
443
|
-
if (!heartRates.length) {
|
|
444
|
-
for (let s = 0; s < i; s++) {
|
|
445
|
-
heartRates.push(new Array(track[s].length).fill(null));
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
if (line.heartRates && line.heartRates.length) {
|
|
449
|
-
heartRates.push(line.heartRates);
|
|
450
|
-
} else {
|
|
451
|
-
heartRates.push(new Array(line.line.length).fill(null));
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
if (track.length === 0) return;
|
|
457
|
-
const properties: {
|
|
458
|
-
coordTimes?: string[] | string[][];
|
|
459
|
-
heartRates?: (number | null)[] | (number | null)[][];
|
|
460
|
-
} & XMLProperties &
|
|
461
|
-
Record<string, string | number> = {
|
|
462
|
-
...getProperties(node),
|
|
463
|
-
...getLineStyle(get1(node, "extensions")),
|
|
464
|
-
};
|
|
465
|
-
if (times.length !== 0)
|
|
466
|
-
properties.coordTimes = track.length === 1 ? times[0] : times;
|
|
467
|
-
if (heartRates.length !== 0) {
|
|
468
|
-
properties.heartRates = track.length === 1 ? heartRates[0] : heartRates;
|
|
469
|
-
}
|
|
470
|
-
if (track.length === 1) {
|
|
471
|
-
return {
|
|
472
|
-
type: "Feature",
|
|
473
|
-
properties,
|
|
474
|
-
geometry: {
|
|
475
|
-
type: "LineString",
|
|
476
|
-
coordinates: track[0],
|
|
477
|
-
},
|
|
478
|
-
};
|
|
479
|
-
} else {
|
|
480
|
-
return {
|
|
481
|
-
type: "Feature",
|
|
482
|
-
properties,
|
|
483
|
-
geometry: {
|
|
484
|
-
type: "MultiLineString",
|
|
485
|
-
coordinates: track,
|
|
486
|
-
},
|
|
487
|
-
};
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
function getRoute(node: Element): GeoJSON.Feature | undefined {
|
|
492
|
-
const line = getPoints(node, "rtept");
|
|
493
|
-
if (line === undefined) return;
|
|
494
|
-
const prop = {
|
|
495
|
-
...getProperties(node),
|
|
496
|
-
...getLineStyle(get1(node, "extensions")),
|
|
497
|
-
};
|
|
498
|
-
return {
|
|
499
|
-
type: "Feature",
|
|
500
|
-
properties: prop,
|
|
501
|
-
geometry: {
|
|
502
|
-
type: "LineString",
|
|
503
|
-
coordinates: line.line,
|
|
504
|
-
},
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
function getPoint(node: Element): GeoJSON.Feature {
|
|
509
|
-
const prop = { ...getProperties(node), ...getMulti(node, ["sym"]) };
|
|
510
|
-
return {
|
|
511
|
-
type: "Feature",
|
|
512
|
-
properties: prop,
|
|
513
|
-
geometry: {
|
|
514
|
-
type: "Point",
|
|
515
|
-
coordinates: coordPair(node).coordinates,
|
|
516
|
-
},
|
|
517
|
-
};
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
function getLineStyle(
|
|
521
|
-
extensions: Element | null,
|
|
522
|
-
): Record<string, string | number> {
|
|
523
|
-
const style: Record<string, string | number> = {};
|
|
524
|
-
if (extensions) {
|
|
525
|
-
const lineStyle = get1(extensions, "line");
|
|
526
|
-
if (lineStyle) {
|
|
527
|
-
const color = nodeVal(get1(lineStyle, "color"));
|
|
528
|
-
const opacity = parseFloat(nodeVal(get1(lineStyle, "opacity")) ?? "0");
|
|
529
|
-
const width = parseFloat(nodeVal(get1(lineStyle, "width")) ?? "0");
|
|
530
|
-
if (color) style.stroke = color;
|
|
531
|
-
if (!isNaN(opacity)) style["stroke-opacity"] = opacity;
|
|
532
|
-
// GPX width is in mm, convert to px with 96 px per inch
|
|
533
|
-
if (!isNaN(width)) style["stroke-width"] = (width * 96) / 25.4;
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
return style;
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
function getProperties(node: Element): XMLProperties & Record<string, string> {
|
|
540
|
-
const prop: XMLProperties & Record<string, string> = getMulti(node, [
|
|
541
|
-
"name",
|
|
542
|
-
"cmt",
|
|
543
|
-
"desc",
|
|
544
|
-
"type",
|
|
545
|
-
"time",
|
|
546
|
-
"keywords",
|
|
547
|
-
]);
|
|
548
|
-
const links = get(node, "link");
|
|
549
|
-
if (links.length !== 0) {
|
|
550
|
-
prop.links = [];
|
|
551
|
-
for (const l of Array.from(links)) {
|
|
552
|
-
const link = {
|
|
553
|
-
href: attr(l, "href"),
|
|
554
|
-
...getMulti(l, ["text", "type"]),
|
|
555
|
-
};
|
|
556
|
-
prop.links.push(link);
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
return prop;
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
function okhash(x: string): number {
|
|
563
|
-
let h = 0;
|
|
564
|
-
if (!x || !x.length) return h;
|
|
565
|
-
for (let i = 0; i < x.length; i++) {
|
|
566
|
-
h = ((h << 5) - h + x.charCodeAt(i)) | 0;
|
|
567
|
-
}
|
|
568
|
-
return h;
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
function get(x: Document | Element, y: string): HTMLCollectionOf<Element> {
|
|
572
|
-
return x.getElementsByTagName(y);
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
function attr(x: Element, y: string): string | null {
|
|
576
|
-
return x.getAttribute(y);
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
function attrf(x: Element, y: string): number {
|
|
580
|
-
return parseFloat(attr(x, y) ?? "0");
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
function get1(x: Element, y: string): Element | null {
|
|
584
|
-
const n = get(x, y);
|
|
585
|
-
return n.length ? n[0] : null;
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/Node.normalize
|
|
589
|
-
function norm(el: Element): Element {
|
|
590
|
-
if (el.normalize) el.normalize();
|
|
591
|
-
return el;
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
// cast array x into numbers
|
|
595
|
-
function numarray(x: string[]): number[] {
|
|
596
|
-
return x.map(parseFloat).map((n) => (isNaN(n) ? null : n)) as number[];
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
// get the content of a text node, if any
|
|
600
|
-
function nodeVal(x: Element | null): string | null {
|
|
601
|
-
if (x) norm(x);
|
|
602
|
-
return x && x.textContent;
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
// get the contents of multiple text nodes, if present
|
|
606
|
-
function getMulti(x: Element, ys: string[]): Record<string, string> {
|
|
607
|
-
const o: Record<string, string> = {};
|
|
608
|
-
let n;
|
|
609
|
-
let k;
|
|
610
|
-
for (k = 0; k < ys.length; k++) {
|
|
611
|
-
n = get1(x, ys[k]);
|
|
612
|
-
if (n) o[ys[k]] = nodeVal(n) ?? "";
|
|
613
|
-
}
|
|
614
|
-
return o;
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
// get one coordinate from a coordinate array, if any
|
|
618
|
-
function coord1(v: string): number[] {
|
|
619
|
-
return numarray(v.replace(/\s*/g, "").split(","));
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
// get all coordinates from a coordinate array as [[],[]]
|
|
623
|
-
function coord(v: string): number[][] {
|
|
624
|
-
const coords = v.replace(/^\s*|\s*$/g, "").split(/\s+/);
|
|
625
|
-
const out = [];
|
|
626
|
-
for (const coord of coords) out.push(coord1(coord));
|
|
627
|
-
return out;
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
// build a set of coordinates, timestamps, and heartrate
|
|
631
|
-
function coordPair(x: Element): {
|
|
632
|
-
coordinates: number[];
|
|
633
|
-
time: string | null;
|
|
634
|
-
heartRate: number | null;
|
|
635
|
-
} {
|
|
636
|
-
const ll = [attrf(x, "lon"), attrf(x, "lat")];
|
|
637
|
-
const ele = get1(x, "ele");
|
|
638
|
-
// handle namespaced attribute in browser
|
|
639
|
-
const heartRate = get1(x, "gpxtpx:hr") || get1(x, "hr");
|
|
640
|
-
const time = get1(x, "time");
|
|
641
|
-
let e: number;
|
|
642
|
-
if (ele) {
|
|
643
|
-
e = parseFloat(nodeVal(ele) ?? "0");
|
|
644
|
-
if (!isNaN(e)) ll.push(e);
|
|
645
|
-
}
|
|
646
|
-
return {
|
|
647
|
-
coordinates: ll,
|
|
648
|
-
time: time ? nodeVal(time) : null,
|
|
649
|
-
heartRate:
|
|
650
|
-
heartRate !== null ? parseFloat(nodeVal(heartRate) ?? "0") : null,
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
export function gpxOrKml(
|
|
655
|
-
doc: string | Document,
|
|
656
|
-
): GeoJSON.FeatureCollection | null {
|
|
657
|
-
try {
|
|
658
|
-
// Converting only once rather than in each converter
|
|
659
|
-
if (typeof doc === "string") doc = str2xml(doc);
|
|
660
|
-
} catch (e) {
|
|
661
|
-
// The doc is a string but not valid XML
|
|
662
|
-
return null;
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
try {
|
|
666
|
-
const result = gpx(doc);
|
|
667
|
-
return result;
|
|
668
|
-
} catch (e) {
|
|
669
|
-
// The doc is valid XML but not valid GPX
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
try {
|
|
673
|
-
const result = kml(doc);
|
|
674
|
-
return result;
|
|
675
|
-
} catch (e) {
|
|
676
|
-
// The doc is valid XML but not valid KML
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
// At this point, the doc is not of a compatible vector format
|
|
680
|
-
return null;
|
|
681
|
-
}
|
package/src/defaults.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { Language } from "./language";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Some default settings for the SDK
|
|
5
|
-
*/
|
|
6
|
-
const defaults = {
|
|
7
|
-
maptilerLogoURL: "https://api.maptiler.com/resources/logo.svg",
|
|
8
|
-
maptilerURL: "https://www.maptiler.com/",
|
|
9
|
-
maptilerApiHost: "api.maptiler.com",
|
|
10
|
-
rtlPluginURL:
|
|
11
|
-
"https://cdn.maptiler.com/mapbox-gl-rtl-text/v0.2.3/mapbox-gl-rtl-text.min.js",
|
|
12
|
-
primaryLanguage: Language.STYLE,
|
|
13
|
-
secondaryLanguage: Language.LOCAL,
|
|
14
|
-
terrainSourceURL: "https://api.maptiler.com/tiles/terrain-rgb-v2/tiles.json",
|
|
15
|
-
terrainSourceId: "maptiler-terrain",
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
Object.freeze(defaults);
|
|
19
|
-
|
|
20
|
-
export { defaults };
|