1
0
Fork 0

Merge pull request #744 from awkirk71/master

Font Clock: Initial Version
master
Gordon Williams 2021-05-24 09:20:19 +01:00 committed by GitHub
commit b6cc5fa45b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 1414 additions and 0 deletions

View File

@ -216,6 +216,32 @@
{"name":"wclock.img","url":"clock-word-icon.js","evaluate":true} {"name":"wclock.img","url":"clock-word-icon.js","evaluate":true}
] ]
}, },
{ "id": "fontclock",
"name": "Font Clock",
"icon": "fontclock.png",
"version":"0.01",
"description": "Choose the font and design of clock face from a library of available designs",
"tags": "clock",
"type":"clock",
"allow_emulator":false,
"readme": "README.md",
"custom":"custom.html",
"storage": [
{"name":"fontclock.app.js","url":"fontclock.js"},
{"name":"fontclock.img","url":"fontclock-icon.js","evaluate":true},
{"name":"fontclock.hand.js","url":"fontclock.hand.js"},
{"name":"fontclock.thinhand.js","url":"fontclock.thinhand.js"},
{"name":"fontclock.thickhand.js","url":"fontclock.thickhand.js"},
{"name":"fontclock.hourscriber.js","url":"fontclock.hourscriber.js"},
{"name":"fontclock.font.js","url":"fontclock.font.js"},
{"name":"fontclock.font.abril_ff50.js","url":"fontclock.font.abril_ff50.js"},
{"name":"fontclock.font.cpstc58.js","url":"fontclock.font.cpstc58.js"},
{"name":"fontclock.font.mntn25.js","url":"fontclock.font.mntn25.js"},
{"name":"fontclock.font.mntn50.js","url":"fontclock.font.mntn50.js"},
{"name":"fontclock.font.vector25.js","url":"fontclock.font.vector25.js"},
{"name":"fontclock.font.vector50.js","url":"fontclock.font.vector50.js"}
]
},
{ "id": "slidingtext", { "id": "slidingtext",
"name": "Sliding Clock", "name": "Sliding Clock",
"icon": "slidingtext.png", "icon": "slidingtext.png",

1
apps/fontclock/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: Initial Release

28
apps/fontclock/README.md Normal file
View File

@ -0,0 +1,28 @@
# Font Clock
The Font Clock allows you to choose the font and clock style.
![](app.png)
## Usage
### Choose the Clock Face from the selection
Before uploading the upload page will ask which clock face you like to choose. Please choose using the provided pull down. As you look through the different selections a sample image will be shown to the right hand side.
Once you have chosen your watch face press the upload button and the selection will be uploaded to the watch
### Button 3
Button 3 (bottom right button) is used to change the background colour.
## Further Details
For further details of design and working please visit [The Project Page](https://www.notion.so/adrianwkirk/Sweep-hand-clock-6aa5b6b3d1074d4e87fc947975b1e4b7)
## Requests
Reach out to adrian@adriankirk.com if you have feature requests or notice bugs.
## Creator
Made by [Adrian Kirk](mailto:adrian@adriankirk.com)

BIN
apps/fontclock/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

210
apps/fontclock/custom.html Normal file
View File

@ -0,0 +1,210 @@
<html>
<head>
<link rel="stylesheet" href="../../css/spectre.min.css">
</head>
<body>
<p>Please select watch display</p>
<table>
<tr>
<td>
<select id="display_selection" name="display_selection" onchange="change_image()" >
</select>
</td>
<td>
<img id="selected_image" src="display-01.png">
</td>
</tr>
</table>
<p>Click <button id="upload" class="btn btn-primary">Upload</button></p>
<script src="../../core/lib/customize.js"></script>
<script>
function change_image() {
var idx = document.getElementById("display_selection").selectedIndex;
set_image(idx);
}
function set_image(idx){
var image = document.getElementById('selected_image');
image.src = "display-0" + (idx + 1) + ".png";
}
var displays_choices=[
{
name: "Abril FatFace 4",
numerals: [12,3,6,9],
fonts: ["abril_ff50"],
radius: 80,
color_schemes : [
{
name: "black",
background : [0.0,0.0,0.0],
second_hand: [1.0,1.0,0.0]
},
{
name: "red",
background : [1.0,0.0,0.0],
second_hand: [1.0,1.0,0.0]
},
{
name: "grey",
background : [0.5,0.5,0.5],
},
{
name: "purple",
background : [1.0,0.0,1.0]
},
{
name: "blue",
background : [0.4,0.7,1.0]
}
]
},
{
name: "Montoon 4",
numerals: [12,3,6,9],
fonts: ["mntn50"],
radius: 80,
color_schemes : [
{
name: "black",
background : [0.0,0.0,0.0],
second_hand: [1.0,1.0,0.0]
},
{
name: "grey",
background : [0.5,0.5,0.5]
}
]
},
{
name: "Vector 12",
numerals: [12,1,2,3,4,5,6,7,8,9,10,11],
fonts: ["vector25"],
radius: 90,
color_schemes : [
{
name: "black",
background : [0.0,0.0,0.0],
second_hand: [1.0,0.0,0.0]
},
{
name: "grey",
background : [0.5,0.5,0.5],
second_hand: [0.0,0.0,0.0]
}
]
},
{
name: "Copaset 4",
numerals: [12,3,6,9],
fonts: ["cpstc58"],
radius: 75,
color_schemes : [
{
name: "black",
background : [0.0,0.0,0.0],
second_hand: [1.0,0.0,0.0]
},
{
name: "red",
background : [1.0,0.0,0.0],
second_hand: [1.0,1.0,0.0]
},
{
name: "grey",
background : [0.5,0.5,0.5],
second_hand: [0.0,0.0,0.0]
},
{
name: "purple",
background : [1.0,0.0,1.0]
},
{
name: "blue",
background : [0.4,0.7,1.0]
}
]
},
{
name: "Vector 4",
numerals: [12,3,6,9],
fonts: ["vector50"],
radius: 75,
color_schemes : [
{
name: "black",
background : [0.0,0.0,0.0],
second_hand: [1.0,0.0,0.0],
},
{
name: "red",
background : [1.0,0.0,0.0],
second_hand: [1.0,1.0,0.0]
},
{
name: "grey",
background : [0.5,0.5,0.5],
second_hand: [0.0,0.0,0.0]
},
{
name: "purple",
background : [1.0,0.0,1.0]
},
{
name: "blue",
background : [0.4,0.7,1.0]
}
]
}
];
var selected_choice = "Abril FatFace 4"
try{
var stored = localStorage.getItem('fontclock.font.json')
if(stored) {
var selected_config = JSON.parse(stored);
selected_choice = selected_config.name;
}
} catch(e){
console.log("failed to load languages:" + e);
}
console.log("selected choice:" + selected_choice);
var selection=document.getElementById("display_selection");
for (var i=0; i<displays_choices.length; i++) {
var option = document.createElement('option');
var curr_choice = displays_choices[i];
option.name = curr_choice.name;
option.text = curr_choice.name;
selection.add(option);
}
selection.value = selected_choice;
set_image(selection.selectedIndex)
// When the 'upload' button is clicked...
document.getElementById("upload").addEventListener("click", function() {
var new_config;
console.log("selection:" + selection.value);
for(var i=0; i<displays_choices.length; i++) {
if (displays_choices[i].name == selection.value) {
new_config = displays_choices[i];
console.log("new_config:" + JSON.stringify(new_config));
}
}
localStorage.setItem('fontclock.font.json',JSON.stringify(new_config));
// send finished app (in addition to contents of app.json)
sendCustomizedApp({
storage:[
{name:"fontclock.font.json", content:JSON.stringify(new_config)},
]
});
});
</script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("lEowkA/4AvmUiAA0/CRHzkczAA0vExM/n/zn8zAIPzCZUi/8j+cvmUzAgI7JBQITHkY6JCwRNEIYITIDoQSEExXyDoQSDn4mKHQ4mKLoImRHQQmPMIYTDExY6HExY6HExQ6HYgISJHQ4TBAgbXOAAb3Ba5giBn8/H4zXHMYfzEww6I+cyPJAtEToizBNoQTFLo0yBAKMI+UikUjIwQSBJg61ICALGMPQgQBJhB6IbJjcGJhw6DCQJMMUIhMOHQavBCRo6CJh46DTJo6EJh5eCTJwADdwISQJiIAo"))

View File

@ -0,0 +1,51 @@
var NumeralFont = require("fontclock.font.js");
const DIM_30x38 = [30,38];
const DIM_49x38 = [49,38];
class DigitNumeralFont extends NumeralFont{
constructor(){
super();
// dimension map provides the dimensions of the character for
// each number for plotting and collision detection
this.widths = atob("DRIhFRwdHhsfGh8fDQ==");
this.font = atob("AAAAAAAAAAAAAAAAAAAAAAAH4AAAAAAD/AAAAAAB/4AAAAAAf+AAAAAAH/gAAAAAB/4AAAAAAf+AAAAAAD/AAAAAAA/gAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAPwAAAAAAf8AAAAAA/+AAAAAB/8AAAAAD/wAAAAAH/gAAAAAP/AAAAAAf+AAAAAA/8AAAAAB/4AAAAAD/wAAAAAH/gAAAAAP/AAAAAAH+AAAAAAB8AAAAAAAIAAAAAAAAAAAAAAAAAAH/8AAAAAP//8AAAAP///wAAAH///+AAAD////4AAB/////AAA/////wAAf////+AAH/////wAD/////8AA//////AAP/gAA/wADwAAAAeAA4AAAADgAMAAAAA4ADAAAAAOAAwAAAADgAMAAAAA4ADgAAAAeAA/gAAA/AAP/////wAD/////8AAf/////AAH/////gAA/////4AAH////8AAB////+AAAP////AAAA////gAAAD///gAAAAH//AAAAAAAAAAAAGAAAAAwABgAAAAMAAYAAAADAAGAAAAAwADgAAAAMAA//////AAP/////wAD/////8AA//////AAP/////wAD/////8AA//////AAP/////wAD/////8AA//////AAP/////wAAAAAAAMAAAAAAADAAAAAAAAwAAAAAAAMAAAAAAAAAAAAAAAAAAAHwAAD8AAH/AAB/AAD/wAA/wAA/+AAf8AAf/gAP/AAH/4AH/wAD/+AD/8AA//gB//AAOPwA//wADD4Aff8AAwAAPn/AAMAAPx/wADAAH8f8AA4AH+H/AAPgP/B/wAD///gf8AA///4H/AAP//8B/wAD//+Af8AAf//AH/AAH//wB/wAA//4A/8AAH/4Af/AAA/8A//wAAD8Af/8AAAAAD+AAAAAAAAAAAAAAAAAAAAAAAAPwAAA/gAP+AAAf8AD/wAAP/gB/+AAH/4Af/wAB/+AH/8AAf/gB//AAP/4wP/wAD/8OD+OAAw/DgPDgAMDAwAA4ADAAcAAOAAwAHAADgAOAH4AA4AD///AAeAA///+A/AAP/////wAD/////8AA//9///AAP//f//gAB//n//4AAf/w//+AAD/8P//AAAf+B//gAAB+AP/wAAAAAB/4AAAAAADwAAAAAAAAAAAAAAAeAAAAAAAfgAAAAAAf4AAAAAAPmAAAAAAPhgAAAAAPwYAAAAAPwGAAAAAHwBgAAAAHwAYDAAAH4AGAwAAH4ABgMAAH4AAYDAAD4AAGAwAD/////8AA//////AAP/////wAD/////8AA//////AAP/////wAD/////8AA//////AAP/////wAD/////8AAAAAAYDAAAAAAGAwAAAAABgMAAAAAAYBAAAAAB/4AAAAAAf+AAAAAAAAAAAAAAAD4AAAAAAB/gAAAAAA/8AAP//wf/gAD//8H/4AA//3B//AAP8Bgf/wAD/A4D/8AAfwOA/jgAH8DAH44AB/gwAAOAAf4MAADgAH+DAAA4AB/g4AAeAAf8PwA/AAH/D///wAB/w///8AAf8P///AAD/j///wAA/4f//4AAP+H//+AAH/A///AAD/wP//gAA/gB//wAAAAAH/4AAAAAAfwAAAAAAAAAAAAAAAAAAAAAD//wAAAAH///AAAAH///8AAAD////gAAD////8AAB/////gAAf////4AAP/////AAH/////wAB/////8AA//////gAP8B4AD4AD4A4AAOAA4AMAADgAOAHAAA4ADABwAAOAAwAcAAHgAMAH4AP4ADD5///8AA5/f///AAP/////wAD/////8AAf/v//+AAH/7///AAA/+f//wAAH/H//4AAA/gf/4AAABgD/8AAAAAAH4AAAAAAAAAAAAAAAAAAAAf/wAAAAAP/8AAAAAD/8AAAAAA/8AAAAAAP+AAA/AAD/gAA/4AA/4AA//AAP+AAf/wAD/gAf/+AA/4AP//gAP+AH//4AD/gD//+AA/4B///gAP+B/+BwAD/g/8AAAA/4f8AAAAP+P8AAAAD/n8AAAAA/78AAAAAP/+AAAAAD/+AAAAAA/+AAAAAAP+AAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAP+AAAB/gH/4AAA/8D//AAAf/h//wAAP/8f/+AAH//v//gAB//7//8AAf/////AAP/////wAD/////+AA//////gAP//+AB4ADgAeAAOAAwADgADgAMAA4AA4ADAAOAAOAA4AHwADgAP//+AD4AD/////+AA//////AAP/////wAD//7//8AAf/+///AAH//P//gAA//x//4AAH/4f/8AAA/8D/+AAAD8Af/AAAAAAB/AAAAAAAAAAAAA/gAAAAAA//APwAAA//8H+AAAf//j/wAAP//4/+AAD///f/gAB/////8AAf//+//AAP///v/wAD///7+eAA////PjgAPgAPwA4ADgAA4AOAAwAAOADgAMAADgA4ADAAA4AeAAwAAcAfgAPAAeA/wAD/////8AA//////AAP/////gAB/////wAAf////8AAD////+AAAf////AAAH////gAAAf///gAAAD///gAAAAH//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8AH4AAAB/gD/AAAAf8B/4AAAP/Af+AAAD/wH/gAAA/8B/4AAAH/Af+AAAB/wD/AAAAP4A/gAAAAwABgAAAAAAAA==");
var scale = 1; // size multiplier for this font
this.size = 50+(scale<<8)+(1<<16);
this.y_offset = -12;
}
getDimensions(hour){
//return this.dimension_map[hour];
switch (hour){
case 10:
case 11:
case 12:
return DIM_49x38;
default:
return DIM_30x38;
}
}
hour_txt(hour){ return hour.toString(); }
draw(hour_txt,x,y){
/* going to leave this in here for future testing.
uncomment this so that it draws a box behind the string
so we can guess the digit dimensions*/
/*var dim = [30,38];
g.setColor(0.5,0,0);
g.fillPoly([x,y,
x+dim[0],y,
x+dim[0],y+dim[1],
x,y+dim[1]
]);
g.setColor(1.0,1.0,1.0);*/
g.setFontAlign(-1.0,-1.0,0);
g.setFontCustom(this.font, 46, this.widths, this.size);
g.drawString(hour_txt,x,y+this.y_offset );
}
getName(){return "Digit";}
}
module.exports = [DigitNumeralFont];

View File

@ -0,0 +1,59 @@
var NumeralFont = require("fontclock.font.js");
const DIM_20x58 = [20,58];
const DIM_30x58 = [30,58];
const DIM_40x58 = [40,58];
const DIM_50x58 = [50,58];
class DigitNumeralFont extends NumeralFont{
constructor(){
super();
// dimension map provides the dimesions of the character for
// each number for plotting and collision detection
this.font = atob("AAAA/+AAAAAAB///wAAAAB////8AAAA/////+AAAP/////8AAD//////8AAf/8AAf/8AD/8AAAH/4Af+AAAAD/wD/gAAAAD/gf4AAAAAH+D/AAAAAAP8P4AAAAAAf5/AAAAAAA/n4AAAAAAB+/gAAAAAAH/+AAAAAAAf/wAAAAAAA//AAAAAAAD/8AAAAAAAP/4AAAAAAB//gAAAAAAH9+AAAAAAAfn8AAAAAAD+fwAAAAAAP4/gAAAAAB/D/AAAAAAP8H/AAAAAB/gP+AAAAAf8Af/AAAAH/gA//gAAD/8AB//8AH//gAB//////8AAB//////AAAB/////wAAAA////4AAAAAP//4AAAAAAAAAAAAAAGAAAAAAAAA8AAAAAAAAH8AAAAAAAA/wAAAAAAAH+AAAAAAAA/wAAAAAAAH+AAAAAAAA/wAAAAAAAH////////w/////////H////////8/////////3//////////////////8AAAAAAAAAAAAAAAAAADAAAAAAAAAcQAAAAAAAHzwAAAAAAA/PwAAAAAAH9/AAAAAAB/34AAAAAAP/fgAAAAAD//+AAAAAAf//wAAAAAH///AAAAAA///8AAAAAH///4AAAAB/4//gAAAAP/D/+AAAAD/wP34AAAAf+A/fwAAAD/wD8/gAAA/8APz/AAAH/gA/H+AAB/4AD8f8AAP/AAPw/8AD/wAA/B/+A/+AAD8D////wAAPwH///8AAA/AH///gAAD8AH//4AAAPwAH/+AAAAAAAAAAAAAAD8AAAAAAAAPwAAAAAAAA/AAgAAAAD/8AHAAAAAP/wB8AAAAA//APwAAAAD/8D/AAAAAP/wf8AAAAB//H/wAAAAH/8//gAAAAfv//+AAAAD+///8AAAAP7//fwAAAB/P/w/gAAAP8/+D/AAAB/j/wH+AAAP8P8AP8AAB/w/gAf8AAf+D4AA/8AH/wPAAB////+AwAAD////gCAAAH///8AAAAAH///AAAAAAD//wAAAAAAA/wAAAAAAAAAAAAAAAAAAAQAAAAAAAAHAAAAAAAAD8AAAAAAAA/wAAAAAAAP/AAAAAAAD/8AAAAAAB//wAAAAAAf//AAAAAAH//8AAAAAB//PwAAAAAf/w/AAAAAP/8D8AAAAD//APwAAAA//gA/AAAAP/4AD8AAAH/+AAPwAAB//gAA/AAAf/4AAD8AAH/8AAAPwAD//AAAA/AAP/wAAAD8AA/8AAAAPwAD/AAAAA/gAPgAAA/////4AAAD////+AAAAP////wAAAA/////AAAAD////8AAAAAA/AAAAAAAAD8AAAAAAAAPwAAAAAAAAAAAAAA8AAAAAAAB/wAAAAAAD//AAAAAP///8AAAAA////wAAAAD////AAAAAP///8AAAAA//4PwAAAAH/8A/gAAAAf/wB+AAAAB+/AH4AAAAP78AfwAAAA/vwA/AAAAH8/AD+AAAA/z8AP8AAAD+PwAf4AAAf4/AA/wAAH/D8AD/gAA/4PwAH/gAf/A/AAP/8f/4AAAAf////AAAAAf///wAAAAA///8AAAAAAf//AAAAAAAH/gAAAAAAAAAAAAAAAAH/4AAAAAAP//8AAAAAD///+AAAAB////8AAAAf////8AAAH//8f/4AAA//8AD/wAAP//AAD/gAB//wAAH/AAP/+AAAH+AB//wAAAP4AP/+AAAAfwB//wAAAB/AP9/AAAAD+B/n4AAAAH4H8/gAAAAfg/j8AAAAB/H8PwAAAAH8fw/AAAAAPz+D8AAAAA/P4PwAAAAD9/A/AAAAAf38D8AAAAB/fgP4AAAAH5+A/gAAAAfv4B/AAAAD+/gH8AAAAPz+AP4AAAB/PwA/wAAAP8/AB/gAAB/gAAD/AAAP8AAAP+AAD/gAAAf+AA/8AAAA//gf/gAAAA////8AAAAB////gAAAAB///4AAAAAB//+AAAAAAA//AAAAAAAAAAAAPwAAAAAAAA/AAAAAAAAD8AAAAAAAAfwAAAAAAAP/AAAAAAAH/8AAAAAAD//wAAAAAD///AAAAAB///8AAAAA///vwAAAA///w/AAAAP//wD8AAAP//4APwAAH//8AA/AAD//+AAD8AD//+AAAPwB///AAAA/A///gAAAD8f//wAAAAP///4AAAAA///4AAAAAD//8AAAAAAP/+AAAAAAA/+AAAAAAAD/AAAAAAAAPgAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAH//wAAAAAB///wAAAAAf///wAAAAD////wAAAAf////gAAAH/wAf/AAAA/8AAP+AAAD/AAAf8AAAf4AAAf4AAD/AAAA/gB/P4AAAB/A///AAAAH8H//8AAAAP4///gAAAAfn//+AAAAB+f//wAAAAH/+B/AAAAAf/4H8AAAAA//APwAAAAD/8A/AAAAAP/4H8AAAAB/fw/wAAAAH9///gAAAAfj//+AAAAB+P//4AAAAP4P//wAAAA/gf//gAAAH8APD/AAAA/wAAH8AAAH+AAAf8AAA/wAAA/4AAH/AAAB/4AB/4AAAD/8A//AAAAH////wAAAAP///+AAAAAP///gAAAAAP//4AAAAAAH/+AAAAAAAAAAAAAAA/wAAAAAAA//8AAAAAAP//+AAAAAD///8AAAAA////8AAAAH////4AAAA/+AD/wAAAH/AAD/gAAA/4AAD/AAAH+AAAH+AAAfwAAAP8APz+AAAAfwA/P4AAAA/gH9/AAAAD+Af34AAAAH4B+fgAAAAfwH7+AAAAA/A/v4AAAAD8D+/AAAAAPwPz8AAAAA/B/PwAAAAD8P8/gAAAAPw/j+AAAAA/H8H4AAAAH8/wfgAAAAf3+B/AAAAB+fwH8AAAAP//AP4AAAB//4A/wAAAH//AB/gAAA//4AD/AAAP//AAH+AAB//wAAf+AAf/+AAAf/AP//gAAA/////8AAAB/////AAAAB////wAAAAB///4AAAAAB//4AAAAAAAAAAAAAAA=");
this.widths = atob("Jg8dGiAaKBsoKA==");
}
getDimensions(hour){
switch(hour){
case 1:
return DIM_20x58;
case 2:
case 3:
case 4:
case 5:
case 7:
return DIM_30x58;
case 6:
case 8:
case 9:
case 11:
case 12:
return DIM_40x58;
case 10:
return DIM_50x58;
default:
return DIM_30x58;
}
}
hour_txt(hour){ return hour.toString(); }
draw(hour_txt,x,y){
/* going to leave this in here for future testing.
uncomment this so that it draws a box behind the string
so we can guess the digit dimensions
dim = [50,58];
g.setColor(0.5,0,0);
g.fillPoly([x,y,
x+dim[0],y,
x+dim[0],y+dim[1],
x,y+dim[1]
]);
g.setColor(1.0,1.0,1.0);*/
//g.setFontCopasetic40x58Numeric();
//g.setFontAlign(-1,-1,0);
g.setFontAlign(-1,-1,0);
g.setFontCustom(this.font, 48, this.widths, 58);
g.drawString(hour_txt,x,y);
}
getName(){return "Digit";}
}
module.exports = [DigitNumeralFont];

View File

@ -0,0 +1,26 @@
/**
* We want to be able to change the font so we set up
* pure virtual for all fonts implementtions to use
*/
class NumeralFont {
/**
* The screen dimensions of what we are going to
* display for the given hour.
*/
getDimensions(hour){return [0,0];}
/**
* The characters that are going to be returned for
* the hour.
*/
hour_txt(hour){ return ""; }
/**
* method to draw text at the required coordinates
*/
draw(hour_txt,x,y){ return "";}
/**
* Called from the settings loader to identify the font
*/
getName(){return "";}
}
module.exports = NumeralFont;

View File

@ -0,0 +1,23 @@
{
"name": "Vector 4",
"numerals": [12,3,6,9],
"fonts": ["vector50"],
"radius": 75,
"color_schemes" : [
{
"name": "black",
"background" : [0.0,0.0,0.0],
"second_hand": [1.0,0.0,0.0],
},
{
"name": "red",
"background" : [1.0,0.0,0.0],
"second_hand": [1.0,1.0,0.0]
},
{
"name": "grey",
"background" : [0.5,0.5,0.5],
"second_hand": [0.0,0.0,0.0]
}
]
}

View File

@ -0,0 +1,60 @@
var NumeralFont = require("fontclock.font.js");
const DIM_25x25 = [25,25];
const DIM_10x25 = [10,25];
const DIM_20x25 = [20,25];
const DIM_31x25 = [31,25];
const DIM_15x25 = [15,25];
class DigitNumeralFont extends NumeralFont{
constructor(){
super();
// dimension map provides the dimensions of the character for
// each number for plotting and collision detection
this.widths = atob("BgsVCw8PEBEUEBQUBw==");
this.font = atob("AAAAAAAAAAAAp9bgAAAAAAAAAAAADr+vAAAAAAAAAAAAAOv68AAAAAAAAAAAAA6/rwAAAAAAAAAAAADr+fAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAXwAAAAAAAAAAAAXz//wAAAAAAAAAXz//7q+AAAAAAAXz//8q+//wAAAAXz//8q+//yr3wAXz//8q+//yr3//ZAL/8q+//yr3//ZMAAAW+//2q3//ZQAAAAAC/2q3//pQAAAAAAAAF3//pQAAAAAAAAAAAnpQAAAAAAAAAAAAAAAAABL3//tgQAAAAAAAAj//su9//0gAAAAAC7/vv///73/gAAAAB/8/9u7u7/+34AAAA78/r/////c/+9QAAf9/P/LvLu/+///AADu/++//+7/7Pv79QAv37+/sQAAb/7978AF/f3vwAAAAD+/v+4Aj9779QAAAADs+/vwCP3vv1AAAAAOz7+/AF/P3fsAAAAC+/v94AL9+/v5AAAD/9/f/QAP3+/8/9ze/7+/v2AAj9+//Lztu+/P//AAAP/f3P////6//fcAAAL/z/y7u7vv7PoAAAAD/+z////9z/oAAAAAAK//3LvO/+QAAAAAAAAH3///6zAAAAAAAAAAAAAAAAAAAAAAC96fQAAAAAAAAAAAAL769AAAAAAAAAAAAAvvr5ZmZmZmZmZmAAC++v//////////8AAL76/bu7u7u7u7uwAAvvr/7u7u7u7u7uAAC++v/u7u7u7u7u4AAL76/KqqqqqqqqqgAAvvr///////////AAAjQlVVVVVVVVVVUAAAAAAAAAAAAAAAAAAAhTAAAAAAAAAyUlAAD7+udQAAAAHfv68AAPv777AAAAX/+/rwAC+/y/kAAAn+77+vAAb8/q9gAB79//v68ACf7frzAF/9/t+/rwAH/d+/QK/u/P/7+vAAX8/t/u/f/P7Pv68AAvv7+uzv3vz/+/rwAA/P3///z/v/Pr+vAACPv9u67939EOv68AAA/6///7/3AA6/rwAAAv/Ku+/iAADr+fAAAACu//5gAAAAAAAAAAAAAAAAAAAAAAAAAAhTAAAAAAAAAAIrIAD7+udgAAAAGo379gAPr7/rAAAAAfv935AB+vvvcjMkFQ/Pv+sAT6/d9K/r+vDs+/3QB/zvvzr+v68Nz7+/AJ/d+/Ov6/rx3Pv78Ab779+I/N/PX8+/zwAvv8/P/5/v7/z7/+AA+/z+m/r7/Kv9/PkACvv7///8+//7398gAB/9/bvvzvy8/89wAABv++/93+nf/b+gAAAALv/e/9//3v+wAAAAAASd21AVrcogAAAAAAAAAAAb753JAAAAAAAAAALP/frusAAAAAAAAE3/zO+u6wAAAAAABe/7z/367rAAAAAAf/+9/7vvrusAAAAG/+rv+s/9+u6wAAAAra//rf+5367rAAAABv/q7/q//vrusAAAAK2v/5z/w1+u6wAAAAb/6d/7IAX67rAAAACsr/+AL//vru//4AAG/+YAAaqr+u7aqgAAnUAAAD///67v//AAAAAAAABVWPruxVUAAAAAAAAAACtphgAAAAAAAAAAAAAAAAAAAAA0U3d3d3d1AADMAAAL76//////0ACr9AAAvvr9zMzMyABd/vAAC++v7u7u7qAPz79QAL76//////wPz975AAvvr8rN7Oyw+vv+wAC++vQN37/ODs+/vgAL769A6/v9wN37+/AAvvr0Dq+/3Q/Pv78AC++vQN38/vv8+/3QAL769Ar8397+7/36AAvvr0Bfv8/s/7/PMAC++vQA77+9/a+fwAAL769ABP3f///f8gAAVnSRAAb/mrzP8wAAAAAAAAAC3///wQAAAAAAAAAAAAJiAAAAAAAAAAA2ZmZiAAAAAAAAAK7//////+YAAAAAA//Lu7u7up77AAAABP+//+7u7v/5/QAAAP7fyN///+y/+/cAAH+/n/2qqqvv7vzwAA/f3+r/////v8+/cAD7+/v82rye38/e6wBPv9zrn9388fv7/NAI/O+va+/Pzw3Pv68Aj93689z7/dDc+vrwBPv+v06/z90Pz7++AA+/3vnO/Pz+/PvuwAD7+/o4/O/56/38+QAN/v5QP8/f//7PzxAAP89QAL+f3czfj6AAAK9wAAH/v///z/EAAADQAAAC79q879EAAAAAAAAAAJ3//YAAAAAAAAAAAAAAAAAAAAAL3p9AAAAAAAAAAAAAvvr0AAAAAAAAAAAAC++vQAAAAAAAAAAAAL769AAAAAAAAFrgAAvvr0AAAAAFrv/9AAC++vQAAFvv/9u98AAL769Wvv/8u9//6gAArN7//8u+//67z/AACv/8u+//27z//roAAFu+//273//rvP/wAAv/273//rvP//xxAABb3//rvP//xxAAAAAL/rvP//thAAAAAAAAXP/+thAAAAAAAAAACutgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGt/qYCvv2kAAAAAAb/69/+/+vP/AAAAAT+z//q/8//6/8QAAP8/7u9/P+7z/v7AADv36//+/v///778gAfv7/Lr/7++3/vz6AG+/7+/9+/v//Pz+0Aj8789d77+/Ds+/zwCf3Pryvuv68N36+vAJ/c+vK+6/rwzfr68An9z68r7r+vDN+vrwCPzvz1v+z78ez6+/AE+/7//fzv3+/Pv98AD7+/ne+/v57e/e/QAO7v3//9/u/v+vr2AAT9/7u9+v68uvz/AAAM/O////v///z/EAAACv+6vP/+u6z/IAAAAATP//1H3//7IAAAAAAAABAAAAEAAAAAAAAABJkwAAAAAAAAAAAAr///+gAAAAEQAAAB783dvP0QAADNAAAA37/93/n8AAC79QAAT5/c/9358wBt/vAADu/v+8/+79Afz79QAPn7+//Pv58Pv975AD+f7/zP3fjw+vv+wAf7789T+/6vTs+/vgCf3fvyP8/789z7+/AG+++/SP7Pvw+fr74AL5/e+837+/X3+v3AAPv7+//d3d797/35AA3+7/vMzMzK75+/MAA/r97//////r/fwAAAz5/7uqqqqt/d8gAAAe/N//////6v9gAAAACv/bqqqr3/4gAAAAAAOM/////aUAAAAAAAAAAAAAAAAAAAAAAAAAAQEQABARAAAAAAAABvvuoF+u6wAAAAAAAG++6gX67rAAAAAAAAb77qBfrusAAAAAAABvvuoF+u6wAAAAAAAE16pwPXunAAAAAAAAAAAAAAAAAAAA==");
var scale = 1; // size multiplier for this font
this.size = 25+(scale<<8)+(4<<16);
this.y_offset = 0;
}
getDimensions(hour){
//return this.dimension_map[hour];
switch(hour){
case 0:
case 12:
return DIM_25x25;
case 1:
return DIM_10x25;
case 6:
case 8:
case 9:
case 11:
return DIM_20x25;
case 10:
return DIM_31x25;
default:
return DIM_15x25;
}
}
hour_txt(hour){ return hour.toString(); }
draw(hour_txt,x,y){
/* going to leave this in here for future testing.
uncomment this so that it draws a box behind the string
so we can guess the digit dimensions*/
/*var dim = [30,25];
g.setColor(0.5,0,0);
g.fillPoly([x,y,
x+dim[0],y,
x+dim[0],y+dim[1],
x,y+dim[1]
]);
g.setColor(1.0,1.0,1.0);*/
g.setFontAlign(-1.0,-1.0,0);
g.setFontCustom(this.font, 46, this.widths, this.size);
g.drawString(hour_txt,x,y+this.y_offset );
}
getName(){return "Digit";}
}
module.exports = [DigitNumeralFont];

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,39 @@
var NumeralFont = require("fontclock.font.js");
const DIM_14x22 = [14,22];
const DIM_27x22 = [27,22];
class DigitNumeralFont extends NumeralFont{
constructor(){
super();
}
getDimensions(hour){
if (hour < 10){
return DIM_14x22;
} else {
return DIM_27x22;
}
}
hour_txt(hour){ return hour.toString(); }
draw(hour_txt,x,y){
if(hour_txt == null)
return;
/* going to leave this in here for future testing.
uncomment this so that it draws a box behind the string
so we can guess the digit dimensions
var dim = [14,22];
g.setColor(0.5,0,0);
g.fillPoly([x,y,
x+dim[0],y,
x+dim[0],y+dim[1],
x,y+dim[1]
]);
g.setColor(1.0,1.0,1.0);*/
g.setFontAlign(-1,-1,0);
g.setFont("Vector",25);
g.drawString(hour_txt,x,y);
}
getName(){return "Digit";}
}
module.exports = [DigitNumeralFont];

View File

@ -0,0 +1,91 @@
var NumeralFont = require("fontclock.font.js");
const DIM_28x44 = [28,44];
const DIM_54x44 = [54,44];
class DigitNumeralFont extends NumeralFont{
constructor(){
super();
}
getDimensions(hour){
if (hour < 10){
return DIM_28x44;
} else {
return DIM_54x44;
}
}
hour_txt(hour){ return hour.toString(); }
draw(hour_txt,x,y){
if(hour_txt == null)
return;
/* going to leave this in here for future testing.
uncomment this so that it draws a box behind the string
so we can guess the digit dimensions
var dim = [14,22];
g.setColor(0.5,0,0);
g.fillPoly([x,y,
x+dim[0],y,
x+dim[0],y+dim[1],
x,y+dim[1]
]);
g.setColor(1.0,1.0,1.0);*/
g.setFontAlign(-1,-1,0);
g.setFont("Vector",50);
g.drawString(hour_txt,x,y);
}
getName(){return "Digit";}
}
const DIM_50x40 = [50,40];
const DIM_70x40 = [70,40];
class RomanNumeralFont extends NumeralFont{
constructor(){
super();
}
getText(hour){
switch (hour){
case 1 : return 'I';
case 2 : return 'II';
case 3 : return 'III';
case 4 : return 'IV';
case 5 : return 'V';
case 6 : return 'VI';
case 7 : return 'VII';
case 8 : return 'VIII';
case 9 : return 'IX';
case 10: return 'X';
case 11: return 'XI';
case 12: return 'XII';
default: return '';
}
}
getDimensions(hour){
switch (hour){
case 3:
case 6:
case 9:
return DIM_50x40;
case 12:
return DIM_70x40;
default:
return DIM_70x40;
}
}
hour_txt(hour){ return this.getText(hour); }
draw(hour_txt,x,y){
/*var dim = DIM_70x40;
g.setColor(0.5,0,0);
g.fillPoly([x,y,
x+dim[0],y,
x+dim[0],y+dim[1],
x,y+dim[1]
]);*/
g.setFontAlign(-1,-1,0);
g.setFont("Vector",50);
g.drawString(hour_txt,x,y);
}
getName(){return "Roman";}
}
module.exports = [DigitNumeralFont,RomanNumeralFont];

View File

@ -0,0 +1,10 @@
class Hand {
/**
* Pure virtual class for all Hand classes to extend.
* a hand class will have 1 main function
* moveTo which will move the hand to the given angle.
*/
moveTo(angle){}
}
module.exports = Hand;

View File

@ -0,0 +1,137 @@
const TWO_PI = 2* Math.PI;
// The problem with the trig inverse functions on
// a full circle is that the sector information will be lost
// Choosing to use arcsin because you can get back the
// sector with the help of the original coordinates
function reifyasin(x,y,asin_angle){
if(x >= 0 && y >= 0){
return asin_angle;
} else if(x >= 0 && y < 0){
return Math.PI - asin_angle;
} else if(x < 0 && y < 0){
return Math.PI - asin_angle;
} else {
return TWO_PI + asin_angle;
}
}
// rebase and angle so be between -pi and pi
// rather than 0 to 2PI
function rebaseNegative(angle){
if(angle > Math.PI){
return angle - TWO_PI;
} else {
return angle;
}
}
// rebase an angle so that it is between 0 to 2pi
// rather than -pi to pi
function rebasePositive(angle){
if(angle < 0){
return angle + TWO_PI;
} else {
return angle;
}
}
/**
* The Hour Scriber is responsible for drawing the numeral
* on the screen at the requested angle.
* It allows for the font to be changed on the fly.
*/
class HourScriber {
constructor(radius, numeral_font, draw_test, bg_colour_supplier, numeral_colour_supplier, hour){
this.radius = radius;
this.numeral_font = numeral_font;
this.draw_test = draw_test;
this.curr_numeral_font = numeral_font;
this.bg_colour_supplier = bg_colour_supplier;
this.numeral_colour_supplier = numeral_colour_supplier;
this.hours = hour;
this.curr_hour_x = -1;
this.curr_hour_y = -1;
this.curr_hours = -1;
this.curr_hour_str = null;
this.last_draw_time = null;
}
setNumeralFont(numeral_font){
this.numeral_font = numeral_font;
}
toString(){
return "HourScriber{numeralfont=" + this.numeral_font.getName() + ",hours=" + this.hours + "}";
}
draw(){
var changed = false;
if(this.curr_hours != this.hours || this.curr_numeral_font !=this.numeral_font){
var background = this.bg_colour_supplier();
g.setColor(background[0],background[1],background[2]);
this.curr_numeral_font.draw(this.curr_hour_str,
this.curr_hour_x,
this.curr_hour_y);
//console.log("erasing old hour display:" + this.curr_hour_str + " color:" + background);
var hours_frac = this.hours / 12;
var angle = TWO_PI*hours_frac;
var dimensions = this.numeral_font.getDimensions(this.hours);
// we set the radial coord to be in the middle
// of the drawn text.
var width = dimensions[0];
var height = dimensions[1];
var delta_center_x = this.radius*Math.sin(angle) - width/2;
var delta_center_y = this.radius*Math.cos(angle) + height/2;
this.curr_hour_x = screen_center_x + delta_center_x;
this.curr_hour_y = screen_center_y - delta_center_y;
this.curr_hour_str = this.numeral_font.hour_txt(this.hours);
// now work out the angle of the beginning and the end of the
// text box so we know when to redraw
// bottom left angle
var x1 = delta_center_x;
var y1 = delta_center_y;
var r1 = Math.sqrt(x1*x1 + y1*y1);
var angle1 = reifyasin(x1,y1,Math.asin(x1/r1));
// bottom right angle
var x2 = delta_center_x;
var y2 = delta_center_y - height;
var r2 = Math.sqrt(x2*x2 + y2*y2);
var angle2 = reifyasin(x2,y2,Math.asin(x2/r2));
// top left angle
var x3 = delta_center_x + width;
var y3 = delta_center_y;
var r3 = Math.sqrt(x3*x3 + y3*y3);
var angle3 = reifyasin(x3,y3, Math.asin(x3/r3));
// top right angle
var x4 = delta_center_x + width;
var y4 = delta_center_y - height;
var r4 = Math.sqrt(x4*x4 + y4*y4);
var angle4 = reifyasin(x4,y4,Math.asin(x4/r4));
if(Math.min(angle1,angle2,angle3,angle4) < Math.PI && Math.max(angle1,angle2,angle3,angle4) > 1.5*Math.PI){
angle1 = rebaseNegative(angle1);
angle2 = rebaseNegative(angle2);
angle3 = rebaseNegative(angle3);
angle3 = rebaseNegative(angle4);
this.angle_from = rebasePositive( Math.min(angle1,angle2,angle3,angle4) );
this.angle_to = rebasePositive( Math.max(angle1,angle2,angle3,angle4) );
} else {
this.angle_from = Math.min(angle1,angle2,angle3,angle4);
this.angle_to = Math.max(angle1,angle2,angle3,angle4);
}
//console.log(angle1 + "/" + angle2 + " / " + angle3 + " / " + angle4);
//console.log( this.angle_from + " to " + this.angle_to);
this.curr_hours = this.hours;
this.curr_numeral_font = this.numeral_font;
changed = true;
}
if(changed ||
this.draw_test(this.angle_from, this.angle_to, this.last_draw_time) ){
var numeral_color = this.numeral_colour_supplier();
g.setColor(numeral_color[0],numeral_color[1],numeral_color[2]);
this.numeral_font.draw(this.curr_hour_str,this.curr_hour_x,this.curr_hour_y);
this.last_draw_time = new Date();
//console.log("redraw digit:" + this.hours);
}
}
}
module.exports = HourScriber;

436
apps/fontclock/fontclock.js Normal file
View File

@ -0,0 +1,436 @@
/**
* Adrian Kirk 2021-03
* Simple Clock showing 1 numeral for the hour
* with a smooth sweep second.
*/
var ThinHand = require("fontclock.thinhand.js");
var ThickHand = require("fontclock.thickhand.js");
var HourScriber = require("fontclock.hourscriber.js");
const screen_center_x = g.getWidth()/2;
const screen_center_y = 10 + (g.getHeight()+10)/2;
const TWO_PI = 2* Math.PI;
SETTING_PREFIX = "fontclock";
// load the date formats and languages required
const FONTS_FILE = SETTING_PREFIX +".font.json";
const DEFAULT_FONTS = [ "cpstc58" ];
const DEFAULT_NUMERALS = [12,3,6,9];
const DEFAULT_RADIUS = 70;
var color_schemes = [
{
name: "black",
background : [0.0,0.0,0.0],
}
];
var fonts = DEFAULT_NUMERALS;
var numerals = DEFAULT_NUMERALS;
var radius = DEFAULT_RADIUS;
var fonts_info = null;
try {
fonts_info = require("Storage").readJSON(FONTS_FILE);
} catch(e){
console.log("failed to load fonts file:" + FONTS_FILE + e);
}
if(fonts_info != null){
console.log("loaded font:" + JSON.stringify(fonts_info));
fonts = fonts_info.fonts;
numerals = fonts_info.numerals;
radius = fonts_info.radius;
color_schemes = fonts_info.color_schemes;
} else {
fonts = DEFAULT_FONTS;
numerals = DEFAULT_NUMERALS;
radius = DEFAULT_RADIUS;
console.log("no fonts loaded defaulting to:" + fonts);
}
if(fonts == null || fonts.length == 0){
fonts = DEFAULT_FONTS;
console.log("defaulting fonts to locale:" + fonts);
}
let color_scheme_index = 0;
// The force draw is set to true to force all objects to redraw themselves
let force_redraw = true;
let bg_colour_supplier = ()=>color_schemes[color_scheme_index].background;
var WHITE = [1.0,1.0,1.0];
function default_white(color){
if(color == null){
return WHITE
} else {
return color;
}
}
// The seconds hand is the main focus and is set to redraw on every cycle
let seconds_hand = new ThinHand(screen_center_x,
screen_center_y,
95,
0,
(angle, last_draw_time) => false,
bg_colour_supplier,
()=>default_white(color_schemes[color_scheme_index].second_hand));
// The minute hand is set to redraw at a 250th of a circle,
// when the second hand is ontop or slighly overtaking
// or when a force_redraw is called
const minute_hand_angle_tolerance = TWO_PI/25
let minutes_hand_redraw = function(angle, last_draw_time){
return force_redraw || (seconds_hand.angle > angle &&
Math.abs(seconds_hand.angle - angle) < minute_hand_angle_tolerance &&
new Date().getTime() - last_draw_time.getTime() > 500);
};
let minutes_hand = new ThinHand(screen_center_x,
screen_center_y,
80, minute_hand_angle_tolerance,
minutes_hand_redraw,
bg_colour_supplier,
()=>default_white(color_schemes[color_scheme_index].minute_hand));
// The hour hand is a thick hand so we have to redraw when the minute hand
// overlaps from its behind angle coverage to its ahead angle coverage.
let hour_hand_redraw = function(angle_from, angle_to, last_draw_time){
return force_redraw || (seconds_hand.angle >= angle_from &&
seconds_hand.angle <= angle_to &&
new Date().getTime() - last_draw_time.getTime() > 500);
};
let hours_hand = new ThickHand(screen_center_x,
screen_center_y,
40,
TWO_PI/600,
hour_hand_redraw,
bg_colour_supplier,
() => default_white(color_schemes[color_scheme_index].hour_hand),
5,
4);
function draw_clock(){
var date = new Date();
draw_background();
draw_hour_digits();
draw_seconds(date);
draw_mins(date);
draw_hours(date);
force_redraw = false;
}
// drawing the second the millisecond as we need the fine gradation
// for the sweep second hand.
function draw_seconds(date){
var seconds = date.getSeconds() + date.getMilliseconds()/1000;
var seconds_frac = seconds / 60;
var seconds_angle = TWO_PI*seconds_frac;
seconds_hand.moveTo(seconds_angle);
}
// drawing the minute includes the second and millisec to make the
// movement as continuous as possible.
function draw_mins(date,seconds_angle){
var mins = date.getMinutes() + date.getSeconds()/60 + date.getMilliseconds()/(60*1000);
var mins_frac = mins / 60;
var mins_angle = TWO_PI*mins_frac;
var redraw = minutes_hand.moveTo(mins_angle);
if(redraw){
//console.log("redraw mins");
}
}
function draw_hours(date){
var hours = (date.getHours() % 12) + date.getMinutes()/60 + date.getSeconds()/3600;
var hours_frac = hours / 12;
var hours_angle = TWO_PI*hours_frac;
var redraw = hours_hand.moveTo(hours_angle);
if(redraw){
//console.log("redraw hours");
}
}
let numeral_fonts = [];
for(var i=0; i< fonts.length; i++) {
var file = SETTING_PREFIX +".font." + fonts[i] + ".js"
console.log("loading font set:" + fonts[i] + "->" + file);
var loaded_fonts = require(file);
for (var j = 0; j < loaded_fonts[j]; j++) {
var loaded_font = new loaded_fonts[j];
numeral_fonts.push(loaded_font);
console.log("loaded font name:" + loaded_font.getName())
}
}
let numeral_fonts_index = 0;
const ONE_POINT_FIVE_PI = 1.5*Math.PI;
/**
* predicate for deciding when the digit has to be redrawn
*/
let hour_numeral_redraw = function(angle_from, angle_to, last_draw_time){
var seconds_hand_angle = seconds_hand.angle;
// we have to cope with the 12 problem where the
// left side of the box has a value almost 2PI and the right
// side has a small positive value. The values are rebased so
// that they can be compared
if(angle_from > angle_to && angle_from > ONE_POINT_FIVE_PI){
angle_from = angle_from - TWO_PI;
if(seconds_hand_angle > Math.PI)
seconds_hand_angle = seconds_hand_angle - TWO_PI;
}
//console.log("initial:" + angle_from + "/" + angle_to + " seconds " + seconds_hand_angle);
var redraw = force_redraw ||
(seconds_hand_angle >= angle_from && seconds_hand_angle <= angle_to && seconds_hand.last_draw_time.getTime() > last_draw_time.getTime()) ||
(minutes_hand.last_draw_time.getTime() > last_draw_time.getTime());
if(redraw){
//console.log(angle_from + "/" + angle_to + " seconds " + seconds_hand_angle);
}
return redraw;
};
// now add the numbers to the clock face
var numeral_colour_supplier = () => default_white(color_schemes[color_scheme_index].numeral);
var hour_scribers = [];
console.log("numerals:" + numerals + " length:" + numerals.length)
console.log("radius:" + radius)
for(var digit_idx=0; digit_idx<numerals.length; digit_idx++){
var digit = numerals[digit_idx];
var scriber = new HourScriber(radius,
numeral_fonts[numeral_fonts_index],
hour_numeral_redraw,
bg_colour_supplier,
numeral_colour_supplier,
digit
);
hour_scribers.push(scriber);
//console.log("digit:" + digit + "->" + scriber);
}
//console.log("hour_scribers:" + hour_scribers );
/**
* Called from button 1 to change the numerals that are
* displayed on the clock face
*/
function next_font() {
var curr_font = numeral_fonts_index;
numeral_fonts_index = numeral_fonts_index + 1;
if (numeral_fonts_index >= numeral_fonts.length) {
numeral_fonts_index = 0;
}
if (curr_font != numeral_fonts_index) {
console.log("numeral font changed")
for (var i = 0; i < hour_scribers.length; i++) {
hour_scribers[i].setNumeralFont(
numeral_fonts[numeral_fonts_index]);
}
force_redraw = true;
return true;
} else {
return false;
}
}
const hour_zone_angle = hour_scribers.length/TWO_PI;
function draw_hour_digits() {
if(force_redraw){
for(var i=0; i<hour_scribers.length; i++){
var scriber = hour_scribers[i];
//console.log("idx:" + i + "->" + scriber);
scriber.draw();
}
} else {
var hour_scriber_idx = (0.5 + (seconds_hand.angle * hour_zone_angle)) | 0;
if (hour_scriber_idx >= hour_scribers.length)
hour_scriber_idx = 0;
//console.log("angle:" + seconds_hand.angle + " idx:" + hour_scriber_idx);
if (hour_scriber_idx >= 0) {
hour_scribers[hour_scriber_idx].draw();
}
}
}
function draw_background(){
if(force_redraw){
background = color_schemes[color_scheme_index].background;
g.setColor(background[0],background[1],background[2]);
g.fillPoly([0,25,
0,240,
240,240,
240,25
]);
}
}
function next_colorscheme(){
var prev_color_scheme_index = color_scheme_index;
color_scheme_index += 1;
color_scheme_index = color_scheme_index % color_schemes.length;
//console.log("color_scheme_index=" + color_scheme_index);
force_redraw = true;
if(prev_color_scheme_index == color_scheme_index){
return false;
} else {
return true;
}
}
/**
* called from load_settings on startup to
* set the color scheme to named value
*/
function set_colorscheme(colorscheme_name){
console.log("setting color scheme:" + colorscheme_name);
for (var i=0; i < color_schemes.length; i++) {
if(color_schemes[i].name == colorscheme_name){
color_scheme_index = i;
force_redraw = true;
console.log("match");
break;
}
}
}
/**
* called from load_settings on startup
* to set the font to named value
*/
function set_font(font_name){
console.log("setting font:" + font_name);
for (var i=0; i < numeral_fonts.length; i++) {
if(numeral_fonts[i].getName() == font_name) {
numeral_fonts_index = i;
force_redraw = true;
console.log("match");
for (var j = 0; j < hour_scribers.length; j++) {
hour_scribers[j].setNumeralFont(numeral_fonts[numeral_fonts_index]);
}
break;
}
}
}
/**
* Called on startup to set the watch to the last preference settings
*/
function load_settings(){
try{
var file = SETTING_PREFIX + ".settings.json";
settings = require("Storage").readJSON(file);
if(settings != null){
console.log(file + " loaded:" + JSON.stringify(settings));
if(settings.color_scheme != null){
set_colorscheme(settings.color_scheme);
}
if(settings.font != null){
set_font(settings.font);
}
} else {
console.log(file + " not found - no settings to load");
}
} catch(e){
console.log("failed to load settings:" + e);
}
}
/**
* Called on button press to save down the last preference settings
*/
function save_settings(){
var settings = {
font : numeral_fonts[numeral_fonts_index].getName(),
color_scheme : color_schemes[color_scheme_index].name,
};
var file = SETTING_PREFIX + ".settings.json";
console.log(file + ": saving:" + JSON.stringify(settings));
require("Storage").writeJSON(file,settings);
}
// Boiler plate code for setting up the clock,
// below
let intervalRef = null;
function clearTimers(){
if(intervalRef) {
clearInterval(intervalRef);
intervalRef = null;
}
}
function startTimers(){
setTimeout(scheduleDrawClock,100);
draw_clock();
}
// The clock redraw is set to 100ms. This is the smallest number
// that give the (my) human eye the illusion of a continious sweep
// second hand.
function scheduleDrawClock(){
if(intervalRef) clearTimers();
intervalRef = setInterval(draw_clock, 100);
draw_clock();
}
function reset_clock(){
force_redraw = true;
}
Bangle.on('lcdPower', (on) => {
if (on) {
console.log("lcdPower: on");
reset_clock();
startTimers();
} else {
console.log("lcdPower: off");
reset_clock();
clearTimers();
}
});
Bangle.on('faceUp',function(up){
console.log("faceUp: " + up + " LCD: " + Bangle.isLCDOn());
if (up && !Bangle.isLCDOn()) {
//console.log("faceUp and LCD off");
clearTimers();
Bangle.setLCDPower(true);
}
});
g.clear();
load_settings();
Bangle.loadWidgets();
Bangle.drawWidgets();
startTimers();
function button1pressed() {
if (next_font()) {
save_settings();
}
}
function button2pressed() {
clearTimers();
// the clock is being unloaded so we clear out the big
// data structures for the launcher
hour_scribers = [];
Bangle.showLauncher();
}
function button3pressed(){
if(next_colorscheme()) {
save_settings();
}
}
// Handle button 1 being pressed
setWatch(button1pressed, BTN1,{repeat:true,edge:"falling"});
// Handle button 1 being pressed
setWatch(button2pressed, BTN2,{repeat:true,edge:"falling"});
// Handle button 3 being pressed
setWatch(button3pressed, BTN3,{repeat:true,edge:"falling"});

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@ -0,0 +1,103 @@
var Hand = require("fontclock.hand.js");
class ThickHand extends Hand {
/**
* The thick hand is created from a filled polygone, so its slower to
* draw so to be used sparingly with few redraws
*/
constructor(centerX,
centerY,
length,
tolerance,
draw_test,
color_bg_supplier,
color_fg_supplier,
base_height,
thickness){
super();
this.centerX = centerX;
this.centerY = centerY;
this.length = length;
this.color_bg_supplier = color_bg_supplier;
this.color_fg_supplier = color_fg_supplier;
this.base_height = base_height;
// angle from the center to the top corners of the rectangle
this.delta_top = Math.atan(thickness/(2*length));
// angle from the center to the bottom corners of the rectangle
this.delta_base = Math.atan(thickness/(2*base_height));
// the radius that the bottom corners of the rectangle move through
this.vertex_radius_base = Math.sqrt( (thickness*thickness/4) + base_height * base_height);
// the radius that the top corners of the rectangle move through
this.vertex_radius_top = Math.sqrt( (thickness*thickness/4) + length * length);
// last records the last plotted values (so we don't have to keep recalculating
this.last_x1 = centerX;
this.last_y1 = centerY;
this.last_x2 = centerX;
this.last_y2 = centerY;
this.last_x3 = centerX;
this.last_y3 = centerY;
this.last_x4 = centerX;
this.last_y4 = centerY;
// The change in angle from the last plotted angle before we actually redraw
this.tolerance = tolerance;
// predicate test that is called if the hand is not going to redraw to see
// if there is an externally defined reason for redrawing (like another hand)
this.draw_test = draw_test;
this.angle = -1;
this.last_draw_time = null;
}
// method to move the hand to a new angle
moveTo(angle){
if(Math.abs(angle - this.angle) > this.tolerance || this.draw_test(this.angle - this.delta_base,this.angle + this.delta_base ,this.last_draw_time) ){
//var background = color_schemes[color_scheme_index].background;
var background = this.color_bg_supplier;
g.setColor(background[0],background[1],background[2]);
g.fillPoly([this.last_x1,
this.last_y1,
this.last_x2,
this.last_y2,
this.last_x3,
this.last_y3,
this.last_x4,
this.last_y4
]);
// bottom left
var x1 = this.centerX +
this.vertex_radius_base*Math.sin(angle - this.delta_base);
var y1 = this.centerY - this.vertex_radius_base*Math.cos(angle - this.delta_base);
// bottom right
var x2 = this.centerX +
this.vertex_radius_base*Math.sin(angle + this.delta_base);
var y2 = this.centerY - this.vertex_radius_base*Math.cos(angle + this.delta_base);
// top right
var x3 = this.centerX + this.vertex_radius_top*Math.sin(angle + this.delta_top);
var y3 = this.centerY - this.vertex_radius_top*Math.cos(angle + this.delta_top);
// top left
var x4 = this.centerX + this.vertex_radius_top*Math.sin(angle - this.delta_top);
var y4 = this.centerY - this.vertex_radius_top*Math.cos(angle - this.delta_top);
//var hand_color = color_schemes[color_scheme_index][this.color_theme];
var hand_color = this.color_fg_supplier();
g.setColor(hand_color[0],hand_color[1],hand_color[2]);
g.fillPoly([x1,y1,
x2,y2,
x3,y3,
x4,y4
]);
this.last_x1 = x1;
this.last_y1 = y1;
this.last_x2 = x2;
this.last_y2 = y2;
this.last_x3 = x3;
this.last_y3 = y3;
this.last_x4 = x4;
this.last_y4 = y4;
this.angle = angle;
this.last_draw_time = new Date();
return true;
} else {
return false;
}
}
}
module.exports = ThickHand;

View File

@ -0,0 +1,67 @@
var Hand = require("fontclock.hand.js");
class ThinHand extends Hand {
/**
* The thin hand is created from a simple line, so its easy and fast
* to draw.
*/
constructor(centerX,
centerY,
length,
tolerance,
draw_test,
color_bg_supplier,
color_fg_supplier){
super();
this.centerX = centerX;
this.centerY = centerY;
this.length = length;
this.color_bg_supplier = color_bg_supplier;
this.color_fg_supplier = color_fg_supplier;
// The last x and y coordinates (not the centre) of the last draw
this.last_x = centerX;
this.last_y = centerY;
// tolerance is the angle tolerance (from the last draw)
// in radians for a redraw to be called.
this.tolerance = tolerance;
// draw test is a predicate (angle, time). This is called
// when the hand thinks that it does not have to draw (from its internal tests)
// to see if it has to draw because of another object.
this.draw_test = draw_test;
// The current angle of the hand. Set to -1 initially
this.angle = -1;
this.last_draw_time = null;
this.active = false;
}
// method to move the hand to a new angle
moveTo(angle){
// first test to see of the angle called is beyond the tolerance
// for a redraw
if(Math.abs(angle - this.angle) > this.tolerance ||
// and then call the predicate to see if a redraw is needed
this.draw_test(this.angle,this.last_draw_time) ){
// rub out the old hand line
var background = this.color_bg_supplier();
g.setColor(background[0],background[1],background[2]);
g.drawLine(this.centerX, this.centerY, this.last_x, this.last_y);
// Now draw the new hand line
var hand_color = this.color_fg_supplier();
g.setColor(hand_color[0],hand_color[1],hand_color[2]);
var x2 = this.centerX + this.length*Math.sin(angle);
var y2 = this.centerY - this.length*Math.cos(angle);
g.drawLine(this.centerX, this.centerY, x2, y2);
// and store the last draw details for the next call
this.last_x = x2;
this.last_y = y2;
this.angle = angle;
this.last_draw_time = new Date();
this.active = true;
return true;
} else {
this.active = false;
return false;
}
}
}
module.exports = ThinHand;