mirror of https://github.com/espruino/BangleApps
Merge remote-tracking branch 'upstream/master'
commit
b55d5269da
|
@ -31,7 +31,7 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label">Select which GNSS system you want.</label>
|
<label class="form-label">Select which GNSS system you want.</label>
|
||||||
<label class="form-radio">
|
<label class="form-radio">
|
||||||
<input type="radio" name="gnss_select" value="1" checked><i class="form-icon"></i> GPS
|
<input type="radio" name="gnss_select" value="1" checked><i class="form-icon"></i> GPS (fastest to get a fix)
|
||||||
</label>
|
</label>
|
||||||
<label class="form-radio">
|
<label class="form-radio">
|
||||||
<input type="radio" name="gnss_select" value="2"><i class="form-icon"></i> BDS
|
<input type="radio" name="gnss_select" value="2"><i class="form-icon"></i> BDS
|
||||||
|
|
|
@ -23,7 +23,16 @@ var SL = W/15; // ship side length
|
||||||
var AS = W/18; // asteroid radius
|
var AS = W/18; // asteroid radius
|
||||||
// radius of ship, assumed a circle inside equilateral traingle of side SS
|
// radius of ship, assumed a circle inside equilateral traingle of side SS
|
||||||
// r = a / root 3 where a is length of equilateral triangle
|
// r = a / root 3 where a is length of equilateral triangle
|
||||||
var SR = SS / Math.sqrt(3);
|
var SR = SS / Math.sqrt(3);
|
||||||
|
var AST = [ // asteroid polygon as X/Y pairs
|
||||||
|
0 ,-1.5,
|
||||||
|
1 , 0,
|
||||||
|
0.5, 0,
|
||||||
|
0.5, 0.5,
|
||||||
|
0 , 1,
|
||||||
|
-1 , 0,
|
||||||
|
-1 , -1
|
||||||
|
];
|
||||||
|
|
||||||
g.clear().setFontAlign(0,-1);
|
g.clear().setFontAlign(0,-1);
|
||||||
|
|
||||||
|
@ -148,15 +157,7 @@ function onFrame() {
|
||||||
a.y += a.vy*d;
|
a.y += a.vy*d;
|
||||||
//g.drawCircle(a.x, a.y, a.rad);
|
//g.drawCircle(a.x, a.y, a.rad);
|
||||||
// a 7 point asteroid with rough circle radius of scale 2
|
// a 7 point asteroid with rough circle radius of scale 2
|
||||||
g.drawPoly([
|
g.drawPoly(g.transformVertices(AST,{x:a.x,y:a.y,scale:a.rad,rotate:t}),true);
|
||||||
a.x , a.y - 1.5 * a.rad,
|
|
||||||
a.x + a.rad , a.y ,
|
|
||||||
a.x + a.rad/2 , a.y ,
|
|
||||||
a.x + a.rad/2 , a.y + a.rad/2 ,
|
|
||||||
a.x , a.y + a.rad ,
|
|
||||||
a.x - a.rad , a.y ,
|
|
||||||
a.x - a.rad , a.y - a.rad
|
|
||||||
],true);
|
|
||||||
|
|
||||||
if (a.x<0) a.x+=W;
|
if (a.x<0) a.x+=W;
|
||||||
if (a.y<0) a.y+=H;
|
if (a.y<0) a.y+=H;
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
0.01: New App!
|
0.01: New App!
|
||||||
|
0.02: Shorten the timeout before executing to 250 ms.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Fast Reset
|
# Fast Reset
|
||||||
|
|
||||||
Reset the watch by holding the hardware button for half a second. If 'Fastload Utils' is installed this will typically be done with fastloading. A buzz acts as indicator.
|
Reset the watch by pressing the hardware button just a little bit longer than a click. If 'Fastload Utils' is installed this will typically be done with fastloading. A buzz acts as indicator.
|
||||||
|
|
||||||
Fast Reset was developed with the app history feature of 'Fastload Utils' in mind. If many apps are in the history stack, the user may want a fast way to exit directly to the clock face without using the firmwares reset function.
|
Fast Reset was developed with the app history feature of 'Fastload Utils' in mind. If many apps are in the history stack, the user may want a fast way to exit directly to the clock face without using the firmwares reset function.
|
||||||
|
|
||||||
|
@ -12,11 +12,11 @@ Just install and it will run as boot code.
|
||||||
|
|
||||||
If 'Fastload Utils' is installed fastloading will be used when possible. Otherwise a standard `load(.bootcde)` is used.
|
If 'Fastload Utils' is installed fastloading will be used when possible. Otherwise a standard `load(.bootcde)` is used.
|
||||||
|
|
||||||
If the hardware button is held for longer the standard reset functionality of the firmware is executed as well (total 1.5 seconds). And eventually the watchdog will be kicked.
|
If the hardware button is held for longer the standard reset functionality of the firmware is executed as well. And eventually the watchdog will be kicked.
|
||||||
|
|
||||||
## Controls
|
## Controls
|
||||||
|
|
||||||
Hold the hardware button for half a second to feel the buzz, loading the clock face.
|
Press the hardware button just a little longer than a click to feel the buzz, loading the clock face.
|
||||||
|
|
||||||
## Requests
|
## Requests
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{let buzzTimeout;
|
{let buzzTimeout;
|
||||||
setWatch((e)=>{
|
setWatch((e)=>{
|
||||||
if (e.state) buzzTimeout = setTimeout(()=>{Bangle.buzz(80,0.40);Bangle.showClock();}, 500);
|
if (e.state) buzzTimeout = setTimeout(()=>{Bangle.buzz(80,0.40);Bangle.showClock();}, 250);
|
||||||
if (!e.state && buzzTimeout) clearTimeout(buzzTimeout);},
|
if (!e.state && buzzTimeout) clearTimeout(buzzTimeout);},
|
||||||
BTN,{repeat:true, edge:'both' });}
|
BTN,{repeat:true, edge:'both' });}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
{ "id": "fastreset",
|
{ "id": "fastreset",
|
||||||
"name": "Fast Reset",
|
"name": "Fast Reset",
|
||||||
"shortName":"Fast Reset",
|
"shortName":"Fast Reset",
|
||||||
"version":"0.01",
|
"version":"0.02",
|
||||||
"description": "Reset the watch by holding the hardware button for half a second. If 'Fastload Utils' is installed this will typically be done with fastloading. A buzz acts as indicator.",
|
"description": "Reset the watch by pressing the hardware button just a little bit longer than a click. If 'Fastload Utils' is installed this will typically be done with fastloading. A buzz acts as indicator.",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"type": "bootloader",
|
"type": "bootloader",
|
||||||
"tags": "system",
|
"tags": "system",
|
||||||
"supports" : ["BANGLEJS2"],
|
"supports" : ["BANGLEJS2"],
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"fastreset.boot.js","url":"boot.js"}
|
{"name":"fastreset.boot.js","url":"boot.js"}
|
||||||
|
|
|
@ -5,3 +5,4 @@
|
||||||
0.05: Prevent drawing into app area.
|
0.05: Prevent drawing into app area.
|
||||||
0.06: Fix issue where .draw was being called by reference (not allowing widgets to be hidden)
|
0.06: Fix issue where .draw was being called by reference (not allowing widgets to be hidden)
|
||||||
0.07: Handle the swipe event that is generated when draging to change light intensity, so it doesn't trigger some other swipe handler.
|
0.07: Handle the swipe event that is generated when draging to change light intensity, so it doesn't trigger some other swipe handler.
|
||||||
|
0.08: Ensure boot code doesn't allocate and leave a gloval variable named 'settings'
|
|
@ -1,5 +1,6 @@
|
||||||
|
{
|
||||||
// load settings
|
// load settings
|
||||||
var settings = Object.assign({
|
let settings = Object.assign({
|
||||||
value: 1,
|
value: 1,
|
||||||
isOn: true
|
isOn: true
|
||||||
}, require("Storage").readJSON("lightswitch.json", true) || {});
|
}, require("Storage").readJSON("lightswitch.json", true) || {});
|
||||||
|
@ -12,6 +13,4 @@ Bangle.removeListener("tap", require("lightswitch.js").tapListener);
|
||||||
|
|
||||||
// add tap listener to unlock and/or flash backlight
|
// add tap listener to unlock and/or flash backlight
|
||||||
if (settings.unlockSide || settings.tapSide) Bangle.on("tap", require("lightswitch.js").tapListener);
|
if (settings.unlockSide || settings.tapSide) Bangle.on("tap", require("lightswitch.js").tapListener);
|
||||||
|
}
|
||||||
// clear variable
|
|
||||||
settings = undefined;
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "lightswitch",
|
"id": "lightswitch",
|
||||||
"name": "Light Switch Widget",
|
"name": "Light Switch Widget",
|
||||||
"shortName": "Light Switch",
|
"shortName": "Light Switch",
|
||||||
"version": "0.07",
|
"version": "0.08",
|
||||||
"description": "A fast way to switch LCD backlight on/off, change the brightness and show the lock status. All in one widget.",
|
"description": "A fast way to switch LCD backlight on/off, change the brightness and show the lock status. All in one widget.",
|
||||||
"icon": "images/app.png",
|
"icon": "images/app.png",
|
||||||
"screenshots": [
|
"screenshots": [
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<link rel="stylesheet" href="../../css/spectre.min.css">
|
<link rel="stylesheet" href="../../css/spectre.min.css">
|
||||||
|
<style>
|
||||||
|
table { width:100%;}
|
||||||
|
.table_t {font-weight:bold;width:40%;};
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
@ -13,6 +17,11 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input id="translations" type="checkbox" /> <label for="translations">Add common language translations like "Yes", "No", "On", "Off"<br/><i>(Not recommended. For translations use the option under <code>More...</code> in the app loader.</i></label>
|
<input id="translations" type="checkbox" /> <label for="translations">Add common language translations like "Yes", "No", "On", "Off"<br/><i>(Not recommended. For translations use the option under <code>More...</code> in the app loader.</i></label>
|
||||||
</div>
|
</div>
|
||||||
|
<p>
|
||||||
|
<table id="examples">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</table>
|
||||||
<p>Then click <button id="upload" class="btn btn-primary">Upload</button></p>
|
<p>Then click <button id="upload" class="btn btn-primary">Upload</button></p>
|
||||||
|
|
||||||
<script src="../../core/lib/customize.js"></script>
|
<script src="../../core/lib/customize.js"></script>
|
||||||
|
@ -93,21 +102,8 @@ exports = { name : "en_GB", currencySym:"£",
|
||||||
checkChars(locale,localeName);
|
checkChars(locale,localeName);
|
||||||
});
|
});
|
||||||
|
|
||||||
var languageSelector = document.getElementById("languages");
|
|
||||||
languageSelector.innerHTML = Object.keys(locales).map(l=>{
|
|
||||||
var localeParts = l.split("_"); // en_GB -> ["en","GB"]
|
|
||||||
var icon = "";
|
|
||||||
// If we have a 2 char ISO country code, use it to get the unicode flag
|
|
||||||
if (localeParts[1] && localeParts[1].length==2)
|
|
||||||
icon = localeParts[1].toUpperCase().replace(/./g, char => String.fromCodePoint(char.charCodeAt(0)+127397) )+" ";
|
|
||||||
if (localeParts[1]=="NAV")
|
|
||||||
icon = "⛵✈️ ";
|
|
||||||
return `<option value="${l}">${icon}${l}</option>`
|
|
||||||
}).join("\n");
|
|
||||||
|
|
||||||
document.getElementById("upload").addEventListener("click", function() {
|
function createLocaleModule(lang) {
|
||||||
|
|
||||||
const lang = languageSelector.options[languageSelector.selectedIndex].value;
|
|
||||||
console.log(`Language ${lang}`);
|
console.log(`Language ${lang}`);
|
||||||
|
|
||||||
const translations = document.getElementById('translations').checked;
|
const translations = document.getElementById('translations').checked;
|
||||||
|
@ -151,7 +147,7 @@ exports = { name : "en_GB", currencySym:"£",
|
||||||
|
|
||||||
var replaceList = {
|
var replaceList = {
|
||||||
"%Y": "d.getFullYear()",
|
"%Y": "d.getFullYear()",
|
||||||
"%y": "(d.getFullYear().toString()).slice(-2)",
|
"%y": "d.getFullYear().toString().slice(-2)",
|
||||||
"%m": "('0'+(d.getMonth()+1).toString()).slice(-2)",
|
"%m": "('0'+(d.getMonth()+1).toString()).slice(-2)",
|
||||||
"%-m": "d.getMonth()+1",
|
"%-m": "d.getMonth()+1",
|
||||||
"%d": "('0'+d.getDate()).slice(-2)",
|
"%d": "('0'+d.getDate()).slice(-2)",
|
||||||
|
@ -182,16 +178,17 @@ exports = { name : "en_GB", currencySym:"£",
|
||||||
`exports.number(n) + ${js(locale.currency_symbol)}`;
|
`exports.number(n) + ${js(locale.currency_symbol)}`;
|
||||||
var temperature = locale.temperature=='°F' ? '(t*9/5)+32' : 't';
|
var temperature = locale.temperature=='°F' ? '(t*9/5)+32' : 't';
|
||||||
|
|
||||||
var localeModule = `
|
function getLocaleModule(isLocal) {
|
||||||
|
return `
|
||||||
function round(n, dp) {
|
function round(n, dp) {
|
||||||
if (dp===undefined) dp=0;
|
if (dp===undefined) dp=0;
|
||||||
var p = Math.min(dp,dp - Math.floor(Math.log(n)/Math.log(10)));
|
var p = Math.max(0,Math.min(dp,dp - Math.floor(Math.log(n)/Math.log(10))));
|
||||||
return n.toFixed(p);
|
return n.toFixed(p);
|
||||||
}
|
}
|
||||||
var is12;
|
var is12;
|
||||||
function getHours(d) {
|
function getHours(d) {
|
||||||
var h = d.getHours();
|
var h = d.getHours();
|
||||||
if (is12 === undefined) is12 = (require('Storage').readJSON('setting.json', 1) || {})["12hour"];
|
if (is12 === undefined) is12 = ${isLocal ? "false" : `(require('Storage').readJSON('setting.json', 1) || {})["12hour"]`};
|
||||||
if (!is12) return ('0' + h).slice(-2);
|
if (!is12) return ('0' + h).slice(-2);
|
||||||
return ((h % 12 == 0) ? 12 : h % 12).toString();
|
return ((h % 12 == 0) ? 12 : h % 12).toString();
|
||||||
}
|
}
|
||||||
|
@ -224,7 +221,54 @@ exports = {
|
||||||
time: (d,short) => short ? \`${timeS}\` : \`${timeN}\`,
|
time: (d,short) => short ? \`${timeS}\` : \`${timeN}\`,
|
||||||
meridian: d => d.getHours() < 12 ? ${js(locale.ampm[0])}:${js(locale.ampm[1])},
|
meridian: d => d.getHours() < 12 ? ${js(locale.ampm[0])}:${js(locale.ampm[1])},
|
||||||
};
|
};
|
||||||
`.trim();
|
`.trim()
|
||||||
|
};
|
||||||
|
|
||||||
|
var exports;
|
||||||
|
eval(getLocaleModule(true));
|
||||||
|
console.log("exports:",exports);
|
||||||
|
|
||||||
|
var date = new Date();
|
||||||
|
document.getElementById("examples").innerHTML = `
|
||||||
|
<tr><td class="table_t"></td><td style="font-weight:bold">Short</td><td style="font-weight:bold">Long</td></tr>
|
||||||
|
<tr><td class="table_t">Day</td><td>${exports.dow(date,1)}</td><td>${exports.dow(date,0)}</td></tr>
|
||||||
|
<tr><td class="table_t">Month</td><td>${exports.month(date,1)}</td><td>${exports.month(date,0)}</td></tr>
|
||||||
|
<tr><td class="table_t">Date</td><td>${exports.date(date,1)}</td><td>${exports.date(date,0)}</td></tr>
|
||||||
|
<tr><td class="table_t">Time</td><td>${exports.time(date,1)}</td><td>${exports.time(date,0)}</td></tr>
|
||||||
|
<tr><td class="table_t">Number</td><td>${exports.number(12.3456789)}</td><td>${exports.number(12.3456789,4)}</td></tr>
|
||||||
|
<tr><td class="table_t">Currency</td><td></td><td>${exports.currency(12.34)}</td></tr>
|
||||||
|
<tr><td class="table_t">Distance</td><td>${exports.distance(12.34,0)}</td><td>${exports.distance(12345.6,1)}</td></tr>
|
||||||
|
<tr><td class="table_t">Speed</td><td></td><td>${exports.speed(123)}</td></tr>
|
||||||
|
<tr><td class="table_t">Temperature</td><td></td><td>${exports.temp(12,0)}</td></tr>
|
||||||
|
`;
|
||||||
|
return getLocaleModule(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var languageSelector = document.getElementById("languages");
|
||||||
|
languageSelector.innerHTML = Object.keys(locales).map(l=>{
|
||||||
|
var locale = locales[l];
|
||||||
|
var localeParts = l.split("_"); // en_GB -> ["en","GB"]
|
||||||
|
var icon = "";
|
||||||
|
// If we have a 2 char ISO country code, use it to get the unicode flag
|
||||||
|
if (locale.icon)
|
||||||
|
icon = locale.icon+" ";
|
||||||
|
else if (localeParts[1] && localeParts[1].length==2)
|
||||||
|
icon = localeParts[1].toUpperCase().replace(/./g, char => String.fromCodePoint(char.charCodeAt(0)+127397) )+" ";
|
||||||
|
return `<option value="${l}">${icon}${l}${locale.notes?" - "+locale.notes:""}</option>`
|
||||||
|
}).join("\n");
|
||||||
|
languageSelector.addEventListener('change', function() {
|
||||||
|
const lang = languageSelector.options[languageSelector.selectedIndex].value;
|
||||||
|
createLocaleModule(lang);
|
||||||
|
});
|
||||||
|
// initial value
|
||||||
|
createLocaleModule(languageSelector.options[languageSelector.selectedIndex].value);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById("upload").addEventListener("click", function() {
|
||||||
|
|
||||||
|
const lang = languageSelector.options[languageSelector.selectedIndex].value;
|
||||||
|
var localeModule = createLocaleModule(lang);
|
||||||
|
|
||||||
console.log("Locale Module is:",localeModule);
|
console.log("Locale Module is:",localeModule);
|
||||||
sendCustomizedApp({
|
sendCustomizedApp({
|
||||||
|
|
|
@ -79,6 +79,44 @@ var locales = {
|
||||||
day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
|
day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
|
||||||
// No translation for english...
|
// No translation for english...
|
||||||
},
|
},
|
||||||
|
"en_US": {
|
||||||
|
lang: "en_US",
|
||||||
|
notes: "USA with MM/DD/YY date",
|
||||||
|
decimal_point: ".",
|
||||||
|
thousands_sep: ",",
|
||||||
|
currency_symbol: "$", currency_first: true,
|
||||||
|
int_curr_symbol: "USD",
|
||||||
|
speed: "mph",
|
||||||
|
distance: { 0: "ft", 1: "mi" },
|
||||||
|
temperature: "°F",
|
||||||
|
ampm: { 0: "am", 1: "pm" },
|
||||||
|
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
|
||||||
|
datePattern: { 0: "%b %d, %Y", 1: "%m/%d/%y" },
|
||||||
|
abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
|
||||||
|
month: "January,February,March,April,May,June,July,August,September,October,November,December",
|
||||||
|
abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
|
||||||
|
day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
|
||||||
|
// No translation for english...
|
||||||
|
},
|
||||||
|
"en_US 2": {
|
||||||
|
lang: "en_US 2", icon:"🇺🇸",
|
||||||
|
notes: "USA with YYYY-MM-DD date",
|
||||||
|
decimal_point: ".",
|
||||||
|
thousands_sep: ",",
|
||||||
|
currency_symbol: "$", currency_first: true,
|
||||||
|
int_curr_symbol: "USD",
|
||||||
|
speed: "mph",
|
||||||
|
distance: { 0: "ft", 1: "mi" },
|
||||||
|
temperature: "°F",
|
||||||
|
ampm: { 0: "am", 1: "pm" },
|
||||||
|
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
|
||||||
|
datePattern: { 0: "%b %d, %Y", 1: "%Y-%m-%d" },
|
||||||
|
abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
|
||||||
|
month: "January,February,March,April,May,June,July,August,September,October,November,December",
|
||||||
|
abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
|
||||||
|
day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
|
||||||
|
// No translation for english...
|
||||||
|
},
|
||||||
"en_IN": {
|
"en_IN": {
|
||||||
lang: "en_IN",
|
lang: "en_IN",
|
||||||
decimal_point: ".",
|
decimal_point: ".",
|
||||||
|
@ -118,7 +156,7 @@ var locales = {
|
||||||
// No translation for english...
|
// No translation for english...
|
||||||
},
|
},
|
||||||
"en_NAV": { // navigation units nautical miles and knots
|
"en_NAV": { // navigation units nautical miles and knots
|
||||||
lang: "en_NAV",
|
lang: "en_NAV", icon: "⛵✈️",
|
||||||
decimal_point: ".",
|
decimal_point: ".",
|
||||||
thousands_sep: ",",
|
thousands_sep: ",",
|
||||||
currency_symbol: "£", currency_first: true,
|
currency_symbol: "£", currency_first: true,
|
||||||
|
@ -154,24 +192,6 @@ var locales = {
|
||||||
trans: { yes: "ja", Yes: "Ja", no: "nein", No: "Nein", ok: "ok", on: "an", off: "aus",
|
trans: { yes: "ja", Yes: "Ja", no: "nein", No: "Nein", ok: "ok", on: "an", off: "aus",
|
||||||
"< Back": "< Zurück", "Delete": "Löschen", "Mark Unread": "Als ungelesen markieren" }
|
"< Back": "< Zurück", "Delete": "Löschen", "Mark Unread": "Als ungelesen markieren" }
|
||||||
},
|
},
|
||||||
"en_US": {
|
|
||||||
lang: "en_US",
|
|
||||||
decimal_point: ".",
|
|
||||||
thousands_sep: ",",
|
|
||||||
currency_symbol: "$", currency_first: true,
|
|
||||||
int_curr_symbol: "USD",
|
|
||||||
speed: "mph",
|
|
||||||
distance: { 0: "ft", 1: "mi" },
|
|
||||||
temperature: "°F",
|
|
||||||
ampm: { 0: "am", 1: "pm" },
|
|
||||||
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
|
|
||||||
datePattern: { 0: "%b %d, %Y", 1: "%m/%d/%y" },
|
|
||||||
abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
|
|
||||||
month: "January,February,March,April,May,June,July,August,September,October,November,December",
|
|
||||||
abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
|
|
||||||
day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
|
|
||||||
// No translation for english...
|
|
||||||
},
|
|
||||||
"en_JP": { // we do not have the font, so it is not ja_JP
|
"en_JP": { // we do not have the font, so it is not ja_JP
|
||||||
lang: "en_JP",
|
lang: "en_JP",
|
||||||
decimal_point: ".",
|
decimal_point: ".",
|
||||||
|
|
|
@ -4,3 +4,4 @@
|
||||||
0.58: show/hide "messages" widget directly, instead of through library stub
|
0.58: show/hide "messages" widget directly, instead of through library stub
|
||||||
0.59: fixes message timeout by using setinterval, as it was intended. So the buzz is triggered every x seconds until the timeout occours.
|
0.59: fixes message timeout by using setinterval, as it was intended. So the buzz is triggered every x seconds until the timeout occours.
|
||||||
0.60: Bump version to allow new buzz.js module to be loaded - fixes memory/performance hog when buzz called
|
0.60: Bump version to allow new buzz.js module to be loaded - fixes memory/performance hog when buzz called
|
||||||
|
0.61: Add repeatCalls option to allow different repeat settings for messages vs calls
|
||||||
|
|
|
@ -204,16 +204,18 @@ exports.buzz = function(msgSrc) {
|
||||||
if ((require("Storage").readJSON("setting.json", 1) || {}).quiet) return Promise.resolve(); // never buzz during Quiet Mode
|
if ((require("Storage").readJSON("setting.json", 1) || {}).quiet) return Promise.resolve(); // never buzz during Quiet Mode
|
||||||
const msgSettings = require("Storage").readJSON("messages.settings.json", true) || {};
|
const msgSettings = require("Storage").readJSON("messages.settings.json", true) || {};
|
||||||
let pattern;
|
let pattern;
|
||||||
|
let repeat;
|
||||||
if (msgSrc && msgSrc.toLowerCase()==="phone") {
|
if (msgSrc && msgSrc.toLowerCase()==="phone") {
|
||||||
// special vibration pattern for incoming calls
|
// special vibration pattern for incoming calls
|
||||||
pattern = msgSettings.vibrateCalls;
|
pattern = msgSettings.vibrateCalls;
|
||||||
|
repeat = msgSettings.repeatCalls;
|
||||||
} else {
|
} else {
|
||||||
pattern = msgSettings.vibrate;
|
pattern = msgSettings.vibrate;
|
||||||
|
repeat = msgSettings.repeat;
|
||||||
}
|
}
|
||||||
if (pattern===undefined) { pattern = ":"; } // pattern may be "", so we can't use || ":" here
|
if (pattern===undefined) { pattern = ":"; } // pattern may be "", so we can't use || ":" here
|
||||||
if (!pattern) return Promise.resolve();
|
if (!pattern) return Promise.resolve();
|
||||||
|
|
||||||
let repeat = msgSettings.repeat;
|
|
||||||
if (repeat===undefined) repeat = 4; // repeat may be zero
|
if (repeat===undefined) repeat = 4; // repeat may be zero
|
||||||
if (repeat)
|
if (repeat)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "messages",
|
"id": "messages",
|
||||||
"name": "Messages",
|
"name": "Messages",
|
||||||
"version": "0.60",
|
"version": "0.61",
|
||||||
"description": "Library to handle, load and store message events received from Android/iOS",
|
"description": "Library to handle, load and store message events received from Android/iOS",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
if (settings.vibrate===undefined) settings.vibrate=":";
|
if (settings.vibrate===undefined) settings.vibrate=":";
|
||||||
if (settings.vibrateCalls===undefined) settings.vibrateCalls=":";
|
if (settings.vibrateCalls===undefined) settings.vibrateCalls=":";
|
||||||
if (settings.repeat===undefined) settings.repeat=4;
|
if (settings.repeat===undefined) settings.repeat=4;
|
||||||
|
if (settings.repeatCalls===undefined) settings.repeatCalls=settings.repeat;
|
||||||
if (settings.vibrateTimeout===undefined) settings.vibrateTimeout=60;
|
if (settings.vibrateTimeout===undefined) settings.vibrateTimeout=60;
|
||||||
if (settings.unreadTimeout===undefined) settings.unreadTimeout=60;
|
if (settings.unreadTimeout===undefined) settings.unreadTimeout=60;
|
||||||
if (settings.maxMessages===undefined) settings.maxMessages=3;
|
if (settings.maxMessages===undefined) settings.maxMessages=3;
|
||||||
|
@ -33,6 +34,12 @@
|
||||||
format: v => v?v+"s":/*LANG*/"Off",
|
format: v => v?v+"s":/*LANG*/"Off",
|
||||||
onchange: v => updateSetting("repeat", v)
|
onchange: v => updateSetting("repeat", v)
|
||||||
},
|
},
|
||||||
|
/*LANG*/'Repeat for calls': {
|
||||||
|
value: settings().repeatCalls,
|
||||||
|
min: 0, max: 10,
|
||||||
|
format: v => v?v+"s":/*LANG*/"Off",
|
||||||
|
onchange: v => updateSetting("repeatCalls", v)
|
||||||
|
},
|
||||||
/*LANG*/'Vibrate timer': {
|
/*LANG*/'Vibrate timer': {
|
||||||
value: settings().vibrateTimeout,
|
value: settings().vibrateTimeout,
|
||||||
min: 0, max: settings().maxUnreadTimeout, step : 10,
|
min: 0, max: settings().maxUnreadTimeout, step : 10,
|
||||||
|
|
|
@ -3,3 +3,4 @@
|
||||||
0.03: Update help screen with more details.
|
0.03: Update help screen with more details.
|
||||||
0.04: Update cards to draw rounded on newer firmware. Make sure in-game menu can't be pulled up during end of game.
|
0.04: Update cards to draw rounded on newer firmware. Make sure in-game menu can't be pulled up during end of game.
|
||||||
0.05: add confirmation prompt to new game to prevent fat fingering new game during existing one.
|
0.05: add confirmation prompt to new game to prevent fat fingering new game during existing one.
|
||||||
|
0.06: fix AI logic typo and add prompt to show what AI played each turn.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "Red 7 Card Game",
|
"name": "Red 7 Card Game",
|
||||||
"shortName" : "Red 7",
|
"shortName" : "Red 7",
|
||||||
"icon": "icon.png",
|
"icon": "icon.png",
|
||||||
"version":"0.05",
|
"version":"0.06",
|
||||||
"description": "An implementation of the card game Red 7 for your watch. Play against the AI and be the last player still in the game to win!",
|
"description": "An implementation of the card game Red 7 for your watch. Play against the AI and be the last player still in the game to win!",
|
||||||
"tags": "game",
|
"tags": "game",
|
||||||
"supports":["BANGLEJS2"],
|
"supports":["BANGLEJS2"],
|
||||||
|
|
|
@ -17,6 +17,9 @@ class Card {
|
||||||
//this.rect = {};
|
//this.rect = {};
|
||||||
this.clippedRect = {};
|
this.clippedRect = {};
|
||||||
}
|
}
|
||||||
|
get description() {
|
||||||
|
return this.cardColor+" "+this.cardNum;
|
||||||
|
}
|
||||||
get number() {
|
get number() {
|
||||||
return this.cardNum;
|
return this.cardNum;
|
||||||
}
|
}
|
||||||
|
@ -514,7 +517,7 @@ class AI {
|
||||||
//Play card that wins
|
//Play card that wins
|
||||||
this.palette.addCard(c);
|
this.palette.addCard(c);
|
||||||
this.hand.removeCard(c);
|
this.hand.removeCard(c);
|
||||||
return true;
|
return { winning: true, paletteAdded: c };
|
||||||
}
|
}
|
||||||
clonePalette.removeCard(c);
|
clonePalette.removeCard(c);
|
||||||
}
|
}
|
||||||
|
@ -524,26 +527,26 @@ class AI {
|
||||||
//Play rule card that wins
|
//Play rule card that wins
|
||||||
ruleStack.addCard(c);
|
ruleStack.addCard(c);
|
||||||
this.hand.removeCard(c);
|
this.hand.removeCard(c);
|
||||||
return true;
|
return { winning: true, ruleAdded: c };
|
||||||
} else {
|
} else {
|
||||||
//Check if any palette play can win with rule.
|
//Check if any palette play can win with rule.
|
||||||
for(let h of this.hand.handCards) {
|
for(let h of this.hand.handCards) {
|
||||||
if(h === c) {}
|
if(h === c) {}
|
||||||
else {
|
else {
|
||||||
clonePalette.addCard(c);
|
clonePalette.addCard(h);
|
||||||
if(isWinningCombo(c, clonePalette, otherPalette)) {
|
if(isWinningCombo(c, clonePalette, otherPalette)) {
|
||||||
ruleStack.addCard(c);
|
ruleStack.addCard(c);
|
||||||
this.hand.removeCard(c);
|
this.hand.removeCard(c);
|
||||||
this.palette.addCard(h);
|
this.palette.addCard(h);
|
||||||
this.hand.removeCard(h);
|
this.hand.removeCard(h);
|
||||||
return true;
|
return { winning: true, ruleAdded: c, paletteAdded: h };
|
||||||
}
|
}
|
||||||
clonePalette.removeCard(c);
|
clonePalette.removeCard(h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return { winning: false };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -726,18 +729,20 @@ function finishTurn() {
|
||||||
if(AIhand.handCards.length === 0) {
|
if(AIhand.handCards.length === 0) {
|
||||||
drawGameOver(true);
|
drawGameOver(true);
|
||||||
} else {
|
} else {
|
||||||
var takenTurn = aiPlayer.takeTurn(ruleCards, playerPalette);
|
var aiResult = aiPlayer.takeTurn(ruleCards, playerPalette);
|
||||||
//Check if game over conditions met.
|
E.showPrompt("AI played: " + ("paletteAdded" in aiResult ? aiResult["paletteAdded"].description+" to pallete. ":"") + ("ruleAdded" in aiResult ? aiResult["ruleAdded"].description+" to rules.":""),{buttons: {"Ok":0}}).then(function(){
|
||||||
if(!takenTurn) {
|
//Check if game over conditions met.
|
||||||
drawGameOver(true);
|
if(!aiResult["winning"]) {
|
||||||
} else if(playerHand.handCards.length === 0) {
|
drawGameOver(true);
|
||||||
drawGameOver(false);
|
} else if(playerHand.handCards.length === 0) {
|
||||||
} else if(!canPlay(playerHand, playerPalette, AIPalette)) {
|
drawGameOver(false);
|
||||||
drawGameOver(false);
|
} else if(!canPlay(playerHand, playerPalette, AIPalette)) {
|
||||||
} else {
|
drawGameOver(false);
|
||||||
E.showMenu();
|
} else {
|
||||||
drawScreen1();
|
E.showMenu();
|
||||||
}
|
drawScreen1();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -843,4 +848,3 @@ drawMainMenu();
|
||||||
setWatch(function(){
|
setWatch(function(){
|
||||||
drawMainMenu();
|
drawMainMenu();
|
||||||
},BTN, {edge: "rising", debounce: 50, repeat: true});
|
},BTN, {edge: "rising", debounce: 50, repeat: true});
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,8 @@ Directories at the end of .mtar should be hashed, not linear searched.
|
||||||
|
|
||||||
Geojson is not really suitable as it takes a lot of storage.
|
Geojson is not really suitable as it takes a lot of storage.
|
||||||
|
|
||||||
It would be nice to support polygons.
|
Web-based tool for preparing maps would be nice.
|
||||||
|
|
||||||
Web-based tool for preparing maps would be nice.
|
Storing 12bit coordinates, but only using 8bits.
|
||||||
|
|
||||||
|
Polygons should go first to get proper z-order.
|
|
@ -386,7 +386,7 @@ function emptyMap() {
|
||||||
m.scale = 2;
|
m.scale = 2;
|
||||||
g.reset().clearRect(R);
|
g.reset().clearRect(R);
|
||||||
redraw(18);
|
redraw(18);
|
||||||
print("Benchmark done (31 sec)");
|
print("Benchmark done");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (fix.fix) menu[/*LANG*/"Center GPS"]=() =>{
|
if (fix.fix) menu[/*LANG*/"Center GPS"]=() =>{
|
||||||
|
@ -400,36 +400,52 @@ function emptyMap() {
|
||||||
|
|
||||||
var gjson = null;
|
var gjson = null;
|
||||||
|
|
||||||
|
function stringFromArray(data) {
|
||||||
|
var count = data.length;
|
||||||
|
var str = "";
|
||||||
|
|
||||||
|
for(var index = 0; index < count; index += 1)
|
||||||
|
str += String.fromCharCode(data[index]);
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
const st = require('Storage');
|
||||||
|
const hs = require('heatshrink');
|
||||||
|
|
||||||
function readTarFile(tar, f) {
|
function readTarFile(tar, f) {
|
||||||
const st = require('Storage');
|
let json_off = st.read(tar, 0, 16) * 1;
|
||||||
json_off = st.read(tar, 0, 16) * 1;
|
|
||||||
if (isNaN(json_off)) {
|
if (isNaN(json_off)) {
|
||||||
print("Don't have archive", tar);
|
print("Don't have archive", tar);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
while (1) {
|
while (1) {
|
||||||
json_len = st.read(tar, json_off, 6) * 1;
|
let json_len = st.read(tar, json_off, 6) * 1;
|
||||||
if (json_len == -1)
|
if (json_len == -1)
|
||||||
break;
|
break;
|
||||||
json_off += 6;
|
json_off += 6;
|
||||||
json = st.read(tar, json_off, json_len);
|
let json = st.read(tar, json_off, json_len);
|
||||||
//print("Have directory, ", json.length, "bytes");
|
//print("Have directory, ", json.length, "bytes");
|
||||||
//print(json);
|
let files = JSON.parse(json);
|
||||||
files = JSON.parse(json);
|
let rec = files[f];
|
||||||
//print(files);
|
if (rec) {
|
||||||
rec = files[f];
|
let cs = st.read(tar, rec.st, rec.si);
|
||||||
if (rec)
|
if (rec.comp == "hs") {
|
||||||
return st.read(tar, rec.st, rec.si);
|
let d = stringFromArray(hs.decompress(cs));
|
||||||
|
//print("Decompressed", d);
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
return cs;
|
||||||
|
}
|
||||||
json_off += json_len;
|
json_off += json_len;
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadVector(name) {
|
function loadVector(name) {
|
||||||
var t1 = getTime();
|
var t1 = getTime();
|
||||||
print(".. Read", name);
|
print(".. Read", name);
|
||||||
//s = require("Storage").read(name);
|
//s = require("Storage").read(name);
|
||||||
var s = readTarFile("delme.mtar", name);
|
var s = readTarFile("world.mtar", name);
|
||||||
if (s == undefined) {
|
if (s == undefined) {
|
||||||
print("Don't have file", name);
|
print("Don't have file", name);
|
||||||
return null;
|
return null;
|
||||||
|
@ -438,8 +454,7 @@ function loadVector(name) {
|
||||||
print(".... Read and parse took ", getTime()-t1);
|
print(".... Read and parse took ", getTime()-t1);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
function drawPoint(a) { /* FIXME: let... */
|
||||||
function drawPoint(a) {
|
|
||||||
lon = a.geometry.coordinates[0];
|
lon = a.geometry.coordinates[0];
|
||||||
lat = a.geometry.coordinates[1];
|
lat = a.geometry.coordinates[1];
|
||||||
|
|
||||||
|
@ -459,7 +474,6 @@ function drawPoint(a) {
|
||||||
g.drawString(a.properties.name, p.x, p.y);
|
g.drawString(a.properties.name, p.x, p.y);
|
||||||
points ++;
|
points ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawLine(a, qual) {
|
function drawLine(a, qual) {
|
||||||
lon = a.geometry.coordinates[0][0];
|
lon = a.geometry.coordinates[0][0];
|
||||||
lat = a.geometry.coordinates[0][1];
|
lat = a.geometry.coordinates[0][1];
|
||||||
|
@ -485,38 +499,196 @@ function drawLine(a, qual) {
|
||||||
i = len-1;
|
i = len-1;
|
||||||
points ++;
|
points ++;
|
||||||
p1 = p2;
|
p1 = p2;
|
||||||
g.flip();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function drawPolygon(a, qual) {
|
||||||
|
lon = a.geometry.coordinates[0][0];
|
||||||
|
lat = a.geometry.coordinates[0][1];
|
||||||
|
i = 1;
|
||||||
|
step = 1;
|
||||||
|
len = a.geometry.coordinates.length;
|
||||||
|
if (len > 62) {
|
||||||
|
step = log2(len) - 5;
|
||||||
|
step = 1<<step;
|
||||||
|
}
|
||||||
|
step = step * qual;
|
||||||
|
var p1 = m.latLonToXY(lat, lon);
|
||||||
|
let pol = [p1.x, p1.y];
|
||||||
|
while (i < len) {
|
||||||
|
lon = a.geometry.coordinates[i][0];
|
||||||
|
lat = a.geometry.coordinates[i][1];
|
||||||
|
var p2 = m.latLonToXY(lat, lon);
|
||||||
|
|
||||||
function drawVector(gjson, qual) {
|
pol.push(p2.x, p2.y);
|
||||||
|
if (i == len-1)
|
||||||
|
break;
|
||||||
|
i = i + step;
|
||||||
|
if (i>len)
|
||||||
|
i = len-1;
|
||||||
|
points ++;
|
||||||
|
}
|
||||||
|
if (a.properties.fill) {
|
||||||
|
g.setColor(a.properties.fill);
|
||||||
|
} else {
|
||||||
|
g.setColor(.75, .75, 1);
|
||||||
|
}
|
||||||
|
g.fillPoly(pol, true);
|
||||||
|
if (a.properties.stroke) {
|
||||||
|
g.setColor(a.properties.stroke);
|
||||||
|
} else {
|
||||||
|
g.setColor(0,0,0)
|
||||||
|
}
|
||||||
|
g.drawPoly(pol, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toScreen(tile, xy) {
|
||||||
|
// w, s, e, n, (x,y in 0..4096 range)
|
||||||
|
let x = xy[0];
|
||||||
|
let y = xy[1];
|
||||||
|
let r = {};
|
||||||
|
r.x = ((x/4096) * (tile[2]-tile[0])) + tile[0];
|
||||||
|
r.y = ((1-(y/4096)) * (tile[3]-tile[1])) + tile[1];
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
var d_off = 1;
|
||||||
|
function getBin(bin, i, prev) {
|
||||||
|
let x = bin[i*3 + d_off ]<<4;
|
||||||
|
let y = bin[i*3 + d_off+1]<<4;
|
||||||
|
//print("Point", x, y, bin);
|
||||||
|
return [x, y];
|
||||||
|
}
|
||||||
|
function getBinLength(bin) {
|
||||||
|
return (bin.length-d_off) / 3;
|
||||||
|
}
|
||||||
|
function newPoint(tile, a, rec, bin) {
|
||||||
|
var p = toScreen(tile, getBin(bin, 0, null));
|
||||||
|
var sz = 2;
|
||||||
|
if (a.properties) {
|
||||||
|
if (a.properties["marker-color"]) {
|
||||||
|
g.setColor(a.properties["marker-color"]);
|
||||||
|
}
|
||||||
|
if (a.properties.marker_size == "small")
|
||||||
|
sz = 1;
|
||||||
|
if (a.properties.marker_size == "large")
|
||||||
|
sz = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
g.fillRect(p.x-sz, p.y-sz, p.x+sz, p.y+sz);
|
||||||
|
if (rec.tags) {
|
||||||
|
g.setColor(0,0,0);
|
||||||
|
g.setFont("Vector", 18).setFontAlign(-1,-1);
|
||||||
|
g.drawString(rec.tags.name, p.x, p.y);
|
||||||
|
}
|
||||||
|
points ++;
|
||||||
|
}
|
||||||
|
function newLine(tile, a, bin) {
|
||||||
|
let xy = getBin(bin, 0, null);
|
||||||
|
let i = 1;
|
||||||
|
let step = 1;
|
||||||
|
let len = getBinLength(bin);
|
||||||
|
let p1 = toScreen(tile, xy);
|
||||||
|
if (a.properties && a.properties.stroke) {
|
||||||
|
g.setColor(a.properties.stroke);
|
||||||
|
}
|
||||||
|
while (i < len) {
|
||||||
|
xy = getBin(bin, i, xy);
|
||||||
|
var p2 = toScreen(tile, xy);
|
||||||
|
|
||||||
|
//print(p1.x, p1.y, p2.x, p2.y);
|
||||||
|
g.drawLine(p1.x, p1.y, p2.x, p2.y);
|
||||||
|
if (i == len-1)
|
||||||
|
break;
|
||||||
|
i = i + step;
|
||||||
|
if (i>len)
|
||||||
|
i = len-1;
|
||||||
|
points ++;
|
||||||
|
p1 = p2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function newPolygon(tile, a, bin) {
|
||||||
|
let xy = getBin(bin, 0, null);
|
||||||
|
i = 1;
|
||||||
|
step = 1;
|
||||||
|
len = getBinLength(bin);
|
||||||
|
if (len > 62) {
|
||||||
|
step = log2(len) - 5;
|
||||||
|
step = 1<<step;
|
||||||
|
}
|
||||||
|
var p1 = toScreen(tile, xy);
|
||||||
|
let pol = [p1.x, p1.y];
|
||||||
|
while (i < len) {
|
||||||
|
xy = getBin(bin, i, xy); // FIXME... when skipping
|
||||||
|
var p2 = toScreen(tile, xy);
|
||||||
|
|
||||||
|
pol.push(p2.x, p2.y);
|
||||||
|
if (i == len-1)
|
||||||
|
break;
|
||||||
|
i = i + step;
|
||||||
|
if (i>len)
|
||||||
|
i = len-1;
|
||||||
|
points ++;
|
||||||
|
}
|
||||||
|
if (a.properties && a.properties.fill) {
|
||||||
|
g.setColor(a.properties.fill);
|
||||||
|
} else {
|
||||||
|
g.setColor(.75, .75, 1);
|
||||||
|
}
|
||||||
|
g.fillPoly(pol, true);
|
||||||
|
if (a.properties && a.properties.stroke) {
|
||||||
|
g.setColor(a.properties.stroke);
|
||||||
|
} else {
|
||||||
|
g.setColor(0,0,0)
|
||||||
|
}
|
||||||
|
g.drawPoly(pol, true);
|
||||||
|
}
|
||||||
|
function newVector(tile, rec) {
|
||||||
|
let bin = E.toUint8Array(atob(rec.b));
|
||||||
|
a = meta.attrs[bin[0]];
|
||||||
|
if (a.type == 1) {
|
||||||
|
newPoint(tile, a, rec, bin);
|
||||||
|
} else if (a.type == 2) {
|
||||||
|
newLine(tile, a, bin);
|
||||||
|
} else if (a.type == 3) {
|
||||||
|
newPolygon(tile, a, bin);
|
||||||
|
} else print("Unknown record", a);
|
||||||
|
g.flip();
|
||||||
|
}
|
||||||
|
function drawVector(gjson, tile, qual) {
|
||||||
var d = gjson;
|
var d = gjson;
|
||||||
points = 0;
|
points = 0;
|
||||||
var t1 = getTime();
|
var t1 = getTime();
|
||||||
|
|
||||||
for (var a of d.features) {
|
let xy1 = m.latLonToXY(tile[1], tile[0]);
|
||||||
if (a.type != "Feature")
|
let xy2 = m.latLonToXY(tile[3], tile[2]);
|
||||||
print("Expecting feature");
|
let t2 = [ xy1.x, xy1.y, xy2.x, xy2.y ];
|
||||||
|
print(t2);
|
||||||
|
|
||||||
|
for (var a of d) { // d.features for geojson
|
||||||
g.setColor(0,0,0);
|
g.setColor(0,0,0);
|
||||||
|
if (a.type != "Feature") {
|
||||||
|
newVector(t2, a);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// marker-size, marker-color, stroke
|
// marker-size, marker-color, stroke
|
||||||
if (qual < 32 && a.geometry.type == "Point")
|
if (qual < 32 && a.geometry.type == "Point")
|
||||||
drawPoint(a);
|
drawPoint(a);
|
||||||
if (qual < 8 && a.geometry.type == "LineString")
|
if (qual < 8 && a.geometry.type == "LineString")
|
||||||
drawLine(a, qual);
|
drawLine(a, qual);
|
||||||
|
if (qual < 8 && a.geometry.type == "Polygon")
|
||||||
|
drawPolygon(a, qual);
|
||||||
}
|
}
|
||||||
print("....", points, "painted in", getTime()-t1, "sec");
|
print("....", points, "painted in", getTime()-t1, "sec");
|
||||||
}
|
}
|
||||||
|
|
||||||
function fname(lon, lat, zoom) {
|
function fname(lon, lat, zoom) {
|
||||||
var bbox = [lon, lat, lon, lat];
|
var bbox = [lon, lat, lon, lat];
|
||||||
var r = xyz(bbox, 13, false, "WGS84");
|
var r = xyz(bbox, 13, false, "WGS84");
|
||||||
//console.log('fname', r);
|
//console.log('fname', r);
|
||||||
return 'z'+zoom+'-'+r.minX+'-'+r.minY+'.json';
|
return 'z'+zoom+'-'+r.minX+'-'+r.minY+'.json';
|
||||||
}
|
}
|
||||||
|
|
||||||
function fnames(zoom) {
|
function fnames(zoom) {
|
||||||
var bb = [m.lon, m.lat, m.lon, m.lat];
|
var bb = [m.lon, m.lat, m.lon, m.lat];
|
||||||
var r = xyz(bb, zoom, false, "WGS84");
|
var r = xyz(bb, zoom, false, "WGS84");
|
||||||
|
let maxt = 16;
|
||||||
while (1) {
|
while (1) {
|
||||||
var bb2 = bbox(r.minX, r.minY, zoom, false, "WGS84");
|
var bb2 = bbox(r.minX, r.minY, zoom, false, "WGS84");
|
||||||
var os = m.latLonToXY(bb2[3], bb2[0]);
|
var os = m.latLonToXY(bb2[3], bb2[0]);
|
||||||
|
@ -525,6 +697,9 @@ function fnames(zoom) {
|
||||||
else if (os.y >= 0)
|
else if (os.y >= 0)
|
||||||
r.minY -= 1;
|
r.minY -= 1;
|
||||||
else break;
|
else break;
|
||||||
|
if (!maxt)
|
||||||
|
break;
|
||||||
|
maxt--;
|
||||||
}
|
}
|
||||||
while (1) {
|
while (1) {
|
||||||
var bb2 = bbox(r.maxX, r.maxY, zoom, false, "WGS84");
|
var bb2 = bbox(r.maxX, r.maxY, zoom, false, "WGS84");
|
||||||
|
@ -534,13 +709,16 @@ function fnames(zoom) {
|
||||||
else if (os.y <= g.getHeight())
|
else if (os.y <= g.getHeight())
|
||||||
r.maxY += 1;
|
r.maxY += 1;
|
||||||
else break;
|
else break;
|
||||||
|
if (!maxt)
|
||||||
|
break;
|
||||||
|
maxt--;
|
||||||
}
|
}
|
||||||
|
if (!maxt)
|
||||||
|
print("!!! Too many tiles, not painting some");
|
||||||
print(".. paint range", r);
|
print(".. paint range", r);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
function log2(x) { return Math.log(x) / Math.log(2); }
|
function log2(x) { return Math.log(x) / Math.log(2); }
|
||||||
|
|
||||||
function getZoom(qual) {
|
function getZoom(qual) {
|
||||||
var z = 16-Math.round(log2(m.scale));
|
var z = 16-Math.round(log2(m.scale));
|
||||||
z += qual;
|
z += qual;
|
||||||
|
@ -551,7 +729,6 @@ function getZoom(qual) {
|
||||||
return meta.max_zoom;
|
return meta.max_zoom;
|
||||||
return z;
|
return z;
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawDebug(text, perc) {
|
function drawDebug(text, perc) {
|
||||||
g.setClipRect(0,0,R.x2,R.y);
|
g.setClipRect(0,0,R.x2,R.y);
|
||||||
g.reset();
|
g.reset();
|
||||||
|
@ -564,7 +741,6 @@ function drawDebug(text, perc) {
|
||||||
g.setClipRect(R.x,R.y,R.x2,R.y2);
|
g.setClipRect(R.x,R.y,R.x2,R.y2);
|
||||||
g.flip();
|
g.flip();
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawAll(qual) {
|
function drawAll(qual) {
|
||||||
var zoom = getZoom(qual);
|
var zoom = getZoom(qual);
|
||||||
var t1 = getTime();
|
var t1 = getTime();
|
||||||
|
@ -583,7 +759,7 @@ function drawAll(qual) {
|
||||||
var n ='z'+zoom+'-'+x+'-'+y+'-'+cnt+'.json';
|
var n ='z'+zoom+'-'+x+'-'+y+'-'+cnt+'.json';
|
||||||
var gjson = loadVector(n);
|
var gjson = loadVector(n);
|
||||||
if (!gjson) break;
|
if (!gjson) break;
|
||||||
drawVector(gjson, 1);
|
drawVector(gjson, bbox(x, y, zoom, false, "WGS84"), 1);
|
||||||
}
|
}
|
||||||
num++;
|
num++;
|
||||||
drawDebug("Zoom "+zoom+" tiles "+num+"/"+tiles, num/tiles);
|
drawDebug("Zoom "+zoom+" tiles "+num+"/"+tiles, num/tiles);
|
||||||
|
@ -611,7 +787,7 @@ function introScreen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
m.scale = 76;
|
m.scale = 76000;
|
||||||
m.lat = 50.001;
|
m.lat = 50.001;
|
||||||
m.lon = 14.759;
|
m.lon = 14.759;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
R = Bangle.appRect;
|
||||||
|
|
||||||
|
function introScreen() {
|
||||||
|
g.reset().clearRect(R);
|
||||||
|
g.setColor(0,0,0).setFont("Vector",25);
|
||||||
|
g.setFontAlign(0,0);
|
||||||
|
g.drawString("Benchmark", 85,35);
|
||||||
|
g.setColor(0,0,0).setFont("Vector",18);
|
||||||
|
g.drawString("Press button", 85,55);
|
||||||
|
}
|
||||||
|
function lineBench() {
|
||||||
|
/* 500 lines a second on hardware, 125 lines with flip */
|
||||||
|
for (let i=0; i<1000; i++) {
|
||||||
|
let x1 = Math.random() * 160;
|
||||||
|
let y1 = Math.random() * 160;
|
||||||
|
let x2 = Math.random() * 160;
|
||||||
|
let y2 = Math.random() * 160;
|
||||||
|
|
||||||
|
g.drawLine(x1, y1, x2, y2);
|
||||||
|
//g.flip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function polyBench() {
|
||||||
|
/* 275 hollow polygons a second on hardware, 99 with flip */
|
||||||
|
/* 261 filled polygons a second on hardware, 99 with flip */
|
||||||
|
for (let i=0; i<1000; i++) {
|
||||||
|
let x1 = Math.random() * 160;
|
||||||
|
let y1 = Math.random() * 160;
|
||||||
|
let x2 = Math.random() * 160;
|
||||||
|
let y2 = Math.random() * 160;
|
||||||
|
let c = Math.random();
|
||||||
|
|
||||||
|
g.setColor(c, c, c);
|
||||||
|
g.fillPoly([80, x1, y1, 80, 80, x2, y2, 80], true);
|
||||||
|
//g.flip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function checksum(d) {
|
||||||
|
let sum = 0;
|
||||||
|
for (i=0; i<d.length; i++) {
|
||||||
|
sum += (d[i]*1);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
function linearRead() {
|
||||||
|
/* 10000b block -> 8.3MB/sec, 781..877 IOPS
|
||||||
|
1000b block -> 920K/sec, 909 IOPS, 0.55 sec
|
||||||
|
100b block -> 100K/sec
|
||||||
|
10b block -> 10K/sec, 1020 IOPS, 914 IOPS with ops counting
|
||||||
|
|
||||||
|
1000b block backwards -- 0.59 sec.
|
||||||
|
100b block -- 5.93.
|
||||||
|
backwards -- 6.27
|
||||||
|
random -- 7.13
|
||||||
|
checksum 5.97 -> 351 seconds with checksum. 1400bytes/second
|
||||||
|
*/
|
||||||
|
|
||||||
|
let size = 500000;
|
||||||
|
let block = 100;
|
||||||
|
let i = 0;
|
||||||
|
let ops = 0;
|
||||||
|
let sum = 0;
|
||||||
|
while (i < size) {
|
||||||
|
//let pos = Math.random() * size;
|
||||||
|
let pos = i;
|
||||||
|
//let pos = size-i;
|
||||||
|
let d = require("Storage").read("delme.mtar", pos, block);
|
||||||
|
//sum += checksum(E.toUint8Array(d));
|
||||||
|
i += block;
|
||||||
|
ops ++;
|
||||||
|
}
|
||||||
|
print(ops, "ops", sum);
|
||||||
|
}
|
||||||
|
function drawBench(name) {
|
||||||
|
g.setColor(0,0,0).setFont("Vector",25);
|
||||||
|
g.setFontAlign(0,0);
|
||||||
|
g.drawString(name, 85,35);
|
||||||
|
g.setColor(0,0,0).setFont("Vector",18);
|
||||||
|
g.drawString("Running", 85,55);
|
||||||
|
g.flip();
|
||||||
|
}
|
||||||
|
function runBench(b, name) {
|
||||||
|
drawBench(name);
|
||||||
|
g.reset().clearRect(R);
|
||||||
|
|
||||||
|
let t1 = getTime();
|
||||||
|
print("--------------------------------------------------");
|
||||||
|
print("Running",name);
|
||||||
|
b();
|
||||||
|
let m = (getTime()-t1) + " sec";
|
||||||
|
print("..done in", m);
|
||||||
|
drawBench(name);
|
||||||
|
g.setColor(0,0,0).setFont("Vector",18);
|
||||||
|
g.drawString(m, 85,85);
|
||||||
|
|
||||||
|
}
|
||||||
|
function redraw() {
|
||||||
|
//runBench(lineBench, "Lines");
|
||||||
|
runBench(polyBench, "Polygons");
|
||||||
|
//runBench(linearRead, "Linear read");
|
||||||
|
}
|
||||||
|
function showMap() {
|
||||||
|
g.reset().clearRect(R);
|
||||||
|
redraw();
|
||||||
|
emptyMap();
|
||||||
|
}
|
||||||
|
function emptyMap() {
|
||||||
|
Bangle.setUI({mode:"custom",drag:e=>{
|
||||||
|
g.reset().clearRect(R);
|
||||||
|
redraw();
|
||||||
|
}, btn: btn=>{
|
||||||
|
mapVisible = false;
|
||||||
|
var menu = {"":{title:"Benchmark"},
|
||||||
|
"< Back": ()=> showMap(),
|
||||||
|
/*LANG*/"Run": () =>{
|
||||||
|
showMap();
|
||||||
|
}};
|
||||||
|
E.showMenu(menu);
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
const st = require('Storage');
|
||||||
|
const hs = require('heatshrink');
|
||||||
|
|
||||||
|
introScreen();
|
||||||
|
emptyMap();
|
|
@ -1,6 +1,6 @@
|
||||||
{ "id": "spacew",
|
{ "id": "spacew",
|
||||||
"name": "Space Weaver",
|
"name": "Space Weaver",
|
||||||
"version":"0.01",
|
"version":"0.02",
|
||||||
"description": "Application for displaying vector maps",
|
"description": "Application for displaying vector maps",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
|
@ -8,6 +8,7 @@
|
||||||
"tags": "outdoors,gps,osm",
|
"tags": "outdoors,gps,osm",
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"spacew.app.js","url":"app.js"},
|
{"name":"spacew.app.js","url":"app.js"},
|
||||||
{"name":"spacew.img","url":"app-icon.js","evaluate":true}
|
{"name":"spacew.img","url":"app-icon.js","evaluate":true},
|
||||||
|
{"name":"world.mtar","url":"world.mtar"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#!/usr/bin/nodejs
|
#!/usr/bin/nodejs
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/49129643/how-do-i-merge-an-array-of-uint8arrays
|
||||||
|
|
||||||
var pc = 1;
|
var pc = 1;
|
||||||
var hack = 0;
|
|
||||||
const hs = require('./heatshrink.js');
|
const hs = require('./heatshrink.js');
|
||||||
|
|
||||||
if (pc) {
|
if (pc) {
|
||||||
|
@ -23,19 +24,21 @@ function writeTar(tar, dir) {
|
||||||
var h_len = 16;
|
var h_len = 16;
|
||||||
var cur = h_len;
|
var cur = h_len;
|
||||||
files = fs.readdirSync(dir);
|
files = fs.readdirSync(dir);
|
||||||
data = '';
|
let data = [];
|
||||||
var directory = '';
|
var directory = '';
|
||||||
var json = {};
|
var json = {};
|
||||||
for (f of files) {
|
for (f of files) {
|
||||||
|
let f_rec = {};
|
||||||
d = fs.readFileSync(dir+f);
|
d = fs.readFileSync(dir+f);
|
||||||
cs = d;
|
if (0) {
|
||||||
//cs = String.fromCharCode.apply(null, hs.compress(d))
|
cs = hs.compress(d);
|
||||||
|
f_rec.comp = "hs";
|
||||||
|
} else
|
||||||
|
cs = d;
|
||||||
print("Processing", f, cur, d.length, cs.length);
|
print("Processing", f, cur, d.length, cs.length);
|
||||||
//if (d.length == 42) continue;
|
data.push(cs);
|
||||||
data = data + cs;
|
|
||||||
var f_rec = {};
|
|
||||||
f_rec.st = cur;
|
f_rec.st = cur;
|
||||||
var len = d.length;
|
var len = cs.length;
|
||||||
f_rec.si = len;
|
f_rec.si = len;
|
||||||
cur = cur + len;
|
cur = cur + len;
|
||||||
json[f] = f_rec;
|
json[f] = f_rec;
|
||||||
|
@ -53,10 +56,10 @@ function writeTar(tar, dir) {
|
||||||
while (header.length < h_len) {
|
while (header.length < h_len) {
|
||||||
header = header+' ';
|
header = header+' ';
|
||||||
}
|
}
|
||||||
if (!hack)
|
fs.writeFileSync(tar, header);
|
||||||
fs.writeFileSync(tar, header+data+directory);
|
for (d of data)
|
||||||
else
|
fs.appendFileSync(tar, Buffer.from(d));
|
||||||
fs.writeFileSync(tar, directory);
|
fs.appendFileSync(tar, directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
function readTarFile(tar, f) {
|
function readTarFile(tar, f) {
|
||||||
|
@ -70,7 +73,7 @@ function readTarFile(tar, f) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pc)
|
if (pc)
|
||||||
writeTar("delme.mtaz", "delme/");
|
writeTar("delme.mtar", "delme/");
|
||||||
else {
|
else {
|
||||||
print(readTarFile("delme.mtar", "ahoj"));
|
print(readTarFile("delme.mtar", "ahoj"));
|
||||||
print(readTarFile("delme.mtar", "nazdar"));
|
print(readTarFile("delme.mtar", "nazdar"));
|
||||||
|
|
|
@ -14,5 +14,5 @@
|
||||||
"linear_tags": true,
|
"linear_tags": true,
|
||||||
"area_tags": false,
|
"area_tags": false,
|
||||||
"exclude_tags": [],
|
"exclude_tags": [],
|
||||||
"include_tags": [ "place", "name", "landuse", "highway" ]
|
"include_tags": [ "place", "name", "landuse", "highway", "natural" ]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,49 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
if [ ".$1" == "-f" ]; then
|
|
||||||
|
# http://bboxfinder.com/#0.000000,0.000000,0.000000,0.000000
|
||||||
|
Z=
|
||||||
|
# Czech republic -- hitting internal limit in nodejs
|
||||||
|
#BBOX=10,60,20,30
|
||||||
|
#Z="--maxz 9"
|
||||||
|
# No Moravia -- ascii conversion takes 43min, "Error: Cannot create a string longer than 0x3fffffe7 characters"
|
||||||
|
#BBOX=10,60,17.75,30
|
||||||
|
#Z="--maxz 9"
|
||||||
|
# Just Moravia -- 266MB delme.pbf -- FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed
|
||||||
|
#BBOX=16.13,60,35,30
|
||||||
|
#Z="--maxz 9"
|
||||||
|
# Roudnice az Kutna hora -- band 1.1 deg -- 145MB delme.pbf, 5m cstocs, 40+m split.
|
||||||
|
# -- band 0.1 deg -- 13MB delme.pbf, 13s split, 21k result.
|
||||||
|
#BBOX=14.20,50.45,15.32,49.20
|
||||||
|
#Z="--maxz 9"
|
||||||
|
# Roudnice az... -- band 0.5 deg -- 91MB delme.pbf, 200k result.
|
||||||
|
# Roudnice az... -- band 0.8 deg -- 120MB delme.pbf, 2.5GB while splitting, 260k result.
|
||||||
|
#BBOX=14.20,50.45,15.0,49.20
|
||||||
|
#Z="--maxz 9"
|
||||||
|
# Prague; 1.2MB map, not really useful
|
||||||
|
#BBOX=14.25,50.17,14.61,49.97
|
||||||
|
#Z="--maxz 14"
|
||||||
|
# Zernovka small -- 3.5 delme.pbf, ~850K result.
|
||||||
|
BBOX=14.7,49.9,14.8,50.1
|
||||||
|
# Zernovka big
|
||||||
|
#BBOX=14.6,49.7,14.9,50.1
|
||||||
|
|
||||||
|
if [ ".$1" == ".-f" ]; then
|
||||||
I=/data/gis/osm/dumps/czech_republic-2023-07-24.osm.pbf
|
I=/data/gis/osm/dumps/czech_republic-2023-07-24.osm.pbf
|
||||||
#I=/data/gis/osm/dumps/zernovka.osm.bz2
|
#I=/data/gis/osm/dumps/zernovka.osm.bz2
|
||||||
O=cr.geojson
|
O=cr.geojson
|
||||||
rm delme.pbf $O
|
rm delme.pbf $O
|
||||||
time osmium extract $I --bbox 14.7,49.9,14.8,50.1 -f pbf -o delme.pbf
|
ls -alh $I
|
||||||
|
time osmium extract $I --bbox $BBOX -f pbf -o delme.pbf
|
||||||
|
ls -alh delme.pbf
|
||||||
time osmium export delme.pbf -c prepare.json -o $O
|
time osmium export delme.pbf -c prepare.json -o $O
|
||||||
|
ls -alh $O
|
||||||
|
# ~.5G in 15min
|
||||||
echo "Converting to ascii"
|
echo "Converting to ascii"
|
||||||
time cstocs utf8 ascii cr.geojson > cr_ascii.geojson
|
time cstocs utf8 ascii cr.geojson > cr_ascii.geojson
|
||||||
mv -f cr_ascii.geojson delme.json
|
mv -f cr_ascii.geojson delme.json
|
||||||
fi
|
fi
|
||||||
rm -r delme/; mkdir delme
|
rm -r delme/; mkdir delme
|
||||||
./split.js
|
time ./split.js $Z
|
||||||
./minitar.js
|
./minitar.js
|
||||||
ls -lS delme/*.json | head -20
|
ls -lS delme/*.json | head -20
|
||||||
cat delme/* | wc -c
|
cat delme/* | wc -c
|
||||||
|
|
|
@ -6,11 +6,11 @@
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const sphm = require('./sphericalmercator.js');
|
const sphm = require('./sphericalmercator.js');
|
||||||
var split = require('geojson-vt')
|
var split = require('geojson-vt');
|
||||||
|
const process = require('process');
|
||||||
|
|
||||||
|
|
||||||
// delme.json needs to be real file, symlink to geojson will not work
|
// delme.json needs to be real file, symlink to geojson will not work
|
||||||
console.log("Loading json");
|
|
||||||
var gjs = require("./delme.json");
|
|
||||||
|
|
||||||
function tileToLatLon(x, y, z, x_, y_) {
|
function tileToLatLon(x, y, z, x_, y_) {
|
||||||
var [ w, s, e, n ] = merc.bbox(x, y, z);
|
var [ w, s, e, n ] = merc.bbox(x, y, z);
|
||||||
|
@ -30,9 +30,39 @@ function convGeom(tile, geom) {
|
||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clamp(i) {
|
||||||
|
if (i<0)
|
||||||
|
return 0;
|
||||||
|
if (i>4095)
|
||||||
|
return 4095;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
function binGeom(tile, geom) {
|
||||||
|
let off = 1;
|
||||||
|
let r = new Uint8Array(geom.length * 3 + off);
|
||||||
|
let j = off;
|
||||||
|
for (i = 0; i< geom.length; i++) {
|
||||||
|
let x = geom[i][0];
|
||||||
|
let y = geom[i][1];
|
||||||
|
x = clamp(x);
|
||||||
|
y = clamp(y);
|
||||||
|
r[j++] = x >> 4;
|
||||||
|
r[j++] = y >> 4;
|
||||||
|
r[j++] = (x & 0x0f) + ((y & 0x0f) << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
function zoomPoint(tags) {
|
function zoomPoint(tags) {
|
||||||
var z = 99;
|
var z = 99;
|
||||||
|
|
||||||
|
if (tags.featurecla == "Admin-0 scale ranksscalerank") z = 2;
|
||||||
|
if (tags.featurecla == "Admin-0 capital") z = 3;
|
||||||
|
if (tags.featurecla == "Admin-1 capital") z = 4;
|
||||||
|
if (tags.featurecla == "Populated place") z = 5;
|
||||||
|
|
||||||
if (tags.place == "city") z = 4;
|
if (tags.place == "city") z = 4;
|
||||||
if (tags.place == "town") z = 8;
|
if (tags.place == "town") z = 8;
|
||||||
if (tags.place == "village") z = 10;
|
if (tags.place == "village") z = 10;
|
||||||
|
@ -40,10 +70,59 @@ function zoomPoint(tags) {
|
||||||
return z;
|
return z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var meta = {};
|
||||||
|
var ac = -1;
|
||||||
|
meta.attrs = [];
|
||||||
|
var a_town = ++ac;
|
||||||
|
meta.attrs[ac] = {};
|
||||||
|
meta.attrs[ac].type = 1;
|
||||||
|
var a_village = ++ac
|
||||||
|
meta.attrs[ac] = {};
|
||||||
|
meta.attrs[ac].type = 1;
|
||||||
|
meta.attrs[ac].properties = {};
|
||||||
|
meta.attrs[ac].properties["marker-color"] = "#800000";
|
||||||
|
var a_way = ++ac;
|
||||||
|
meta.attrs[ac] = {};
|
||||||
|
meta.attrs[ac].type = 2;
|
||||||
|
var a_secondary = ++ac;
|
||||||
|
meta.attrs[ac] = {};
|
||||||
|
meta.attrs[ac].type = 2;
|
||||||
|
meta.attrs[ac].properties = {};
|
||||||
|
meta.attrs[ac].properties.stroke = "#000040";
|
||||||
|
var a_tertiary = ++ac;
|
||||||
|
meta.attrs[ac] = {};
|
||||||
|
meta.attrs[ac].type = 2;
|
||||||
|
meta.attrs[ac].properties = {};
|
||||||
|
meta.attrs[ac].properties.stroke = "#000080";
|
||||||
|
var a_track = ++ac;
|
||||||
|
meta.attrs[ac] = {};
|
||||||
|
meta.attrs[ac].type = 2;
|
||||||
|
meta.attrs[ac].properties = {};
|
||||||
|
meta.attrs[ac].properties.stroke = "#404040";
|
||||||
|
var a_path = ++ac;
|
||||||
|
meta.attrs[ac] = {};
|
||||||
|
meta.attrs[ac].type = 2;
|
||||||
|
meta.attrs[ac].properties = {};
|
||||||
|
meta.attrs[ac].properties.stroke = "#408040";
|
||||||
|
var a_polygon = ++ac;
|
||||||
|
meta.attrs[ac] = {};
|
||||||
|
meta.attrs[ac].type = 3;
|
||||||
|
var a_forest = ++ac;
|
||||||
|
meta.attrs[ac] = {};
|
||||||
|
meta.attrs[ac].properties = {};
|
||||||
|
meta.attrs[ac].properties.fill = "#c0ffc0";
|
||||||
|
meta.attrs[ac].type = 3;
|
||||||
|
var a_water = ++ac;
|
||||||
|
meta.attrs[ac] = {};
|
||||||
|
meta.attrs[ac].properties = {};
|
||||||
|
meta.attrs[ac].properties.fill = "#c0c0ff";
|
||||||
|
meta.attrs[ac].type = 3;
|
||||||
|
|
||||||
function paintPoint(tags) {
|
function paintPoint(tags) {
|
||||||
var p = {};
|
var p = {};
|
||||||
|
|
||||||
if (tags.place == "village") p["marker-color"] = "#ff0000";
|
if (tags.place == "city" || tags.place == "town") { p.attr = a_town; }
|
||||||
|
if (tags.place == "village") { p.attr = a_village; p["marker-color"] = "#ff0000"; }
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -51,15 +130,17 @@ function paintPoint(tags) {
|
||||||
function zoomWay(tags) {
|
function zoomWay(tags) {
|
||||||
var z = 99;
|
var z = 99;
|
||||||
|
|
||||||
|
if (tags.scalerank == 0) z = 0;
|
||||||
|
|
||||||
if (tags.highway == "motorway") z = 7;
|
if (tags.highway == "motorway") z = 7;
|
||||||
if (tags.highway == "primary") z = 9;
|
if (tags.highway == "primary") z = 9;
|
||||||
if (tags.highway == "secondary") z = 13;
|
if (tags.highway == "secondary") z = 13;
|
||||||
if (tags.highway == "tertiary") z = 14;
|
if (tags.highway == "tertiary") z = 14;
|
||||||
if (tags.highway == "unclassified") z = 16;
|
if (tags.highway == "unclassified") z = 15;
|
||||||
if (tags.highway == "residential") z = 17;
|
if (tags.highway == "residential") z = 15;
|
||||||
if (tags.highway == "track") z = 17;
|
if (tags.highway == "track") z = 15;
|
||||||
if (tags.highway == "path") z = 17;
|
if (tags.highway == "path") z = 16;
|
||||||
if (tags.highway == "footway") z = 17;
|
if (tags.highway == "footway") z = 16;
|
||||||
|
|
||||||
return z;
|
return z;
|
||||||
}
|
}
|
||||||
|
@ -67,52 +148,120 @@ function zoomWay(tags) {
|
||||||
function paintWay(tags) {
|
function paintWay(tags) {
|
||||||
var p = {};
|
var p = {};
|
||||||
|
|
||||||
|
p.attr = a_way;
|
||||||
if (tags.highway == "motorway" || tags.highway == "primary") /* ok */;
|
if (tags.highway == "motorway" || tags.highway == "primary") /* ok */;
|
||||||
if (tags.highway == "secondary" || tags.highway == "tertiary") p.stroke = "#0000ff";
|
if (tags.highway == "secondary" || tags.highway == "tertiary") { p.stroke = "#0000ff"; p.attr = a_secondary; }
|
||||||
if (tags.highway == "tertiary" || tags.highway == "unclassified" || tags.highway == "residential") p.stroke = "#00ff00";
|
if (tags.highway == "tertiary" || tags.highway == "unclassified" || tags.highway == "residential") { p.stroke = "#00ff00"; p.attr = a_tertiary; }
|
||||||
if (tags.highway == "track") p.stroke = "#ff0000";
|
if (tags.highway == "track") { p.stroke = "#ff0000"; p.attr = a_track; }
|
||||||
if (tags.highway == "path" || tags.highway == "footway") p.stroke = "#800000";
|
if (tags.highway == "path" || tags.highway == "footway") { p.stroke = "#800000"; p.attr = a_path; }
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
function zoomPolygon(tags) {
|
||||||
|
var z = 99;
|
||||||
|
|
||||||
|
if (tags.scalerank == 0) z = 0;
|
||||||
|
|
||||||
|
if (tags.landuse == "forest") z = 16;
|
||||||
|
if (tags.natural == "water") z = 16;
|
||||||
|
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
function paintPolygon(tags) {
|
||||||
|
var p = {};
|
||||||
|
|
||||||
|
p.attr = a_polygon;
|
||||||
|
if (tags.landuse == "forest") { p.fill = "#c0ffc0"; p.attr = a_forest; }
|
||||||
|
if (tags.natural == "water") { p.fill = "#c0c0ff"; p.attr = a_water; }
|
||||||
|
|
||||||
|
if (tags.featurecla == "Admin-0 sovereignty") p.attr = a_way;
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeFeatures(name, feat)
|
function writeFeatures(name, feat)
|
||||||
{
|
{
|
||||||
var n = {};
|
if (0) {
|
||||||
n.type = "FeatureCollection";
|
var n = {};
|
||||||
n.features = feat;
|
n.type = "FeatureCollection";
|
||||||
|
n.features = feat;
|
||||||
|
|
||||||
fs.writeFile(name+'.json', JSON.stringify(n), on_error);
|
fs.writeFile(name+'.json', JSON.stringify(n), on_error);
|
||||||
|
} else {
|
||||||
|
if (feat.length > 0)
|
||||||
|
fs.writeFile(name+'.json', JSON.stringify(feat), on_error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function btoa(s) {
|
||||||
|
return Buffer.from(s).toString('base64');
|
||||||
|
}
|
||||||
|
|
||||||
|
// E.toString()
|
||||||
|
|
||||||
function toGjson(name, d, tile) {
|
function toGjson(name, d, tile) {
|
||||||
var cnt = 0;
|
var cnt = 0;
|
||||||
var feat = [];
|
var feat = [];
|
||||||
for (var a of d) {
|
for (var a of d) {
|
||||||
var f = {};
|
let f = {}; // geojson output
|
||||||
|
let b = {}; // moving towards binary output
|
||||||
var zoom = 99;
|
var zoom = 99;
|
||||||
var p = {};
|
var p = {};
|
||||||
|
var bin = [];
|
||||||
|
if (!a.tags)
|
||||||
|
a.tags = a.properties;
|
||||||
f.properties = a.tags;
|
f.properties = a.tags;
|
||||||
f.type = "Feature";
|
f.type = "Feature";
|
||||||
f.geometry = {};
|
f.geometry = {};
|
||||||
if (a.type == 1) {
|
if (a.type == 1) {
|
||||||
f.geometry.type = "Point";
|
f.geometry.type = "Point";
|
||||||
f.geometry.coordinates = convGeom(tile, a.geometry)[0];
|
f.geometry.coordinates = convGeom(tile, a.geometry)[0];
|
||||||
|
bin = binGeom(tile, a.geometry);
|
||||||
zoom = zoomPoint(a.tags);
|
zoom = zoomPoint(a.tags);
|
||||||
p = paintPoint(a.tags);
|
p = paintPoint(a.tags);
|
||||||
} else if (a.type == 2) {
|
} else if (a.type == 2) {
|
||||||
f.geometry.type = "LineString";
|
f.geometry.type = "LineString";
|
||||||
f.geometry.coordinates = convGeom(tile, a.geometry[0]);
|
f.geometry.coordinates = convGeom(tile, a.geometry[0]);
|
||||||
|
bin = binGeom(tile, a.geometry[0]);
|
||||||
zoom = zoomWay(a.tags);
|
zoom = zoomWay(a.tags);
|
||||||
p = paintWay(a.tags);
|
p = paintWay(a.tags);
|
||||||
|
if (zoom == 99) {
|
||||||
|
f.geometry.type = "Polygon";
|
||||||
|
zoom = zoomPolygon(a.tags);
|
||||||
|
p = paintPolygon(a.tags);
|
||||||
|
}
|
||||||
|
} else if (a.type == 3) {
|
||||||
|
f.geometry.type = "Polygon";
|
||||||
|
f.geometry.coordinates = convGeom(tile, a.geometry[0]);
|
||||||
|
bin = binGeom(tile, a.geometry[0]);
|
||||||
|
zoom = zoomPolygon(a.tags);
|
||||||
|
p = paintPolygon(a.tags);
|
||||||
} else {
|
} else {
|
||||||
//console.log("Unknown type", a.type);
|
console.log("Unknown type", a.type);
|
||||||
}
|
}
|
||||||
//zoom -= 4; // Produces way nicer map, at expense of space.
|
//zoom -= 4; // Produces way nicer map, at expense of space.
|
||||||
if (tile.z < zoom)
|
if (tile.z < zoom)
|
||||||
continue;
|
continue;
|
||||||
f.properties = Object.assign({}, f.properties, p);
|
f.properties = Object.assign({}, f.properties, p);
|
||||||
feat.push(f);
|
//feat.push(f); FIXME
|
||||||
|
bin[0] = p.attr;
|
||||||
|
b.b = btoa(bin);
|
||||||
|
b.tags = {};
|
||||||
|
if (a.tags.name)
|
||||||
|
b.tags.name = a.tags.name;
|
||||||
|
if (a.tags.nameascii)
|
||||||
|
b.tags.name = a.tags.nameascii;
|
||||||
|
if (a.tags.sr_subunit)
|
||||||
|
b.tags.name = a.tags.sr_subunit;
|
||||||
|
|
||||||
|
//delete(a.tags.highway);
|
||||||
|
//delete(a.tags.landuse);
|
||||||
|
//delete(a.tags.natural);
|
||||||
|
//delete(a.tags.place);
|
||||||
|
// b.properties = p
|
||||||
|
feat.push(b);
|
||||||
var s = JSON.stringify(feat);
|
var s = JSON.stringify(feat);
|
||||||
if (s.length > 6000) {
|
if (s.length > 6000) {
|
||||||
console.log("tile too big, splitting", cnt);
|
console.log("tile too big, splitting", cnt);
|
||||||
|
@ -135,16 +284,41 @@ var merc = new sphm({
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("Splitting data");
|
console.log("Splitting data");
|
||||||
var meta = {}
|
|
||||||
meta.min_zoom = 0;
|
meta.min_zoom = 0;
|
||||||
meta.max_zoom = 17; // HERE
|
meta.max_zoom = 16; // HERE
|
||||||
// = 16 ... split3 takes > 30 minutes
|
// = 16 ... split3 takes > 30 minutes
|
||||||
// = 13 ... 2 minutes
|
// = 13 ... 2 minutes
|
||||||
|
if (process.argv[2] == "-h") {
|
||||||
|
console.log("help here");
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
if (process.argv[2] == "--maxz") {
|
||||||
|
meta.max_zoom = 1*process.argv[3];
|
||||||
|
console.log("... max zoom", meta.max_zoom);
|
||||||
|
}
|
||||||
|
if (process.argv[2] == "--world") {
|
||||||
|
console.log("Loading world");
|
||||||
|
meta.max_zoom = 4;
|
||||||
|
var g_sovereign = require("./ne_10m_admin_0_sovereignty.json");
|
||||||
|
var g_labels = require("./ne_10m_admin_0_label_points.json");
|
||||||
|
var g_places = require("./ne_10m_populated_places_simple.json");
|
||||||
|
|
||||||
|
gjs = {}
|
||||||
|
gjs.type = "FeatureCollection";
|
||||||
|
//gjs.features = g_sovereign.features + g_labels.features + g_places.features;
|
||||||
|
gjs.features = g_sovereign.features.concat(g_labels.features).concat(g_places.features);
|
||||||
|
console.log(gjs);
|
||||||
|
} else {
|
||||||
|
console.log("Loading json");
|
||||||
|
gjs = require("./delme.json");
|
||||||
|
}
|
||||||
|
|
||||||
var index = split(gjs, Object.assign({
|
var index = split(gjs, Object.assign({
|
||||||
maxZoom: meta.max_zoom,
|
maxZoom: meta.max_zoom,
|
||||||
indexMaxZoom: meta.max_zoom,
|
indexMaxZoom: meta.max_zoom,
|
||||||
indexMaxPoints: 0,
|
indexMaxPoints: 0,
|
||||||
tolerance: 30,
|
tolerance: 10,
|
||||||
|
buffer: 0,
|
||||||
}), {});
|
}), {});
|
||||||
console.log("Producing output");
|
console.log("Producing output");
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
zoom() {
|
zoom() {
|
||||||
echo "Zoom $1"
|
VAL=`cat delme/z$1-* | wc -c`
|
||||||
cat delme/z$1-* | wc -c
|
echo "Zoom $1 -- " $[$VAL/1024]
|
||||||
echo "M..k..."
|
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "Total data"
|
echo "Total data"
|
||||||
|
@ -16,7 +15,17 @@ zoom 14
|
||||||
zoom 13
|
zoom 13
|
||||||
zoom 12
|
zoom 12
|
||||||
zoom 11
|
zoom 11
|
||||||
zoom 10
|
zoom 9
|
||||||
|
zoom 8
|
||||||
|
zoom 7
|
||||||
|
zoom 6
|
||||||
|
zoom 5
|
||||||
|
zoom 4
|
||||||
|
zoom 3
|
||||||
|
zoom 2
|
||||||
|
zoom 1
|
||||||
|
zoom 0
|
||||||
|
|
||||||
echo "Zoom 1..9"
|
echo "Zoom 1..9"
|
||||||
cat delme/z?-* | wc -c
|
cat delme/z?-* | wc -c
|
||||||
echo "M..k..."
|
echo "M..k..."
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/bash
|
||||||
|
if [ ".$1" == ".-f" ]; then
|
||||||
|
wget https://raw.githubusercontent.com/martynafford/natural-earth-geojson/master/10m/cultural/ne_10m_admin_0_sovereignty.json
|
||||||
|
wget https://raw.githubusercontent.com/martynafford/natural-earth-geojson/master/10m/cultural/ne_10m_admin_0_label_points.json
|
||||||
|
wget https://raw.githubusercontent.com/martynafford/natural-earth-geojson/master/10m/cultural/ne_10m_populated_places_simple.json
|
||||||
|
fi
|
||||||
|
rm delme.json
|
||||||
|
rm -r delme/; mkdir delme
|
||||||
|
./split.js --world
|
||||||
|
./minitar.js
|
||||||
|
ls -lS delme/*.json | head -20
|
||||||
|
cat delme/* | wc -c
|
||||||
|
ls -l delme.mtar
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
||||||
|
0.01: First release
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Last announced heartrate BPM Widget
|
||||||
|
|
||||||
|
* Displays the last announced bpm measurement from Bangle.on('HRM', ...);
|
||||||
|
* it does not enable the heartrate sensor to do measurements it waits on such annoucement. I use it to view the last read value when letting the system take a reading every 10 minutes.
|
||||||
|
* saves last read value to a file so it can display that last value between app starts / reboots
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Code based on Lato Pedometer Written by: [Hugh Barney](https://github.com/hughbarney)
|
||||||
|
Code Modified by: [Willems Davy](https://github.com/joyrider3774)
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"id": "widhr",
|
||||||
|
"name": "Last announced heartrate BPM Widget",
|
||||||
|
"shortName":"Last Heartrate BPM",
|
||||||
|
"icon": "widhr.icon.png",
|
||||||
|
"screenshots": [{"url":"screenshot_widhr.png"}],
|
||||||
|
"version":"0.01",
|
||||||
|
"type": "widget",
|
||||||
|
"supports": ["BANGLEJS2"],
|
||||||
|
"readme": "README.md",
|
||||||
|
"description": "Displays the last announced heartrate BPM from `Bangle.on(\"HRM\", ...);` (it does not enable the hrm sensor it expects the system or other app todo so)",
|
||||||
|
"tags": "widget",
|
||||||
|
"data": [
|
||||||
|
{"name":"widhr.data.json"}
|
||||||
|
],
|
||||||
|
"storage": [
|
||||||
|
{"name":"widhr.wid.js","url":"widhr.wid.js"}
|
||||||
|
]
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
Binary file not shown.
After Width: | Height: | Size: 7.1 KiB |
|
@ -0,0 +1,30 @@
|
||||||
|
function widhr_hrm(hrm) {
|
||||||
|
require("Storage").writeJSON("widhr.data.json", {"bpm":hrm.bpm});
|
||||||
|
WIDGETS["widhr"].draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bangle.on('HRM', widhr_hrm);
|
||||||
|
|
||||||
|
function widhr_draw() {
|
||||||
|
var json = require("Storage").readJSON("widhr.data.json");
|
||||||
|
var bpm = json === undefined ? 0 : json.bpm;
|
||||||
|
//3x6 from bpm text in 6x8 font
|
||||||
|
var w = (bpm.toString().length)*8 > 3 * 6 ? (bpm.toString().length)*8 : 3 * 6;
|
||||||
|
if (w != this.width)
|
||||||
|
{
|
||||||
|
this.width = w;
|
||||||
|
setTimeout(() => Bangle.drawWidgets(),10); return;
|
||||||
|
}
|
||||||
|
g.reset();
|
||||||
|
g.setColor(g.theme.bg);
|
||||||
|
g.fillRect(this.x, this.y, this.x + this.width, this.y + 23); // erase background
|
||||||
|
g.setColor(g.theme.fg);
|
||||||
|
g.setFont("6x8:1");
|
||||||
|
g.setFontAlign(-1, 0);
|
||||||
|
g.drawString("bpm", this.x, this.y + 5);
|
||||||
|
g.setFont("4x6:2");
|
||||||
|
g.setFontAlign(-1, 0);
|
||||||
|
g.drawString(bpm, this.x, this.y + 17);
|
||||||
|
}
|
||||||
|
|
||||||
|
WIDGETS["widhr"]={area:"tl",sortorder:-1,width:13,draw:widhr_draw};
|
2
core
2
core
|
@ -1 +1 @@
|
||||||
Subproject commit 431a3fb743da5c370729ab748cb2c177e70a345b
|
Subproject commit 37a22e0c49666ec3947ad0daaf5f5675101ca485
|
Loading…
Reference in New Issue