forked from FOSS/BangleApps
Merge pull request #1947 from pebl-hank/hBatteryWidget
H battery widget - fixing the refresh issuesmaster
commit
e0470d48f0
|
@ -0,0 +1,7 @@
|
|||
0.01: Release for Bangle 2 (2021/11/18)
|
||||
0.02: Internal id update to wid_* as per Gordon's request (2021/11/21)
|
||||
0.03: Support dark themes
|
||||
0.04: Increase screen update rate when charging
|
||||
0.05: Deleting Background - making Font larger
|
||||
0.06: Fixing refresh issues
|
||||
0.07
|
|
@ -0,0 +1,15 @@
|
|||
# A Battery Widget (with percentage)
|
||||
|
||||
Show the current battery level and charging status in the top right of the clock, with charge percentage
|
||||
|
||||
* Works with Bangle 2
|
||||
* Simple design, no settings
|
||||
* Red when the batterly level is below 30%
|
||||
* Blue when charging
|
||||
* 40 pixels wide
|
||||
|
||||

|
||||
|
||||
## Creator
|
||||
[@alainsaas](https://github.com/alainsaas)
|
||||
Mod by Hank
|
Binary file not shown.
After Width: | Height: | Size: 65 KiB |
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"id": "hwid_a_battery_widget",
|
||||
"name": "A Battery Widget (with percentage) - Hanks Mod",
|
||||
"shortName":"H Battery Widget",
|
||||
"icon": "widget.png",
|
||||
"version":"0.07",
|
||||
"type": "widget",
|
||||
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"description": "Simple and slim battery widget with charge status and percentage",
|
||||
"tags": "widget,battery",
|
||||
"storage": [
|
||||
{"name":"hwid_a_battery_widget.wid.js","url":"widget.js"}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
(function(){
|
||||
const intervalLow = 60000; // update time when not charging
|
||||
const intervalHigh = 2000; // update time when charging
|
||||
var old_l;
|
||||
|
||||
let COLORS = {
|
||||
'white': g.theme.dark ? "#000" : "#fff",
|
||||
'black': g.theme.dark ? "#fff" : "#000",
|
||||
'charging': "#08f",
|
||||
'high': g.theme.dark ? "#fff" : "#000",
|
||||
'low': "#f00",
|
||||
};
|
||||
|
||||
const levelColor = (l) => {
|
||||
if (Bangle.isCharging()) return COLORS.charging;
|
||||
if (l >= 30) return COLORS.high;
|
||||
return COLORS.low;
|
||||
};
|
||||
|
||||
function draw() {
|
||||
var s = 29;
|
||||
var x = this.x, y = this.y;
|
||||
const l = E.getBattery();
|
||||
let xl = x+4+l*(s-12)/100;
|
||||
if (l != old_l){ // Delete the old value from screen
|
||||
old_l = l;
|
||||
let xl_old = x+4+old_l*(s-12)/100;
|
||||
g.setColor(COLORS.white);
|
||||
// g.fillRect(x+2,y+5,x+s-6,y+18);
|
||||
g.fillRect(x,y,xl+4,y+16+3); //Clear
|
||||
g.setFontAlign(0,0);
|
||||
g.setFont('Vector',16);
|
||||
g.drawString(old_l, x + 14, y + 10);
|
||||
g.fillRect(x+4,y+14+3,xl_old,y+16+3); // charging bar
|
||||
}
|
||||
|
||||
g.setColor(levelColor(l));
|
||||
g.fillRect(x+4,y+14+3,xl,y+16+3); // charging bar
|
||||
g.fillRect((x+4+100*(s-12)/100)-1,y+14+3,x+4+100*(s-12)/100,y+16+3); // charging bar "full mark"
|
||||
// Show percentage
|
||||
g.setColor(COLORS.black);
|
||||
g.setFontAlign(0,0);
|
||||
g.setFont('Vector',16);
|
||||
g.drawString(l, x + 14, y + 10);
|
||||
|
||||
if (Bangle.isCharging()) changeInterval(id, intervalHigh);
|
||||
else changeInterval(id, intervalLow);
|
||||
}
|
||||
|
||||
Bangle.on('charging',function(charging) { draw(); });
|
||||
var id = setInterval(()=>WIDGETS["wid_a_battery_widget"].draw(), intervalLow);
|
||||
|
||||
WIDGETS["wid_a_battery_widget"]={area:"tr",width:30,draw:draw};
|
||||
})();
|
Binary file not shown.
After Width: | Height: | Size: 877 B |
|
@ -0,0 +1 @@
|
|||
0.15: Initial release - be patient as this is the first try :)
|
|
@ -0,0 +1,30 @@
|
|||
# Hanks World Clock - See the time in four locations
|
||||
|
||||
In addition to the main clock and date in your current location, you can add up to three other locations. Great for travel or remote working.
|
||||
Additionally we show the sunset/sunrise and seconds for the current location and the day name is shown in your locale.
|
||||
|
||||

|
||||
|
||||
## Usage
|
||||
|
||||
Provide names and the UTC offsets for up to three other timezones in the app store. These are stored in a json file on your watch. UTC offsets can be decimal (e.g., 5.5 for India).
|
||||
|
||||
The clock does not handle summer time / daylight saving time changes automatically. If one of your three locations changes its UTC offset, you can simply change the setting in the app store and update. Currently the clock only supports 24 hour time format for the additional time zones.
|
||||
|
||||
|
||||
## Requests
|
||||
|
||||
Please use [the Espruino Forum](http://forum.espruino.com/microcosms/1424/) if you have feature requests or notice bugs.
|
||||
|
||||
## Creator
|
||||
|
||||
Created by Hank.
|
||||
|
||||
Based on the great work of
|
||||
=================
|
||||
World Clock - 4 time zones
|
||||
Made by [Scott Hale](https://www.github.com/computermacgyver), based upon the [Simple Clock](https://github.com/espruino/BangleApps/tree/master/apps/sclock).
|
||||
===== a n d =====
|
||||
Sun Clock
|
||||
[Sun Clock](https://github.com/espruino/BangleApps/tree/master/apps/sunclock)
|
||||
=================
|
|
@ -0,0 +1,266 @@
|
|||
const big = g.getWidth()>200;
|
||||
// Font for primary time and date
|
||||
const primaryTimeFontSize = big?6:5;
|
||||
const primaryDateFontSize = big?3:2;
|
||||
require("Font5x9Numeric7Seg").add(Graphics);
|
||||
require("FontTeletext10x18Ascii").add(Graphics);
|
||||
|
||||
// Font for single secondary time
|
||||
const secondaryTimeFontSize = 4;
|
||||
const secondaryTimeZoneFontSize = 2;
|
||||
|
||||
// Font / columns for multiple secondary times
|
||||
const secondaryRowColFontSize = 2;
|
||||
const xcol1 = 10;
|
||||
const xcol2 = g.getWidth() - xcol1;
|
||||
|
||||
const font = "6x8";
|
||||
|
||||
/* TODO: we could totally use 'Layout' here and
|
||||
avoid a whole bunch of hard-coded offsets */
|
||||
|
||||
|
||||
const xyCenter = g.getWidth() / 2;
|
||||
const xyCenterSeconds = xyCenter + (big ? 85 : 68);
|
||||
const yAmPm = xyCenter - (big ? 70 : 48);
|
||||
const yposTime = big ? 70 : 55;
|
||||
const yposTime2 = yposTime + (big ? 100 : 60);
|
||||
const yposDate = big ? 135 : 95;
|
||||
const yposWorld = big ? 170 : 120;
|
||||
|
||||
const OFFSET_TIME_ZONE = 0;
|
||||
const OFFSET_HOURS = 1;
|
||||
|
||||
var offsets = require("Storage").readJSON("hworldclock.settings.json") || [];
|
||||
|
||||
//=======Sun
|
||||
setting = require("Storage").readJSON("setting.json",1);
|
||||
E.setTimeZone(setting.timezone); // timezone = 1 for MEZ, = 2 for MESZ
|
||||
SunCalc = require("hsuncalc.js");
|
||||
const LOCATION_FILE = "mylocation.json";
|
||||
var rise = "07:00";
|
||||
var set = "20:00";
|
||||
var pos = {altitude: 20, azimuth: 135};
|
||||
var noonpos = {altitude: 37, azimuth: 180};
|
||||
//=======Sun
|
||||
|
||||
var ampm = "AM";
|
||||
|
||||
// TESTING CODE
|
||||
// Used to test offset array values during development.
|
||||
// Uncomment to override secondary offsets value
|
||||
/*
|
||||
const mockOffsets = {
|
||||
zeroOffsets: [],
|
||||
oneOffset: [["UTC", 0]],
|
||||
twoOffsets: [
|
||||
["Tokyo", 9],
|
||||
["UTC", 0],
|
||||
],
|
||||
fourOffsets: [
|
||||
["Tokyo", 9],
|
||||
["UTC", 0],
|
||||
["Denver", -7],
|
||||
["Miami", -5],
|
||||
],
|
||||
};*/
|
||||
|
||||
// Uncomment one at a time to test various offsets array scenarios
|
||||
//offsets = mockOffsets.zeroOffsets; // should render nothing below primary time
|
||||
//offsets = mockOffsets.oneOffset; // should render larger in two rows
|
||||
//offsets = mockOffsets.twoOffsets; // should render two in columns
|
||||
//offsets = mockOffsets.fourOffsets; // should render in columns
|
||||
|
||||
// END TESTING CODE
|
||||
|
||||
// Check settings for what type our clock should be
|
||||
var _12hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]||false;
|
||||
|
||||
// timeout used to update every minute
|
||||
var drawTimeout;
|
||||
var drawTimeoutSeconds;
|
||||
|
||||
g.setBgColor(0, 0, 0);
|
||||
|
||||
// schedule a draw for the next minute
|
||||
function queueDraw() {
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = setTimeout(function() {
|
||||
drawTimeout = undefined;
|
||||
draw();
|
||||
}, 60000 - (Date.now() % 60000));
|
||||
}
|
||||
|
||||
function doublenum(x) {
|
||||
return x < 10 ? "0" + x : "" + x;
|
||||
}
|
||||
|
||||
function getCurrentTimeFromOffset(dt, offset) {
|
||||
return new Date(dt.getTime() + offset * 60 * 60 * 1000);
|
||||
}
|
||||
|
||||
function updatePos() {
|
||||
coord = require("Storage").readJSON(LOCATION_FILE,1)|| {"lat":53.3,"lon":10.1,"location":"Pattensen"};
|
||||
pos = SunCalc.getPosition(Date.now(), coord.lat, coord.lon);
|
||||
times = SunCalc.getTimes(Date.now(), coord.lat, coord.lon);
|
||||
rise = times.sunrise.toString().split(" ")[4].substr(0,5);
|
||||
set = times.sunset.toString().split(" ")[4].substr(0,5);
|
||||
noonpos = SunCalc.getPosition(times.solarNoon, coord.lat, coord.lon);
|
||||
}
|
||||
|
||||
|
||||
function drawSeconds() {
|
||||
// get date
|
||||
var d = new Date();
|
||||
var da = d.toString().split(" ");
|
||||
|
||||
// default draw styles
|
||||
g.reset();
|
||||
g.setBgColor(0, 0, 0);
|
||||
|
||||
// drawSting centered
|
||||
g.setFontAlign(0, 0);
|
||||
|
||||
// draw time
|
||||
var time = da[4].split(":");
|
||||
var seconds = time[2];
|
||||
|
||||
g.setFont("5x9Numeric7Seg",primaryTimeFontSize - 3);
|
||||
g.setColor("#22ff05");
|
||||
//g.setFont(font, primaryTimeFontSize-3);
|
||||
g.drawString(`${seconds}`, xyCenterSeconds, yposTime+14, true);
|
||||
}
|
||||
|
||||
function draw() {
|
||||
// get date
|
||||
var d = new Date();
|
||||
var da = d.toString().split(" ");
|
||||
|
||||
// default draw styles
|
||||
g.reset();
|
||||
g.setBgColor(0, 0, 0);
|
||||
|
||||
// drawSting centered
|
||||
g.setFontAlign(0, 0);
|
||||
|
||||
// draw time
|
||||
var time = da[4].split(":");
|
||||
var hours = time[0],
|
||||
minutes = time[1];
|
||||
|
||||
|
||||
if (_12hour){
|
||||
//do 12 hour stuff
|
||||
if (hours > 12) {
|
||||
ampm = "PM";
|
||||
hours = hours - 12;
|
||||
} else {
|
||||
ampm = "AM";
|
||||
}
|
||||
}
|
||||
|
||||
//g.setFont(font, primaryTimeFontSize);
|
||||
g.setFont("5x9Numeric7Seg",primaryTimeFontSize);
|
||||
g.setColor("#22ff05");
|
||||
g.drawString(`${doublenum(hours)}:${minutes}`, xyCenter-10, yposTime, true);
|
||||
|
||||
// am / PM ?
|
||||
if (_12hour){
|
||||
//do 12 hour stuff
|
||||
//var ampm = require("locale").medidian(new Date()); Not working
|
||||
g.setFont("Vector", 17);
|
||||
g.setColor("#22ff05");
|
||||
g.drawString(ampm, xyCenterSeconds, yAmPm, true);
|
||||
}
|
||||
|
||||
drawSeconds(); // To make sure...
|
||||
|
||||
// draw Day, name of month, Date
|
||||
//DATE
|
||||
var localDate = require("locale").date(new Date(), 1);
|
||||
localDate = localDate.substring(0, localDate.length - 5)
|
||||
g.setFont("Vector", 17);
|
||||
g.drawString(require("locale").dow(new Date(), 1).toUpperCase() + ", " + localDate, xyCenter, yposDate, true);
|
||||
|
||||
|
||||
|
||||
g.setFont(font, primaryDateFontSize);
|
||||
// set gmt to UTC+0
|
||||
var gmt = new Date(d.getTime() + d.getTimezoneOffset() * 60 * 1000);
|
||||
|
||||
// Loop through offset(s) and render
|
||||
offsets.forEach((offset, index) => {
|
||||
dx = getCurrentTimeFromOffset(gmt, offset[OFFSET_HOURS]);
|
||||
hours = doublenum(dx.getHours());
|
||||
minutes = doublenum(dx.getMinutes());
|
||||
|
||||
|
||||
if (offsets.length === 1) {
|
||||
var date = [require("locale").dow(new Date(), 1), require("locale").date(new Date(), 1)];
|
||||
// For a single secondary timezone, draw it bigger and drop time zone to second line
|
||||
const xOffset = 30;
|
||||
g.setFont(font, secondaryTimeFontSize);
|
||||
g.drawString(`${hours}:${minutes}`, xyCenter, yposTime2, true);
|
||||
g.setFont(font, secondaryTimeZoneFontSize);
|
||||
g.drawString(offset[OFFSET_TIME_ZONE], xyCenter, yposTime2 + 30, true);
|
||||
|
||||
// draw Day, name of month, Date
|
||||
g.setFont(font, secondaryTimeZoneFontSize);
|
||||
g.drawString(date, xyCenter, yposDate, true);
|
||||
} else if (index < 3) {
|
||||
// For > 1 extra timezones, render as columns / rows
|
||||
g.setFont(font, secondaryRowColFontSize);
|
||||
g.setFontAlign(-1, 0);
|
||||
g.drawString(
|
||||
offset[OFFSET_TIME_ZONE],
|
||||
xcol1,
|
||||
yposWorld + index * 15,
|
||||
true
|
||||
);
|
||||
g.setFontAlign(1, 0);
|
||||
g.drawString(`${hours}:${minutes}`, xcol2, yposWorld + index * 15, true);
|
||||
}
|
||||
});
|
||||
|
||||
g.setFontAlign(-1, 0);
|
||||
g.setFont("Vector",12);
|
||||
g.drawString(`^${rise}`, 10, 3 + yposWorld + 3 * 15, true); // draw riseset
|
||||
g.setFontAlign(1, 0);
|
||||
g.drawString(`v${set}`, xcol2, 3 + yposWorld + 3 * 15, true); // draw riseset
|
||||
|
||||
queueDraw();
|
||||
}
|
||||
|
||||
// clean app screen
|
||||
g.clear();
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
updatePos();
|
||||
setInterval(drawSeconds, 1E3);
|
||||
|
||||
|
||||
|
||||
// Stop updates when LCD is off, restart when on
|
||||
Bangle.on('lcdPower',on=>{
|
||||
if (on) {
|
||||
draw(); // draw immediately, queue redraw
|
||||
drawSeconds(); // draw immediately, queue redraw
|
||||
setInterval(updatePos, 60*5E3); // refesh every 5 mins
|
||||
setInterval(drawSeconds, 1E3);
|
||||
updatePos();
|
||||
} else { // stop draw timer
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
if (drawTimeoutSeconds) clearTimeout(drawTimeoutSeconds);
|
||||
drawTimeout = undefined;
|
||||
drawTimeoutSeconds = undefined;
|
||||
setInterval(updatePos, 60*50E3); // refesh every 50 mins
|
||||
setInterval(drawSeconds, 10E3);
|
||||
updatePos();
|
||||
}
|
||||
});
|
||||
|
||||
// draw now
|
||||
drawSeconds();
|
||||
draw();
|
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
|
@ -0,0 +1,76 @@
|
|||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="../../css/spectre.min.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>You can add up to 3 timezones. Please give a name and UTC offset in hours.
|
||||
If you want less than 3, clear the checkbox to the left.</p>
|
||||
|
||||
<table id="hworldclock-offsets">
|
||||
<tr>
|
||||
<th>Enabled?</th>
|
||||
<th>Name</th>
|
||||
<th>UTC Offset</th>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>Click <button id="upload" class="btn btn-primary">Upload</button></p>
|
||||
|
||||
<script src="../../core/lib/customize.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
var offsets=[];
|
||||
try{
|
||||
var stored = localStorage.getItem('hworldclock-offset-list')
|
||||
if(stored) offsets = JSON.parse(stored);
|
||||
if (!offsets || offsets.length!=3) {
|
||||
throw "Offsets invalid";
|
||||
}
|
||||
} catch(e){
|
||||
offsets=[
|
||||
[true,"London",0],
|
||||
[true,"NY",-5],
|
||||
[true, "Denver",-6],
|
||||
|
||||
];
|
||||
}
|
||||
console.log(offsets);
|
||||
var tbl=document.getElementById("hworldclock-offsets");
|
||||
for (var i=0; i<3; i++) {
|
||||
var $offset = document.createElement('tr')
|
||||
$offset.innerHTML = `
|
||||
<td><input type="checkbox" id="enabled_${i}" ${offsets[i][0]? "checked" : ""}></td>
|
||||
<td><input type="text" id="name_${i}" value="${offsets[i][1]}"></td>
|
||||
<td><input type="number" id="offset_${i}" value="${offsets[i][2]}"></td>`
|
||||
tbl.append($offset);
|
||||
}
|
||||
|
||||
// When the 'upload' button is clicked...
|
||||
document.getElementById("upload").addEventListener("click", function() {
|
||||
var storage_offsets=[];
|
||||
var app_offsets=[];
|
||||
for (var i=0; i<3; i++) {
|
||||
var checked=document.getElementById("enabled_"+i).checked;
|
||||
var name=document.getElementById("name_"+i).value;
|
||||
var offset=document.getElementById("offset_"+i).value;
|
||||
if (checked) {
|
||||
app_offsets.push([name,offset]);
|
||||
}
|
||||
storage_offsets.push([checked,name,offset]);
|
||||
}
|
||||
console.log(storage_offsets);
|
||||
console.log(app_offsets);
|
||||
localStorage.setItem('worldclock-offset-list',JSON.stringify(storage_offsets));
|
||||
// send finished app (in addition to contents of app.json)
|
||||
sendCustomizedApp({
|
||||
storage:[
|
||||
{name:"hworldclock.settings.json", content:JSON.stringify(app_offsets)},
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,298 @@
|
|||
/* Module suncalc.js
|
||||
(c) 2011-2015, Vladimir Agafonkin
|
||||
SunCalc is a JavaScript library for calculating sun/moon position and light phases.
|
||||
https://github.com/mourner/suncalc
|
||||
|
||||
PB: Usage:
|
||||
E.setTimeZone(2); // 1 = MEZ, 2 = MESZ
|
||||
SunCalc = require("suncalc.js");
|
||||
pos = SunCalc.getPosition(Date.now(), 53.3, 10.1);
|
||||
times = SunCalc.getTimes(Date.now(), 53.3, 10.1);
|
||||
rise = times.sunrise; // Date object
|
||||
rise_str = rise.getHours() + ':' + rise.getMinutes(); //hh:mm
|
||||
*/
|
||||
var exports={};
|
||||
|
||||
// shortcuts for easier to read formulas
|
||||
|
||||
var PI = Math.PI,
|
||||
sin = Math.sin,
|
||||
cos = Math.cos,
|
||||
tan = Math.tan,
|
||||
asin = Math.asin,
|
||||
atan = Math.atan2,
|
||||
acos = Math.acos,
|
||||
rad = PI / 180;
|
||||
|
||||
// sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas
|
||||
|
||||
// date/time constants and conversions
|
||||
|
||||
var dayMs = 1000 * 60 * 60 * 24,
|
||||
J1970 = 2440588,
|
||||
J2000 = 2451545;
|
||||
|
||||
function toJulian(date) { return date.valueOf() / dayMs - 0.5 + J1970; }
|
||||
function fromJulian(j) { return new Date((j + 0.5 - J1970) * dayMs); } // PB: onece removed + 0.5; included it again 4 Jan 2021
|
||||
function toDays(date) { return toJulian(date) - J2000; }
|
||||
|
||||
|
||||
// general calculations for position
|
||||
|
||||
var e = rad * 23.4397; // obliquity of the Earth
|
||||
|
||||
function rightAscension(l, b) { return atan(sin(l) * cos(e) - tan(b) * sin(e), cos(l)); }
|
||||
function declination(l, b) { return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l)); }
|
||||
|
||||
function azimuth(H, phi, dec) { return atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi)); }
|
||||
function altitude(H, phi, dec) { return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H)); }
|
||||
|
||||
function siderealTime(d, lw) { return rad * (280.16 + 360.9856235 * d) - lw; }
|
||||
|
||||
function astroRefraction(h) {
|
||||
if (h < 0) // the following formula works for positive altitudes only.
|
||||
h = 0; // if h = -0.08901179 a div/0 would occur.
|
||||
|
||||
// formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
|
||||
// 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad:
|
||||
return 0.0002967 / Math.tan(h + 0.00312536 / (h + 0.08901179));
|
||||
}
|
||||
|
||||
// general sun calculations
|
||||
|
||||
function solarMeanAnomaly(d) { return rad * (357.5291 + 0.98560028 * d); }
|
||||
|
||||
function eclipticLongitude(M) {
|
||||
|
||||
var C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center
|
||||
P = rad * 102.9372; // perihelion of the Earth
|
||||
|
||||
return M + C + P + PI;
|
||||
}
|
||||
|
||||
function sunCoords(d) {
|
||||
|
||||
var M = solarMeanAnomaly(d),
|
||||
L = eclipticLongitude(M);
|
||||
|
||||
return {
|
||||
dec: declination(L, 0),
|
||||
ra: rightAscension(L, 0)
|
||||
};
|
||||
}
|
||||
|
||||
// calculates sun position for a given date and latitude/longitude
|
||||
|
||||
exports.getPosition = function (date, lat, lng) {
|
||||
|
||||
var lw = rad * -lng,
|
||||
phi = rad * lat,
|
||||
d = toDays(date),
|
||||
|
||||
c = sunCoords(d),
|
||||
H = siderealTime(d, lw) - c.ra;
|
||||
|
||||
return {
|
||||
azimuth: Math.round((azimuth(H, phi, c.dec) / rad + 180) % 360), // PB: converted to deg
|
||||
altitude: Math.round( altitude(H, phi, c.dec) / rad) // PB: converted to deg
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// sun times configuration (angle, morning name, evening name)
|
||||
|
||||
var times = [
|
||||
[-0.833, 'sunrise', 'sunset' ]
|
||||
];
|
||||
|
||||
// calculations for sun times
|
||||
var J0 = 0.0009;
|
||||
|
||||
function julianCycle(d, lw) { return Math.round(d - J0 - lw / (2 * PI)); }
|
||||
|
||||
function approxTransit(Ht, lw, n) { return J0 + (Ht + lw) / (2 * PI) + n; }
|
||||
function solarTransitJ(ds, M, L) { return J2000 + ds + 0.0053 * sin(M) - 0.0069 * sin(2 * L); }
|
||||
|
||||
function hourAngle(h, phi, d) { return acos((sin(h) - sin(phi) * sin(d)) / (cos(phi) * cos(d))); }
|
||||
function observerAngle(height) { return -2.076 * Math.sqrt(height) / 60; }
|
||||
|
||||
// returns set time for the given sun altitude
|
||||
function getSetJ(h, lw, phi, dec, n, M, L) {
|
||||
|
||||
var w = hourAngle(h, phi, dec),
|
||||
a = approxTransit(w, lw, n);
|
||||
return solarTransitJ(a, M, L);
|
||||
}
|
||||
|
||||
|
||||
// calculates sun times for a given date, latitude/longitude, and, optionally,
|
||||
// the observer height (in meters) relative to the horizon
|
||||
|
||||
exports.getTimes = function (date, lat, lng, height) {
|
||||
|
||||
height = height || 0;
|
||||
|
||||
var lw = rad * -lng,
|
||||
phi = rad * lat,
|
||||
|
||||
dh = observerAngle(height),
|
||||
|
||||
d = toDays(date),
|
||||
n = julianCycle(d, lw),
|
||||
ds = approxTransit(0, lw, n),
|
||||
|
||||
M = solarMeanAnomaly(ds),
|
||||
L = eclipticLongitude(M),
|
||||
dec = declination(L, 0),
|
||||
|
||||
Jnoon = solarTransitJ(ds, M, L),
|
||||
|
||||
i, len, time, h0, Jset, Jrise;
|
||||
|
||||
|
||||
var result = {
|
||||
solarNoon: fromJulian(Jnoon),
|
||||
nadir: fromJulian(Jnoon - 0.5)
|
||||
};
|
||||
|
||||
for (i = 0, len = times.length; i < len; i += 1) {
|
||||
time = times[i];
|
||||
h0 = (time[0] + dh) * rad;
|
||||
|
||||
Jset = getSetJ(h0, lw, phi, dec, n, M, L);
|
||||
Jrise = Jnoon - (Jset - Jnoon);
|
||||
|
||||
result[time[1]] = fromJulian(Jrise);
|
||||
result[time[2]] = fromJulian(Jset);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
// moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas
|
||||
|
||||
function moonCoords(d) { // geocentric ecliptic coordinates of the moon
|
||||
|
||||
var L = rad * (218.316 + 13.176396 * d), // ecliptic longitude
|
||||
M = rad * (134.963 + 13.064993 * d), // mean anomaly
|
||||
F = rad * (93.272 + 13.229350 * d), // mean distance
|
||||
|
||||
l = L + rad * 6.289 * sin(M), // longitude
|
||||
b = rad * 5.128 * sin(F), // latitude
|
||||
dt = 385001 - 20905 * cos(M); // distance to the moon in km
|
||||
|
||||
return {
|
||||
ra: rightAscension(l, b),
|
||||
dec: declination(l, b),
|
||||
dist: dt
|
||||
};
|
||||
}
|
||||
|
||||
getMoonPosition = function (date, lat, lng) {
|
||||
|
||||
var lw = rad * -lng,
|
||||
phi = rad * lat,
|
||||
d = toDays(date),
|
||||
|
||||
c = moonCoords(d),
|
||||
H = siderealTime(d, lw) - c.ra,
|
||||
h = altitude(H, phi, c.dec),
|
||||
// formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
|
||||
pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H));
|
||||
|
||||
h = h + astroRefraction(h); // altitude correction for refraction
|
||||
|
||||
return {
|
||||
azimuth: azimuth(H, phi, c.dec),
|
||||
altitude: h,
|
||||
distance: c.dist,
|
||||
parallacticAngle: pa
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// calculations for illumination parameters of the moon,
|
||||
// based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and
|
||||
// Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
|
||||
|
||||
getMoonIllumination = function (date) {
|
||||
|
||||
var d = toDays(date || new Date()),
|
||||
s = sunCoords(d),
|
||||
m = moonCoords(d),
|
||||
|
||||
sdist = 149598000, // distance from Earth to Sun in km
|
||||
|
||||
phi = acos(sin(s.dec) * sin(m.dec) + cos(s.dec) * cos(m.dec) * cos(s.ra - m.ra)),
|
||||
inc = atan(sdist * sin(phi), m.dist - sdist * cos(phi)),
|
||||
angle = atan(cos(s.dec) * sin(s.ra - m.ra), sin(s.dec) * cos(m.dec) -
|
||||
cos(s.dec) * sin(m.dec) * cos(s.ra - m.ra));
|
||||
|
||||
return {
|
||||
fraction: (1 + cos(inc)) / 2,
|
||||
phase: 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math.PI,
|
||||
angle: angle
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
function hoursLater(date, h) {
|
||||
return new Date(date.valueOf() + h * dayMs / 24);
|
||||
}
|
||||
|
||||
// calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article
|
||||
|
||||
getMoonTimes = function (date, lat, lng, inUTC) {
|
||||
var t = new Date(date);
|
||||
if (inUTC) t.setUTCHours(0, 0, 0, 0);
|
||||
else t.setHours(0, 0, 0, 0);
|
||||
|
||||
var hc = 0.133 * rad,
|
||||
h0 = SunCalc.getMoonPosition(t, lat, lng).altitude - hc,
|
||||
h1, h2, rise, set, a, b, xe, ye, d, roots, x1, x2, dx;
|
||||
|
||||
// go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set)
|
||||
for (var i = 1; i <= 24; i += 2) {
|
||||
h1 = SunCalc.getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc;
|
||||
h2 = SunCalc.getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc;
|
||||
|
||||
a = (h0 + h2) / 2 - h1;
|
||||
b = (h2 - h0) / 2;
|
||||
xe = -b / (2 * a);
|
||||
ye = (a * xe + b) * xe + h1;
|
||||
d = b * b - 4 * a * h1;
|
||||
roots = 0;
|
||||
|
||||
if (d >= 0) {
|
||||
dx = Math.sqrt(d) / (Math.abs(a) * 2);
|
||||
x1 = xe - dx;
|
||||
x2 = xe + dx;
|
||||
if (Math.abs(x1) <= 1) roots++;
|
||||
if (Math.abs(x2) <= 1) roots++;
|
||||
if (x1 < -1) x1 = x2;
|
||||
}
|
||||
|
||||
if (roots === 1) {
|
||||
if (h0 < 0) rise = i + x1;
|
||||
else set = i + x1;
|
||||
|
||||
} else if (roots === 2) {
|
||||
rise = i + (ye < 0 ? x2 : x1);
|
||||
set = i + (ye < 0 ? x1 : x2);
|
||||
}
|
||||
|
||||
if (rise && set) break;
|
||||
|
||||
h0 = h2;
|
||||
}
|
||||
|
||||
var result = {};
|
||||
|
||||
if (rise) result.rise = hoursLater(t, rise);
|
||||
if (set) result.set = hoursLater(t, set);
|
||||
|
||||
if (!rise && !set) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true;
|
||||
|
||||
return result;
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwgJC/ABEE+EA4EAj9E8HF//gn/gwP///wt/MgF//8gh/8gYLBwEP+EHAofghgFD4EOj//gEPA4ILBGgIxB/wFBgwFB/lsgCKBj/4oxHBvAFBJoV8gP4TQX+gJUBAAN/Aok+AoVgAoXogAfBjkA8AfBAoXAAoUYY4cAiCDEAooA/ABg"))
|
Binary file not shown.
After Width: | Height: | Size: 3.4 KiB |
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"id": "hworldclock",
|
||||
"name": "Hanks World Clock",
|
||||
"shortName": "Hanks World Clock",
|
||||
"version": "0.15",
|
||||
"description": "Current time zone plus up to three others",
|
||||
"allow_emulator":true,
|
||||
"icon": "app.png",
|
||||
"screenshots": [{"url":"screenshot_hworld.png"}],
|
||||
"type": "clock",
|
||||
"tags": "clock",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"custom": "custom.html",
|
||||
"storage": [
|
||||
{"name":"hworldclock.app.js","url":"app.js"},
|
||||
{"name":"hworldclock.img","url":"hworldclock-icon.js","evaluate":true},
|
||||
{"name":"hsuncalc.js","url":"hsuncalc.js"}
|
||||
],
|
||||
"data": [{"name":"hworldclock.settings.json"}]
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 3.4 KiB |
Loading…
Reference in New Issue