1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | Object.defineProperty(exports, "__esModule", { value: true });
|
6 | const jszip_1 = __importDefault(require("jszip"));
|
7 | const tools_1 = require("@toba/tools");
|
8 | const xmldom_1 = require("xmldom");
|
9 | const xml_1 = require("./xml");
|
10 | const xmlConfig = {
|
11 | locator: {},
|
12 | errorHandler: {
|
13 | warning: () => { },
|
14 | error: console.error,
|
15 | fatalError: console.error
|
16 | }
|
17 | };
|
18 | const roundFromString = (places) => (n) => parseFloat(parseFloat(n).toFixed(places));
|
19 | function coordinates(node, name) {
|
20 | const lines = node.getElementsByTagName(name);
|
21 | if (lines != null && lines.length > 0) {
|
22 | const segments = [];
|
23 | for (let i = 0; i < lines.length; i++) {
|
24 | const coordinates = xml_1.xml.firstValue(lines[i], 'coordinates');
|
25 | if (coordinates != null) {
|
26 | const locations = [];
|
27 | const points = coordinates.trim().split(' ');
|
28 | points.forEach(p => {
|
29 | const location = [];
|
30 | const parts = p.split(',').map(roundFromString(6));
|
31 | if (parts.length >= 2) {
|
32 | location[0] = parts[0];
|
33 | location[1] = parts[1];
|
34 | if (parts.length >= 3) {
|
35 | location[2] = parts[2];
|
36 | }
|
37 | locations.push(location);
|
38 | }
|
39 | });
|
40 | if (locations.length > 0) {
|
41 | segments.push(locations);
|
42 | }
|
43 | }
|
44 | }
|
45 | if (segments.length > 0) {
|
46 | return segments;
|
47 | }
|
48 | }
|
49 | return null;
|
50 | }
|
51 | function location(node) {
|
52 | const locations = coordinates(node, 'Point');
|
53 | if (locations != null && locations.length > 0) {
|
54 | if (locations.length > 1) {
|
55 | return locations[0][0];
|
56 | }
|
57 | else {
|
58 | return locations[0][0];
|
59 | }
|
60 | }
|
61 | return null;
|
62 | }
|
63 | function line(node) {
|
64 | const l = coordinates(node, 'LineString');
|
65 | return l == null || l.length == 0 ? null : l;
|
66 | }
|
67 | const clean = (text) => tools_1.is.value(text)
|
68 | ? text
|
69 | .replace(/[\r\n]/g, '')
|
70 | .replace('<Null>', '')
|
71 | .replace('<Null>', '')
|
72 | : null;
|
73 | function parseDescription(properties) {
|
74 | if (tools_1.is.defined(properties, 'description') &&
|
75 | /<html/.test(properties.description)) {
|
76 | const source = properties
|
77 | .description.replace(/^<!\[CDATA\[/, '')
|
78 | .replace(/\]\]>$/, '');
|
79 | let html = null;
|
80 | try {
|
81 | html = new xmldom_1.DOMParser(xmlConfig).parseFromString(source, "text/xml");
|
82 | }
|
83 | catch (ex) {
|
84 | return properties;
|
85 | }
|
86 | const tables = html.getElementsByTagName('table');
|
87 | let most = 0;
|
88 | let index = -1;
|
89 | for (let i = 0; i < tables.length; i++) {
|
90 | const t = tables[i];
|
91 | if (t.childNodes.length > most) {
|
92 | most = t.childNodes.length;
|
93 | index = i;
|
94 | }
|
95 | }
|
96 | if (index > 0) {
|
97 | const rows = tables[index].getElementsByTagName('tr');
|
98 | for (let i = 0; i < rows.length; i++) {
|
99 | const cols = rows[i].getElementsByTagName('td');
|
100 | const key = clean(xml_1.xml.value(cols[0]));
|
101 | const value = tools_1.maybeNumber(clean(xml_1.xml.value(cols[1])));
|
102 | if (key !== null && value !== null) {
|
103 | properties[key.replace(' ', '_')] = value;
|
104 | }
|
105 | }
|
106 | delete properties['description'];
|
107 | }
|
108 | }
|
109 | return properties;
|
110 | }
|
111 | async function fromKMZ(data) {
|
112 | const zip = new jszip_1.default();
|
113 | const archive = await zip.loadAsync(data);
|
114 | for (const name in archive.files) {
|
115 | if (name.endsWith('.kml')) {
|
116 | const text = await archive.files[name].async('text');
|
117 | return new xmldom_1.DOMParser(xmlConfig).parseFromString(text, "text/xml");
|
118 | }
|
119 | }
|
120 | return null;
|
121 | }
|
122 | function properties(node, extras = []) {
|
123 | const names = extras.concat(['name', 'description']);
|
124 | const properties = {};
|
125 | for (const key of names) {
|
126 | let value = xml_1.xml.firstValue(node, key);
|
127 | if (!tools_1.is.empty(value)) {
|
128 | switch (key) {
|
129 | case 'name':
|
130 | value = tools_1.titleCase(value);
|
131 | break;
|
132 | case 'description':
|
133 | value = value.replace(/[\n\r]/g, ' ').replace(/\s{2,}/g, ' ');
|
134 | break;
|
135 | default:
|
136 | break;
|
137 | }
|
138 | properties[key] = tools_1.maybeNumber(value);
|
139 | }
|
140 | }
|
141 | return parseDescription(properties);
|
142 | }
|
143 | exports.kml = {
|
144 | fromKMZ,
|
145 | location,
|
146 | line,
|
147 | coordinates,
|
148 | properties,
|
149 | parseDescription
|
150 | };
|
151 |
|
\ | No newline at end of file |