I'm working on a clock animated using HTML5's canvas and javascript. It should have three moving hands, but only two seem to render and work (hour and minute). I don't see any runtime errors stopping the third one from being rendered. What's wrong with the third hand?
Example Clock BTW this is not an Earth clock so the math may look odd.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Wyrdling Clock</title>
</head>
<body onload="init();">
<div style="position: relative;">
<canvas id="clock_layer1" width="1080" height="1080" style="position: absolute; left: 0; top: 0; z-index: 0;"></canvas>
<canvas id="clock_layer2" width="1080" height="1080" style="position: absolute; left: 0; top: 0; z-index: 1;"></canvas>
<canvas id="clock_layer3" width="1080" height="1080" style="position: absolute; left: 0; top: 0; z-index: 2;"></canvas>
<canvas id="clock_layer4" width="1080" height="1080" style="position: absolute; left: 0; top: 0; z-index: 3;"></canvas>
</div>
</body>
<script>
var clock_face = null,
hour_hand = null,
minute_hand = null,
second_hand = null,
cycle_hand = null,
ctx_l1 = null,
ctx_l2 = null,
ctx_l3 = null,
ctx_l4 = null,
degrees = 0;
var WyrdTimeStarts = new Date("2019-05-22");
var HEIGHT = 1080;
var WIDTH = 1080;
var HALF_HEIGHT = HEIGHT / 2;
var HALF_WIDTH = WIDTH / 2;
var FPS = 15;
var CIRCLE_TO_HOUR_RATIO = 360 / 9;
var CIRCLE_TO_MINUTES_RATIO = 360 / 60;
var CIRCLE_TO_SECOND_RATIO = 360 / 60;
var CIRCLE_TO_CYCLE_RATIO = 360 / 3;
var CIRCLE_TO_MS_RATIO = 360 / 60000;
var DEGRESS_TO_RADIANS = Math.PI / 180;
var RADIANS_TO_DEGREES = 180 / Math.PI;
function fCleanCanvas() {
// clear canvas
ctx_l1.clearRect(0, 0, HEIGHT, WIDTH);
ctx_l2.clearRect(0, 0, HEIGHT, WIDTH);
ctx_l3.clearRect(0, 0, HEIGHT, WIDTH);
ctx_l4.clearRect(0, 0, HEIGHT, WIDTH);
} // End function fCleanCanvas
function fMinuteAngle(currentMinutes) {
// Calculate the expected angle
return Math.floor(CIRCLE_TO_MINUTES_RATIO * currentMinutes, 0);
} // End function fMinuteAngle
function fHourAngle(currentHours) {
// Calculate the expected angle
return Math.floor(CIRCLE_TO_HOUR_RATIO * currentHours, 0);
} // End function fHourAngle
function fSecondAngle(currentTime) {
// Calculate the expected angle
var secondsToMilliseconds = currentTime.getSeconds() * 1000;
var totalMilliseconds = currentTime.getMilliseconds() + secondsToMilliseconds;
return Math.floor(CIRCLE_TO_MS_RATIO * totalMilliseconds, 0);
} // End function fSecondAngle
function fDayCycleAngle(currentHours) {
// Calculate the expected angle
return Math.floor(((360/3) * (currentHours/9)),0);
} // End function fDayCycleAngle
function fDrawAsRotatedInLayer(image, angle, x) {
switch (x) {
case 1:
// Rotate around this point
ctx_l1.rotate(angle * DEGRESS_TO_RADIANS);
// Draw the image back and up
ctx_l1.drawImage(image, 0 - HALF_HEIGHT, 0 - HALF_WIDTH);
break;
case 2:
// Rotate around this point
ctx_l2.rotate(angle * DEGRESS_TO_RADIANS);
// Draw the image back and up
ctx_l2.drawImage(image, 0 - HALF_HEIGHT, 0 - HALF_WIDTH);
break;
case 3:
// Rotate around this point
ctx_l3.rotate(angle * DEGRESS_TO_RADIANS);
// Draw the image back and up
ctx_l3.drawImage(image, 0 - HALF_HEIGHT, 0 - HALF_WIDTH);
break;
case 3:
// Rotate around this point
ctx_l4.rotate(angle * DEGRESS_TO_RADIANS);
// Draw the image back and up
ctx_l4.drawImage(image, 0 - HALF_HEIGHT, 0 - HALF_WIDTH);
break;
default:
break;
}
} // End function fDrawAsRotatedInLayer
function draw() {
var currentTime = new Date();
var today = new Date();
var diffMs = (today - WyrdTimeStarts); // milliseconds in the Wyrd so far
var diffDays = Math.floor(diffMs / 97200000); // Wyrd days
var diffHrs = (diffMs % 97200000) / 3600000; // hours
var diffMins = ((diffMs % 97200000) % 3600000) / 60000; // minutes
fCleanCanvas();
// Draw the clock background onto canvas layer 1
ctx_l1.drawImage(clock_face_base, 0, 0);
// Save canvas layer 1's drawing state
ctx_l1.save();
// Move to center point for rotation of hour hand
ctx_l1.translate(HALF_HEIGHT, HALF_WIDTH);
fDrawAsRotatedInLayer(hour_hand, fHourAngle(diffHrs), 1);
// Restore canvas layer 1's previous drawing state
ctx_l1.restore();
// Draw the clock's middle layer onto canvas layer 2
ctx_l2.drawImage(clock_face_mid, 0, 0);
// Save canvas layer 2's drawing state
ctx_l2.save();
// Move to center point for rotation of minute hand
ctx_l2.translate(HALF_HEIGHT, HALF_WIDTH);
fDrawAsRotatedInLayer(minute_hand, fMinuteAngle(diffMins), 2);
// Restore canvas layer 2's previous drawing state
ctx_l2.restore();
// Save canvas layer 3's drawing state
ctx_l3.save();
// Move to center point for rotation of day cycle (shows which 9 hour segment of the 27 hour day is it)
ctx_l3.translate(HALF_HEIGHT, HALF_WIDTH);
fDrawAsRotatedInLayer(cycle_hand, fDayCycleAngle(diffHrs), 3);
// Restore canvas layer 3's previous drawing state
ctx_l3.restore();
// Draw the clock's cap onto canvas layer 4
ctx_l4.drawImage(clock_face_top, 0, 0);
// Save canvas layer 4's drawing state
ctx_l4.save();
// Move to center point for rotation of second hand
ctx_l4.translate(HALF_HEIGHT, HALF_WIDTH);
fDrawAsRotatedInLayer(second_hand, fSecondAngle(currentTime), 4);
// Restore canvas layer 4's previous drawing state
ctx_l4.restore();
window.requestAnimationFrame(draw, 1000 / FPS);
} // End function draw
function imgLoaded() {
// Image loaded event complete. Start the timer
window.requestAnimationFrame(draw, 1000 / FPS);
} // End function imgLoaded
function init() {
// Grab the clock element
var canvas1 = document.getElementById('clock_layer1');
var canvas2 = document.getElementById('clock_layer2');
var canvas3 = document.getElementById('clock_layer3');
var canvas4 = document.getElementById('clock_layer4');
// Canvas supported?
if(canvas1.getContext('2d')) {
ctx_l1 = canvas1.getContext('2d');
ctx_l2 = canvas2.getContext('2d');
ctx_l3 = canvas3.getContext('2d');
ctx_l4 = canvas4.getContext('2d');
// Load the hour hand image
hour_hand = new Image();
hour_hand.src = 'Wyrdling Clock - hand 1.png';
// Load the minute hand image
minute_hand = new Image();
minute_hand.src = 'Wyrdling Clock - hand 2.png';
// Load the cycle hand image
cycle_hand = new Image();
cycle_hand.src = 'Wyrdling Clock - hand 3.png';
// Load the second hand image
second_hand = new Image();
second_hand.src = 'Wyrdling Clock - hand 4.png';
// Load the clock face part 2 image
clock_face_mid = new Image();
clock_face_mid.src = 'Wyrdling Clock - face 2.png';
// Load the clock face part 3 image
clock_face_top = new Image();
clock_face_top.src = 'Wyrdling Clock - face 3.png';
// Load the clock face base image
clock_face_base = new Image();
clock_face_base.src = 'Wyrdling Clock - face 1.png';
clock_face_base.onload = imgLoaded;
} else {
alert("Canvas not supported!");
} // End if(canvas1.getContext('2d'))
} // End function init
</script>
</html>
Once you see it, you are going to kick yourself for this.
Look at the switch in fDrawAsRotatedInLayer
you have 2 times case 3:
. It never enters the branch for the seconds handle