BangleApps/apps/cc_astro/app.js

185 lines
3.9 KiB
JavaScript

// ----- const -----
const center = {
"x": g.getWidth()/2,
"y": g.getHeight()/2
};
const parameters = {
"earthOrbitRadius": 80,
"venusOrbitRadius": 60,
"mercuryOrbitRadius": 40,
"earthRadius": 6,
"venusRadius": 6,
"mercuryRadius": 4,
"sunRadius": 12,
"maxSunRadius": 115
};
// ----- global vars -----
let drawTimeout;
let queueMillis = 1000;
let unlock = true;
let lastBatteryStates = [E.getBattery()];
// ----- functions -----
function updateState() {
updateBatteryStates();
if (Bangle.isLCDOn()) {
if (!Bangle.isLocked()) {
queueMillis = 1000;
unlock = true;
}
else {
queueMillis = 60000;
unlock = false;
}
draw();
}
else {
if (drawTimeout)
clearTimeout(drawTimeout);
drawTimeout = undefined;
}
}
function updateBatteryStates() {
lastBatteryStates.push(E.getBattery());
if (lastBatteryStates.length > 5)
lastBatteryStates.shift(); // remove 1st item
}
function draw() {
drawBackground();
drawHands();
queueDraw();
}
function drawBackground() {
clearScreen();
drawSun();
}
function clearScreen() {
g.setBgColor(0, 0, 0);
g.clear();
}
function drawSun() {
const batteryState = calcAvgBatteryState();
if (batteryState <= 25)
g.setColor(1, 0, 0); // red sun, if battery low
else
g.setColor(1, 1, 0);
let r = parameters.sunRadius;
if (batteryState <= 20) {
const relSize = (20 - batteryState) / 20;
const dr = parameters.maxSunRadius - parameters.sunRadius;
r = parameters.sunRadius + relSize * dr;
}
g.fillCircle(center.x, center.y, r);
}
function drawHands() {
const date = new Date();
drawHourHand(date.getHours(), date.getMinutes());
drawMinuteHand(date.getMinutes());
if (unlock) {
drawSecondHand(date.getSeconds());
}
}
function drawHourHand(hours, minutes) {
const r = parameters.earthOrbitRadius;
const phi = 30 * (hours + minutes/60) * (Math.PI / 180) - Math.PI/2;
const x = center.x + r * Math.cos(phi);
const y = center.y + r * Math.sin(phi);
g.setColor(1, 1, 1);
g.drawCircle(center.x, center.y, r);
g.setColor(0, 1, 1);
g.fillCircle(x, y, parameters.earthRadius);
}
function drawMinuteHand(minutes) {
const r = parameters.venusOrbitRadius;
const phi = 6 * minutes * (Math.PI / 180) - Math.PI/2;
const x = center.x + r * Math.cos(phi);
const y = center.y + r * Math.sin(phi);
g.setColor(1, 1, 1);
g.drawCircle(center.x, center.y, r);
g.setColor(1, 1, 1);
g.fillCircle(x, y, parameters.venusRadius);
}
function drawSecondHand(seconds) {
const r = parameters.mercuryOrbitRadius;
const phi = 6 * seconds * (Math.PI / 180) - Math.PI/2;
const x = center.x + r * Math.cos(phi);
const y = center.y + r * Math.sin(phi);
g.setColor(1, 1, 1);
g.drawCircle(center.x, center.y, r);
g.setColor(1, 0, 1);
g.fillCircle(x, y, parameters.mercuryRadius);
}
function calcAvgBatteryState() {
const n = lastBatteryStates.length;
if (n == 0)
return 100;
let sum = lastBatteryStates.reduce((acc, value) => acc + value, 0);
return Math.round(sum / n);
}
function queueDraw() {
if (drawTimeout)
clearTimeout(drawTimeout);
drawTimeout = setTimeout(function() {
drawTimeout = undefined;
draw();
}, queueMillis - (Date.now() % queueMillis));
}
//// main running sequence ////
// Show launcher when middle button pressed, and widgets that we're clock
Bangle.setUI({
mode: "clock",
remove: function() {
Bangle.removeListener('lcdPower', updateState);
Bangle.removeListener('lock', updateState);
Bangle.removeListener('charging', draw);
// We clear drawTimout after removing all listeners, because they can add one again
if (drawTimeout)
clearTimeout(drawTimeout);
drawTimeout = undefined;
require("widget_utils").show();
}
});
// Stop updates when LCD is off, restart when on
Bangle.on('lcdPower', updateState);
Bangle.on('lock', updateState);
Bangle.on('charging', draw); // Immediately redraw when charger (dis)connected
updateState();
draw();