Parsing GPX files.
This commit is contained in:
parent
c545ff1d15
commit
a559a37952
|
@ -32,8 +32,8 @@
|
||||||
"@types/react-router": "^5.1.11",
|
"@types/react-router": "^5.1.11",
|
||||||
"@types/react-router-dom": "^5.1.7",
|
"@types/react-router-dom": "^5.1.7",
|
||||||
"cordova-plugin-geolocation": "^4.1.0",
|
"cordova-plugin-geolocation": "^4.1.0",
|
||||||
"gpx-parser-builder": "^1.0.2",
|
|
||||||
"ionicons": "^6.0.3",
|
"ionicons": "^6.0.3",
|
||||||
|
"isomorphic-xml2js": "^0.1.3",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
@ -9096,14 +9096,6 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/gpx-parser-builder": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/gpx-parser-builder/-/gpx-parser-builder-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-zCTGKANSytYLIicVYUUFTYhz3mbDEtIemWZvC3Vb0j8DhwPMbDSCIl9blMClxSLrr7gGbwLAk1nhj3Z41oC5sw==",
|
|
||||||
"dependencies": {
|
|
||||||
"isomorphic-xml2js": "~0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/graceful-fs": {
|
"node_modules/graceful-fs": {
|
||||||
"version": "4.2.10",
|
"version": "4.2.10",
|
||||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
|
||||||
|
@ -24639,14 +24631,6 @@
|
||||||
"slash": "^3.0.0"
|
"slash": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"gpx-parser-builder": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/gpx-parser-builder/-/gpx-parser-builder-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-zCTGKANSytYLIicVYUUFTYhz3mbDEtIemWZvC3Vb0j8DhwPMbDSCIl9blMClxSLrr7gGbwLAk1nhj3Z41oC5sw==",
|
|
||||||
"requires": {
|
|
||||||
"isomorphic-xml2js": "~0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"graceful-fs": {
|
"graceful-fs": {
|
||||||
"version": "4.2.10",
|
"version": "4.2.10",
|
||||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
|
||||||
|
|
|
@ -27,8 +27,8 @@
|
||||||
"@types/react-router": "^5.1.11",
|
"@types/react-router": "^5.1.11",
|
||||||
"@types/react-router-dom": "^5.1.7",
|
"@types/react-router-dom": "^5.1.7",
|
||||||
"cordova-plugin-geolocation": "^4.1.0",
|
"cordova-plugin-geolocation": "^4.1.0",
|
||||||
"gpx-parser-builder": "^1.0.2",
|
|
||||||
"ionicons": "^6.0.3",
|
"ionicons": "^6.0.3",
|
||||||
|
"isomorphic-xml2js": "^0.1.3",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Geolocation } from '@awesome-cordova-plugins/geolocation';
|
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
import { mapActions } from '../../store/map';
|
import GPX from '../../lib/gpx-parser-builder';
|
||||||
|
|
||||||
import '../../theme/get-location.css';
|
import '../../theme/get-location.css';
|
||||||
import { IonIcon, IonItem } from '@ionic/react';
|
import { IonIcon, IonItem } from '@ionic/react';
|
||||||
import { downloadSharp } from 'ionicons/icons';
|
import { downloadSharp } from 'ionicons/icons';
|
||||||
|
import { tracksActions } from '../../store/tracks';
|
||||||
|
|
||||||
const GpxImport: React.FC<{}> = () => {
|
const GpxImport: React.FC<{}> = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
@ -23,6 +23,8 @@ const GpxImport: React.FC<{}> = () => {
|
||||||
() => {
|
() => {
|
||||||
// this will then display a text file
|
// this will then display a text file
|
||||||
console.log(fileReader.result);
|
console.log(fileReader.result);
|
||||||
|
const track = GPX.parse(fileReader.result);
|
||||||
|
dispatch(tracksActions.push(JSON.parse(JSON.stringify(track))));
|
||||||
},
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 Zheng-Xiang Ke
|
||||||
|
|
||||||
|
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.
|
|
@ -0,0 +1,91 @@
|
||||||
|
# gpx-parser-builder
|
||||||
|
A simple gpx parser and builder between GPX string and JavaScript object. It is dependent on [isomorphic-xml2js](https://github.com/RikkiGibson/isomorphic-xml2js).
|
||||||
|
|
||||||
|
[![npm](https://img.shields.io/npm/dt/gpx-parser-builder.svg)](https://www.npmjs.com/package/gpx-parser-builder)
|
||||||
|
[![GitHub stars](https://img.shields.io/github/stars/kf99916/gpx-parser-builder.svg)](https://github.com/kf99916/gpx-parser-builder/stargazers)
|
||||||
|
[![GitHub forks](https://img.shields.io/github/forks/kf99916/gpx-parser-builder.svg)](https://github.com/kf99916/gpx-parser-builder/network)
|
||||||
|
[![npm](https://img.shields.io/npm/v/gpx-parser-builder.svg)](https://www.npmjs.com/package/gpx-parser-builder)
|
||||||
|
[![GitHub license](https://img.shields.io/github/license/kf99916/gpx-parser-builder.svg)](https://github.com/kf99916/gpx-parser-builder/blob/master/LICENSE)
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
gpx-parser-builder is written with ECMAScript 6. You can leverage [Babel](https://babeljs.io/) and [Webpack](https://webpack.js.org/) to make all browsers available.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install gpx-parser-builder --save
|
||||||
|
```
|
||||||
|
|
||||||
|
## Version
|
||||||
|
|
||||||
|
v1.0.0+ is a breaking change for v0.2.2-. v1.0.0+ fully supports gpx files including waypoints, routes, and tracks. Every gpx type is 1-1 corresponding to a JavaScript class.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import GPX from 'gpx-parser-builder';
|
||||||
|
|
||||||
|
// Parse gpx
|
||||||
|
const gpx = GPX.parse('GPX_STRING');
|
||||||
|
|
||||||
|
window.console.dir(gpx.metadata);
|
||||||
|
window.console.dir(gpx.wpt);
|
||||||
|
window.console.dir(gpx.trk);
|
||||||
|
|
||||||
|
// Build gpx
|
||||||
|
window.console.log(gpx.toString());
|
||||||
|
```
|
||||||
|
|
||||||
|
Get more details about usage with the unit tests.
|
||||||
|
|
||||||
|
### GPX
|
||||||
|
|
||||||
|
The GPX JavaScript object.
|
||||||
|
|
||||||
|
`constructor(object)`
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const gpx = new Gpx({$:{...}, metadat: {...}, wpt:[{...},{...}]}, trk: {...}, rte: {...})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Member Variables
|
||||||
|
|
||||||
|
`$` the attributes for the gpx element. Default value:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
'version': '1.1',
|
||||||
|
'creator': 'gpx-parser-builder',
|
||||||
|
'xmlns': 'http://www.topografix.com/GPX/1/1',
|
||||||
|
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||||
|
'xsi:schemaLocation': 'http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`metadata` the metadata for the gpx.
|
||||||
|
|
||||||
|
`wpt` array of waypoints. It is corresponded to `<wpt>`. The type of all elements in `wpt` is `Waypoint`;
|
||||||
|
|
||||||
|
`rte` array of routes. It is corresponded to `<rte>`. The type of all elements in `rte` is `Route`;
|
||||||
|
|
||||||
|
`trk` array of tracks. It is corresponded to `<trk>`. The type of all elements in `trk` is `Track`;
|
||||||
|
|
||||||
|
#### Static Methods
|
||||||
|
|
||||||
|
`parse(gpxString)` parse gpx string to Gpx object. return `null` if parsing failed.
|
||||||
|
|
||||||
|
#### Member Methods
|
||||||
|
|
||||||
|
`toString(options)` GPX object to gpx string. The options is for [isomorphic-xml2js](https://github.com/RikkiGibson/isomorphic-xml2js).
|
||||||
|
|
||||||
|
## Save as GPX file in the frontend
|
||||||
|
|
||||||
|
You can leverage [StreamSaver.js](https://github.com/jimmywarting/StreamSaver.js) or [FileSaver.js](https://github.com/eligrey/FileSaver.js) to save as GPX file. ⚠️Not all borwsers support the above file techniques. ⚠️️️
|
||||||
|
|
||||||
|
## Author
|
||||||
|
|
||||||
|
Zheng-Xiang Ke, kf99916@gmail.com
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
gpx-parser-builder is available under the MIT license. See the LICENSE file for more info.
|
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"name": "gpx-parser-builder",
|
||||||
|
"version": "1.0.2",
|
||||||
|
"description": "A simple gpx parser and builder between GPX string and JavaScript object",
|
||||||
|
"main": "./src/gpx.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "mocha --require @babel/register test/**/*.js"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/kf99916/gpx-parser-builder.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"gpx",
|
||||||
|
"parser",
|
||||||
|
"builder"
|
||||||
|
],
|
||||||
|
"author": "Zheng-Xiang Ke",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/kf99916/gpx-parser-builder/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/kf99916/gpx-parser-builder",
|
||||||
|
"files": [
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "~7.7",
|
||||||
|
"@babel/preset-env": "~7.7",
|
||||||
|
"@babel/register": "~7.7",
|
||||||
|
"mocha": "~6.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"isomorphic-xml2js": "~0.1"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
export default class Bounds {
|
||||||
|
constructor(object) {
|
||||||
|
this.minlat = object.minlat;
|
||||||
|
this.minlon = object.minlon;
|
||||||
|
this.maxlat = object.maxlat;
|
||||||
|
this.maxlon = object.maxlon;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
export default class Copyright {
|
||||||
|
constructor(object) {
|
||||||
|
this.author = object.author;
|
||||||
|
this.year = object.year;
|
||||||
|
this.license = object.license;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
declare module 'gpx-parser-builder' {
|
||||||
|
class GPX {
|
||||||
|
static parse(gpxString: any): any;
|
||||||
|
constructor(object: any);
|
||||||
|
$: any;
|
||||||
|
extensions: any;
|
||||||
|
metadata: any;
|
||||||
|
wpt: any;
|
||||||
|
rte: any;
|
||||||
|
trk: any;
|
||||||
|
toString(options: any): string;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
import * as xml2js from 'isomorphic-xml2js';
|
||||||
|
import Metadata from './metadata';
|
||||||
|
import Waypoint from './waypoint';
|
||||||
|
import Route from './route';
|
||||||
|
import Track from './track';
|
||||||
|
import {removeEmpty, allDatesToISOString} from './utils';
|
||||||
|
|
||||||
|
const defaultAttributes = {
|
||||||
|
version: '1.1',
|
||||||
|
creator: 'gpx-parser-builder',
|
||||||
|
xmlns: 'http://www.topografix.com/GPX/1/1',
|
||||||
|
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||||
|
'xsi:schemaLocation':
|
||||||
|
'http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd'
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class GPX {
|
||||||
|
constructor(object) {
|
||||||
|
this.$ = Object.assign({}, defaultAttributes, object.$ || object.attributes || {});
|
||||||
|
this.extensions = object.extensions;
|
||||||
|
|
||||||
|
if (object.metadata) {
|
||||||
|
this.metadata = new Metadata(object.metadata);
|
||||||
|
}
|
||||||
|
if (object.wpt) {
|
||||||
|
if (!Array.isArray(object.wpt)) {
|
||||||
|
object.wpt = [object.wpt];
|
||||||
|
}
|
||||||
|
this.wpt = object.wpt.map(wpt => new Waypoint(wpt));
|
||||||
|
}
|
||||||
|
if (object.rte) {
|
||||||
|
if (!Array.isArray(object.rte)) {
|
||||||
|
object.rte = [object.rte];
|
||||||
|
}
|
||||||
|
this.rte = object.rte.map(rte => new Route(rte));
|
||||||
|
}
|
||||||
|
if (object.trk) {
|
||||||
|
if (!Array.isArray(object.trk)) {
|
||||||
|
object.trk = [object.trk];
|
||||||
|
}
|
||||||
|
this.trk = object.trk.map(trk => new Track(trk));
|
||||||
|
}
|
||||||
|
|
||||||
|
removeEmpty(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
static parse(gpxString) {
|
||||||
|
let gpx;
|
||||||
|
xml2js.parseString(gpxString, {
|
||||||
|
explicitArray: false
|
||||||
|
}, (err, xml) => {
|
||||||
|
if (err) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!xml.gpx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpx = new GPX({
|
||||||
|
attributes: xml.gpx.$,
|
||||||
|
metadata: xml.gpx.metadata,
|
||||||
|
wpt: xml.gpx.wpt,
|
||||||
|
rte: xml.gpx.rte,
|
||||||
|
trk: xml.gpx.trk
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return gpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
toString(options) {
|
||||||
|
options = options || {};
|
||||||
|
options.rootName = 'gpx';
|
||||||
|
|
||||||
|
const builder = new xml2js.Builder(options), gpx = new GPX(this);
|
||||||
|
allDatesToISOString(gpx);
|
||||||
|
return builder.buildObject(gpx);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
export default class Link {
|
||||||
|
constructor(object) {
|
||||||
|
this.$ = {};
|
||||||
|
this.$.href = object.$.href || object.href;
|
||||||
|
this.text = object.text;
|
||||||
|
this.type = object.type;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
import Copyright from './copyright';
|
||||||
|
import Link from './link';
|
||||||
|
import Person from './person';
|
||||||
|
import Bounds from './bounds';
|
||||||
|
|
||||||
|
export default class Metadata {
|
||||||
|
constructor(object) {
|
||||||
|
this.name = object.name;
|
||||||
|
this.desc = object.desc;
|
||||||
|
this.time = object.time ? new Date(object.time) : new Date();
|
||||||
|
this.keywords = object.keywords;
|
||||||
|
this.extensions = object.extensions;
|
||||||
|
if (object.author) {
|
||||||
|
this.author = new Person(object.author);
|
||||||
|
}
|
||||||
|
if (object.link) {
|
||||||
|
if (!Array.isArray(object.link)) {
|
||||||
|
object.link = [object.link];
|
||||||
|
}
|
||||||
|
this.link = object.link.map(l => new Link(l));
|
||||||
|
}
|
||||||
|
if (object.bounds) {
|
||||||
|
this.bounds = new Bounds(object.bounds);
|
||||||
|
}
|
||||||
|
if (object.copyright) {
|
||||||
|
this.copyright = new Copyright(object.copyright);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
import Link from './link';
|
||||||
|
|
||||||
|
export default class Person {
|
||||||
|
constructor(object) {
|
||||||
|
this.name = object.name;
|
||||||
|
this.email = object.emil;
|
||||||
|
this.link = new Link(object.link);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
import Waypoint from './waypoint';
|
||||||
|
import Link from './link';
|
||||||
|
|
||||||
|
export default class Route {
|
||||||
|
constructor(object) {
|
||||||
|
this.name = object.name;
|
||||||
|
this.cmt = object.cmt;
|
||||||
|
this.desc = object.desc;
|
||||||
|
this.src = object.src;
|
||||||
|
this.number = object.number;
|
||||||
|
this.type = object.type;
|
||||||
|
this.extensions = object.extensions;
|
||||||
|
if (object.link) {
|
||||||
|
if (!Array.isArray(object.link)) {
|
||||||
|
this.link = [object.link];
|
||||||
|
}
|
||||||
|
this.link = object.link.map(l => new Link(l));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (object.rtept) {
|
||||||
|
if (!Array.isArray(object.rtept)) {
|
||||||
|
this.rtept = [object.rtept];
|
||||||
|
}
|
||||||
|
this.rtept = object.rtept.map(pt => new Waypoint(pt));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
import Waypoint from './waypoint';
|
||||||
|
|
||||||
|
export default class TrackSegment {
|
||||||
|
constructor(object) {
|
||||||
|
if (object.trkpt) {
|
||||||
|
if (!Array.isArray(object.trkpt)) {
|
||||||
|
object.trkpt = [object.trkpt];
|
||||||
|
}
|
||||||
|
this.trkpt = object.trkpt.map(pt => new Waypoint(pt));
|
||||||
|
}
|
||||||
|
this.extensions = object.extensions;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
import TrackSegment from './track-segment';
|
||||||
|
import Link from './link';
|
||||||
|
|
||||||
|
export default class Track {
|
||||||
|
constructor(object) {
|
||||||
|
this.name = object.name;
|
||||||
|
this.cmt = object.cmt;
|
||||||
|
this.desc = object.desc;
|
||||||
|
this.src = object.src;
|
||||||
|
this.number = object.number;
|
||||||
|
this.type = object.type;
|
||||||
|
this.extensions = object.extensions;
|
||||||
|
if (object.link) {
|
||||||
|
if (!Array.isArray(object.link)) {
|
||||||
|
object.link = [object.link];
|
||||||
|
}
|
||||||
|
this.link = object.link.map(l => new Link(l));
|
||||||
|
}
|
||||||
|
if (object.trkseg) {
|
||||||
|
if (!Array.isArray(object.trkseg)) {
|
||||||
|
object.trkseg = [object.trkseg];
|
||||||
|
}
|
||||||
|
this.trkseg = object.trkseg.map(seg => new TrackSegment(seg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
function removeEmpty(obj) {
|
||||||
|
Object.entries(obj).forEach(([key, val]) => {
|
||||||
|
if (val && val instanceof Object) {
|
||||||
|
removeEmpty(val);
|
||||||
|
} else if (val == null) {
|
||||||
|
delete obj[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function allDatesToISOString(obj) {
|
||||||
|
Object.entries(obj).forEach(([key, val]) => {
|
||||||
|
if (val) {
|
||||||
|
if (val instanceof Date) {
|
||||||
|
obj[key] = val.toISOString().split('.')[0] + 'Z';
|
||||||
|
} else if (val instanceof Object) {
|
||||||
|
allDatesToISOString(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export { removeEmpty, allDatesToISOString };
|
|
@ -0,0 +1,32 @@
|
||||||
|
import Link from './link';
|
||||||
|
|
||||||
|
export default class Waypoint {
|
||||||
|
constructor(object) {
|
||||||
|
this.$ = {};
|
||||||
|
this.$.lat = object.$.lat === 0 || object.lat === 0 ? 0 : object.$.lat || object.lat || -1;
|
||||||
|
this.$.lon = object.$.lon === 0 || object.lon === 0 ? 0 : object.$.lon || object.lon || -1;
|
||||||
|
this.ele = object.ele;
|
||||||
|
this.time = object.time ? new Date(object.time) : new Date();
|
||||||
|
this.magvar = object.magvar;
|
||||||
|
this.geoidheight = object.geoidheight;
|
||||||
|
this.name = object.name;
|
||||||
|
this.cmt = object.cmt;
|
||||||
|
this.desc = object.desc;
|
||||||
|
this.src = object.src;
|
||||||
|
this.sym = object.sym;
|
||||||
|
this.type = object.type;
|
||||||
|
this.sat = object.sat;
|
||||||
|
this.hdop = object.hdop;
|
||||||
|
this.vdop = object.vdop;
|
||||||
|
this.pdop = object.pdop;
|
||||||
|
this.ageofdgpsdata = object.ageofdgpsdata;
|
||||||
|
this.dgpsid = object.dgpsid;
|
||||||
|
this.extensions = object.extensions;
|
||||||
|
if (object.link) {
|
||||||
|
if (!Array.isArray(object.link)) {
|
||||||
|
object.link = [object.link];
|
||||||
|
}
|
||||||
|
this.link = object.link.map(l => new Link(l));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
import { configureStore } from '@reduxjs/toolkit';
|
import { configureStore } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
import mapReducer from './map';
|
import mapReducer from './map';
|
||||||
|
import tracksReducer from './tracks';
|
||||||
|
|
||||||
const store = configureStore({
|
const store = configureStore({
|
||||||
reducer: { map: mapReducer },
|
reducer: { map: mapReducer, tracks: tracksReducer },
|
||||||
});
|
});
|
||||||
|
|
||||||
export default store;
|
export default store;
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
|
interface TracksState {
|
||||||
|
index: number;
|
||||||
|
tracks: { [index: string]: any };
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialTracks: TracksState = {
|
||||||
|
index: 0,
|
||||||
|
tracks: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const tracksSlice = createSlice({
|
||||||
|
name: 'tracks',
|
||||||
|
initialState: initialTracks,
|
||||||
|
reducers: {
|
||||||
|
add: (state, action) => {
|
||||||
|
state.tracks[action.payload.id] = action.payload.track;
|
||||||
|
},
|
||||||
|
push: (state, action) => {
|
||||||
|
state.tracks['$' + state.index] = action.payload;
|
||||||
|
state.index++;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const tracksActions = tracksSlice.actions;
|
||||||
|
|
||||||
|
export default tracksSlice.reducer;
|
Loading…
Reference in New Issue