Intial version of font clock

master
adrian w kirk 2021-05-22 00:38:30 +01:00
parent e029071678
commit 0692ae20aa
25 changed files with 1444 additions and 0 deletions

View File

@ -216,6 +216,32 @@
{"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":true,
"readme": "README.md",
"custom":"custom.html",
"storage": [
{"name":"fontclock.app.js","url":"fonclock.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",
"name": "Sliding Clock",
"icon": "slidingtext.png",

1
apps/fontclock/ChangeLog Normal file
View File

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

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

@ -0,0 +1,43 @@
# Sweep Clock
The Sweep Clock provides a clock with a perfectly smooth sweep second hand with a single Numeral Display.
![](app.png)
## Usage
### Button 1
Use Button 1 (the top right button) to change the numeral type
| Default clock face | Roman Numeral Font | No Digits |
| ---- | ---- | ---- |
| ![](./numeral-01.jpg) | ![](numeral-02.jpg) | ![](numeral-03.jpg) |
### Button 3
Button 3 (bottom right button) is used to change the colour
| Red | Grey | Purple |
| ---- | ---- | ---- |
| ![](./color-01.jpg) | ![](color-02.jpg) | ![](color-03.jpg) |
### Button 4
Button 4 (bottom left of screen) is used to change the date positioning (or to remove from the screen)
| Top Right | Bottom Right | Bottom Left | Top Left |
| ---- | ---- | ---- | ---- |
| ![](./date-01.jpg) | ![](date-02.jpg) | ![](date-03.jpg) | ![](date-04.jpg) |
## 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: 33 KiB

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

@ -0,0 +1,200 @@
<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],
},
{
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],
},
{
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]
}
]
}
];
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/4AGmYIHABHzmVCCaE0kUin4TPmUimQTQ+UzmcvJ6EjCaP/kYABCaEymYTl+Q7SMgITTmQTQPAK0RMgITm+QTS+ciPCcikQpPY4MjmYTO+czmcyHh4TCmcvJ54nCPCBjBJx4oECc8zJ6ATTn48RE4YTTHh4SDH4ImRFBwTGFBgTGFBgSGFBYmHUgITRmcyFBASFAoUjE5PzkQLBHJxiDAQP/GxAA=="))

File diff suppressed because one or more lines are too long

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,76 @@
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.dimension_map = {
0 : [25,25],
1 : [10,25],
2 : [15,25],
3 : [15,25],
4 : [15,25],
5 : [15,25],
6 : [20,25],
7 : [15,25],
8 : [20,25],
9 : [20,25],
10 : [31,25],
11 : [20,25],
12: [25,25]
};*/
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,55 @@
var NumeralFont = require("fontclock.font.js");
const DIM_14x22 = [14,22];
const DIM_27x22 = [27,22];
class DigitNumeralFont extends NumeralFont{
constructor(){
super();
// dimension map provides the dimesions of the character for
// each number for plotting and collision detection
/*this.dimension_map = {
1 : [14,22],
2 : [14,22],
3 : [14,22],
4 : [14,22],
5 : [14,22],
6 : [14,22],
7 : [14,22],
8 : [14,22],
9 : [14,22],
10: [27,22],
11: [27,22],
12: [27,22]
};*/
}
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,42 @@
var NumeralFont = require("fontclock.font.js");
const DIM_28x44 = [28,44];
const DIM_54x44 = [54,44];
class DigitNumeralFont extends NumeralFont{
constructor(){
super();
// dimension map provides the dimesions of the character for
// each number for plotting and collision detection
}
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";}
}
module.exports = [DigitNumeralFont];

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");
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;

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

@ -0,0 +1,432 @@
/**
* 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;
try{
var fonts_info = require("Storage").readJSON(FONTS_FILE);
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);
}
} catch(e){
console.log("failed to load fonts:" + e);
}
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) {
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 true;
} else {
return false;
}
}
/**
* 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: 2.6 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;