Merge branch 'upstream/master' into fix/improve-formatter-check
commit
b2ff9dbb78
|
|
@ -1 +1 @@
|
||||||
0.01: New Widget!
|
0.01: New Clock Info!
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: New Clock!
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Clock Name
|
||||||
|
|
||||||
|
More info on making Clock Faces: https://www.espruino.com/Bangle.js+Clock
|
||||||
|
|
||||||
|
Describe the Clock...
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Describe how to use it
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
Name the function
|
||||||
|
|
||||||
|
## Controls
|
||||||
|
|
||||||
|
Name the buttons and what they are used for
|
||||||
|
|
||||||
|
## Requests
|
||||||
|
|
||||||
|
Name who should be contacted for support/update requests
|
||||||
|
|
||||||
|
## Creator
|
||||||
|
|
||||||
|
Your name
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwwJC/AH4A/AH4AgA=="))
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
// timeout used to update every minute
|
||||||
|
var drawTimeout;
|
||||||
|
|
||||||
|
// schedule a draw for the next minute
|
||||||
|
function queueDraw() {
|
||||||
|
if (drawTimeout) clearTimeout(drawTimeout);
|
||||||
|
drawTimeout = setTimeout(function() {
|
||||||
|
drawTimeout = undefined;
|
||||||
|
draw();
|
||||||
|
}, 60000 - (Date.now() % 60000));
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
// queue next draw in one minute
|
||||||
|
queueDraw();
|
||||||
|
// Work out where to draw...
|
||||||
|
var x = g.getWidth()/2;
|
||||||
|
var y = g.getHeight()/2;
|
||||||
|
g.reset();
|
||||||
|
// work out locale-friendly date/time
|
||||||
|
var date = new Date();
|
||||||
|
var timeStr = require("locale").time(date,1);
|
||||||
|
var dateStr = require("locale").date(date);
|
||||||
|
// draw time
|
||||||
|
g.setFontAlign(0,0).setFont("Vector",48);
|
||||||
|
g.clearRect(0,y-15,g.getWidth(),y+25); // clear the background
|
||||||
|
g.drawString(timeStr,x,y);
|
||||||
|
// draw date
|
||||||
|
y += 35;
|
||||||
|
g.setFontAlign(0,0).setFont("6x8");
|
||||||
|
g.clearRect(0,y-4,g.getWidth(),y+4); // clear the background
|
||||||
|
g.drawString(dateStr,x,y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the screen once, at startup
|
||||||
|
g.clear();
|
||||||
|
// draw immediately at first, queue update
|
||||||
|
draw();
|
||||||
|
|
||||||
|
// Show launcher when middle button pressed
|
||||||
|
Bangle.setUI("clock");
|
||||||
|
// Load widgets
|
||||||
|
Bangle.loadWidgets();
|
||||||
|
Bangle.drawWidgets();
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
|
|
@ -0,0 +1,15 @@
|
||||||
|
{ "id": "7chname",
|
||||||
|
"name": "My clock human readable name",
|
||||||
|
"shortName":"Short Name",
|
||||||
|
"version":"0.01",
|
||||||
|
"description": "A detailed description of my clock",
|
||||||
|
"icon": "icon.png",
|
||||||
|
"type": "clock",
|
||||||
|
"tags": "clock",
|
||||||
|
"supports" : ["BANGLEJS2"],
|
||||||
|
"readme": "README.md",
|
||||||
|
"storage": [
|
||||||
|
{"name":"7chname.app.js","url":"app.js"},
|
||||||
|
{"name":"7chname.img","url":"app-icon.js","evaluate":true}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -32,3 +32,4 @@
|
||||||
Allow alarm enable/disable
|
Allow alarm enable/disable
|
||||||
0.31: Implement API for activity fetching
|
0.31: Implement API for activity fetching
|
||||||
0.32: Added support for loyalty cards from gadgetbridge
|
0.32: Added support for loyalty cards from gadgetbridge
|
||||||
|
0.33: Fix alarms created in Gadgetbridge not repeating
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,12 @@
|
||||||
for (var j = 0; j < event.d.length; j++) {
|
for (var j = 0; j < event.d.length; j++) {
|
||||||
// prevents all alarms from going off at once??
|
// prevents all alarms from going off at once??
|
||||||
var dow = event.d[j].rep;
|
var dow = event.d[j].rep;
|
||||||
if (!dow) dow = 127; //if no DOW selected, set alarm to all DOW
|
var rp = false;
|
||||||
|
if (!dow) {
|
||||||
|
dow = 127; //if no DOW selected, set alarm to all DOW
|
||||||
|
} else {
|
||||||
|
rp = true;
|
||||||
|
}
|
||||||
var last = (event.d[j].h * 3600000 + event.d[j].m * 60000 < currentTime) ? (new Date()).getDate() : 0;
|
var last = (event.d[j].h * 3600000 + event.d[j].m * 60000 < currentTime) ? (new Date()).getDate() : 0;
|
||||||
var a = require("sched").newDefaultAlarm();
|
var a = require("sched").newDefaultAlarm();
|
||||||
a.id = "gb"+j;
|
a.id = "gb"+j;
|
||||||
|
|
@ -89,6 +94,7 @@
|
||||||
a.on = event.d[j].on !== undefined ? event.d[j].on : true;
|
a.on = event.d[j].on !== undefined ? event.d[j].on : true;
|
||||||
a.t = event.d[j].h * 3600000 + event.d[j].m * 60000;
|
a.t = event.d[j].h * 3600000 + event.d[j].m * 60000;
|
||||||
a.dow = ((dow&63)<<1) | (dow>>6); // Gadgetbridge sends DOW in a different format
|
a.dow = ((dow&63)<<1) | (dow>>6); // Gadgetbridge sends DOW in a different format
|
||||||
|
a.rp = rp;
|
||||||
a.last = last;
|
a.last = last;
|
||||||
alarms.push(a);
|
alarms.push(a);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "android",
|
"id": "android",
|
||||||
"name": "Android Integration",
|
"name": "Android Integration",
|
||||||
"shortName": "Android",
|
"shortName": "Android",
|
||||||
"version": "0.32",
|
"version": "0.33",
|
||||||
"description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.",
|
"description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"tags": "tool,system,messages,notifications,gadgetbridge",
|
"tags": "tool,system,messages,notifications,gadgetbridge",
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "BTHome Temperature and Pressure",
|
"name": "BTHome Temperature and Pressure",
|
||||||
"shortName":"BTHome T",
|
"shortName":"BTHome T",
|
||||||
"version":"0.02",
|
"version":"0.02",
|
||||||
"description": "Displays temperature and pressure, and advertises them over bluetooth using BTHome.io standard",
|
"description": "Displays temperature and pressure, and advertises them over bluetooth for Home Assistant using BTHome.io standard",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"tags": "bthome,bluetooth,temperature",
|
"tags": "bthome,bluetooth,temperature",
|
||||||
"supports" : ["BANGLEJS2"],
|
"supports" : ["BANGLEJS2"],
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "ha",
|
"id": "ha",
|
||||||
"name": "Home Assistant",
|
"name": "Home Assistant",
|
||||||
"version": "0.10",
|
"version": "0.10",
|
||||||
"description": "Integrates your Bangle.js into Home Assistant.",
|
"description": "Integrates your Bangle.js into Home Assistant using Android Integration/Gadgetbridge",
|
||||||
"icon": "ha.png",
|
"icon": "ha.png",
|
||||||
"type": "app",
|
"type": "app",
|
||||||
"tags": "tool,clkinfo,bluetooth",
|
"tags": "tool,clkinfo,bluetooth",
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
"name": "Home Assistant Sensors",
|
"name": "Home Assistant Sensors",
|
||||||
"shortName": "HA sensors",
|
"shortName": "HA sensors",
|
||||||
"version": "0.02",
|
"version": "0.02",
|
||||||
"description": "Send sensor values to Home Assistant using the Android Integration.",
|
"description": "Send sensor values to Home Assistant using Android Integration/Gadgetbridge",
|
||||||
"icon": "ha.png",
|
"icon": "ha.png",
|
||||||
"type": "bootloader",
|
"type": "bootloader",
|
||||||
"tags": "tool,sensors",
|
"tags": "tool,sensors",
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
0.01: New App!
|
0.01: New App!
|
||||||
|
0.02: Add more control styles
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,21 @@ in the future this app will be able to support other types of remote (see below)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Run the app, and ensure you're not connected to your watch via Bluetooth
|
Run the app, then choose the type of controls you want and ensure you're not connected
|
||||||
(a warning will pop up if so).
|
to your watch via Bluetooth (a warning will pop up if so).
|
||||||
|
|
||||||
|
Linear mode controls A/B axes individually, and allows you to vary the speed of the
|
||||||
|
motors based on the distance you drag from the centre. Other modes just use on/off
|
||||||
|
buttons.
|
||||||
|
|
||||||
|
| Mode | up | down | left | right |
|
||||||
|
|------------|------|------|------|-------|
|
||||||
|
| **Linear** | +A | -A | -B | +B |
|
||||||
|
| **Normal** | +A | -A | -B | +B |
|
||||||
|
| **Tank** | -A+B | +A-B | +A+B | -A-B |
|
||||||
|
| **Merged** | -A-B | +A+B | +A-B | -A+B |
|
||||||
|
|
||||||
|
In all cases pressing the C/D buttons will turn on C/D outputs
|
||||||
|
|
||||||
Now press the arrow keys on the screen to control the robot.
|
Now press the arrow keys on the screen to control the robot.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
var lego = require("mouldking");
|
var lego = require("mouldking");
|
||||||
lego.start();
|
|
||||||
E.on('kill', () => {
|
E.on('kill', () => {
|
||||||
// return to normal Bluetooth advertising
|
// return to normal Bluetooth advertising
|
||||||
NRF.setAdvertising({},{showName:true});
|
NRF.setAdvertising({},{showName:true});
|
||||||
|
|
@ -12,59 +11,133 @@ var controlState = "";
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
Bangle.drawWidgets();
|
Bangle.drawWidgets();
|
||||||
var R = Bangle.appRect;
|
var R = Bangle.appRect;
|
||||||
// we'll divide up into 3x3
|
|
||||||
function getBoxCoords(x,y) {
|
|
||||||
return {
|
|
||||||
x : R.x + R.w*x/3,
|
|
||||||
y : R.y + R.h*y/3
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function draw() {
|
function startLegoButtons(controls) {
|
||||||
g.reset().clearRect(R);
|
// we'll divide up into 3x3
|
||||||
var c, ninety = Math.PI/2;
|
function getBoxCoords(x,y) {
|
||||||
var colOn = "#f00", colOff = g.theme.fg;
|
return {
|
||||||
c = getBoxCoords(1.5, 0.5);
|
x : R.x + R.w*x/3,
|
||||||
g.setColor(controlState=="up"?colOn:colOff).drawImage(arrowIcon,c.x,c.y,{rotate:0});
|
y : R.y + R.h*y/3
|
||||||
c = getBoxCoords(2.5, 1.5);
|
};
|
||||||
g.setColor(controlState=="right"?colOn:colOff).drawImage(arrowIcon,c.x,c.y,{rotate:ninety});
|
|
||||||
c = getBoxCoords(0.5, 1.5);
|
|
||||||
g.setColor(controlState=="left"?colOn:colOff).drawImage(arrowIcon,c.x,c.y,{rotate:-ninety});
|
|
||||||
c = getBoxCoords(1.5, 1.5);
|
|
||||||
g.setColor(controlState=="down"?colOn:colOff).drawImage(arrowIcon,c.x,c.y,{rotate:ninety*2});
|
|
||||||
if (NRF.getSecurityStatus().connected) {
|
|
||||||
c = getBoxCoords(1.5, 2.5);
|
|
||||||
g.setFontAlign(0,0).setFont("6x8").drawString("WARNING:\nBluetooth Connected\nYou must disconnect\nbefore LEGO will work",c.x,c.y);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
draw();
|
|
||||||
NRF.on('connect', draw);
|
|
||||||
NRF.on('disconnect', draw);
|
|
||||||
|
|
||||||
function setControlState(s) {
|
function draw() {
|
||||||
controlState = s;
|
g.reset().clearRect(R);
|
||||||
var c = {};
|
var c, ninety = Math.PI/2;
|
||||||
var speed = 3;
|
var colOn = "#f00", colOff = g.theme.fg;
|
||||||
if (s=="up") c={a:-speed,b:-speed};
|
c = getBoxCoords(1.5, 0.5);
|
||||||
if (s=="down") c={a:speed,b:speed};
|
g.setColor(controlState=="up"?colOn:colOff).drawImage(arrowIcon,c.x,c.y,{rotate:0});
|
||||||
if (s=="left") c={a:speed,b:-speed};
|
c = getBoxCoords(2.5, 1.5);
|
||||||
if (s=="right") c={a:-speed,b:speed};
|
g.setColor(controlState=="right"?colOn:colOff).drawImage(arrowIcon,c.x,c.y,{rotate:ninety});
|
||||||
|
c = getBoxCoords(0.5, 1.5);
|
||||||
|
g.setColor(controlState=="left"?colOn:colOff).drawImage(arrowIcon,c.x,c.y,{rotate:-ninety});
|
||||||
|
c = getBoxCoords(1.5, 1.5);
|
||||||
|
g.setColor(controlState=="down"?colOn:colOff).drawImage(arrowIcon,c.x,c.y,{rotate:ninety*2});
|
||||||
|
if (NRF.getSecurityStatus().connected) {
|
||||||
|
c = getBoxCoords(1.5, 2.5);
|
||||||
|
g.setFontAlign(0,0).setFont("6x8").drawString("WARNING:\nBluetooth Connected\nYou must disconnect\nbefore LEGO will work",c.x,c.y);
|
||||||
|
}
|
||||||
|
g.setFont("6x8:3").setFontAlign(0,0);
|
||||||
|
c = getBoxCoords(0.5, 0.5);
|
||||||
|
g.setColor(controlState=="c"?colOn:colOff).drawString("C",c.x,c.y);
|
||||||
|
c = getBoxCoords(2.5, 0.5);
|
||||||
|
g.setColor(controlState=="d"?colOn:colOff).drawString("D",c.x,c.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setControlState(s) {
|
||||||
|
controlState = s;
|
||||||
|
var c = {};
|
||||||
|
if (s in controls)
|
||||||
|
c = controls[s];
|
||||||
|
draw();
|
||||||
|
lego.set(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
lego.start();
|
||||||
|
Bangle.setUI({mode:"custom", drag : e => {
|
||||||
|
var x = Math.floor(E.clip((e.x - R.x) * 3 / R.w,0,2.99));
|
||||||
|
var y = Math.floor(E.clip((e.y - R.y) * 3 / R.h,0,2.99));
|
||||||
|
if (!e.b) {
|
||||||
|
setControlState("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (y==0) { // top row
|
||||||
|
if (x==0) setControlState("c");
|
||||||
|
if (x==1) setControlState("up");
|
||||||
|
if (x==2) setControlState("d");
|
||||||
|
} else if (y==1) {
|
||||||
|
if (x==0) setControlState("left");
|
||||||
|
if (x==1) setControlState("down");
|
||||||
|
if (x==2) setControlState("right");
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
|
||||||
draw();
|
draw();
|
||||||
lego.set(c);
|
NRF.on('connect', draw);
|
||||||
|
NRF.on('disconnect', draw);
|
||||||
}
|
}
|
||||||
|
|
||||||
Bangle.on('drag',e => {
|
function startLegoLinear() {
|
||||||
var x = Math.floor(E.clip((e.x - R.x) * 3 / R.w,0,2.99));
|
var mx = R.x+R.w/2;
|
||||||
var y = Math.floor(E.clip((e.y - R.y) * 3 / R.h,0,2.99));
|
var my = R.y+R.h/2;
|
||||||
if (!e.b) {
|
var x=0,y=0;
|
||||||
setControlState("");
|
var scale = 10;
|
||||||
return;
|
|
||||||
}
|
function draw() {
|
||||||
if (y==0) { // top row
|
g.reset().clearRect(R);
|
||||||
if (x==1) setControlState("up");
|
for (var i=3;i<60;i+=10)
|
||||||
} else if (y==1) {
|
g.drawCircle(mx,my,i);
|
||||||
if (x==0) setControlState("left");
|
g.setColor("#F00");
|
||||||
if (x==1) setControlState("down");
|
var px = E.clip(mx + x*scale, R.x+20, R.x2-20);
|
||||||
if (x==2) setControlState("right");
|
var py = E.clip(my + y*scale, R.y+20, R.y2-20);
|
||||||
|
g.fillCircle(px, py, 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lego.start();
|
||||||
|
Bangle.setUI({mode:"custom", drag : e => {
|
||||||
|
x = Math.round((e.x - mx) / scale);
|
||||||
|
y = Math.round((e.y - my) / scale);
|
||||||
|
if (!e.b) {
|
||||||
|
x=0; y=0;
|
||||||
|
}
|
||||||
|
lego.set({a:x, b:y});
|
||||||
|
draw();
|
||||||
|
}});
|
||||||
|
|
||||||
|
draw();
|
||||||
|
NRF.on('connect', draw);
|
||||||
|
NRF.on('disconnect', draw);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mappings of button to output
|
||||||
|
const CONTROLS = {
|
||||||
|
normal : {
|
||||||
|
up : {a: 7,b: 0},
|
||||||
|
down : {a:-7,b: 0},
|
||||||
|
left : {a: 0,b:-7},
|
||||||
|
right: {a: 0,b: 7},
|
||||||
|
c : {c:7},
|
||||||
|
d : {d:7}
|
||||||
|
}, tank : {
|
||||||
|
up : {a:-7,b:7},
|
||||||
|
down : {a: 7,b:-7},
|
||||||
|
left : {a: 7,b:7},
|
||||||
|
right: {a:-7,b:-7},
|
||||||
|
c : {c:7},
|
||||||
|
d : {d:7}
|
||||||
|
}, merged : {
|
||||||
|
up : {a: 7,b: 7},
|
||||||
|
down : {a:-7,b:-7},
|
||||||
|
left : {a: 7,b:-7},
|
||||||
|
right: {a:-7,b: 7},
|
||||||
|
c : {c:7},
|
||||||
|
d : {d:7}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
E.showMenu({ "" : {title:"LEGO Remote", back:()=>load()},
|
||||||
|
"Linear" : () => startLegoLinear(),
|
||||||
|
"Normal" : () => startLego(CONTROLS.normal),
|
||||||
|
"Tank" : () => startLego(CONTROLS.tank),
|
||||||
|
"Marged" : () => startLego(CONTROLS.merged),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{ "id": "legoremote",
|
{ "id": "legoremote",
|
||||||
"name": "LEGO Remote control",
|
"name": "LEGO Remote control",
|
||||||
"shortName":"LEGO Remote",
|
"shortName":"LEGO Remote",
|
||||||
"version":"0.01",
|
"version":"0.02",
|
||||||
"description": "Use your Bangle.js to control LEGO models. See the README for compatibility",
|
"description": "Use your Bangle.js to control LEGO models. See the README for compatibility",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"tags": "toy,lego,bluetooth",
|
"tags": "toy,lego,bluetooth",
|
||||||
|
|
|
||||||
|
|
@ -33,3 +33,5 @@
|
||||||
0.26: Ensure that when redrawing, we always cancel any in-progress track draw
|
0.26: Ensure that when redrawing, we always cancel any in-progress track draw
|
||||||
0.27: Display message if no map is installed
|
0.27: Display message if no map is installed
|
||||||
0.28: Fix rounding errors
|
0.28: Fix rounding errors
|
||||||
|
0.29: Keep exit at bottom of menu
|
||||||
|
Speed up latLonToXY for track rendering
|
||||||
|
|
@ -172,7 +172,6 @@ function showMenu() {
|
||||||
var menu = {
|
var menu = {
|
||||||
"":{title:/*LANG*/"Map"},
|
"":{title:/*LANG*/"Map"},
|
||||||
"< Back": ()=> showMap(),
|
"< Back": ()=> showMap(),
|
||||||
/*LANG*/"Exit": () => load(),
|
|
||||||
};
|
};
|
||||||
// If we have a GPS fix, add a menu item to center it
|
// If we have a GPS fix, add a menu item to center it
|
||||||
if (fix.fix) menu[/*LANG*/"Center GPS"]=() =>{
|
if (fix.fix) menu[/*LANG*/"Center GPS"]=() =>{
|
||||||
|
|
@ -180,7 +179,6 @@ function showMenu() {
|
||||||
m.lon = fix.lon;
|
m.lon = fix.lon;
|
||||||
showMap();
|
showMap();
|
||||||
};
|
};
|
||||||
|
|
||||||
menu = Object.assign(menu, {
|
menu = Object.assign(menu, {
|
||||||
/*LANG*/"Zoom In": () =>{
|
/*LANG*/"Zoom In": () =>{
|
||||||
m.scale /= 2;
|
m.scale /= 2;
|
||||||
|
|
@ -234,6 +232,7 @@ function showMenu() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
menu[/*LANG*/"Exit"] = () => load();
|
||||||
E.showMenu(menu);
|
E.showMenu(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "openstmap",
|
"id": "openstmap",
|
||||||
"name": "OpenStreetMap",
|
"name": "OpenStreetMap",
|
||||||
"shortName": "OpenStMap",
|
"shortName": "OpenStMap",
|
||||||
"version": "0.28",
|
"version": "0.29",
|
||||||
"description": "Loads map tiles from OpenStreetMap onto your Bangle.js and displays a map of where you are. Once installed this also adds map functionality to `GPS Recorder` and `Recorder` apps",
|
"description": "Loads map tiles from OpenStreetMap onto your Bangle.js and displays a map of where you are. Once installed this also adds map functionality to `GPS Recorder` and `Recorder` apps",
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
|
|
|
||||||
|
|
@ -38,17 +38,17 @@ if (m.map) {
|
||||||
m.lat = m.map.lat; // position of middle of screen
|
m.lat = m.map.lat; // position of middle of screen
|
||||||
m.lon = m.map.lon; // position of middle of screen
|
m.lon = m.map.lon; // position of middle of screen
|
||||||
}
|
}
|
||||||
|
var CX = g.getWidth()/2;
|
||||||
|
var CY = g.getHeight()/2;
|
||||||
|
|
||||||
// return number of tiles drawn
|
// return number of tiles drawn
|
||||||
exports.draw = function() {
|
exports.draw = function() {
|
||||||
var cx = g.getWidth()/2;
|
|
||||||
var cy = g.getHeight()/2;
|
|
||||||
var p = Bangle.project({lat:m.lat,lon:m.lon});
|
var p = Bangle.project({lat:m.lat,lon:m.lon});
|
||||||
let count = 0;
|
let count = 0;
|
||||||
m.maps.forEach((map,idx) => {
|
m.maps.forEach((map,idx) => {
|
||||||
var d = map.scale/m.scale;
|
var d = map.scale/m.scale;
|
||||||
var ix = (p.x-map.center.x)/m.scale + (map.imgx*d/2) - cx;
|
var ix = (p.x-map.center.x)/m.scale + (map.imgx*d/2) - CX;
|
||||||
var iy = (map.center.y-p.y)/m.scale + (map.imgy*d/2) - cy;
|
var iy = (map.center.y-p.y)/m.scale + (map.imgy*d/2) - CY;
|
||||||
var o = {};
|
var o = {};
|
||||||
var s = map.tilesize;
|
var s = map.tilesize;
|
||||||
if (d!=1) { // if the two are different, add scaling
|
if (d!=1) { // if the two are different, add scaling
|
||||||
|
|
@ -85,14 +85,12 @@ exports.draw = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Convert lat/lon to pixels on the screen
|
/// Convert lat/lon to pixels on the screen
|
||||||
exports.latLonToXY = function(lat, lon) {
|
exports.latLonToXY = function(lat, lon) { "ram"
|
||||||
var p = Bangle.project({lat:m.lat,lon:m.lon});
|
var p = Bangle.project({lat:m.lat,lon:m.lon}),
|
||||||
var q = Bangle.project({lat:lat, lon:lon});
|
q = Bangle.project({lat:lat, lon:lon});
|
||||||
var cx = g.getWidth()/2;
|
|
||||||
var cy = g.getHeight()/2;
|
|
||||||
return {
|
return {
|
||||||
x : Math.round((q.x-p.x)/m.scale + cx),
|
x : Math.round((q.x-p.x)/m.scale + CX),
|
||||||
y : Math.round(cy - (q.y-p.y)/m.scale)
|
y : Math.round(CY - (q.y-p.y)/m.scale)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -102,4 +100,4 @@ exports.scroll = function(x,y) {
|
||||||
var b = Bangle.project({lat:m.lat+1,lon:m.lon+1});
|
var b = Bangle.project({lat:m.lat+1,lon:m.lon+1});
|
||||||
this.lon += x * m.scale / (a.x-b.x);
|
this.lon += x * m.scale / (a.x-b.x);
|
||||||
this.lat -= y * m.scale / (a.y-b.y);
|
this.lat -= y * m.scale / (a.y-b.y);
|
||||||
};
|
};
|
||||||
|
|
@ -45,3 +45,4 @@
|
||||||
0.36: When recording with 1 second periods, log time with one decimal.
|
0.36: When recording with 1 second periods, log time with one decimal.
|
||||||
0.37: 1 second periods + gps log => log when gps event is received, not with
|
0.37: 1 second periods + gps log => log when gps event is received, not with
|
||||||
setInterval.
|
setInterval.
|
||||||
|
0.38: Tweaks to speed up track rendering
|
||||||
|
|
@ -213,230 +213,230 @@ function viewTrack(filename, info) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
menu['< Back'] = () => { viewTracks(); };
|
menu['< Back'] = () => { viewTracks(); };
|
||||||
|
return E.showMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
function plotTrack(info) { "ram"
|
function plotTrack(info) { "ram"
|
||||||
function distance(lat1,long1,lat2,long2) { "ram"
|
function distance(lat1,long1,lat2,long2) { "ram"
|
||||||
var x = (long1-long2) * Math.cos((lat1+lat2)*Math.PI/360);
|
var x = (long1-long2) * Math.cos((lat1+lat2)*Math.PI/360);
|
||||||
var y = lat2 - lat1;
|
var y = lat2 - lat1;
|
||||||
return Math.sqrt(x*x + y*y) * 6371000 * Math.PI / 180;
|
return Math.sqrt(x*x + y*y) * 6371000 * Math.PI / 180;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to convert lat/lon to XY
|
// Function to convert lat/lon to XY
|
||||||
var getMapXY;
|
var XY;
|
||||||
if (info.qOSTM) {
|
if (info.qOSTM) {
|
||||||
// scale map to view full track
|
// scale map to view full track
|
||||||
const max = Bangle.project({lat: info.maxLat, lon: info.maxLong});
|
const max = Bangle.project({lat: info.maxLat, lon: info.maxLong});
|
||||||
const min = Bangle.project({lat: info.minLat, lon: info.minLong});
|
const min = Bangle.project({lat: info.minLat, lon: info.minLong});
|
||||||
const scaleX = (max.x-min.x)/Bangle.appRect.w;
|
const scaleX = (max.x-min.x)/Bangle.appRect.w;
|
||||||
const scaleY = (max.y-min.y)/Bangle.appRect.h;
|
const scaleY = (max.y-min.y)/Bangle.appRect.h;
|
||||||
osm.scale = Math.ceil((scaleX > scaleY ? scaleX : scaleY)*1.1); // add 10% margin
|
osm.scale = Math.ceil((scaleX > scaleY ? scaleX : scaleY)*1.1); // add 10% margin
|
||||||
getMapXY = osm.latLonToXY.bind(osm);
|
XY = osm.latLonToXY.bind(osm);
|
||||||
} else {
|
} else {
|
||||||
getMapXY = function(lat, lon) { "ram"
|
XY = function(lat, lon) { "ram"
|
||||||
return {x:cx + Math.round((long - info.lon)*info.lfactor*info.scale),
|
return {x:cx + Math.round((long - info.lon)*info.lfactor*info.scale),
|
||||||
y:cy + Math.round((info.lat - lat)*info.scale)};
|
y:cy + Math.round((info.lat - lat)*info.scale)};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
E.showMenu(); // remove menu
|
E.showMenu(); // remove menu
|
||||||
E.showMessage(/*LANG*/"Drawing...",/*LANG*/"Track "+info.fn);
|
E.showMessage(/*LANG*/"Drawing...",/*LANG*/"Track "+info.fn);
|
||||||
g.flip(); // on buffered screens, draw a not saying we're busy
|
g.flip(); // on buffered screens, draw a not saying we're busy
|
||||||
g.clear(1);
|
g.clear(1);
|
||||||
var s = require("Storage");
|
var s = require("Storage");
|
||||||
var W = g.getWidth();
|
var G = g;
|
||||||
var H = g.getHeight();
|
var W = g.getWidth();
|
||||||
var cx = W/2;
|
var H = g.getHeight();
|
||||||
var cy = 24 + (H-24)/2;
|
var cx = W/2;
|
||||||
if (!info.qOSTM) {
|
var cy = 24 + (H-24)/2;
|
||||||
g.setColor("#f00").fillRect(9,80,11,120).fillPoly([9,60,19,80,0,80]);
|
if (!info.qOSTM) {
|
||||||
g.setColor(g.theme.fg).setFont("6x8").setFontAlign(0,0).drawString("N",10,50);
|
g.setColor("#f00").fillRect(9,80,11,120).fillPoly([9,60,19,80,0,80]);
|
||||||
} else {
|
g.setColor(g.theme.fg).setFont("6x8").setFontAlign(0,0).drawString("N",10,50);
|
||||||
osm.lat = info.lat;
|
} else {
|
||||||
osm.lon = info.lon;
|
osm.lat = info.lat;
|
||||||
osm.draw();
|
osm.lon = info.lon;
|
||||||
g.setColor("#000");
|
osm.draw();
|
||||||
|
g.setColor("#000");
|
||||||
|
}
|
||||||
|
var latIdx = info.fields.indexOf("Latitude");
|
||||||
|
var lonIdx = info.fields.indexOf("Longitude");
|
||||||
|
g.drawString(asTime(info.duration),10,220);
|
||||||
|
var f = require("Storage").open(info.filename,"r");
|
||||||
|
if (f===undefined) return;
|
||||||
|
var l = f.readLine(f);
|
||||||
|
l = f.readLine(f); // skip headers
|
||||||
|
var ox=0;
|
||||||
|
var oy=0;
|
||||||
|
var olat,olong,dist=0;
|
||||||
|
var i=0, c = l.split(",");
|
||||||
|
// skip until we find our first data
|
||||||
|
while(l!==undefined && c[latIdx]=="") {
|
||||||
|
c = l.split(",");
|
||||||
|
l = f.readLine(f);
|
||||||
|
}
|
||||||
|
// now start plotting
|
||||||
|
var lat = +c[latIdx];
|
||||||
|
var long = +c[lonIdx];
|
||||||
|
var mp = XY(lat, long);
|
||||||
|
g.moveTo(mp.x,mp.y);
|
||||||
|
g.setColor("#0f0");
|
||||||
|
g.fillCircle(mp.x,mp.y,5);
|
||||||
|
if (info.qOSTM) g.setColor("#f09");
|
||||||
|
else g.setColor(g.theme.fg);
|
||||||
|
l = f.readLine(f);
|
||||||
|
g.flip(); // force update
|
||||||
|
while(l!==undefined) {
|
||||||
|
c = l.split(",");l = f.readLine(f);
|
||||||
|
if (c[latIdx]=="")continue;
|
||||||
|
lat = +c[latIdx];
|
||||||
|
long = +c[lonIdx];
|
||||||
|
mp = XY(lat, long);
|
||||||
|
G.lineTo(mp.x,mp.y);
|
||||||
|
if (info.qOSTM) G.fillCircle(mp.x,mp.y,2); // make the track more visible
|
||||||
|
var d = distance(olat,olong,lat,long);
|
||||||
|
if (!isNaN(d)) dist+=d;
|
||||||
|
olat = lat;
|
||||||
|
olong = long;
|
||||||
|
ox = mp.x;
|
||||||
|
oy = mp.y;
|
||||||
|
if (++i > 100) { G.flip();i=0; }
|
||||||
|
}
|
||||||
|
g.setColor("#f00");
|
||||||
|
g.fillCircle(ox,oy,5);
|
||||||
|
if (info.qOSTM) g.setColor("#000");
|
||||||
|
else g.setColor(g.theme.fg);
|
||||||
|
g.drawString(require("locale").distance(dist,2),g.getWidth() / 2, g.getHeight() - 20);
|
||||||
|
g.setFont("6x8",2);
|
||||||
|
g.setFontAlign(0,0,3);
|
||||||
|
var isBTN3 = "BTN3" in global;
|
||||||
|
g.drawString(/*LANG*/"Back",g.getWidth() - 10, isBTN3 ? (g.getHeight() - 40) : (g.getHeight()/2));
|
||||||
|
setWatch(function() {
|
||||||
|
viewTrack(info.fn, info);
|
||||||
|
}, isBTN3?BTN3:BTN1);
|
||||||
|
Bangle.drawWidgets();
|
||||||
|
g.flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
function plotGraph(info, style) { "ram"
|
||||||
|
E.showMenu(); // remove menu
|
||||||
|
E.showMessage(/*LANG*/"Calculating...",/*LANG*/"Track "+info.fn);
|
||||||
|
var filename = info.filename;
|
||||||
|
var infn = new Float32Array(80);
|
||||||
|
var infc = new Uint16Array(80);
|
||||||
|
var title;
|
||||||
|
var lt = 0; // last time
|
||||||
|
var tn = 0; // count for each time period
|
||||||
|
var strt, dur = info.duration;
|
||||||
|
var f = require("Storage").open(filename,"r");
|
||||||
|
if (f===undefined) return;
|
||||||
|
var l = f.readLine(f);
|
||||||
|
l = f.readLine(f); // skip headers
|
||||||
|
var nl = 0, c, i;
|
||||||
|
var factor = 1; // multiplier used for values when graphing
|
||||||
|
var timeIdx = info.fields.indexOf("Time");
|
||||||
|
if (l!==undefined) {
|
||||||
|
c = l.split(",");
|
||||||
|
strt = c[timeIdx];
|
||||||
|
}
|
||||||
|
if (style=="Heartrate") {
|
||||||
|
title = /*LANG*/"Heartrate (bpm)";
|
||||||
|
var hrmIdx = info.fields.indexOf("Heartrate");
|
||||||
|
while(l!==undefined) {
|
||||||
|
++nl;c=l.split(",");l = f.readLine(f);
|
||||||
|
if (c[hrmIdx]=="") continue;
|
||||||
|
i = Math.round(80*(c[timeIdx] - strt)/dur);
|
||||||
|
infn[i]+=+c[hrmIdx];
|
||||||
|
infc[i]++;
|
||||||
}
|
}
|
||||||
|
} else if (style=="Altitude") {
|
||||||
|
title = /*LANG*/"Altitude (m)";
|
||||||
|
var altIdx = info.fields.indexOf("Barometer Altitude");
|
||||||
|
if (altIdx<0) altIdx = info.fields.indexOf("Altitude");
|
||||||
|
while(l!==undefined) {
|
||||||
|
++nl;c=l.split(",");l = f.readLine(f);
|
||||||
|
if (c[altIdx]=="") continue;
|
||||||
|
i = Math.round(80*(c[timeIdx] - strt)/dur);
|
||||||
|
infn[i]+=+c[altIdx];
|
||||||
|
infc[i]++;
|
||||||
|
}
|
||||||
|
} else if (style=="Speed") {
|
||||||
|
// use locate to work out units
|
||||||
|
var localeStr = require("locale").speed(1,5); // get what 1kph equates to
|
||||||
|
let units = localeStr.replace(/[0-9.]*/,"");
|
||||||
|
factor = parseFloat(localeStr)*3.6; // m/sec to whatever out units are
|
||||||
|
// title
|
||||||
|
title = /*LANG*/"Speed"+` (${units})`;
|
||||||
var latIdx = info.fields.indexOf("Latitude");
|
var latIdx = info.fields.indexOf("Latitude");
|
||||||
var lonIdx = info.fields.indexOf("Longitude");
|
var lonIdx = info.fields.indexOf("Longitude");
|
||||||
g.drawString(asTime(info.duration),10,220);
|
|
||||||
var f = require("Storage").open(info.filename,"r");
|
|
||||||
if (f===undefined) return;
|
|
||||||
var l = f.readLine(f);
|
|
||||||
l = f.readLine(f); // skip headers
|
|
||||||
var ox=0;
|
|
||||||
var oy=0;
|
|
||||||
var olat,olong,dist=0;
|
|
||||||
var i=0, c = l.split(",");
|
|
||||||
// skip until we find our first data
|
// skip until we find our first data
|
||||||
while(l!==undefined && c[latIdx]=="") {
|
while(l!==undefined && c[latIdx]=="") {
|
||||||
c = l.split(",");
|
c = l.split(",");
|
||||||
l = f.readLine(f);
|
l = f.readLine(f);
|
||||||
}
|
}
|
||||||
// now start plotting
|
// now iterate
|
||||||
var lat = +c[latIdx];
|
var p,lp = Bangle.project({lat:c[1],lon:c[2]});
|
||||||
var long = +c[lonIdx];
|
var t,dx,dy,d,lt = c[timeIdx];
|
||||||
var mp = getMapXY(lat, long);
|
|
||||||
g.moveTo(mp.x,mp.y);
|
|
||||||
g.setColor("#0f0");
|
|
||||||
g.fillCircle(mp.x,mp.y,5);
|
|
||||||
if (info.qOSTM) g.setColor("#f09");
|
|
||||||
else g.setColor(g.theme.fg);
|
|
||||||
l = f.readLine(f);
|
|
||||||
g.flip(); // force update
|
|
||||||
while(l!==undefined) {
|
while(l!==undefined) {
|
||||||
c = l.split(",");l = f.readLine(f);
|
++nl;c=l.split(",");
|
||||||
if (c[latIdx]=="")continue;
|
l = f.readLine(f);
|
||||||
lat = +c[latIdx];
|
if (c[latIdx] == "") {
|
||||||
long = +c[lonIdx];
|
continue;
|
||||||
mp = getMapXY(lat, long);
|
}
|
||||||
g.lineTo(mp.x,mp.y);
|
t = c[timeIdx];
|
||||||
if (info.qOSTM) g.fillCircle(mp.x,mp.y,2); // make the track more visible
|
i = Math.round(80*(t - strt)/dur);
|
||||||
var d = distance(olat,olong,lat,long);
|
p = Bangle.project({lat:c[latIdx],lon:c[lonIdx]});
|
||||||
if (!isNaN(d)) dist+=d;
|
dx = p.x-lp.x;
|
||||||
olat = lat;
|
dy = p.y-lp.y;
|
||||||
olong = long;
|
d = Math.sqrt(dx*dx+dy*dy);
|
||||||
ox = mp.x;
|
if (t!=lt) {
|
||||||
oy = mp.y;
|
infn[i]+=d / (t-lt); // speed
|
||||||
if (++i > 100) { g.flip();i=0; }
|
|
||||||
}
|
|
||||||
g.setColor("#f00");
|
|
||||||
g.fillCircle(ox,oy,5);
|
|
||||||
if (info.qOSTM) g.setColor("#000");
|
|
||||||
else g.setColor(g.theme.fg);
|
|
||||||
g.drawString(require("locale").distance(dist,2),g.getWidth() / 2, g.getHeight() - 20);
|
|
||||||
g.setFont("6x8",2);
|
|
||||||
g.setFontAlign(0,0,3);
|
|
||||||
var isBTN3 = "BTN3" in global;
|
|
||||||
g.drawString(/*LANG*/"Back",g.getWidth() - 10, isBTN3 ? (g.getHeight() - 40) : (g.getHeight()/2));
|
|
||||||
setWatch(function() {
|
|
||||||
viewTrack(info.fn, info);
|
|
||||||
}, isBTN3?BTN3:BTN1);
|
|
||||||
Bangle.drawWidgets();
|
|
||||||
g.flip();
|
|
||||||
}
|
|
||||||
|
|
||||||
function plotGraph(info, style) { "ram"
|
|
||||||
E.showMenu(); // remove menu
|
|
||||||
E.showMessage(/*LANG*/"Calculating...",/*LANG*/"Track "+info.fn);
|
|
||||||
var filename = info.filename;
|
|
||||||
var infn = new Float32Array(80);
|
|
||||||
var infc = new Uint16Array(80);
|
|
||||||
var title;
|
|
||||||
var lt = 0; // last time
|
|
||||||
var tn = 0; // count for each time period
|
|
||||||
var strt, dur = info.duration;
|
|
||||||
var f = require("Storage").open(filename,"r");
|
|
||||||
if (f===undefined) return;
|
|
||||||
var l = f.readLine(f);
|
|
||||||
l = f.readLine(f); // skip headers
|
|
||||||
var nl = 0, c, i;
|
|
||||||
var factor = 1; // multiplier used for values when graphing
|
|
||||||
var timeIdx = info.fields.indexOf("Time");
|
|
||||||
if (l!==undefined) {
|
|
||||||
c = l.split(",");
|
|
||||||
strt = c[timeIdx];
|
|
||||||
}
|
|
||||||
if (style=="Heartrate") {
|
|
||||||
title = /*LANG*/"Heartrate (bpm)";
|
|
||||||
var hrmIdx = info.fields.indexOf("Heartrate");
|
|
||||||
while(l!==undefined) {
|
|
||||||
++nl;c=l.split(",");l = f.readLine(f);
|
|
||||||
if (c[hrmIdx]=="") continue;
|
|
||||||
i = Math.round(80*(c[timeIdx] - strt)/dur);
|
|
||||||
infn[i]+=+c[hrmIdx];
|
|
||||||
infc[i]++;
|
infc[i]++;
|
||||||
}
|
}
|
||||||
} else if (style=="Altitude") {
|
lp = p;
|
||||||
title = /*LANG*/"Altitude (m)";
|
lt = t;
|
||||||
var altIdx = info.fields.indexOf("Barometer Altitude");
|
|
||||||
if (altIdx<0) altIdx = info.fields.indexOf("Altitude");
|
|
||||||
while(l!==undefined) {
|
|
||||||
++nl;c=l.split(",");l = f.readLine(f);
|
|
||||||
if (c[altIdx]=="") continue;
|
|
||||||
i = Math.round(80*(c[timeIdx] - strt)/dur);
|
|
||||||
infn[i]+=+c[altIdx];
|
|
||||||
infc[i]++;
|
|
||||||
}
|
|
||||||
} else if (style=="Speed") {
|
|
||||||
// use locate to work out units
|
|
||||||
var localeStr = require("locale").speed(1,5); // get what 1kph equates to
|
|
||||||
let units = localeStr.replace(/[0-9.]*/,"");
|
|
||||||
factor = parseFloat(localeStr)*3.6; // m/sec to whatever out units are
|
|
||||||
// title
|
|
||||||
title = /*LANG*/"Speed"+` (${units})`;
|
|
||||||
var latIdx = info.fields.indexOf("Latitude");
|
|
||||||
var lonIdx = info.fields.indexOf("Longitude");
|
|
||||||
// skip until we find our first data
|
|
||||||
while(l!==undefined && c[latIdx]=="") {
|
|
||||||
c = l.split(",");
|
|
||||||
l = f.readLine(f);
|
|
||||||
}
|
|
||||||
// now iterate
|
|
||||||
var p,lp = Bangle.project({lat:c[1],lon:c[2]});
|
|
||||||
var t,dx,dy,d,lt = c[timeIdx];
|
|
||||||
while(l!==undefined) {
|
|
||||||
++nl;c=l.split(",");
|
|
||||||
l = f.readLine(f);
|
|
||||||
if (c[latIdx] == "") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
t = c[timeIdx];
|
|
||||||
i = Math.round(80*(t - strt)/dur);
|
|
||||||
p = Bangle.project({lat:c[latIdx],lon:c[lonIdx]});
|
|
||||||
dx = p.x-lp.x;
|
|
||||||
dy = p.y-lp.y;
|
|
||||||
d = Math.sqrt(dx*dx+dy*dy);
|
|
||||||
if (t!=lt) {
|
|
||||||
infn[i]+=d / (t-lt); // speed
|
|
||||||
infc[i]++;
|
|
||||||
}
|
|
||||||
lp = p;
|
|
||||||
lt = t;
|
|
||||||
}
|
|
||||||
} else throw new Error("Unknown type "+style);
|
|
||||||
var min=100000,max=-100000;
|
|
||||||
for (var i=0;i<infn.length;i++) {
|
|
||||||
if (infc[i]>0) infn[i]=factor*infn[i]/infc[i];
|
|
||||||
else { // no data - search back and see if we can find something
|
|
||||||
for (var j=i-1;j>=0;j--)
|
|
||||||
if (infc[j]) { infn[i]=infn[j]; break; }
|
|
||||||
}
|
|
||||||
var n = infn[i];
|
|
||||||
if (n>max) max=n;
|
|
||||||
if (n<min) min=n;
|
|
||||||
}
|
}
|
||||||
// work out a nice grid value
|
} else throw new Error("Unknown type "+style);
|
||||||
var heightDiff = max-min;
|
var min=100000,max=-100000;
|
||||||
var grid = 1;
|
for (var i=0;i<infn.length;i++) {
|
||||||
while (heightDiff/grid > 8) {
|
if (infc[i]>0) infn[i]=factor*infn[i]/infc[i];
|
||||||
grid*=2;
|
else { // no data - search back and see if we can find something
|
||||||
|
for (var j=i-1;j>=0;j--)
|
||||||
|
if (infc[j]) { infn[i]=infn[j]; break; }
|
||||||
}
|
}
|
||||||
// draw
|
var n = infn[i];
|
||||||
g.clear(1).setFont("6x8",1);
|
if (n>max) max=n;
|
||||||
var r = require("graph").drawLine(g, infn, {
|
if (n<min) min=n;
|
||||||
x:4,y:24,
|
|
||||||
width: g.getWidth()-24,
|
|
||||||
height: g.getHeight()-(24+8),
|
|
||||||
axes : true,
|
|
||||||
gridy : grid,
|
|
||||||
gridx : infn.length / 3,
|
|
||||||
title: title,
|
|
||||||
miny: min,
|
|
||||||
maxy: max,
|
|
||||||
xlabel : x=>Math.round(x*dur/(60*infn.length))+/*LANG*/" min" // minutes
|
|
||||||
});
|
|
||||||
g.setFont("6x8",2);
|
|
||||||
g.setFontAlign(0,0,3);
|
|
||||||
var isBTN3 = "BTN3" in global;
|
|
||||||
g.drawString(/*LANG*/"Back",g.getWidth() - 10, isBTN3 ? (g.getHeight() - 40) : (g.getHeight()/2));
|
|
||||||
setWatch(function() {
|
|
||||||
viewTrack(info.filename, info);
|
|
||||||
}, isBTN3?BTN3:BTN1);
|
|
||||||
g.flip();
|
|
||||||
}
|
}
|
||||||
|
// work out a nice grid value
|
||||||
return E.showMenu(menu);
|
var heightDiff = max-min;
|
||||||
|
var grid = 1;
|
||||||
|
while (heightDiff/grid > 8) {
|
||||||
|
grid*=2;
|
||||||
|
}
|
||||||
|
// draw
|
||||||
|
g.clear(1).setFont("6x8",1);
|
||||||
|
var r = require("graph").drawLine(g, infn, {
|
||||||
|
x:4,y:24,
|
||||||
|
width: g.getWidth()-24,
|
||||||
|
height: g.getHeight()-(24+8),
|
||||||
|
axes : true,
|
||||||
|
gridy : grid,
|
||||||
|
gridx : infn.length / 3,
|
||||||
|
title: title,
|
||||||
|
miny: min,
|
||||||
|
maxy: max,
|
||||||
|
xlabel : x=>Math.round(x*dur/(60*infn.length))+/*LANG*/" min" // minutes
|
||||||
|
});
|
||||||
|
g.setFont("6x8",2);
|
||||||
|
g.setFontAlign(0,0,3);
|
||||||
|
var isBTN3 = "BTN3" in global;
|
||||||
|
g.drawString(/*LANG*/"Back",g.getWidth() - 10, isBTN3 ? (g.getHeight() - 40) : (g.getHeight()/2));
|
||||||
|
setWatch(function() {
|
||||||
|
viewTrack(info.filename, info);
|
||||||
|
}, isBTN3?BTN3:BTN1);
|
||||||
|
g.flip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
showMainMenu();
|
showMainMenu();
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "recorder",
|
"id": "recorder",
|
||||||
"name": "Recorder",
|
"name": "Recorder",
|
||||||
"shortName": "Recorder",
|
"shortName": "Recorder",
|
||||||
"version": "0.37",
|
"version": "0.38",
|
||||||
"description": "Record GPS position, heart rate and more in the background, then download to your PC.",
|
"description": "Record GPS position, heart rate and more in the background, then download to your PC.",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"tags": "tool,outdoors,gps,widget,clkinfo",
|
"tags": "tool,outdoors,gps,widget,clkinfo",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue