forked from FOSS/BangleApps
Copy waypointer to wpmoto
parent
d46f9bd1ee
commit
058d39a285
|
@ -0,0 +1,176 @@
|
||||||
|
# Waypointer - navigate to waypoints
|
||||||
|
|
||||||
|
The app is aimed at navigation whilst walking. Please note that it
|
||||||
|
would be foolish in the extreme to rely on this as your only
|
||||||
|
navigation aid!
|
||||||
|
|
||||||
|
Please refer to the section on calibration of the compass. This
|
||||||
|
should be done each time the app is going to be used.
|
||||||
|
|
||||||
|
The main part of the display is a compass arrow that points in the
|
||||||
|
direction you need to walk in. Once you have selected a waypoint a
|
||||||
|
bearing from your current position (received from a GPS fix) is
|
||||||
|
calculated and the compass is set to point in that direction. If the
|
||||||
|
arrow is pointing to the left, turning left should straighten the arrow
|
||||||
|
up so that it is pointing straight ahead.
|
||||||
|
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The large digits are the bearing from the current position. On the
|
||||||
|
left is the distance to the waypoint in local units. The top of the
|
||||||
|
display is a circular compass which displays the direction you will
|
||||||
|
need to travel in to reach the selected waypoint. The blue text is
|
||||||
|
the name of the current waypoint. NONE means that there is no
|
||||||
|
waypoint set and so bearing and distance will remain at 0. To select
|
||||||
|
a waypoint, press BTN2 (middle) and wait for the blue text to turn
|
||||||
|
white. Then use BTN1 and BTN3 to select a waypoint. The waypoint
|
||||||
|
choice is fixed by pressing BTN2 again. In the screen shot below a
|
||||||
|
waypoint giving the location of Stone Henge has been selected.
|
||||||
|
|
||||||
|
The screenshot above shows that Stone Henge is 259.9 miles from the
|
||||||
|
current location. To travel towards Stone Henge I need to turn
|
||||||
|
slightly left until the arrow is pointing straight ahead. As you
|
||||||
|
continue to walk in the pointed direction you should see the distance
|
||||||
|
to the waypoint reduce. The frequency of updates will depend on
|
||||||
|
which settings you have used in the GPS.
|
||||||
|
|
||||||
|
At the top of the screen you can see two widgets. These are the [GPS
|
||||||
|
Power
|
||||||
|
Widget](https://github.com/espruino/BangleApps/tree/master/apps/widgps)
|
||||||
|
and the [Compass Power Indicator Widget]. These can be installed
|
||||||
|
seperately and provide you a indication of when the GPS and Compass
|
||||||
|
are switched on and drawing power.
|
||||||
|
|
||||||
|
|
||||||
|
## Marking Waypoints
|
||||||
|
|
||||||
|
The app lets you mark your current location as follows. There are
|
||||||
|
vacant slots in the waypoint file which can be allocated a
|
||||||
|
location. In the distributed waypoint file these are labelled WP0 to
|
||||||
|
WP4. Select one of these - WP2 is shown below.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Bearing and distance are both zero as WP2 has currently no GPS
|
||||||
|
location associated with it. To mark the location, press BTN2.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The app indicates that WP2 is now marked by adding the prefix @ to
|
||||||
|
it's name. The distance should be small as shown in the screen shot
|
||||||
|
as you have just marked your current location.
|
||||||
|
|
||||||
|
## Waypoint JSON file
|
||||||
|
|
||||||
|
When the app is loaded from the app loader, a file named
|
||||||
|
`waypoints.json` is loaded along with the javascript etc. The file
|
||||||
|
has the following contents:
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name":"NONE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"No10",
|
||||||
|
"lat":51.5032,
|
||||||
|
"lon":-0.1269
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"Stone",
|
||||||
|
"lat":51.1788,
|
||||||
|
"lon":-1.8260
|
||||||
|
},
|
||||||
|
{ "name":"WP0" },
|
||||||
|
{ "name":"WP1" },
|
||||||
|
{ "name":"WP2" },
|
||||||
|
{ "name":"WP3" },
|
||||||
|
{ "name":"WP4" }
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
The file contains the initial NONE waypoint which is useful if you
|
||||||
|
just want to display course and speed. The next two entries are
|
||||||
|
waypoints to No 10 Downing Street and to Stone Henge - obtained from
|
||||||
|
Google Maps. The last five entries are entries which can be *marked*.
|
||||||
|
|
||||||
|
You add and delete entries using the Web IDE to load and then save
|
||||||
|
the file from and to watch storage. The app itself does not limit the
|
||||||
|
number of entries although it does load the entire file into RAM
|
||||||
|
which will obviously limit this.
|
||||||
|
|
||||||
|
|
||||||
|
## Waypoint Editor
|
||||||
|
|
||||||
|
Clicking on the download icon of gpsnav in the app loader invokes the
|
||||||
|
waypoint editor. The editor downloads and displays the current
|
||||||
|
`waypoints.json` file. Clicking the `Edit` button beside an entry
|
||||||
|
causes the entry to be deleted from the list and displayed in the
|
||||||
|
edit boxes. It can be restored - by clicking the `Add waypoint`
|
||||||
|
button. A new markable entry is created by using the `Add name`
|
||||||
|
button. The edited `waypoints.json` file is uploaded to the Bangle by
|
||||||
|
clicking the `Upload` button.
|
||||||
|
|
||||||
|
|
||||||
|
## Calibration of the Compass
|
||||||
|
|
||||||
|
The Compass should be calibrated before using the App to navigate to
|
||||||
|
a waypoint (or a series of waypoints). To do this use either the
|
||||||
|
Arrow Compass or the [Navigation
|
||||||
|
Compass](https://github.com/espruino/BangleApps/tree/master/apps/magnav).
|
||||||
|
Open the compass app and clicking on BTN3. The calibration process
|
||||||
|
takes 30 seconds during which you should move the watch slowly
|
||||||
|
through figures of 8. It is important that during calibration the
|
||||||
|
watch is fully rotated around each of it axes. If the app does give
|
||||||
|
the correct direction heading or is not stable with respect to tilt
|
||||||
|
and roll - redo the calibration by pressing *BTN3*. Calibration data
|
||||||
|
is recorded in a storage file named `magnav.json`.
|
||||||
|
|
||||||
|
|
||||||
|
## Advantages and Disadvantages
|
||||||
|
|
||||||
|
This approach has some advantages and disadvantages. First following
|
||||||
|
the arrow is fairly easy to do and once the bearing has been
|
||||||
|
established it does not matter if there is not another GPS fix for a
|
||||||
|
while as the compass will continue to point in the general direction.
|
||||||
|
Second the GPS will only supply a course to the waypoint (a bearing)
|
||||||
|
once you are travelling above 8m/s or 28kph. This is not a practical
|
||||||
|
walking speed. 5kmph is considered a marching pace.
|
||||||
|
|
||||||
|
One disadvantage is that the compass is not very accurate. I have
|
||||||
|
observed it being 20-30 degrees off when compared to a hiking
|
||||||
|
compass. Sometime its is necessary to walk in the opposite direction
|
||||||
|
for a bit to establish the correct direction to go in. The accuracy
|
||||||
|
of the compass is impacted by the magnetic clamps on the charging
|
||||||
|
cable, so it is particularly important that you recalibtrate the
|
||||||
|
compass after the watch has been charged. That said I have found I
|
||||||
|
am successfully able to follow a chain of waypoints as a route.
|
||||||
|
|
||||||
|
|
||||||
|
## Possible Future Enhancements
|
||||||
|
|
||||||
|
- Buzz when the GPS establishes its first fix.
|
||||||
|
|
||||||
|
- Add a small LED to show the status of the GPS during the phase of
|
||||||
|
establishing a first fix.
|
||||||
|
|
||||||
|
- Add an option to calibrate the Compass without having to use the
|
||||||
|
Arrow Compass or the Navigation Compass.
|
||||||
|
|
||||||
|
- Investigate the accuracy of the Compass and how it changes
|
||||||
|
throughout the day after the watch battery has been fully charged.
|
||||||
|
|
||||||
|
- Investigate the possibility of setting the GPS in low speed mode so
|
||||||
|
that a current course value can be obtained.
|
||||||
|
|
||||||
|
- Buzz when you arrive within 20m of a waypoint to signify arrival
|
||||||
|
|
||||||
|
|
||||||
|
## Acknowledgements
|
||||||
|
|
||||||
|
The majority of the code in this application is a merge of
|
||||||
|
[jeffmer's](https://github.com/jeffmer/JeffsBangleAppsDev) GPS
|
||||||
|
Navigation and Compass Navigation Applications.
|
||||||
|
|
|
@ -0,0 +1,283 @@
|
||||||
|
var pal_by = new Uint16Array([0x0000,0xFFC0],0,1); // black, yellow
|
||||||
|
var pal_bw = new Uint16Array([0x0000,0xffff],0,1); // black, white
|
||||||
|
var pal_bb = new Uint16Array([0x0000,0x07ff],0,1); // black, blue
|
||||||
|
|
||||||
|
// having 3 2 color pallette keeps the memory requirement lower
|
||||||
|
var buf1 = Graphics.createArrayBuffer(160,160,1, {msb:true});
|
||||||
|
var buf2 = Graphics.createArrayBuffer(80,40,1, {msb:true});
|
||||||
|
var arrow_img = require("heatshrink").decompress(atob("lEowIPMjAEDngEDvwED/4DCgP/wAEBgf/4AEBg//8AEBh//+AEBj///AEBn///gEBv///wmCAAImCAAIoBFggE/AkaaEABo="));
|
||||||
|
|
||||||
|
function flip1(x,y) {
|
||||||
|
g.drawImage({width:160,height:160,bpp:1,buffer:buf1.buffer, palette:pal_by},x,y);
|
||||||
|
buf1.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
function flip2_bw(x,y) {
|
||||||
|
g.drawImage({width:80,height:40,bpp:1,buffer:buf2.buffer, palette:pal_bw},x,y);
|
||||||
|
buf2.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
function flip2_bb(x,y) {
|
||||||
|
g.drawImage({width:80,height:40,bpp:1,buffer:buf2.buffer, palette:pal_bb},x,y);
|
||||||
|
buf2.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
var candraw = true;
|
||||||
|
var wp_bearing = 0;
|
||||||
|
var direction = 0;
|
||||||
|
var wpindex=0;
|
||||||
|
var loc = require("locale");
|
||||||
|
var selected = false;
|
||||||
|
|
||||||
|
var previous = {
|
||||||
|
bs: '',
|
||||||
|
dst: '',
|
||||||
|
wp_name: '',
|
||||||
|
course: 0,
|
||||||
|
selected: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// clear the attributes that control the display refresh
|
||||||
|
function clear_previous() {
|
||||||
|
previous.bs = '-';
|
||||||
|
previous.dst = '-';
|
||||||
|
previous.wp_name = '-';
|
||||||
|
previous.course = -999;
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawCompass(course) {
|
||||||
|
if(!candraw) return;
|
||||||
|
if (Math.abs(previous.course - course) < 9) return; // reduce number of draws due to compass jitter
|
||||||
|
previous.course = course;
|
||||||
|
|
||||||
|
buf1.setColor(1);
|
||||||
|
buf1.fillCircle(80,80,79,79);
|
||||||
|
buf1.setColor(0);
|
||||||
|
buf1.fillCircle(80,80,69,69);
|
||||||
|
buf1.setColor(1);
|
||||||
|
buf1.drawImage(arrow_img, 80, 80, {scale:3, rotate:radians(course)} );
|
||||||
|
flip1(40, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** COMPASS CODE ***********/
|
||||||
|
|
||||||
|
var heading = 0;
|
||||||
|
function newHeading(m,h){
|
||||||
|
var s = Math.abs(m - h);
|
||||||
|
var delta = (m>h)?1:-1;
|
||||||
|
if (s>=180){s=360-s; delta = -delta;}
|
||||||
|
if (s<2) return h;
|
||||||
|
var hd = h + delta*(1 + Math.round(s/5));
|
||||||
|
if (hd<0) hd+=360;
|
||||||
|
if (hd>360)hd-= 360;
|
||||||
|
return hd;
|
||||||
|
}
|
||||||
|
|
||||||
|
var CALIBDATA = require("Storage").readJSON("magnav.json",1)||null;
|
||||||
|
|
||||||
|
function tiltfixread(O,S){
|
||||||
|
var start = Date.now();
|
||||||
|
var m = Bangle.getCompass();
|
||||||
|
var g = Bangle.getAccel();
|
||||||
|
m.dx =(m.x-O.x)*S.x; m.dy=(m.y-O.y)*S.y; m.dz=(m.z-O.z)*S.z;
|
||||||
|
var d = Math.atan2(-m.dx,m.dy)*180/Math.PI;
|
||||||
|
if (d<0) d+=360;
|
||||||
|
var phi = Math.atan(-g.x/-g.z);
|
||||||
|
var cosphi = Math.cos(phi), sinphi = Math.sin(phi);
|
||||||
|
var theta = Math.atan(-g.y/(-g.x*sinphi-g.z*cosphi));
|
||||||
|
var costheta = Math.cos(theta), sintheta = Math.sin(theta);
|
||||||
|
var xh = m.dy*costheta + m.dx*sinphi*sintheta + m.dz*cosphi*sintheta;
|
||||||
|
var yh = m.dz*sinphi - m.dx*cosphi;
|
||||||
|
var psi = Math.atan2(yh,xh)*180/Math.PI;
|
||||||
|
if (psi<0) psi+=360;
|
||||||
|
return psi;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note actual mag is 360-m, error in firmware
|
||||||
|
function read_compass() {
|
||||||
|
var d = tiltfixread(CALIBDATA.offset,CALIBDATA.scale);
|
||||||
|
heading = newHeading(d,heading);
|
||||||
|
direction = wp_bearing - heading;
|
||||||
|
if (direction < 0) direction += 360;
|
||||||
|
if (direction > 360) direction -= 360;
|
||||||
|
drawCompass(direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***** END Compass ***********/
|
||||||
|
|
||||||
|
var speed = 0;
|
||||||
|
var satellites = 0;
|
||||||
|
var wp;
|
||||||
|
var dist=0;
|
||||||
|
|
||||||
|
function radians(a) {
|
||||||
|
return a*Math.PI/180;
|
||||||
|
}
|
||||||
|
|
||||||
|
function degrees(a) {
|
||||||
|
var d = a*180/Math.PI;
|
||||||
|
return (d+360)%360;
|
||||||
|
}
|
||||||
|
|
||||||
|
function bearing(a,b){
|
||||||
|
var delta = radians(b.lon-a.lon);
|
||||||
|
var alat = radians(a.lat);
|
||||||
|
var blat = radians(b.lat);
|
||||||
|
var y = Math.sin(delta) * Math.cos(blat);
|
||||||
|
var x = Math.cos(alat)*Math.sin(blat) -
|
||||||
|
Math.sin(alat)*Math.cos(blat)*Math.cos(delta);
|
||||||
|
return Math.round(degrees(Math.atan2(y, x)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function distance(a,b){
|
||||||
|
var x = radians(a.lon-b.lon) * Math.cos(radians((a.lat+b.lat)/2));
|
||||||
|
var y = radians(b.lat-a.lat);
|
||||||
|
return Math.round(Math.sqrt(x*x + y*y) * 6371000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function drawN(){
|
||||||
|
buf2.setFont("Vector",24);
|
||||||
|
var bs = wp_bearing.toString();
|
||||||
|
bs = wp_bearing<10?"00"+bs : wp_bearing<100 ?"0"+bs : bs;
|
||||||
|
var dst = loc.distance(dist);
|
||||||
|
|
||||||
|
// -1=left (default), 0=center, 1=right
|
||||||
|
|
||||||
|
// show distance on the left
|
||||||
|
if (previous.dst !== dst) {
|
||||||
|
previous.dst = dst
|
||||||
|
buf2.setColor(1);
|
||||||
|
buf2.setFontAlign(-1,-1);
|
||||||
|
buf2.setFont("Vector", 20);
|
||||||
|
buf2.drawString(dst,0,0);
|
||||||
|
flip2_bw(0, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bearing, place in middle at bottom of compass
|
||||||
|
if (previous.bs !== bs) {
|
||||||
|
previous.bs = bs;
|
||||||
|
buf2.setColor(1);
|
||||||
|
buf2.setFontAlign(0, -1);
|
||||||
|
buf2.setFont("Vector",38);
|
||||||
|
buf2.drawString(bs,40,0);
|
||||||
|
flip2_bw(80, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// waypoint name on right
|
||||||
|
if (previous.wp_name !== wp.name || previous.selected !== selected) {
|
||||||
|
previous.selected = selected;
|
||||||
|
buf2.setColor(1);
|
||||||
|
buf2.setFontAlign(1,-1); // right, bottom
|
||||||
|
buf2.setFont("Vector", 20);
|
||||||
|
buf2.drawString(wp.name, 80, 0);
|
||||||
|
|
||||||
|
if (selected)
|
||||||
|
flip2_bw(160, 200);
|
||||||
|
else
|
||||||
|
flip2_bb(160, 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var savedfix;
|
||||||
|
|
||||||
|
function onGPS(fix) {
|
||||||
|
savedfix = fix;
|
||||||
|
if (fix!==undefined){
|
||||||
|
satellites = fix.satellites;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candraw) {
|
||||||
|
if (fix!==undefined && fix.fix==1){
|
||||||
|
dist = distance(fix,wp);
|
||||||
|
if (isNaN(dist)) dist = 0;
|
||||||
|
wp_bearing = bearing(fix,wp);
|
||||||
|
if (isNaN(wp_bearing)) wp_bearing = 0;
|
||||||
|
drawN();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var intervalRef;
|
||||||
|
|
||||||
|
function stopdraw() {
|
||||||
|
candraw=false;
|
||||||
|
prev_course = -1;
|
||||||
|
if(intervalRef) {clearInterval(intervalRef);}
|
||||||
|
}
|
||||||
|
|
||||||
|
function startTimers() {
|
||||||
|
candraw=true;
|
||||||
|
intervalRefSec = setInterval(function() {
|
||||||
|
read_compass();
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawAll(){
|
||||||
|
g.setColor(1,1,1);
|
||||||
|
drawN();
|
||||||
|
drawCompass(direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
function startdraw(){
|
||||||
|
g.clear();
|
||||||
|
Bangle.drawWidgets();
|
||||||
|
startTimers();
|
||||||
|
candraw=true;
|
||||||
|
drawAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setButtons(){
|
||||||
|
setWatch(nextwp.bind(null,-1), BTN1, {repeat:true,edge:"falling"});
|
||||||
|
setWatch(doselect, BTN2, {repeat:true,edge:"falling"});
|
||||||
|
setWatch(nextwp.bind(null,1), BTN3, {repeat:true,edge:"falling"});
|
||||||
|
}
|
||||||
|
|
||||||
|
Bangle.on('lcdPower',function(on) {
|
||||||
|
if (on) {
|
||||||
|
clear_previous();
|
||||||
|
startdraw();
|
||||||
|
} else {
|
||||||
|
stopdraw();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"NONE"}];
|
||||||
|
wp=waypoints[0];
|
||||||
|
|
||||||
|
function nextwp(inc){
|
||||||
|
if (!selected) return;
|
||||||
|
wpindex+=inc;
|
||||||
|
if (wpindex>=waypoints.length) wpindex=0;
|
||||||
|
if (wpindex<0) wpindex = waypoints.length-1;
|
||||||
|
wp = waypoints[wpindex];
|
||||||
|
drawN();
|
||||||
|
}
|
||||||
|
|
||||||
|
function doselect(){
|
||||||
|
if (selected && wpindex!=0 && waypoints[wpindex].lat===undefined && savedfix.fix) {
|
||||||
|
waypoints[wpindex] ={name:"@"+wp.name, lat:savedfix.lat, lon:savedfix.lon};
|
||||||
|
wp = waypoints[wpindex];
|
||||||
|
require("Storage").writeJSON("waypoints.json", waypoints);
|
||||||
|
}
|
||||||
|
selected=!selected;
|
||||||
|
drawN();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bangle.on('kill',()=>{
|
||||||
|
Bangle.setCompassPower(0);
|
||||||
|
Bangle.setGPSPower(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
g.clear();
|
||||||
|
Bangle.setLCDBrightness(1);
|
||||||
|
Bangle.loadWidgets();
|
||||||
|
Bangle.drawWidgets();
|
||||||
|
// load widgets can turn off GPS
|
||||||
|
Bangle.setGPSPower(1);
|
||||||
|
Bangle.setCompassPower(1);
|
||||||
|
drawAll();
|
||||||
|
startTimers();
|
||||||
|
Bangle.on('GPS', onGPS);
|
||||||
|
setButtons();
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwwhC/AFcBiAWViMRDCkBiUhC68RC64AFGxsRC4UiAAY2HOAQAEC4MSn//AAXzGAwWGC4czC4f/mIwEFwIlEBoIXDBQnyGAkRiYWE/8yLAIXBGAhgEFw5WBC4R0BkYaBmRfFF44XCNI6OGGAQlBAAIXIX4yPJaBq/JC5oeHC/4X/C/4X/C/4X/C/4X/C88RiIXUDAIWVAH4AVA="))
|
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 74 KiB |
|
@ -0,0 +1,170 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="../../css/spectre.min.css">
|
||||||
|
<link rel="stylesheet" href="../../css/spectre-icons.min.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h4>List of waypoints</h4>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Lat.</th>
|
||||||
|
<th>Long.</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="waypoints">
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<br>
|
||||||
|
<h4>Add a new waypoint</h4>
|
||||||
|
<form id="add_waypoint_form">
|
||||||
|
<div class="columns">
|
||||||
|
<div class="column col-3 col-xs-8">
|
||||||
|
<input class="form-input input-sm" type="text" id="add_waypoint_name" placeholder="Name">
|
||||||
|
</div>
|
||||||
|
<div class="column col-3 col-xs-8">
|
||||||
|
<input class="form-input input-sm" value="0.0000" type="number" step="any" id="add_latitude" placeholder="Lat">
|
||||||
|
</div>
|
||||||
|
<div class="column col-3 col-xs-8">
|
||||||
|
<input class="form-input input-sm" value="0.0000" type="number" step="any" id="add_longtitude" placeholder="Long">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="columns">
|
||||||
|
<div class="column col-3 col-xs-8">
|
||||||
|
<button id="add_name_button" class="btn btn-primary btn-sm">Add Name Only</button>
|
||||||
|
</div>
|
||||||
|
<div class="column col-3 col-xs-8">
|
||||||
|
<button id="add_waypoint_button" class="btn btn-primary btn-sm">Add Waypoint</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<br>
|
||||||
|
<button id="Download" class="btn btn-error">Reload</button> <button id="Upload" class="btn btn-primary">Upload</button>
|
||||||
|
|
||||||
|
<script src="../../core/lib/interface.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
var waypoints = []
|
||||||
|
|
||||||
|
var $name = document.getElementById('add_waypoint_name')
|
||||||
|
var $form = document.getElementById('add_waypoint_form')
|
||||||
|
var $button = document.getElementById('add_waypoint_button')
|
||||||
|
var $name_button = document.getElementById('add_name_button')
|
||||||
|
var $latitude = document.getElementById('add_latitude')
|
||||||
|
var $longtitude = document.getElementById('add_longtitude')
|
||||||
|
var $list = document.getElementById('waypoints')
|
||||||
|
|
||||||
|
function compare(a, b){
|
||||||
|
var x = a.name.toLowerCase();
|
||||||
|
var y = b.name.toLowerCase();
|
||||||
|
if (x=="none") {return -1};
|
||||||
|
if (y=="none") {return 1};
|
||||||
|
if (x < y) {return -1;}
|
||||||
|
if (x > y) {return 1;}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$button.addEventListener('click', event => {
|
||||||
|
event.preventDefault()
|
||||||
|
var name = $name.value.trim()
|
||||||
|
if(!name) return;
|
||||||
|
var lat = parseFloat($latitude.value).toPrecision(5);
|
||||||
|
var lon = parseFloat($longtitude.value).toPrecision(5);
|
||||||
|
|
||||||
|
waypoints.push({
|
||||||
|
name, lat,lon,
|
||||||
|
});
|
||||||
|
|
||||||
|
waypoints.sort(compare);
|
||||||
|
|
||||||
|
renderWaypoints()
|
||||||
|
$name.value = ''
|
||||||
|
$latitude.value = (0).toPrecision(5);
|
||||||
|
$longtitude.value = (0).toPrecision(5);
|
||||||
|
});
|
||||||
|
|
||||||
|
$name_button.addEventListener('click', event => {
|
||||||
|
event.preventDefault()
|
||||||
|
var name = $name.value.trim()
|
||||||
|
if(!name) return;
|
||||||
|
|
||||||
|
waypoints.push({
|
||||||
|
name
|
||||||
|
});
|
||||||
|
waypoints.sort(compare);
|
||||||
|
|
||||||
|
renderWaypoints()
|
||||||
|
$name.value = ''
|
||||||
|
$latitude.value = 0.0000
|
||||||
|
$longtitude.value = 0.0000
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function removeWaypoint(index){
|
||||||
|
$name.value = waypoints[index].name
|
||||||
|
$latitude.value = waypoints[index].lat
|
||||||
|
$longtitude.value = waypoints[index].lon
|
||||||
|
waypoints = waypoints.filter((p,i) => i!==index)
|
||||||
|
renderWaypoints()
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderWaypoints(){
|
||||||
|
$list.innerHTML = ''
|
||||||
|
waypoints.forEach((waypoint,index) => {
|
||||||
|
var $waypoint = document.createElement('tr')
|
||||||
|
if (index==0){
|
||||||
|
$waypoint.innerHTML = `<td>${waypoint.name}</td>`
|
||||||
|
} else if(waypoint.lat==undefined){
|
||||||
|
$waypoint.innerHTML = `<td>${waypoint.name}</td><td>------</td><td>-----</td><td><button class="btn btn-action btn-primary" onclick="removeWaypoint(${index})"><i class="icon icon-edit"></i></button></td>`
|
||||||
|
} else {
|
||||||
|
$waypoint.innerHTML = `<td>${waypoint.name}</td><td>${waypoint.lat}</td><td>${waypoint.lon}</td><td><button class="btn btn-action btn-primary" onclick="removeWaypoint(${index})"><i class="icon icon-edit"></i></button></td>`
|
||||||
|
}
|
||||||
|
$list.appendChild($waypoint)
|
||||||
|
})
|
||||||
|
$name.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
function downloadJSONfile(fileid, callback) {
|
||||||
|
Puck.write(`\x10(function() {
|
||||||
|
var pts = require("Storage").readJSON("${fileid}")||[{name:"NONE"}];
|
||||||
|
Bluetooth.print(JSON.stringify(pts));
|
||||||
|
})()\n`,contents=>{
|
||||||
|
var storedpts = JSON.parse(contents);
|
||||||
|
callback(storedpts);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function uploadFile(fileid, contents) {
|
||||||
|
Puck.write(`\x10(function() {
|
||||||
|
require("Storage").write("${fileid}",'${contents}');
|
||||||
|
Bluetooth.print("OK");
|
||||||
|
})()\n`,ret=>{
|
||||||
|
console.log("uploadFile",ret);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function gotStored(pts){
|
||||||
|
waypoints = pts;
|
||||||
|
renderWaypoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onInit() {
|
||||||
|
downloadJSONfile("waypoints.json", gotStored);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("Download").addEventListener("click", function() {
|
||||||
|
downloadJSONfile("waypoints.json", gotStored);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("Upload").addEventListener("click", function() {
|
||||||
|
var data = JSON.stringify(waypoints);
|
||||||
|
uploadFile("waypoints.json",data);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,20 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name":"NONE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"No10",
|
||||||
|
"lat":51.5032,
|
||||||
|
"lon":-0.1269
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"Stone",
|
||||||
|
"lat":51.1788,
|
||||||
|
"lon":-1.8260
|
||||||
|
},
|
||||||
|
{ "name":"WP0" },
|
||||||
|
{ "name":"WP1" },
|
||||||
|
{ "name":"WP2" },
|
||||||
|
{ "name":"WP3" },
|
||||||
|
{ "name":"WP4" }
|
||||||
|
]
|
Binary file not shown.
After Width: | Height: | Size: 60 KiB |
Binary file not shown.
After Width: | Height: | Size: 73 KiB |
Loading…
Reference in New Issue