UNPKG

4.76 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const tools_1 = require("@toba/tools");
4const xmldom_1 = require("xmldom");
5const index_1 = require("./index");
6var Type;
7(function (Type) {
8 Type["Feature"] = "Feature";
9 Type["Collection"] = "FeatureCollection";
10 Type["Point"] = "Point";
11 Type["Line"] = "LineString";
12 Type["MultiLine"] = "MultiLineString";
13})(Type = exports.Type || (exports.Type = {}));
14const features = () => ({
15 type: Type.Collection,
16 features: []
17});
18const geometry = (type, coordinates) => ({
19 type,
20 coordinates
21});
22function trackFromGPX(node, maxPossibleSpeed = 0) {
23 let count = 0;
24 let topSpeed = 0;
25 let totalTime = 0;
26 let totalSpeed = 0;
27 let totalDistance = 0;
28 const points = Array.from(node.getElementsByTagName('trkseg'))
29 .map(segment => index_1.gpx.line(segment, 'trkpt'))
30 .filter(line => line !== null && line[0].length > 0);
31 const track = points.map(line => {
32 totalTime += index_1.measure.duration(line);
33 totalDistance += index_1.measure.length(line);
34 return index_1.measure.simplify(line.map(point => {
35 const speed = point[4];
36 if (maxPossibleSpeed === 0 || speed < maxPossibleSpeed) {
37 count++;
38 totalSpeed += speed;
39 if (speed > topSpeed) {
40 topSpeed = parseFloat(speed.toFixed(1));
41 }
42 }
43 return point.slice(0, 3);
44 }));
45 });
46 return track.length === 0 || track[0].length === 0
47 ? null
48 : {
49 type: Type.Feature,
50 properties: Object.assign(index_1.gpx.properties(node), {
51 topSpeed,
52 avgSpeed: parseFloat((totalSpeed / count).toFixed(1)),
53 duration: totalTime,
54 distance: parseFloat(totalDistance.toFixed(2))
55 }),
56 geometry: track.length === 1
57 ? geometry(Type.Line, track[0])
58 : geometry(Type.MultiLine, track)
59 };
60}
61const routeFromGPX = (node) => ({
62 type: Type.Feature,
63 properties: index_1.gpx.properties(node),
64 geometry: geometry(Type.Line, index_1.gpx.line(node, 'rtept'))
65});
66const pointFromGPX = (node) => ({
67 type: Type.Feature,
68 properties: index_1.gpx.properties(node, ['sym']),
69 geometry: geometry(Type.Point, index_1.gpx.location(node))
70});
71function pointFromKML(node) {
72 const location = index_1.kml.location(node);
73 return location == null
74 ? null
75 : {
76 type: Type.Feature,
77 properties: index_1.kml.properties(node, ['sym']),
78 geometry: geometry(Type.Point, location)
79 };
80}
81const lineFeature = (type, node, lines) => ({
82 type: Type.Feature,
83 properties: index_1.kml.properties(node),
84 geometry: geometry(type, lines)
85});
86function lineFromKML(node) {
87 const lines = index_1.kml.line(node);
88 return lines != null
89 ? lines.length > 1
90 ? lineFeature(Type.MultiLine, node, lines)
91 : lineFeature(Type.Line, node, lines[0])
92 : null;
93}
94const parseNodes = (doc, name, parser) => Array.from(doc.getElementsByTagName(name))
95 .map(parser)
96 .filter(f => tools_1.is.value(f));
97function featuresFromGPX(gpxString) {
98 const geo = features();
99 let gpx = null;
100 try {
101 gpx = new xmldom_1.DOMParser().parseFromString(gpxString);
102 }
103 catch (err) {
104 console.error(err);
105 return null;
106 }
107 const tracks = parseNodes(gpx, 'trk', trackFromGPX);
108 const routes = parseNodes(gpx, 'rte', routeFromGPX);
109 const points = parseNodes(gpx, 'wpt', pointFromGPX);
110 geo.features = geo.features.concat(tracks, routes, points);
111 return geo;
112}
113function postProcess(features, transformer = null) {
114 if (transformer !== null) {
115 features.forEach(f => {
116 f.properties = transformer(f.properties);
117 });
118 }
119 return features;
120}
121const featuresFromKML = (kml, transformer = null) => {
122 const geo = features();
123 let doc = null;
124 if (tools_1.is.text(kml)) {
125 kml = kml.replace(/[\r\n]/g, '').replace(/>\s+</g, '><');
126 try {
127 doc = new xmldom_1.DOMParser().parseFromString(kml);
128 }
129 catch (err) {
130 console.error(err);
131 return null;
132 }
133 }
134 else {
135 doc = kml;
136 }
137 if (doc !== null) {
138 const lines = parseNodes(doc, 'Placemark', lineFromKML);
139 const points = parseNodes(doc, 'Placemark', pointFromKML);
140 geo.features = postProcess(geo.features.concat(lines, points), transformer);
141 }
142 return geo;
143};
144exports.geoJSON = {
145 Type,
146 features,
147 geometry,
148 featuresFromGPX,
149 featuresFromKML
150};