GeoGPXer is a JavaScript library designed to convert GPX data into GeoJSON format efficiently. It supports the conversion of waypoints, tracks, and routes, with additional handling for GPX extensions.
Этот скрипт недоступен для установки пользователем. Он является библиотекой, которая подключается к другим скриптам мета-ключом // @require https://update.greasyfork.org/scripts/523870/1534525/GeoGPXer.js
// ==UserScript== // @name GeoGPXer // @namespace https://github.com/JS55CT // @description GeoGPXer is a JavaScript library designed to convert GPX data into GeoJSON format efficiently. It supports the conversion of waypoints, tracks, and routes, with additional handling for GPX extensions. // @version 2.0.0 // @author JS55CT // @license MIT // @match *://this-library-is-not-supposed-to-run.com/* // ==/UserScript== /*********************************************************** * ## Project Home < https://github.com/JS55CT/GeoGPXer > * MIT License * Copyright (c) 2022 hu de yi * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Derived from logic of https://github.com/M-Reimer/gpx2geojson/tree/master (LGPL-3.0 license) **************************************************************/ /** * @desc The GeoGPXer namespace. * @namespace * @global */ var GeoGPXer = (function () { // Define the GeoGPXer constructor function GeoGPXer(obj) { if (obj instanceof GeoGPXer) return obj; if (!(this instanceof GeoGPXer)) return new GeoGPXer(obj); this._wrapped = obj; } /** * @desc Parses GPX text and returns an XML Document. * @param {String} gpxText - The GPX data as a string. * @return {Document} Parsed XML Document. */ GeoGPXer.prototype.read = function (gpxText) { const parser = new DOMParser(); const xmlDoc = parser.parseFromString(gpxText, "application/xml"); // Check for parsing errors by looking for parser error tags const parseErrors = xmlDoc.getElementsByTagName("parsererror"); if (parseErrors.length > 0) { // If there are parsing errors, log them and throw an error const errorMessages = Array.from(parseErrors) .map((errorElement, index) => { return `Parsing Error ${index + 1}: ${errorElement.textContent}`; }) .join("\n"); console.error(errorMessages); throw new Error("Failed to parse GPX. See console for details."); } // If parsing is successful, return the parsed XML document return xmlDoc; }; /** * @desc Converts an XML Document to GeoJSON FeatureCollection. * @param {Document} document - Parsed XML document of GPX data. * @param {Boolean} includeElevation - Whether to include elevation data in coordinates. * @return {Object} GeoJSON FeatureCollection. */ GeoGPXer.prototype.toGeoJSON = function (document, includeElevation = false) { const features = []; for (const n of document.firstChild.childNodes) { switch (n.tagName) { case "wpt": features.push(this.wptToPoint(n, includeElevation)); break; case "trk": features.push(this.trkToMultiLineString(n, includeElevation)); break; case "rte": features.push(this.rteToLineString(n, includeElevation)); break; } } return { type: "FeatureCollection", features: features, }; }; /** * @desc Extracts coordinates from a node. * @param {Node} node - GPX node containing coordinates. * @param {Boolean} includeElevation - Whether to include elevation data. * @return {Array} Array of coordinates [longitude, latitude, elevation]. */ GeoGPXer.prototype.coordFromNode = function (node, includeElevation = false) { const coords = [parseFloat(node.getAttribute("lon")), parseFloat(node.getAttribute("lat"))]; if (includeElevation) { const eleNode = node.getElementsByTagName("ele")[0]; const elevation = eleNode ? parseFloat(eleNode.textContent) : 0; coords.push(elevation); } return coords; }; /** * @desc Creates a GeoJSON feature. * @param {String} type - Type of geometry (Point, LineString, etc.). * @param {Array} coords - Coordinates for the geometry. * @param {Object} props - Properties of the feature. * @return {Object} GeoJSON feature. */ GeoGPXer.prototype.makeFeature = function (type, coords, props) { return { type: "Feature", geometry: { type: type, coordinates: coords, }, properties: props, }; }; /** * @desc Converts a waypoint node to a GeoJSON Point feature. * @param {Node} node - GPX waypoint node. * @param {Boolean} includeElevation - Whether to include elevation data. * @return {Object} GeoJSON Point feature. */ GeoGPXer.prototype.wptToPoint = function (node, includeElevation = false) { const coord = this.coordFromNode(node, includeElevation); const props = this.extractProperties(node); return this.makeFeature("Point", coord, props); }; /** * @desc Converts a track node to a GeoJSON MultiLineString feature. * @param {Node} node - GPX track node. * @param {Boolean} includeElevation - Whether to include elevation data. * @return {Object} GeoJSON MultiLineString feature. */ GeoGPXer.prototype.trkToMultiLineString = function (node, includeElevation = false) { const coordslst = []; const props = this.extractProperties(node); for (const n of node.childNodes) { if (n.tagName === "trkseg") { const coords = []; coordslst.push(coords); for (const trkpt of n.getElementsByTagName("trkpt")) { coords.push(this.coordFromNode(trkpt, includeElevation)); } } } return this.makeFeature("MultiLineString", coordslst, props); }; /** * @desc Converts a route node to a GeoJSON LineString feature. * @param {Node} node - GPX route node. * @param {Boolean} includeElevation - Whether to include elevation data. * @return {Object} GeoJSON LineString feature. */ GeoGPXer.prototype.rteToLineString = function (node, includeElevation = false) { const coords = []; const props = this.extractProperties(node); for (const n of node.childNodes) { if (n.tagName === "rtept") { coords.push(this.coordFromNode(n, includeElevation)); } } return this.makeFeature("LineString", coords, props); }; /** * @desc Extracts properties from a GPX node. * @param {Node} node - GPX node. * @return {Object} Properties extracted from the node. */ GeoGPXer.prototype.extractProperties = function (node) { const props = {}; for (const n of node.childNodes) { if (n.nodeType === Node.ELEMENT_NODE && n.tagName !== "extensions") { props[n.tagName] = n.textContent; } } const extensions = node.getElementsByTagName("extensions"); if (extensions.length > 0) { for (const ext of extensions[0].childNodes) { if (ext.nodeType === Node.ELEMENT_NODE) { props[`ex_${ext.tagName}`] = ext.textContent; } } } return props; }; return GeoGPXer; // Return the GeoGPXer constructor })();