UNPKG

mahaseel-gpxparser

Version:
463 lines (422 loc) 13.6 kB
/** * GPX file parser * * @constructor */ let gpxParser = function () { this.xmlSource = ""; this.metadata = {}; this.waypoints = []; this.tracks = []; this.routes = []; }; /** * Parse a gpx formatted string to a GPXParser Object * * @param {string} gpxstring - A GPX formatted String * * @return {gpxParser} A GPXParser object */ gpxParser.prototype.parse = function (gpxstring) { let keepThis = this; const { JSDOM } = require("jsdom"); const { window } = new JSDOM(""); let domParser = new window.DOMParser(); this.xmlSource = domParser.parseFromString(gpxstring, "text/xml"); let metadata = this.xmlSource.querySelector("metadata"); if (metadata != null) { this.metadata.name = this.getElementValue(metadata, "name"); this.metadata.desc = this.getElementValue(metadata, "desc"); this.metadata.time = this.getElementValue(metadata, "time"); let author = {}; let authorElem = metadata.querySelector("author"); if (authorElem != null) { author.name = this.getElementValue(authorElem, "name"); author.email = {}; // let emailElem = authorElem.querySelector("email"); // if (emailElem != null) { // author.email.id = emailElem.getAttribute("id"); // author.email.domain = emailElem.getAttribute("domain"); // } // let link = {}; // let linkElem = authorElem.querySelector("link"); // if (linkElem != null) { // link.href = linkElem.getAttribute("href"); // link.text = this.getElementValue(linkElem, "text"); // link.type = this.getElementValue(linkElem, "type"); // } // author.link = link; } this.metadata.author = author; let link = {}; // let linkElem = this.queryDirectSelector(metadata, "link"); // if (linkElem != null) { // link.href = linkElem.getAttribute("href"); // link.text = this.getElementValue(linkElem, "text"); // link.type = this.getElementValue(linkElem, "type"); // this.metadata.link = link; // } } var wpts = [].slice.call(this.xmlSource.querySelectorAll("wpt")); for (let idx in wpts) { var wpt = wpts[idx]; let pt = {}; pt.name = keepThis.getElementValue(wpt, "name"); pt.sym = keepThis.getElementValue(wpt, "sym"); pt.lat = parseFloat(wpt.getAttribute("lat")); pt.lon = parseFloat(wpt.getAttribute("lon")); let floatValue = parseFloat(keepThis.getElementValue(wpt, "ele")); pt.ele = isNaN(floatValue) ? null : floatValue; pt.cmt = keepThis.getElementValue(wpt, "cmt"); pt.desc = keepThis.getElementValue(wpt, "desc"); let time = keepThis.getElementValue(wpt, "time"); pt.time = time == null ? null : new Date(time); keepThis.waypoints.push(pt); } // var rtes = [].slice.call(this.xmlSource.querySelectorAll("rte")); // for (let idx in rtes) { // let rte = rtes[idx]; // let route = {}; // route.name = keepThis.getElementValue(rte, "name"); // route.cmt = keepThis.getElementValue(rte, "cmt"); // route.desc = keepThis.getElementValue(rte, "desc"); // route.src = keepThis.getElementValue(rte, "src"); // route.number = keepThis.getElementValue(rte, "number"); // // let type = keepThis.queryDirectSelector(rte, "type"); // route.type = type != null ? type.innerHTML : null; // // let link = {}; // let linkElem = rte.querySelector("link"); // if (linkElem != null) { // link.href = linkElem.getAttribute("href"); // link.text = keepThis.getElementValue(linkElem, "text"); // link.type = keepThis.getElementValue(linkElem, "type"); // } // route.link = link; // // let routepoints = []; // var rtepts = [].slice.call(rte.querySelectorAll("rtept")); // // for (let idxIn in rtepts) { // let rtept = rtepts[idxIn]; // let pt = {}; // pt.lat = parseFloat(rtept.getAttribute("lat")); // pt.lon = parseFloat(rtept.getAttribute("lon")); // // let floatValue = parseFloat(keepThis.getElementValue(rtept, "ele")); // pt.ele = isNaN(floatValue) ? null : floatValue; // // let time = keepThis.getElementValue(rtept, "time"); // pt.time = time == null ? null : new Date(time); // // routepoints.push(pt); // } // // route.distance = keepThis.calculDistance(routepoints); // route.elevation = keepThis.calcElevation(routepoints); // route.slopes = keepThis.calculSlope(routepoints, route.distance.cumul); // route.points = routepoints; // // keepThis.routes.push(route); // } // // var trks = [].slice.call(this.xmlSource.querySelectorAll("trk")); // for (let idx in trks) { // let trk = trks[idx]; // let track = {}; // // track.name = keepThis.getElementValue(trk, "name"); // track.cmt = keepThis.getElementValue(trk, "cmt"); // track.desc = keepThis.getElementValue(trk, "desc"); // track.src = keepThis.getElementValue(trk, "src"); // track.number = keepThis.getElementValue(trk, "number"); // // let type = keepThis.queryDirectSelector(trk, "type"); // track.type = type != null ? type.innerHTML : null; // // let link = {}; // let linkElem = trk.querySelector("link"); // if (linkElem != null) { // link.href = linkElem.getAttribute("href"); // link.text = keepThis.getElementValue(linkElem, "text"); // link.type = keepThis.getElementValue(linkElem, "type"); // } // track.link = link; // // let trackpoints = []; // let trkpts = [].slice.call(trk.querySelectorAll("trkpt")); // for (let idxIn in trkpts) { // var trkpt = trkpts[idxIn]; // let pt = {}; // pt.lat = parseFloat(trkpt.getAttribute("lat")); // pt.lon = parseFloat(trkpt.getAttribute("lon")); // // let floatValue = parseFloat(keepThis.getElementValue(trkpt, "ele")); // pt.ele = isNaN(floatValue) ? null : floatValue; // // let time = keepThis.getElementValue(trkpt, "time"); // pt.time = time == null ? null : new Date(time); // // trackpoints.push(pt); // } // track.distance = keepThis.calculDistance(trackpoints); // track.elevation = keepThis.calcElevation(trackpoints); // track.slopes = keepThis.calculSlope(trackpoints, track.distance.cumul); // track.points = trackpoints; // // keepThis.tracks.push(track); // } }; /** * Get value from a XML DOM element * * @param {Element} parent - Parent DOM Element * @param {string} needle - Name of the searched element * * @return {} The element value */ gpxParser.prototype.getElementValue = function (parent, needle) { let elem = parent.querySelector(needle); if (elem != null) { return elem.innerHTML != undefined ? elem.innerHTML : elem.childNodes[0].data; } return elem; }; /** * Search the value of a direct child XML DOM element * * @param {Element} parent - Parent DOM Element * @param {string} needle - Name of the searched element * * @return {} The element value */ gpxParser.prototype.queryDirectSelector = function (parent, needle) { let elements = parent.querySelectorAll(needle); let finalElem = elements[0]; if (elements.length > 1) { let directChilds = parent.childNodes; for (idx in directChilds) { elem = directChilds[idx]; if (elem.tagName === needle) { finalElem = elem; } } } return finalElem; }; /** * Calcul the Distance Object from an array of points * * @param {} points - An array of points with lat and lon properties * * @return {DistanceObject} An object with total distance and Cumulative distances */ // gpxParser.prototype.calculDistance = function (points) { // let distance = {}; // let totalDistance = 0; // let cumulDistance = []; // for (var i = 0; i < points.length - 1; i++) { // totalDistance += this.calcDistanceBetween(points[i], points[i + 1]); // cumulDistance[i] = totalDistance; // } // cumulDistance[points.length - 1] = totalDistance; // // distance.total = totalDistance; // distance.cumul = cumulDistance; // // return distance; // }; // // /** // * Calcul Distance between two points with lat and lon // * // * @param {} wpt1 - A geographic point with lat and lon properties // * @param {} wpt2 - A geographic point with lat and lon properties // * // * @returns {float} The distance between the two points // */ // gpxParser.prototype.calcDistanceBetween = function (wpt1, wpt2) { // let latlng1 = {}; // latlng1.lat = wpt1.lat; // latlng1.lon = wpt1.lon; // let latlng2 = {}; // latlng2.lat = wpt2.lat; // latlng2.lon = wpt2.lon; // var rad = Math.PI / 180, // lat1 = latlng1.lat * rad, // lat2 = latlng2.lat * rad, // sinDLat = Math.sin(((latlng2.lat - latlng1.lat) * rad) / 2), // sinDLon = Math.sin(((latlng2.lon - latlng1.lon) * rad) / 2), // a = sinDLat * sinDLat + Math.cos(lat1) * Math.cos(lat2) * sinDLon * sinDLon, // c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); // return 6371000 * c; // }; /** * Generate Elevation Object from an array of points * * @param {} points - An array of points with ele property * * @returns {ElevationObject} An object with negative and positive height difference and average, max and min altitude data */ // gpxParser.prototype.calcElevation = function (points) { // var dp = 0, // dm = 0, // ret = {}; // // for (var i = 0; i < points.length - 1; i++) { // let rawNextElevation = points[i + 1].ele; // let rawElevation = points[i].ele; // // if (rawNextElevation !== null && rawElevation !== null) { // let diff = parseFloat(rawNextElevation) - parseFloat(rawElevation); // // if (diff < 0) { // dm += diff; // } else if (diff > 0) { // dp += diff; // } // } // } // // var elevation = []; // var sum = 0; // // for (var i = 0, len = points.length; i < len; i++) { // let rawElevation = points[i].ele; // // if (rawElevation !== null) { // var ele = parseFloat(points[i].ele); // elevation.push(ele); // sum += ele; // } // } // // ret.max = Math.max.apply(null, elevation) || null; // ret.min = Math.min.apply(null, elevation) || null; // ret.pos = Math.abs(dp) || null; // ret.neg = Math.abs(dm) || null; // ret.avg = sum / elevation.length || null; // // return ret; // }; /** * Generate slopes Object from an array of Points and an array of Cumulative distance * * @param {} points - An array of points with ele property * @param {} cumul - An array of cumulative distance * * @returns {SlopeObject} An array of slopes */ // gpxParser.prototype.calculSlope = function (points, cumul) { // let slopes = []; // // for (var i = 0; i < points.length - 1; i++) { // let point = points[i]; // let nextPoint = points[i + 1]; // let elevationDiff = nextPoint.ele - point.ele; // let distance = cumul[i + 1] - cumul[i]; // // let slope = (elevationDiff * 100) / distance; // slopes.push(slope); // } // // return slopes; // }; // /** * Export the GPX object to a GeoJSON formatted Object * * @returns {} a GeoJSON formatted Object */ gpxParser.prototype.toGeoJSON = function () { var GeoJSON = { type: "FeatureCollection", features: [], properties: { name: this.metadata.name, desc: this.metadata.desc, time: this.metadata.time, author: this.metadata.author, link: this.metadata.link, }, }; for (idx in this.tracks) { let track = this.tracks[idx]; var feature = { type: "Feature", geometry: { type: "LineString", coordinates: [], }, properties: {}, }; feature.properties.name = track.name; feature.properties.cmt = track.cmt; feature.properties.desc = track.desc; feature.properties.src = track.src; feature.properties.number = track.number; feature.properties.link = track.link; feature.properties.type = track.type; for (idx in track.points) { let pt = track.points[idx]; var geoPt = []; geoPt.push(pt.lon); geoPt.push(pt.lat); geoPt.push(pt.ele); feature.geometry.coordinates.push(geoPt); } GeoJSON.features.push(feature); } for (idx in this.routes) { let track = this.routes[idx]; var feature = { type: "Feature", geometry: { type: "LineString", coordinates: [], }, properties: {}, }; feature.properties.name = track.name; feature.properties.cmt = track.cmt; feature.properties.desc = track.desc; feature.properties.src = track.src; feature.properties.number = track.number; feature.properties.link = track.link; feature.properties.type = track.type; for (idx in track.points) { let pt = track.points[idx]; var geoPt = []; geoPt.push(pt.lon); geoPt.push(pt.lat); geoPt.push(pt.ele); feature.geometry.coordinates.push(geoPt); } GeoJSON.features.push(feature); } for (idx in this.waypoints) { let pt = this.waypoints[idx]; var feature = { type: "Feature", geometry: { type: "Point", coordinates: [], }, properties: {}, }; feature.properties.name = pt.name; feature.properties.sym = pt.sym; feature.properties.cmt = pt.cmt; feature.properties.desc = pt.desc; feature.geometry.coordinates = [pt.lon, pt.lat, pt.ele]; GeoJSON.features.push(feature); } return GeoJSON; }; if (typeof module !== "undefined") { module.exports = gpxParser; }