26
apps.json
|
@ -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":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",
|
||||
"name": "Sliding Clock",
|
||||
"icon": "slidingtext.png",
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
0.01: Initial Release
|
|
@ -0,0 +1,28 @@
|
|||
# Font Clock
|
||||
|
||||
The Font Clock allows you to choose the font and clock style.
|
||||
|
||||

|
||||
|
||||
## 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)
|
After Width: | Height: | Size: 24 KiB |
|
@ -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>
|
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 8.7 KiB |
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 6.1 KiB |
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("lEowkA/4AvmUiAA0/CRHzkczAA0vExM/n/zn8zAIPzCZUi/8j+cvmUzAgI7JBQITHkY6JCwRNEIYITIDoQSEExXyDoQSDn4mKHQ4mKLoImRHQQmPMIYTDExY6HExY6HExQ6HYgISJHQ4TBAgbXOAAb3Ba5giBn8/H4zXHMYfzEww6I+cyPJAtEToizBNoQTFLo0yBAKMI+UikUjIwQSBJg61ICALGMPQgQBJhB6IbJjcGJhw6DCQJMMUIhMOHQavBCRo6CJh46DTJo6EJh5eCTJwADdwISQJiIAo"))
|
|
@ -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];
|
|
@ -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];
|
|
@ -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;
|
|
@ -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]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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];
|
|
@ -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];
|
|
@ -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];
|
|
@ -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;
|
|
@ -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;
|
|
@ -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"});
|
||||
|
After Width: | Height: | Size: 6.5 KiB |
|
@ -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;
|
|
@ -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;
|