mahaseel-gpxparser
Version:
463 lines (422 loc) • 13.6 kB
JavaScript
/**
* 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;
}