Skip to content

Commit 519cccc

Browse files
committed
added gpx exporter
1 parent 25e39c6 commit 519cccc

File tree

4 files changed

+121
-0
lines changed

4 files changed

+121
-0
lines changed

index.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ <h1>Welcome to the Enhanced Blackbox Explorer!</h1>
181181
<a class="btn btn-primary btn-workspaces-export" data-toggle="tooltip" title="Export your workspace configurations to file">
182182
Export Workspaces...</a>
183183
<a class="btn btn-primary btn-csv-export" data-toggle="tooltip" title="Export your current graphs to CSV file"> Export CSV...</a>
184+
<a class="btn btn-primary btn-gpx-export" data-toggle="tooltip" title="Export your flight to GPX file"> Export GPX...</a>
184185
<span class="btn btn-primary btn-file" data-toggle="tooltip" title="Open another log file, video file, exported workspace file or configuration dump file">
185186
Open log file/video
186187
<input type="file" class="file-open" accept=".bbl,.txt,.cfl,.bfl,.log,.avi,.mov,.mp4,.mpeg,.json" multiple />
@@ -3100,6 +3101,7 @@ <h4 class="modal-title">Advanced User Settings</h4>
31003101
<script src="js/graph_spectrum.js"></script>
31013102
<script src="js/sticks.js"></script>
31023103
<script src="js/csv-exporter.js"></script>
3104+
<script src="js/gpx-exporter.js"></script>
31033105
<script src="js/gui.js"></script>
31043106
<script src="js/header_dialog.js"></script>
31053107
<script src="js/keys_dialog.js"></script>

js/gpx-exporter.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"use strict";
2+
3+
/**
4+
* @constructor
5+
* @param {FlightLog} flightLog
6+
*/
7+
let GpxExporter = function(flightLog) {
8+
9+
/**
10+
* @param {function} success is a callback triggered when export is done
11+
*/
12+
function dump(success) {
13+
let frames = _(flightLog.getChunksInTimeRange(flightLog.getMinTime(), flightLog.getMaxTime()))
14+
.map(chunk => chunk.frames).value(),
15+
worker = new Worker("/js/webworkers/gpx-export-worker.js");
16+
17+
worker.onmessage = event => {
18+
success(event.data);
19+
worker.terminate();
20+
};
21+
worker.postMessage({
22+
sysConfig: flightLog.getSysConfig(),
23+
fieldNames: flightLog.getMainFieldNames(),
24+
frames: frames,
25+
});
26+
}
27+
28+
// exposed functions
29+
return {
30+
dump: dump,
31+
};
32+
};

js/main.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,28 @@ function BlackboxLogViewer() {
923923
CsvExporter(flightLog, options).dump(onSuccess);
924924
}
925925

926+
function exportGpx(file) {
927+
928+
function onSuccess(data) {
929+
console.debug("Gpx export finished in", (performance.now() - startTime) / 1000, "secs");
930+
if (!data) {
931+
console.debug("Empty data, nothing to save");
932+
return;
933+
}
934+
let blob = new Blob([data], {type: 'GPX File'}),
935+
e = document.createEvent('MouseEvents'),
936+
a = document.createElement('a');
937+
a.download = file || $(".log-filename").text() + ".gpx";
938+
a.href = window.URL.createObjectURL(blob);
939+
a.dataset.downloadurl = ['GPX File', a.download, a.href].join(':');
940+
e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
941+
a.dispatchEvent(e);
942+
}
943+
944+
let startTime = performance.now();
945+
GpxExporter(flightLog).dump(onSuccess);
946+
}
947+
926948
function newGraphConfig(newConfig) {
927949
lastGraphConfig = graphConfig; // Remember the last configuration.
928950
graphConfig = newConfig;
@@ -1441,6 +1463,11 @@ function BlackboxLogViewer() {
14411463
exportCsv();
14421464
e.preventDefault();
14431465
});
1466+
$(".btn-gpx-export").click(function(e) {
1467+
setGraphState(GRAPH_STATE_PAUSED);
1468+
exportGpx();
1469+
e.preventDefault();
1470+
});
14441471

14451472
if (FlightLogVideoRenderer.isSupported()) {
14461473
$(".btn-video-export").click(function(e) {

js/webworkers/gpx-export-worker.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
importScripts("/node_modules/lodash/lodash.min.js");
2+
3+
onmessage = function (event) {
4+
const header = `<?xml version="1.0" encoding="UTF-8"?>
5+
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/1/1" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.topografix.com/GPX/gpx_style/0/2 http://www.topografix.com/GPX/gpx_style/0/2/gpx_style.xsd" xmlns:gpx_style="http://www.topografix.com/GPX/gpx_style/0/2"
6+
version="1.1"
7+
creator="https://github.com/betaflight/blackbox-log-viewer">
8+
<metadata>
9+
<author>
10+
<name>Betaflight Blackbox Explorer</name>
11+
<link href="https://github.com/betaflight/blackbox-log-viewer"></link>
12+
</author>
13+
</metadata>`;
14+
15+
const footer = "</gpx>";
16+
17+
const timeIndex = event.data.fieldNames.indexOf("time");
18+
const latIndex = event.data.fieldNames.indexOf("GPS_coord[0]");
19+
const lngIndex = event.data.fieldNames.indexOf("GPS_coord[1]");
20+
const altitudeIndex = event.data.fieldNames.indexOf("GPS_altitude");
21+
const speedIndex = event.data.fieldNames.indexOf("GPS_speed");
22+
const groundCourseIndex = event.data.fieldNames.indexOf("GPS_ground_course");
23+
const numSatIndex = event.data.fieldNames.indexOf("GPS_numSat");
24+
25+
let trkpts = "";
26+
for (var chunk of event.data.frames) {
27+
for (var frame of chunk) {
28+
if (!frame[latIndex] || !frame[lngIndex]) continue;
29+
const timeMillis = Math.floor(frame[timeIndex] / 1000);
30+
const lat = frame[latIndex] / 10000000;
31+
const lng = frame[lngIndex] / 10000000;
32+
const altitude = frame[altitudeIndex] / 10;
33+
const speed = frame[speedIndex] / 100;
34+
const groundCourse = frame[groundCourseIndex] / 10;
35+
const numSat = frame[numSatIndex];
36+
37+
let date = new Date(event.data.sysConfig["Log start datetime"]);
38+
date.setTime(date.getTime() + timeMillis);
39+
40+
let trkpt = `<trkpt lat="${lat}" lon="${lng}">`;
41+
trkpt += `<ele>${altitude}</ele>`;
42+
trkpt += `<time>${date.toISOString()}</time>`;
43+
trkpt += `<speed>${speed}</speed>`;
44+
trkpt += `<degreesType>${groundCourse}</degreesType>`;
45+
trkpt += `<sat>${numSat}</sat>`;
46+
trkpt += `</trkpt>\n`;
47+
48+
trkpts += trkpt;
49+
}
50+
}
51+
52+
let trk =
53+
`<trk>
54+
<name>new</name>
55+
<type>Flight</type>
56+
<trkseg>${trkpts}</trkseg>
57+
</trk>`;
58+
59+
postMessage(header + "\n" + trk + "\n" + footer);
60+
};

0 commit comments

Comments
 (0)