forked from FOSS/BangleApps
Big refactor to attempt to merge all the waypoints code into one place. At least 3 apps had basically identical interface.html files, and yet wpmoto had a great map-based editor.
parent
e9fdb1dee5
commit
91728c147f
|
@ -3,4 +3,4 @@
|
|||
0.03: Add Waypoint Editor
|
||||
0.04: Fix great circle formula
|
||||
0.05: Use locale for speed and distance + fix Vector font sizes
|
||||
|
||||
0.06: Move waypoints.json (and editor) to 'waypoints' app
|
||||
|
|
|
@ -51,10 +51,10 @@ function drawCompass(course) {
|
|||
|
||||
//displayed heading
|
||||
var heading = 0;
|
||||
function newHeading(m,h){
|
||||
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>=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;
|
||||
|
@ -125,7 +125,7 @@ function drawN(){
|
|||
g.setColor(0,0,0);
|
||||
g.fillRect(10,230,60,239);
|
||||
g.setColor(1,1,1);
|
||||
g.drawString("Sats " + satellites.toString(),10,230);
|
||||
g.drawString("Sats " + satellites.toString(),10,230);
|
||||
}
|
||||
|
||||
var savedfix;
|
||||
|
@ -193,11 +193,11 @@ var SCREENACCESS = {
|
|||
},
|
||||
release:function(){
|
||||
this.withApp=true;
|
||||
startdraw();
|
||||
startdraw();
|
||||
setButtons();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Bangle.on('lcdPower',function(on) {
|
||||
if (!SCREENACCESS.withApp) return;
|
||||
if (on) {
|
||||
|
@ -207,7 +207,7 @@ Bangle.on('lcdPower',function(on) {
|
|||
}
|
||||
});
|
||||
|
||||
var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"NONE"}];
|
||||
var waypoints = require("waypoints").load();
|
||||
wp=waypoints[0];
|
||||
|
||||
function nextwp(inc){
|
||||
|
@ -223,7 +223,7 @@ 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);
|
||||
require("waypoints").save(waypoints);
|
||||
}
|
||||
selected=!selected;
|
||||
drawN();
|
||||
|
|
|
@ -6,6 +6,6 @@ function drawN(){var a=loc.speed(speed);buf.setColor(1);buf.setFont("6x8",2);buf
|
|||
0,30);buf.setColor(selected?1:2);buf.drawString(wp.name,140,0);buf.setColor(1);buf.drawString(a,60,0);buf.drawString(loc.distance(dist),60,30);flip(buf,Yoff+130);g.setFont("6x8",1);g.setColor(0,0,0);g.fillRect(10,230,60,239);g.setColor(1,1,1);g.drawString("Sats "+satellites.toString(),10,230)}var savedfix;
|
||||
function onGPS(a){savedfix=a;void 0!==a&&(course=isNaN(a.course)?course:Math.round(a.course),speed=isNaN(a.speed)?speed:a.speed,satellites=a.satellites);candraw&&(void 0!==a&&1==a.fix&&(dist=distance(a,wp),isNaN(dist)&&(dist=0),brg=bearing(a,wp),isNaN(brg)&&(brg=0)),drawN())}var intervalRef;function stopdraw(){candraw=!1;intervalRef&&clearInterval(intervalRef)}
|
||||
function startTimers(){candraw=!0;intervalRefSec=setInterval(function(){heading=newHeading(course,heading);course!=heading&&drawCompass(heading)},200)}function drawAll(){g.setColor(1,.5,.5);g.fillPoly([120,Yoff+50,110,Yoff+70,130,Yoff+70]);g.setColor(1,1,1);drawN();drawCompass(heading)}function startdraw(){g.clear();Bangle.drawWidgets();startTimers();drawAll()}
|
||||
function setButtons(){setWatch(nextwp.bind(null,-1),BTN1,{repeat:!0,edge:"falling"});setWatch(doselect,BTN2,{repeat:!0,edge:"falling"});setWatch(nextwp.bind(null,1),BTN3,{repeat:!0,edge:"falling"})}var SCREENACCESS={withApp:!0,request:function(){this.withApp=!1;stopdraw();clearWatch()},release:function(){this.withApp=!0;startdraw();setButtons()}};Bangle.on("lcdPower",function(a){SCREENACCESS.withApp&&(a?startdraw():stopdraw())});var waypoints=require("Storage").readJSON("waypoints.json")||[{name:"NONE"}];
|
||||
wp=waypoints[0];function nextwp(a){selected&&(wpindex+=a,wpindex>=waypoints.length&&(wpindex=0),0>wpindex&&(wpindex=waypoints.length-1),wp=waypoints[wpindex],drawN())}function doselect(){selected&&0!=wpindex&&void 0===waypoints[wpindex].lat&&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()}g.clear();Bangle.setLCDBrightness(1);Bangle.loadWidgets();Bangle.drawWidgets();
|
||||
function setButtons(){setWatch(nextwp.bind(null,-1),BTN1,{repeat:!0,edge:"falling"});setWatch(doselect,BTN2,{repeat:!0,edge:"falling"});setWatch(nextwp.bind(null,1),BTN3,{repeat:!0,edge:"falling"})}var SCREENACCESS={withApp:!0,request:function(){this.withApp=!1;stopdraw();clearWatch()},release:function(){this.withApp=!0;startdraw();setButtons()}};Bangle.on("lcdPower",function(a){SCREENACCESS.withApp&&(a?startdraw():stopdraw())});var waypoints=require("waypoints").load();
|
||||
wp=waypoints[0];function nextwp(a){selected&&(wpindex+=a,wpindex>=waypoints.length&&(wpindex=0),0>wpindex&&(wpindex=waypoints.length-1),wp=waypoints[wpindex],drawN())}function doselect(){selected&&0!=wpindex&&void 0===waypoints[wpindex].lat&&savedfix.fix&&(waypoints[wpindex]={name:"@"+wp.name,lat:savedfix.lat,lon:savedfix.lon},wp=waypoints[wpindex],require("waypoints").save(waypoints));selected=!selected;drawN()}g.clear();Bangle.setLCDBrightness(1);Bangle.loadWidgets();Bangle.drawWidgets();
|
||||
Bangle.setGPSPower(1);drawAll();startTimers();Bangle.on("GPS",onGPS);setButtons();
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
{
|
||||
"id": "gpsnav",
|
||||
"name": "GPS Navigation",
|
||||
"version": "0.05",
|
||||
"version": "0.06",
|
||||
"description": "Displays GPS Course and Speed, + Directions to waypoint and waypoint recording, now with waypoint editor",
|
||||
"icon": "icon.png",
|
||||
"tags": "tool,outdoors,gps",
|
||||
"supports": ["BANGLEJS"],
|
||||
"readme": "README.md",
|
||||
"interface": "waypoints.html",
|
||||
"dependencies" : { "waypoints":"type" },
|
||||
"storage": [
|
||||
{"name":"gpsnav.app.js","url":"app.min.js"},
|
||||
{"name":"gpsnav.img","url":"app-icon.js","evaluate":true}
|
||||
],
|
||||
"data": [{"name":"waypoints.json","url":"waypoints.json"}]
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,170 +0,0 @@
|
|||
<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>
|
|
@ -1,20 +0,0 @@
|
|||
[
|
||||
{
|
||||
"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" }
|
||||
]
|
|
@ -11,3 +11,4 @@
|
|||
0.11: Detect when waypoints.json is not present, error E-WPT
|
||||
0.12: Added stepo2 as a replacement for stepo and digi
|
||||
0.13: Added long press BTN2 toggle gpsrec status in GPS clock
|
||||
0.14: Move waypoints.json (and editor) to 'waypoints' app
|
||||
|
|
|
@ -60,7 +60,7 @@ The following buttons depend on which face is currently in use
|
|||

|
||||
|
||||
- now replaced by Stepo2 but still available if you install manually
|
||||
- Requires one of the pedominter widgets to be installed
|
||||
- Requires one of the pedominter widgets to be installed
|
||||
- Displays the time in large font
|
||||
- Display current step count in a doughnut gauge
|
||||
- Show step count in the middle of the doughnut gauge
|
||||
|
@ -208,14 +208,8 @@ 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.
|
||||
Clicking on the download icon of `Waypoints` in the app loader invokes the
|
||||
waypoint editor. See the `Waypoints` app for more information.
|
||||
|
||||
|
||||
### Calibration of the Compass
|
||||
|
|
|
@ -23,7 +23,7 @@ function nextFace(){
|
|||
iface += 1
|
||||
iface = iface % FACES.length;
|
||||
face = FACES[iface]();
|
||||
|
||||
|
||||
g.clear();
|
||||
g.reset();
|
||||
face.init(gpsObj, swObj, hrmObj, tripObject);
|
||||
|
@ -64,7 +64,7 @@ function buttonReleased(btn) {
|
|||
clearInterval(pressTimer);
|
||||
pressTimer = undefined;
|
||||
}
|
||||
|
||||
|
||||
if ( dur >= 1.5 ) {
|
||||
switch(btn) {
|
||||
case 1:
|
||||
|
@ -165,11 +165,11 @@ GPS.prototype.getLastFix = function() {
|
|||
GPS.prototype.determineGPSState = function() {
|
||||
this.log_debug("determineGPSState");
|
||||
gpsPowerState = Bangle.isGPSOn();
|
||||
|
||||
|
||||
//this.log_debug("last_fix.fix " + this.last_fix.fix);
|
||||
//this.log_debug("gpsPowerState " + this.gpsPowerState);
|
||||
//this.log_debug("last_fix.satellites " + this.last_fix.satellites);
|
||||
|
||||
|
||||
if (!gpsPowerState) {
|
||||
this.gpsState = this.GPS_OFF;
|
||||
this.resetLastFix();
|
||||
|
@ -178,9 +178,9 @@ GPS.prototype.determineGPSState = function() {
|
|||
} else {
|
||||
this.gpsState = this.GPS_SATS;
|
||||
}
|
||||
|
||||
|
||||
this.log_debug("gpsState=" + this.gpsState);
|
||||
|
||||
|
||||
if (this.gpsState !== this.GPS_OFF) {
|
||||
if (this.listenerCount === 0) {
|
||||
Bangle.on('GPS', processFix);
|
||||
|
@ -196,9 +196,9 @@ GPS.prototype.determineGPSState = function() {
|
|||
}
|
||||
};
|
||||
|
||||
GPS.prototype.getGPSTime = function() {
|
||||
GPS.prototype.getGPSTime = function() {
|
||||
var time;
|
||||
|
||||
|
||||
if (this.last_fix !== undefined && this.last_fix.time !== undefined && this.last_fix.time.toUTCString !== undefined &&
|
||||
(this.gpsState == this.GPS_SATS || this.gpsState == this.GPS_RUNNING)) {
|
||||
time = this.last_fix.time.toUTCString().split(" ");
|
||||
|
@ -216,7 +216,7 @@ GPS.prototype.toggleGPSPower = function() {
|
|||
this.gpsPowerState = Bangle.isGPSOn();
|
||||
this.gpsPowerState = !this.gpsPowerState;
|
||||
Bangle.setGPSPower((this.gpsPowerState ? 1 : 0), 'kitchen');
|
||||
|
||||
|
||||
this.resetLastFix();
|
||||
this.determineGPSState();
|
||||
|
||||
|
@ -247,11 +247,11 @@ GPS.prototype.processFix = function(fix) {
|
|||
//this.log_debug("GPS:processFix()");
|
||||
//this.log_debug(fix);
|
||||
this.last_fix.time = fix.time;
|
||||
|
||||
|
||||
if (this.gpsState == this.GPS_TIME) {
|
||||
this.gpsState = this.GPS_SATS;
|
||||
}
|
||||
|
||||
|
||||
if (fix.fix) {
|
||||
//this.log_debug("Got fix - setting state to GPS_RUNNING");
|
||||
this.gpsState = this.GPS_RUNNING;
|
||||
|
@ -271,10 +271,10 @@ GPS.prototype.formatTime = function(now) {
|
|||
GPS.prototype.timeSince = function(t) {
|
||||
var hms = t.split(":");
|
||||
var now = new Date();
|
||||
|
||||
|
||||
var sn = 3600*(now.getHours()) + 60*(now.getMinutes()) + 1*(now.getSeconds());
|
||||
var st = 3600*(hms[0]) + 60*(hms[1]) + 1*(hms[2]);
|
||||
|
||||
|
||||
return (sn - st);
|
||||
};
|
||||
|
||||
|
@ -313,7 +313,7 @@ GPS.prototype.getWPdistance = function() {
|
|||
GPS.prototype.getWPbearing = function() {
|
||||
//log_debug(this.last_fix);
|
||||
//log_debug(this.wp_current);
|
||||
|
||||
|
||||
if (this.wp_current.name === "E-WPT" || this.wp_current.name === "NONE" || this.wp_current.lat === undefined || this.wp_current.lat === 0)
|
||||
return 0;
|
||||
else
|
||||
|
@ -321,7 +321,7 @@ GPS.prototype.getWPbearing = function() {
|
|||
}
|
||||
|
||||
GPS.prototype.loadFirstWaypoint = function() {
|
||||
var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"E-WPT"}];
|
||||
var waypoints = require("waypoints").load();
|
||||
this.wp_index = 0;
|
||||
this.wp_current = waypoints[this.wp_index];
|
||||
log_debug(this.wp_current);
|
||||
|
@ -345,10 +345,10 @@ GPS.prototype.markWaypoint = function() {
|
|||
return;
|
||||
|
||||
log_debug("GPS::markWaypoint()");
|
||||
|
||||
var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"E-WPT"}];
|
||||
|
||||
var waypoints = require("waypoints").load();
|
||||
this.wp_current = waypoints[this.wp_index];
|
||||
|
||||
|
||||
if (this.waypointHasLocation()) {
|
||||
waypoints[this.wp_index] = {name:this.wp_current.name, lat:0, lon:0};
|
||||
} else {
|
||||
|
@ -356,12 +356,12 @@ GPS.prototype.markWaypoint = function() {
|
|||
}
|
||||
|
||||
this.wp_current = waypoints[this.wp_index];
|
||||
require("Storage").writeJSON("waypoints.json", waypoints);
|
||||
require("waypoints").save(waypoints);
|
||||
log_debug("GPS::markWaypoint() written");
|
||||
}
|
||||
|
||||
GPS.prototype.nextWaypoint = function(inc) {
|
||||
var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"E-WPT"}];
|
||||
var waypoints = require("waypoints").load();
|
||||
this.wp_index+=inc;
|
||||
if (this.wp_index>=waypoints.length) this.wp_index=0;
|
||||
if (this.wp_index<0) this.wp_index = waypoints.length-1;
|
||||
|
@ -520,7 +520,7 @@ function STOPWATCH() {
|
|||
this.redrawLaps = true;
|
||||
this.redrawTime = true;
|
||||
}
|
||||
|
||||
|
||||
STOPWATCH.prototype.log_debug = function(o) {
|
||||
//console.log(o);
|
||||
}
|
||||
|
@ -531,7 +531,7 @@ STOPWATCH.prototype.timeToText = function(t) {
|
|||
let secs = Math.floor(t/1000)%60;
|
||||
let text;
|
||||
|
||||
if (hrs === 0)
|
||||
if (hrs === 0)
|
||||
text = ("0"+mins).substr(-2) + ":" + ("0"+secs).substr(-2);
|
||||
else
|
||||
text = (""+hrs) + ":" + ("0"+mins).substr(-2) + ":" + ("0"+secs).substr(-2);
|
||||
|
@ -551,7 +551,7 @@ STOPWATCH.prototype.stopStart = function() {
|
|||
|
||||
if (this.running)
|
||||
this.tStart = Date.now() + this.tStart - this.tCurrent;
|
||||
|
||||
|
||||
this.tTotal = Date.now() + this.tTotal - this.tCurrent;
|
||||
this.tCurrent = Date.now();
|
||||
this.redrawButtons = true;
|
||||
|
@ -623,7 +623,7 @@ STOPWATCH.prototype.drawLaptimes = function() {
|
|||
g.setFont("Vector",24);
|
||||
g.setFontAlign(-1,-1);
|
||||
g.clearRect(4, 205, 239, 229); // clear the last line of the lap times
|
||||
|
||||
|
||||
let laps = 0;
|
||||
for (let i in this.lapTimes) {
|
||||
g.drawString(this.lapTimes.length-i + ": " + this.timeToText(this.lapTimes[i]), 4, this.timeY + 40 + i*24);
|
||||
|
@ -645,7 +645,7 @@ STOPWATCH.prototype.drawTime = function() {
|
|||
g.setFont("Vector",38);
|
||||
g.setFontAlign(0,0);
|
||||
g.clearRect(0, this.timeY-21, 200, this.timeY+21);
|
||||
g.setColor(0xFFC0);
|
||||
g.setColor(0xFFC0);
|
||||
g.drawString(txtTotal, xTotal, this.timeY);
|
||||
|
||||
// current lap time
|
||||
|
@ -691,7 +691,7 @@ function HRM() {
|
|||
this.bpm = 0;
|
||||
this.confidence = 0;
|
||||
}
|
||||
|
||||
|
||||
HRM.prototype.log_debug = function(o) {
|
||||
//console.log(o);
|
||||
}
|
||||
|
@ -782,7 +782,7 @@ Debug Object
|
|||
function DEBUG() {
|
||||
this.logfile = require("Storage").open("debug.log","a");
|
||||
}
|
||||
|
||||
|
||||
DEBUG.prototype.log = function(msg) {
|
||||
let timestamp = new Date().toString().split(" ")[4];
|
||||
let line = timestamp + ", " + msg + "\n";
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
{
|
||||
"id": "kitchen",
|
||||
"name": "Kitchen Combo",
|
||||
"version": "0.13",
|
||||
"version": "0.14",
|
||||
"description": "Combination of the Stepo, Walkersclock, Arrow and Waypointer apps into a multiclock format. 'Everything but the kitchen sink'",
|
||||
"icon": "kitchen.png",
|
||||
"type": "clock",
|
||||
"tags": "tool,outdoors,gps",
|
||||
"supports": ["BANGLEJS"],
|
||||
"readme": "README.md",
|
||||
"interface": "waypoints.html",
|
||||
"dependencies" : { "waypoints":"type" },
|
||||
"storage": [
|
||||
{"name":"kitchen.app.js","url":"kitchen.app.js"},
|
||||
{"name":"stepo2.kit.js","url":"stepo2.kit.js"},
|
||||
|
@ -16,6 +16,5 @@
|
|||
{"name":"gps.kit.js","url":"gps.kit.js"},
|
||||
{"name":"compass.kit.js","url":"compass.kit.js"},
|
||||
{"name":"kitchen.img","url":"kitchen.icon.js","evaluate":true}
|
||||
],
|
||||
"data": [{"name":"waypoints.json","url":"waypoints.json"}]
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,170 +0,0 @@
|
|||
<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>
|
|
@ -1,20 +0,0 @@
|
|||
[
|
||||
{
|
||||
"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" }
|
||||
]
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
You can switch between three display modes. One showing speed and altitude (A), one showing speed and distance to waypoint (D) and a large dispay of time and selected waypoint.
|
||||
|
||||
Within the [A]ltitude and [D]istance displays modes one figure is displayed on the watch face using the largest possible characters depending on the number of digits. The other is in a smaller characters below that. Both are always visible. You can display the current or maximum observed speed/altitude values. Current time is always displayed.
|
||||
Within the [A]ltitude and [D]istance displays modes one figure is displayed on the watch face using the largest possible characters depending on the number of digits. The other is in a smaller characters below that. Both are always visible. You can display the current or maximum observed speed/altitude values. Current time is always displayed.
|
||||
|
||||
The waypoints list is the same as that used with the [GPS Navigation](https://banglejs.com/apps/#gps%20navigation) app so the same set of waypoints can be used across both apps. Refer to that app for waypoint file information.
|
||||
|
||||
|
@ -36,7 +36,7 @@ BTN4 : Left Display Tap : Swaps which figure is in the large display. You can ha
|
|||
|
||||
## App Settings
|
||||
|
||||
Select the desired display units. Speed can be as per the default locale, kph, knots, mph or m/s. Distance can be km, miles or nautical miles. Altitude can be feet or metres. Select one of three colour schemes. Default (three colours), high contrast (all white on black) or night ( all red on black ).
|
||||
Select the desired display units. Speed can be as per the default locale, kph, knots, mph or m/s. Distance can be km, miles or nautical miles. Altitude can be feet or metres. Select one of three colour schemes. Default (three colours), high contrast (all white on black) or night ( all red on black ).
|
||||
|
||||
## Kalman Filter
|
||||
|
||||
|
@ -67,13 +67,11 @@ This app will work quite happily on its own but will use the [GPS Setup App](htt
|
|||
|
||||
When using the GPS Setup App this app switches the GPS to SuperE (default) mode while the display is lit and showing fix information. This ensures that that fixes are updated every second or so. 10 seconds after the display is blanked by the watch this app will switch the GPS to PSMOO mode and will only attempt to get a fix every two minutes. This improves power saving while the display is off and the delay gives an opportunity to restore the display before the GPS power mode is switched.
|
||||
|
||||
The MAX values continue to be collected with the display off so may appear a little odd after the intermittent fixes of the low power mode.
|
||||
The MAX values continue to be collected with the display off so may appear a little odd after the intermittent fixes of the low power mode.
|
||||
|
||||
## Waypoints
|
||||
|
||||
Waypoints are used in [D]istance mode. Create a file waypoints.json and write to storage on the Bangle.js using the IDE. The first 6 characters of the name are displayed in Speed+[D]istance mode.
|
||||
|
||||
The [GPS Navigation](https://banglejs.com/apps/#gps%20navigation) app in the App Loader has a really nice waypoints file editor. (Must be connected to your Bangle.JS and then click on the Download icon.)
|
||||
Waypoints are used in Distance and VMG modes. See the `Waypoints` app for information on how to create/edit waypoints. The first 6 characters of the name are displayed in Speed+[D]istance mode.
|
||||
|
||||
Sample waypoints.json (My sailing waypoints)
|
||||
|
||||
|
@ -149,5 +147,3 @@ Developed for my use in sailing, cycling and motorcycling. If you find this soft
|
|||
Many thanks to Gordon Williams. Awesome job.
|
||||
|
||||
Special thanks also to @jeffmer, for the [GPS Navigation](https://banglejs.com/apps/#gps%20navigation) app and @hughbarney for the Low power GPS code development and Wouter Bulten for the Kalman filter code.
|
||||
|
||||
|
||||
|
|
|
@ -209,7 +209,7 @@ function nxtWp(inc){
|
|||
}
|
||||
|
||||
function loadWp() {
|
||||
var w = require("Storage").readJSON('waypoints.json')||[{name:"NONE"}];
|
||||
var w = require("waypoints").load();
|
||||
if (cfg.wp>=w.length) cfg.wp=0;
|
||||
if (cfg.wp<0) cfg.wp = w.length-1;
|
||||
savSettings();
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
"type": "app",
|
||||
"tags": "tool,outdoors",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"dependencies" : { "waypoints":"type" },
|
||||
"readme": "README.md",
|
||||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{"name":"speedalt.app.js","url":"app.js"},
|
||||
{"name":"speedalt.img","url":"app-icon.js","evaluate":true},
|
||||
{"name":"speedalt.settings.js","url":"settings.js"}
|
||||
],
|
||||
"data": [{"name":"speedalt.json"}]
|
||||
]
|
||||
}
|
||||
|
|
|
@ -15,3 +15,4 @@
|
|||
0.15: Droidscript mirroring prog automatically uses last connection address. Auto connects when run.
|
||||
0.16: Add configuration item Wpt File Suffix. A one character suffix to append to the waypoints.json file. A number of other apps also use this file name. Using the file name suffix allows the speedalt2 waypoints to be retained if one of these other apps is installed for a different use.
|
||||
0.17: Use default Bangle formatter for booleans
|
||||
0.18: Move waypoints.json to 'waypoints' app (with editor)
|
||||
|
|
|
@ -25,7 +25,7 @@ Touch functions as BTN1 short press.
|
|||
|
||||
## App Settings
|
||||
|
||||
Select the desired display units. Speed can be as per the default locale, kph, knots, mph or m/s. Distance can be km, miles or nautical miles. Altitude can be feet or metres. Select one of three colour schemes. Default (three colours), high contrast (all white on black) or night ( all red on black ).
|
||||
Select the desired display units. Speed can be as per the default locale, kph, knots, mph or m/s. Distance can be km, miles or nautical miles. Altitude can be feet or metres. Select one of three colour schemes. Default (three colours), high contrast (all white on black) or night ( all red on black ).
|
||||
|
||||
## Kalman Filter
|
||||
|
||||
|
@ -43,7 +43,7 @@ This app will work quite happily on its own but will use the [GPS Setup App](htt
|
|||
|
||||
When using the GPS Setup App this app switches the GPS to SuperE (default) mode while the display is lit and showing fix information. This ensures that that fixes are updated every second or so. 10 seconds after the display is blanked by the watch this app will switch the GPS to PSMOO mode and will only attempt to get a fix every two minutes. This improves power saving while the display is off and the delay gives an opportunity to restore the display before the GPS power mode is switched.
|
||||
|
||||
The MAX values continue to be collected with the display off so may appear a little odd after the intermittent fixes of the low power mode.
|
||||
The MAX values continue to be collected with the display off so may appear a little odd after the intermittent fixes of the low power mode.
|
||||
|
||||
## Velocity Made Good - VMG
|
||||
|
||||
|
@ -63,9 +63,9 @@ The Droidscript script file is called : **GPS Adv Sports II.js**
|
|||
|
||||
**Important Gotcha :** For the BLE comms to find and connect to the Bangle.js it must be paired with the Android device but **NOT** connected. The Bangle.js must have been set in the Bluetooth settings as connectable.
|
||||
|
||||
Start/Stop buttons tell the Bangle.js to start or stop sending BLE data packets to the Android device. While stopped the Bangle.js reverts to full power saving mode when the screen is asleep.
|
||||
Start/Stop buttons tell the Bangle.js to start or stop sending BLE data packets to the Android device. While stopped the Bangle.js reverts to full power saving mode when the screen is asleep.
|
||||
|
||||
When running a blue 'led' will flash each time a data packet is recieved to refresh the android display.
|
||||
When running a blue 'led' will flash each time a data packet is recieved to refresh the android display.
|
||||
|
||||
An orange 'led' will flash for each reconnection attempt if no data is received for 30 seconds. It will keep trying to reconnect so you can restart the Bangle, run another Bangle app or temprarily turn off bluetooth. The android mirror display will automatically reconnect when the GPS Adv Sports II app is running on the Bangle again. ( Designed to leave the Android device running as the display mirror in a sealed case all day while retaining the ability to do other functions on the Bangle.js and returning to the GPS Speed Alt II app. )
|
||||
|
||||
|
@ -74,14 +74,12 @@ Android Screen Mirroring:<br>
|
|||
|
||||
## Waypoints
|
||||
|
||||
Waypoints are used in Distance and VMG modes. Create a file waypoints.json and write to storage on the Bangle.js using the IDE. The first 6 characters of the name are displayed in Speed+[D]istance mode.
|
||||
|
||||
The [GPS Navigation](https://banglejs.com/apps/#gps%20navigation) app in the App Loader has a really nice waypoints file editor. (Must be connected to your Bangle.JS and then click on the Download icon.)
|
||||
Waypoints are used in Distance and VMG modes. See the `Waypoints` app for information on how to create/edit waypoints. The first 6 characters of the name are displayed in Speed+[D]istance mode.
|
||||
|
||||
By default the waypoints file is called waypoints.json
|
||||
|
||||
**Note** : The waypoints.json file is used by a number of different gps apps. The setting 'Wpt File Suffix' allows one of waypoints1.json, waypoints2.json or waypoints3.json to be used instead. This allows the other apps to be used with a different set of waypoints without losing the speedalt2 waypoint set.
|
||||
|
||||
**Note** : The waypoints.json file is used by a number of different gps apps. The setting 'Wpt File Suffix' allows one of waypoints.1.json, waypoints.2.json or waypoints.3.json to be used instead. This allows the other apps to be used with a different set of waypoints without losing the speedalt2 waypoint set.
|
||||
|
||||
Sample waypoints.json (My sailing waypoints)
|
||||
|
||||
<pre>
|
||||
|
@ -156,4 +154,3 @@ Developed for my use in sailing, cycling and motorcycling. If you find this soft
|
|||
Many thanks to Gordon Williams. Awesome job.
|
||||
|
||||
Special thanks also to @jeffmer, for the [GPS Navigation](https://banglejs.com/apps/#gps%20navigation) app and @hughbarney for the Low power GPS code development and Wouter Bulten for the Kalman filter code.
|
||||
|
||||
|
|
|
@ -185,7 +185,7 @@ let LED = // LED as minimal and only definition (as instance / singleton)
|
|||
, reset: function() { this.set(false); } // turn off
|
||||
, write: function(v) { this.set(v); } // turn on w/ no arg or truey, else off
|
||||
, toggle: function() { this.set( ! this.isOn); } // toggle the LED
|
||||
}, LED1 = LED; // LED1 as 'synonym' for LED
|
||||
}, LED1 = LED; // LED1 as 'synonym' for LED
|
||||
|
||||
|
||||
var lf = {fix:0,satellites:0};
|
||||
|
@ -210,7 +210,7 @@ function nxtWp(){
|
|||
}
|
||||
|
||||
function loadWp() {
|
||||
var w = require("Storage").readJSON('waypoints'+cfg.wptSfx+'.json')||[{name:"NONE"}];
|
||||
var w = require("waypoints").load(cfg.wptSfx);
|
||||
if (cfg.wp>=w.length) cfg.wp=0;
|
||||
if (cfg.wp<0) cfg.wp = w.length-1;
|
||||
savSettings();
|
||||
|
@ -239,7 +239,7 @@ function bearing(a,b){
|
|||
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);
|
||||
|
||||
|
||||
// Distance in metres
|
||||
var d = Math.sqrt(x*x + y*y) * 6371000;
|
||||
return d;
|
||||
|
@ -251,38 +251,38 @@ function drawScrn(dat) {
|
|||
|
||||
buf.clear();
|
||||
buf.setBgColor(0);
|
||||
|
||||
|
||||
var n;
|
||||
n = dat.val.toString();
|
||||
|
||||
|
||||
var s=50; // Font size
|
||||
var l=n.length;
|
||||
|
||||
|
||||
if ( l <= 7 ) s=55;
|
||||
if ( l <= 6 ) s=60;
|
||||
if ( l <= 5 ) s=80;
|
||||
if ( l <= 4 ) s=100;
|
||||
if ( l <= 3 ) s=120;
|
||||
|
||||
buf.setFontAlign(0,0); //Centre
|
||||
buf.setColor(1);
|
||||
|
||||
buf.setFontAlign(0,0); //Centre
|
||||
buf.setColor(1);
|
||||
buf.setFontVector(s);
|
||||
buf.drawString(n,126,52);
|
||||
|
||||
|
||||
|
||||
// Primary Units
|
||||
buf.setFontAlign(-1,1); //left, bottom
|
||||
buf.setColor(2);
|
||||
buf.setColor(2);
|
||||
buf.setFontVector(35);
|
||||
buf.drawString(dat.unit,5,164);
|
||||
|
||||
buf.drawString(dat.unit,5,164);
|
||||
|
||||
drawMax(dat.max); // MAX display indicator
|
||||
drawWP(dat.wp); // Waypoint name
|
||||
drawSats(dat.sats);
|
||||
|
||||
|
||||
g.reset();
|
||||
g.drawImage(img,0,40);
|
||||
|
||||
|
||||
LED1.write(!pwrSav);
|
||||
|
||||
}
|
||||
|
@ -295,7 +295,7 @@ function drawPosn(dat) {
|
|||
var x, y;
|
||||
x=210;
|
||||
y=0;
|
||||
buf.setFontAlign(1,-1);
|
||||
buf.setFontAlign(1,-1);
|
||||
buf.setFontVector(60);
|
||||
buf.setColor(1);
|
||||
|
||||
|
@ -320,45 +320,45 @@ function drawPosn(dat) {
|
|||
|
||||
function drawClock() {
|
||||
if (!canDraw) return;
|
||||
|
||||
|
||||
buf.clear();
|
||||
buf.setBgColor(0);
|
||||
|
||||
|
||||
var x, y;
|
||||
x=185;
|
||||
y=0;
|
||||
buf.setFontAlign(1,-1);
|
||||
buf.setFontAlign(1,-1);
|
||||
buf.setFontVector(94);
|
||||
time = require("locale").time(new Date(),1);
|
||||
|
||||
|
||||
buf.setColor(1);
|
||||
|
||||
|
||||
buf.drawString(time.substring(0,2),x,y);
|
||||
buf.drawString(time.substring(3,5),x,y+80);
|
||||
|
||||
|
||||
g.reset();
|
||||
g.drawImage(img,0,40);
|
||||
|
||||
|
||||
LED1.write(!pwrSav);
|
||||
}
|
||||
|
||||
function drawWP(wp) {
|
||||
buf.setColor(3);
|
||||
buf.setColor(3);
|
||||
buf.setFontAlign(0,1); //left, bottom
|
||||
buf.setFontVector(40);
|
||||
buf.drawString(wp,120,132);
|
||||
buf.drawString(wp,120,132);
|
||||
}
|
||||
|
||||
function drawSats(sats) {
|
||||
buf.setColor(3);
|
||||
buf.setColor(3);
|
||||
buf.setFont("6x8", 2);
|
||||
buf.setFontAlign(1,1); //right, bottom
|
||||
buf.drawString(sats,240,160);
|
||||
buf.drawString(sats,240,160);
|
||||
}
|
||||
|
||||
function drawMax(max) {
|
||||
buf.setFontVector(30);
|
||||
buf.setColor(2);
|
||||
buf.setColor(2);
|
||||
buf.setFontAlign(0,1); //centre, bottom
|
||||
buf.drawString(max,120,164);
|
||||
}
|
||||
|
@ -369,7 +369,7 @@ if ( emulator ) {
|
|||
fix.speed = 10 + (Math.random()*5);
|
||||
fix.alt = 354 + (Math.random()*50);
|
||||
fix.lat = -38.92;
|
||||
fix.lon = 175.7613350;
|
||||
fix.lon = 175.7613350;
|
||||
fix.course = 245;
|
||||
fix.satellites = 12;
|
||||
fix.time = new Date();
|
||||
|
@ -378,7 +378,7 @@ if ( emulator ) {
|
|||
|
||||
var m;
|
||||
|
||||
var sp = '---';
|
||||
var sp = '---';
|
||||
var al = sp;
|
||||
var di = sp;
|
||||
var brg = ''; // bearing
|
||||
|
@ -390,15 +390,15 @@ if ( emulator ) {
|
|||
var lon = '---.--';
|
||||
var sats = sp;
|
||||
var vmg = sp;
|
||||
|
||||
|
||||
|
||||
|
||||
// Waypoint name
|
||||
var wpName = wp.name;
|
||||
if ( wpName == undefined || wpName == 'NONE' ) wpName = '';
|
||||
wpName = wpName.substring(0,8);
|
||||
wpName = wpName.substring(0,8);
|
||||
|
||||
if (fix.fix) lf = fix;
|
||||
|
||||
|
||||
if (lf.fix) {
|
||||
|
||||
// Smooth data
|
||||
|
@ -408,10 +408,10 @@ if ( emulator ) {
|
|||
lf.smoothed = 1;
|
||||
if ( maxN <= 15 ) maxN++;
|
||||
}
|
||||
|
||||
|
||||
// Bearing to waypoint
|
||||
brg = bearing(lf,wp);
|
||||
|
||||
|
||||
// Current course
|
||||
crs = lf.course;
|
||||
|
||||
|
@ -447,19 +447,19 @@ if ( emulator ) {
|
|||
if ( di >= 100 ) di = parseFloat(di).toFixed(1);
|
||||
if ( di >= 1000 ) di = parseFloat(di).toFixed(0);
|
||||
if (isNaN(di)) di = '------';
|
||||
|
||||
|
||||
// Age of last fix (secs)
|
||||
age = Math.max(0,Math.round(getTime())-(lf.time.getTime()/1000));
|
||||
|
||||
// Lat / Lon
|
||||
ns = 'N';
|
||||
if ( lf.lat < 0 ) ns = 'S';
|
||||
lat = Math.abs(lf.lat.toFixed(2));
|
||||
lat = Math.abs(lf.lat.toFixed(2));
|
||||
|
||||
ew = 'E';
|
||||
if ( lf.lon < 0 ) ew = 'W';
|
||||
lon = Math.abs(lf.lon.toFixed(2));
|
||||
|
||||
lon = Math.abs(lf.lon.toFixed(2));
|
||||
|
||||
// Sats
|
||||
if ( age > 10 ) {
|
||||
sats = 'Age:'+Math.round(age);
|
||||
|
@ -573,7 +573,7 @@ if ( emulator ) {
|
|||
ew:ew
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if ( cfg.modeA == 5 ) {
|
||||
// Large clock
|
||||
drawClock();
|
||||
|
@ -585,14 +585,14 @@ function prevScrn() {
|
|||
cfg.modeA = cfg.modeA-1;
|
||||
if ( cfg.modeA < 0 ) cfg.modeA = 5;
|
||||
savSettings();
|
||||
onGPS(lf);
|
||||
onGPS(lf);
|
||||
}
|
||||
|
||||
function nextScrn() {
|
||||
cfg.modeA = cfg.modeA+1;
|
||||
if ( cfg.modeA > 5 ) cfg.modeA = 0;
|
||||
savSettings();
|
||||
onGPS(lf);
|
||||
onGPS(lf);
|
||||
}
|
||||
|
||||
// Next function on a screen
|
||||
|
@ -610,7 +610,7 @@ function nextFunc(dur) {
|
|||
function updateClock() {
|
||||
if (!canDraw) return;
|
||||
if ( cfg.modeA != 5 ) return;
|
||||
drawClock();
|
||||
drawClock();
|
||||
if ( emulator ) {maxSpd++;maxAlt++;}
|
||||
}
|
||||
|
||||
|
@ -661,10 +661,10 @@ function setButtons(){
|
|||
var dur = e.time - e.lastTime;
|
||||
nextFunc(dur);
|
||||
}, BTN1, { edge:"falling",repeat:true});
|
||||
|
||||
// Power saving on/off
|
||||
|
||||
// Power saving on/off
|
||||
setWatch(function(e){
|
||||
pwrSav=!pwrSav;
|
||||
pwrSav=!pwrSav;
|
||||
if ( pwrSav ) {
|
||||
var s = require('Storage').readJSON('setting.json',1)||{};
|
||||
var t = s.timeout||10;
|
||||
|
@ -676,7 +676,7 @@ function setButtons(){
|
|||
}
|
||||
LED1.write(!pwrSav);
|
||||
}, BTN2, {repeat:true,edge:"falling"});
|
||||
|
||||
|
||||
// BTN3 - next screen
|
||||
setWatch(function(e){
|
||||
nextScrn();
|
||||
|
@ -685,7 +685,7 @@ function setButtons(){
|
|||
|
||||
Bangle.on('lcdPower',function(on) {
|
||||
if (!SCREENACCESS.withApp) return;
|
||||
if (on) startDraw();
|
||||
if (on) startDraw();
|
||||
else stopDraw();
|
||||
});
|
||||
|
||||
|
@ -702,7 +702,7 @@ Bangle.on('touch', function(button){
|
|||
|
||||
// == Main Prog
|
||||
|
||||
// Read settings.
|
||||
// Read settings.
|
||||
let cfg = require('Storage').readJSON('speedalt2.json',1)||{};
|
||||
|
||||
cfg.spd = cfg.spd||1; // Multiplier for speed unit conversions. 0 = use the locale values for speed
|
||||
|
@ -713,13 +713,13 @@ cfg.dist = cfg.dist||1000;// Multiplier for distnce unit conversions.
|
|||
cfg.dist_unit = cfg.dist_unit||'km'; // Displayed altitude units
|
||||
cfg.colour = cfg.colour||0; // Colour scheme.
|
||||
cfg.wp = cfg.wp||0; // Last selected waypoint for dist
|
||||
cfg.modeA = cfg.modeA||0; // 0=Speed 1=Alt 2=Dist 3 = vmg 4=Position 5=Clock
|
||||
cfg.modeA = cfg.modeA||0; // 0=Speed 1=Alt 2=Dist 3 = vmg 4=Position 5=Clock
|
||||
cfg.primSpd = cfg.primSpd||0; // 1 = Spd in primary, 0 = Spd in secondary
|
||||
|
||||
cfg.spdFilt = cfg.spdFilt==undefined?true:cfg.spdFilt;
|
||||
cfg.spdFilt = cfg.spdFilt==undefined?true:cfg.spdFilt;
|
||||
cfg.altFilt = cfg.altFilt==undefined?true:cfg.altFilt;
|
||||
cfg.touch = cfg.touch==undefined?true:cfg.touch;
|
||||
cfg.wptSfx = cfg.wptSfx==undefined?'':cfg.wptSfx;
|
||||
cfg.wptSfx = cfg.wptSfx==undefined?'':cfg.wptSfx;
|
||||
|
||||
if ( cfg.spdFilt ) var spdFilter = new KalmanFilter({R: 0.1 , Q: 1 });
|
||||
if ( cfg.altFilt ) var altFilter = new KalmanFilter({R: 0.01, Q: 2 });
|
||||
|
@ -749,7 +749,7 @@ var SCREENACCESS = {
|
|||
withApp:true,
|
||||
request:function(){this.withApp=false;stopDraw();},
|
||||
release:function(){this.withApp=true;startDraw();}
|
||||
};
|
||||
};
|
||||
|
||||
var gpssetup;
|
||||
try {
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
"id": "speedalt2",
|
||||
"name": "GPS Adventure Sports II",
|
||||
"shortName":"GPS Adv Sport II",
|
||||
"version":"0.17",
|
||||
"version":"0.18",
|
||||
"description": "GPS speed, altitude and distance to waypoint display. Designed for easy viewing and use during outdoor activities such as para-gliding, hang-gliding, sailing, cycling etc.",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
"tags": "tool,outdoors",
|
||||
"supports": ["BANGLEJS"],
|
||||
"dependencies" : { "waypoints":"type" },
|
||||
"readme": "README.md",
|
||||
"allow_emulator": true,
|
||||
"storage": [
|
||||
|
@ -16,10 +17,6 @@
|
|||
{"name":"speedalt2.settings.js","url":"settings.js"}
|
||||
],
|
||||
"data": [
|
||||
{"name":"speedalt2.json"},
|
||||
{"name":"waypoints.json"},
|
||||
{"name":"waypoints1.json"},
|
||||
{"name":"waypoints2.json"},
|
||||
{"name":"waypoints3.json"}
|
||||
{"name":"speedalt2.json"}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
0.01: New app!
|
||||
0.02: Make Bangle.js 2 compatible
|
||||
0.03: Silently use built in heading when no magnav calibration file is present
|
||||
0.04: Move waypoints.json (and editor) to 'waypoints' app
|
||||
|
|
|
@ -61,58 +61,10 @@ 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.
|
||||
## Setting Waypoints
|
||||
|
||||
Check out the documentation for the `Waypoints` app. This provides
|
||||
the ability to set waypoints from your browser.
|
||||
|
||||
## Calibration of the Compass
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ 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(buf1.getWidth()/2,buf1.getHeight()/2,79*scale);
|
||||
buf1.setColor(0);
|
||||
|
@ -63,10 +63,10 @@ function drawCompass(course) {
|
|||
/***** COMPASS CODE ***********/
|
||||
|
||||
var heading = 0;
|
||||
function newHeading(m,h){
|
||||
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>=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;
|
||||
|
@ -147,9 +147,9 @@ function drawN(){
|
|||
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;
|
||||
|
@ -159,7 +159,7 @@ function drawN(){
|
|||
buf2.drawString(dst,0,0);
|
||||
flip2_bw(0, g.getHeight()-40*scale);
|
||||
}
|
||||
|
||||
|
||||
// bearing, place in middle at bottom of compass
|
||||
if (previous.bs !== bs) {
|
||||
previous.bs = bs;
|
||||
|
@ -192,7 +192,7 @@ function onGPS(fix) {
|
|||
if (fix!==undefined){
|
||||
satellites = fix.satellites;
|
||||
}
|
||||
|
||||
|
||||
if (candraw) {
|
||||
if (fix!==undefined && fix.fix==1){
|
||||
dist = distance(fix,wp);
|
||||
|
@ -240,7 +240,7 @@ function setButtons(){
|
|||
else { doselect(); }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Bangle.on('lcdPower',function(on) {
|
||||
if (on) {
|
||||
clear_previous();
|
||||
|
@ -250,7 +250,7 @@ Bangle.on('lcdPower',function(on) {
|
|||
}
|
||||
});
|
||||
|
||||
var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"NONE"}];
|
||||
var waypoints = require("waypoints").load();
|
||||
wp=waypoints[0];
|
||||
|
||||
function nextwp(inc){
|
||||
|
@ -266,7 +266,7 @@ 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);
|
||||
require("waypoints").save(waypoints);
|
||||
}
|
||||
selected=!selected;
|
||||
drawN();
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
{
|
||||
"id": "waypointer",
|
||||
"name": "Way Pointer",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "Navigate to a waypoint using the GPS for bearing and compass to point way, uses the same waypoint interface as GPS Navigation",
|
||||
"icon": "waypointer.png",
|
||||
"tags": "tool,outdoors,gps",
|
||||
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||
"dependencies" : { "waypoints":"type" },
|
||||
"readme": "README.md",
|
||||
"interface": "waypoints.html",
|
||||
"storage": [
|
||||
{"name":"waypointer.app.js","url":"app.js"},
|
||||
{"name":"waypointer.img","url":"icon.js","evaluate":true}
|
||||
],
|
||||
"data": [{"name":"waypoints.json","url":"waypoints.json"}]
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,170 +0,0 @@
|
|||
<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);
|
||||
var lon = parseFloat($longtitude.value);
|
||||
|
||||
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>
|
|
@ -1,20 +0,0 @@
|
|||
[
|
||||
{
|
||||
"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" }
|
||||
]
|
|
@ -0,0 +1 @@
|
|||
0.01: New App!
|
|
@ -0,0 +1,56 @@
|
|||
# Waypoints
|
||||
|
||||
This app provides a common way to set up the `waypoints.json` file,
|
||||
which several other apps rely on for navigation.
|
||||
|
||||
## 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 `Waypoints` 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.
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwJC/AH4A/AH4AgA=="))
|
|
@ -0,0 +1,34 @@
|
|||
// place your const, vars, functions or classes here
|
||||
|
||||
// clear the screen
|
||||
g.clear();
|
||||
|
||||
var n = 0;
|
||||
|
||||
// redraw the screen
|
||||
function draw() {
|
||||
g.reset().clearRect(Bangle.appRect);
|
||||
g.setFont("6x8").setFontAlign(0,0).drawString("Up / Down",g.getWidth()/2,g.getHeight()/2 - 20);
|
||||
g.setFont("Vector",60).setFontAlign(0,0).drawString(n,g.getWidth()/2,g.getHeight()/2 + 30);
|
||||
}
|
||||
|
||||
// Respond to user input
|
||||
Bangle.setUI({mode: "updown"}, function(dir) {
|
||||
if (dir<0) {
|
||||
n--;
|
||||
draw();
|
||||
} else if (dir>0) {
|
||||
n++;
|
||||
draw();
|
||||
} else {
|
||||
n = 0;
|
||||
draw();
|
||||
}
|
||||
});
|
||||
|
||||
// First draw...
|
||||
draw();
|
||||
|
||||
// Load widgets
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
|
@ -4,6 +4,7 @@
|
|||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="../../css/spectre.min.css">
|
||||
<link rel="stylesheet" href="../../css/spectre-icons.min.css">
|
||||
<link rel="stylesheet" href="../../css/spectre-icons.min.css">
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.css">
|
||||
|
||||
|
@ -11,6 +12,8 @@
|
|||
html, body { height: 100% }
|
||||
.flex-col { display:flex; flex-direction:column; height:100% }
|
||||
#map { width:100%; height:100% }
|
||||
#tab-map { width:100%; height:100% }
|
||||
#tab-list { width:100%; height:100% }
|
||||
|
||||
/* https://stackoverflow.com/a/58686215 */
|
||||
.arrow-icon {
|
||||
|
@ -23,6 +26,7 @@
|
|||
transform-origin: center center;
|
||||
font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -32,8 +36,57 @@
|
|||
<span id="status"></span>
|
||||
<span id="routestatus"></span>
|
||||
</div>
|
||||
<div>
|
||||
<ul class="tab tab-block">
|
||||
<li class="tab-item active" id="tabitem-map">
|
||||
<a href="#">Map</a>
|
||||
</li>
|
||||
<li class="tab-item" id="tabitem-list">
|
||||
<a href="#">List</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div style="flex: 1">
|
||||
<div id="tab-map">
|
||||
<div id="map"></div>
|
||||
</div>
|
||||
<div id="tab-list" style="display:none">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -44,8 +97,23 @@
|
|||
<script src="../../core/lib/interface.js"></script>
|
||||
|
||||
<script>
|
||||
var map;
|
||||
var waypoints = [];
|
||||
|
||||
// ========================================================================== tabs
|
||||
document.getElementById('tabitem-map').addEventListener('click',function() {
|
||||
document.getElementById('tabitem-map').classList.remove("active");
|
||||
document.getElementById('tabitem-list').classList.add("active");
|
||||
document.getElementById('tab-map').style.display="block";
|
||||
document.getElementById('tab-list').style.display="none";
|
||||
});
|
||||
document.getElementById('tabitem-list').addEventListener('click',function() {
|
||||
document.getElementById('tabitem-map').classList.add("active");
|
||||
document.getElementById('tabitem-list').classList.remove("active");
|
||||
document.getElementById('tab-map').style.display="none";
|
||||
document.getElementById('tab-list').style.display="block";
|
||||
});
|
||||
// ========================================================================== MAP
|
||||
var map;
|
||||
var mapmarkers = L.layerGroup();
|
||||
var searchresult = L.layerGroup();
|
||||
var dynamicarrow = L.layerGroup();
|
||||
|
@ -100,9 +168,6 @@
|
|||
L.featureGroup(getArrows(latlngs, 'black', 2, map)).addTo(dynamicarrow)
|
||||
map.addLayer(dynamicarrow);
|
||||
});
|
||||
clean();
|
||||
renderAllWaypoints();
|
||||
|
||||
/*** status ***/
|
||||
|
||||
function clean() {
|
||||
|
@ -152,11 +217,11 @@
|
|||
dirty();
|
||||
}
|
||||
|
||||
function renderWaypoints(wps, isroute, parentidx) {
|
||||
function renderWaypointsMap(wps, isroute, parentidx) {
|
||||
var latlngs = [];
|
||||
for (var i = 0; i < wps.length; i++) {
|
||||
if (wps[i].route) {
|
||||
renderWaypoints(wps[i].route, true, i);
|
||||
renderWaypointsMap(wps[i].route, true, i);
|
||||
continue;
|
||||
}
|
||||
if (wps[i].lat == null || wps[i].lon == null)
|
||||
|
@ -182,7 +247,8 @@
|
|||
|
||||
function renderAllWaypoints() {
|
||||
mapmarkers.clearLayers();
|
||||
renderWaypoints(waypoints, false, 0);
|
||||
renderWaypointsMap(waypoints, false, 0);
|
||||
renderWaypointsList();
|
||||
map.addLayer(mapmarkers);
|
||||
}
|
||||
|
||||
|
@ -234,51 +300,18 @@
|
|||
|
||||
/*** Bangle.js ***/
|
||||
|
||||
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);
|
||||
clean();
|
||||
});
|
||||
}
|
||||
|
||||
function uploadFile(fileid, contents) {
|
||||
Puck.write(`\x10(function() {
|
||||
require("Storage").write("${fileid}",'${contents}');
|
||||
Bluetooth.print("OK");
|
||||
})()\n`, ret => {
|
||||
console.log("uploadFile", ret);
|
||||
if (ret == "OK")
|
||||
clean();
|
||||
});
|
||||
}
|
||||
|
||||
function gotStored(pts) {
|
||||
waypoints = pts;
|
||||
|
||||
var latlngs = waypoints.map(p => [p.lat, p.lon]);
|
||||
var latlngs = waypoints.filter(p => isFinite(p.lat)&&isFinite(p.lon)).map(p => [p.lat, p.lon]);
|
||||
var poly = L.polygon(latlngs);
|
||||
map.fitBounds(poly.getBounds());
|
||||
var bounds = poly.getBounds();
|
||||
if (bounds.isValid())
|
||||
map.fitBounds(bounds);
|
||||
|
||||
renderAllWaypoints();
|
||||
}
|
||||
|
||||
function onInit() {
|
||||
downloadJSONfile("waypoints.json", gotStored);
|
||||
}
|
||||
|
||||
$('#download').on('click', function() {
|
||||
downloadJSONfile("waypoints.json", gotStored);
|
||||
});
|
||||
|
||||
$('#upload').click(function() {
|
||||
var data = JSON.stringify(waypoints);
|
||||
uploadFile("waypoints.json",data);
|
||||
});
|
||||
|
||||
$('#statusarea').click(closeRoute);
|
||||
|
||||
/*** map arrows ***/
|
||||
|
@ -348,5 +381,136 @@
|
|||
this.x = (round ? Math.round(x) : x);
|
||||
this.y = (round ? Math.round(y) : y);
|
||||
}
|
||||
|
||||
// ========================================================================== LIST
|
||||
|
||||
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);
|
||||
var lon = parseFloat($longtitude.value);
|
||||
|
||||
waypoints.push({
|
||||
name, lat,lon,
|
||||
});
|
||||
|
||||
waypoints.sort(compare);
|
||||
|
||||
renderAllWaypoints()
|
||||
$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);
|
||||
|
||||
renderAllWaypoints()
|
||||
$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)
|
||||
renderAllWaypoints()
|
||||
}
|
||||
|
||||
function renderWaypointsList(){
|
||||
$list.innerHTML = ''
|
||||
waypoints.forEach((waypoint,index) => {
|
||||
var $waypoint = document.createElement('tr')
|
||||
if (index==0){
|
||||
$waypoint.innerHTML = `<td>${waypoint.name}</td><td></td><td></td>`
|
||||
} else if(waypoint.lat==undefined){
|
||||
$waypoint.innerHTML = `<td>${waypoint.name}</td><td>------</td><td>-----</td>`;
|
||||
} else {
|
||||
$waypoint.innerHTML = `<td>${waypoint.name}</td><td>${waypoint.lat.toFixed(6)}</td><td>${waypoint.lon.toFixed(6)}</td>`;
|
||||
}
|
||||
$waypoint.innerHTML += `<td><button class="btn btn-action btn-primary" onclick="removeWaypoint(${index})"><i class="icon icon-delete"></i></button></td>`;
|
||||
$list.appendChild($waypoint)
|
||||
})
|
||||
$name.focus()
|
||||
}
|
||||
|
||||
function renderWaypoints() {
|
||||
renderWaypointsList();
|
||||
renderWaypointsMap();
|
||||
}
|
||||
|
||||
// ========================================================================== UPLOAD/DOWNLOAD
|
||||
|
||||
function downloadJSONfile(fileid, callback) {
|
||||
// TODO: use interface.js-provided stuff?
|
||||
Puck.write(`\x10(function() {
|
||||
var pts = require("Storage").readJSON("${fileid}")||[{name:"NONE"}];
|
||||
Bluetooth.print(JSON.stringify(pts));
|
||||
})()\n`, contents => {
|
||||
if (contents=='[{name:"NONE"}]') contents="[]";
|
||||
var storedpts = JSON.parse(contents);
|
||||
callback(storedpts);
|
||||
clean();
|
||||
});
|
||||
}
|
||||
|
||||
function uploadFile(fileid, contents) {
|
||||
// TODO: use interface.js-provided stuff?
|
||||
Puck.write(`\x10(function() {
|
||||
require("Storage").write("${fileid}",'${contents}');
|
||||
Bluetooth.print("OK");
|
||||
})()\n`, ret => {
|
||||
console.log("uploadFile", ret);
|
||||
if (ret == "OK")
|
||||
clean();
|
||||
});
|
||||
}
|
||||
|
||||
function onInit() {
|
||||
downloadJSONfile("waypoints.json", gotStored);
|
||||
}
|
||||
|
||||
$('#download').on('click', function() {
|
||||
downloadJSONfile("waypoints.json", gotStored);
|
||||
});
|
||||
|
||||
$('#upload').click(function() {
|
||||
var data = JSON.stringify(waypoints);
|
||||
uploadFile("waypoints.json",data);
|
||||
});
|
||||
|
||||
// ========================================================================== FINALLY...
|
||||
clean();
|
||||
renderAllWaypoints();
|
||||
</script>
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,7 @@
|
|||
exports.load = (num) => {
|
||||
return require("Storage").readJSON(`waypoints${num?`.${num}`:""}.json`)||[{name:"NONE"}];
|
||||
};
|
||||
|
||||
exports.save = (waypoints,num) => {
|
||||
require("Storage").writeJSON(`waypoints${num?`.${num}`:""}.json`, waypoints);
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
{ "id": "waypoints",
|
||||
"name": "Waypoints",
|
||||
"version":"0.01",
|
||||
"description": "Provides 'waypoints.json' used by various navigation apps, as well as a way to edit it from the App Loader with maps or a list",
|
||||
"icon": "app.png",
|
||||
"tags": "tool,outdoors,gps",
|
||||
"type": "waypoints",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"interface": "interface.html",
|
||||
"storage": [
|
||||
{"name":"waypoints","url":"lib.js"}
|
||||
],
|
||||
"data": [
|
||||
{"name":"waypoints.json","url":"waypoints.json"},
|
||||
{"name":"waypoints.1.json"},
|
||||
{"name":"waypoints.2.json"},
|
||||
{"name":"waypoints.3.json"}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
[
|
||||
{
|
||||
"name":"No10",
|
||||
"lat":51.5032,
|
||||
"lon":-0.1269
|
||||
},
|
||||
{
|
||||
"name":"Stone",
|
||||
"lat":51.1788,
|
||||
"lon":-1.8260
|
||||
}
|
||||
]
|
|
@ -1,2 +1,3 @@
|
|||
...
|
||||
0.02: First update with ChangeLog Added
|
||||
0.03: Move waypoints.json (and editor) to 'waypoints' app
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
var loc = require("locale");
|
||||
|
||||
var waypoints = require("Storage").readJSON("waypoints.json") || [];
|
||||
var waypoints = require("waypoints").load();
|
||||
var wp = waypoints[0];
|
||||
if (wp == undefined) wp = {name:"NONE"};
|
||||
var wp_bearing = 0;
|
||||
|
@ -196,7 +196,7 @@ function addCurrentWaypoint() {
|
|||
}
|
||||
|
||||
function saveWaypoints() {
|
||||
require("Storage").writeJSON("waypoints.json", waypoints);
|
||||
require("waypoints").save(waypoints);
|
||||
}
|
||||
|
||||
function deleteWaypoint(w) {
|
||||
|
|
|
@ -2,17 +2,16 @@
|
|||
"id": "wpmoto",
|
||||
"name": "Waypointer Moto",
|
||||
"shortName": "Waypointer Moto",
|
||||
"version": "0.02",
|
||||
"version": "0.03",
|
||||
"description": "Waypoint-based motorcycle navigation aid",
|
||||
"icon": "wpmoto.png",
|
||||
"tags": "tool,outdoors,gps",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"screenshots": [{"url":"screenshot.png"},{"url":"screenshot-menu.png"},{"url":"screenshot-delete.png"}],
|
||||
"readme": "README.md",
|
||||
"interface": "wpmoto.html",
|
||||
"dependencies" : { "waypoints":"type" },
|
||||
"storage": [
|
||||
{"name":"wpmoto.app.js","url":"app.js"},
|
||||
{"name":"wpmoto.img","url":"icon.js","evaluate":true}
|
||||
],
|
||||
"data": [{"name":"waypoints.json","url":"waypoints.json"}]
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[
|
||||
{
|
||||
"name":"NONE"
|
||||
},
|
||||
]
|
|
@ -77,12 +77,13 @@ const APP_KEYS = [
|
|||
const STORAGE_KEYS = ['name', 'url', 'content', 'evaluate', 'noOverwite', 'supports'];
|
||||
const DATA_KEYS = ['name', 'wildcard', 'storageFile', 'url', 'content', 'evaluate'];
|
||||
const SUPPORTS_DEVICES = ["BANGLEJS","BANGLEJS2"]; // device IDs allowed for 'supports'
|
||||
const METADATA_TYPES = ["app","clock","widget","bootloader","RAM","launch","textinput","scheduler","notify","locale","settings"]; // values allowed for "type" field
|
||||
const METADATA_TYPES = ["app","clock","widget","bootloader","RAM","launch","textinput","scheduler","notify","locale","settings","waypoints"]; // values allowed for "type" field
|
||||
const FORBIDDEN_FILE_NAME_CHARS = /[,;]/; // used as separators in appid.info
|
||||
const VALID_DUPLICATES = [ '.tfmodel', '.tfnames' ];
|
||||
const GRANDFATHERED_ICONS = ["s7clk", "snek", "astral", "alpinenav", "slomoclock", "arrow", "pebble", "rebble"];
|
||||
const INTERNAL_FILES_IN_APP_TYPE = { // list of app types and files they SHOULD provide...
|
||||
'textinput' : ['textinput'],
|
||||
'waypoints' : ['waypoints'],
|
||||
// notify?
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue