Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

clock responsive to full screen + CSS for canvas #1

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
# Analog Clock (Canvas)
[Video Guide](https://youtu.be/1q7EEd6Huf0)

[Digital wall clock with Raspberry Pi](https://ampron.eu/article/use-case/digital-wall-clock-with-raspberry-pi/)
277 changes: 170 additions & 107 deletions clock.js
Original file line number Diff line number Diff line change
@@ -1,115 +1,178 @@
let canvas, ctx;

//https://stackoverflow.com/questions/29675279/how-to-style-canvas-elements-with-css


/* Function to get information from CSS into Canvas:
- An div element is created and added to the DOM.
- The CSS information of the element is saved to an array and available for the canvas.
- After that, the element is removed from the DOM again.
*/

// "Cache"
var classProperties = {};
function getPropeties(className){
if (true === classProperties[className]) {
return classProperties[className];
}

// Create an element with the class name and add it to the DOM
let element = document.createElement('div');
element.style.display = 'none;'
//element.classList.add(className);
element.setAttribute('id', className);
document.body.appendChild(element);

// Get needed stuff from the DOM and put it in the cache
let compStyles = window.getComputedStyle(element);
// create font like '18px Noto Sans'
let font = (canvas.width / 16)+"px "+compStyles.fontFamily.slice(1,-1);
classProperties[className] = {
fill: compStyles.backgroundColor,
lineWidth: compStyles.fontSize,
stroke: compStyles.borderColor,
second: compStyles.outlineColor,
color: compStyles.color,
font: font
}
// Remove the element from the DOM again
element.remove();
return classProperties[className];
}

function draw () {
let time = (function () {
let midnight = new Date();
midnight.setHours(0);
midnight.setMinutes(0);
midnight.setSeconds(0);
midnight.setMilliseconds(0);
return Date.now() - midnight.getTime();
})(),
hours = time / (60 * 60 * 1000),
minutes = hours * 60 % 60,
seconds = minutes * 60 % 60,
c = {x: canvas.width / 2, y: canvas.height / 2};

ctx.clearRect(0, 0, canvas.width, canvas.height);

ctx.lineCap = 'round';

secondHand();
minuteHand();
hourHand();
face();

function face () {
// Border
ctx.lineWidth = 5;
ctx.strokeStyle = 'black';
ctx.beginPath();
ctx.arc(c.x, c.y, 140, 0, Math.PI * 2);
ctx.stroke();

// Dashes
ctx.lineWidth = 3;
for (let i = 0; i < 60; i++) {
let r = 135,
l = 5;
ctx.strokeStyle = 'rgba(0, 0, 0, 0.25)';
if (i % 5 === 0)
r -= l,
l *= 2,
ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)';
let v = new Vector(r, Math.PI * 2 * (i / 60) - Math.PI / 2);
ctx.beginPath();
ctx.moveTo(v.getX() + c.x, v.getY() + c.y);
v.setMag(r + l);
ctx.lineTo(v.getX() + c.x, v.getY() + c.y);
ctx.stroke();
}

// Numbers
ctx.font = '18px Noto Sans';
ctx.fillStyle = 'black';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
for (let i = 1; i <= 12; i++) {
let v = new Vector(113, Math.PI * 2 * (i / 12) - Math.PI / 2);
ctx.fillText(i, v.getX() + c.x, v.getY() + c.y);
}

// Center button
ctx.beginPath();
ctx.arc(c.x, c.y, 3.75, 0, Math.PI * 2);
ctx.fillStyle = 'white';
ctx.strokeStyle = 'black';
ctx.lineWidth = 2.5;
ctx.fill();
ctx.stroke();
}

function secondHand () {
ctx.lineWidth = 1.5;
ctx.strokeStyle = 'black';
ctx.beginPath();
let a = Math.PI * 2 * (seconds / 60) - Math.PI / 2;
let v = new Vector(95, a);
let v2 = new Vector(-20, a);
ctx.moveTo(v2.getX() + c.x, v2.getY() + c.y);
ctx.lineTo(v.getX() + c.x, v.getY() + c.y);
ctx.stroke();
}

function minuteHand () {
ctx.lineWidth = 4;
ctx.strokeStyle = 'black';
ctx.beginPath();
let a = Math.PI * 2 * (minutes / 60) - Math.PI / 2;
let v = new Vector(95, a);
ctx.moveTo(c.x, c.y);
ctx.lineTo(v.getX() + c.x, v.getY() + c.y);
ctx.stroke();
}

function hourHand () {
ctx.lineWidth = 4;
ctx.strokeStyle = 'black';
ctx.beginPath();
let a = Math.PI * 2 * (hours / 12) - Math.PI / 2;
let v = new Vector(60, a);
ctx.moveTo(c.x, c.y);
ctx.lineTo(v.getX() + c.x, v.getY() + c.y);
ctx.stroke();
}

let time = (function () {
let midnight = new Date();
midnight.setHours(0);
midnight.setMinutes(0);
midnight.setSeconds(0);
midnight.setMilliseconds(0);
return Date.now() - midnight.getTime();
})(),

hours = time / (60 * 60 * 1000),
minutes = hours * 60 % 60,
seconds = Math.round(minutes * 60 % 60),

c = {x: canvas.width / 2, y: canvas.height / 2};

ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.lineCap = 'round';

background();
hourHand();
minuteHand();
secondHand();
face();

function background() {
// Background
ctx_bgr.beginPath();
ctx_bgr.arc(c.x, c.y, canvas.width / 2 - canvas.width / 60, 0, Math.PI * 2);
ctx_bgr.fillStyle = classProperties.clockface.fill;
ctx_bgr.fill();
}

function face () {

// Border
let lwf = canvas.width / 300;
ctx.lineWidth = lwf;
ctx.strokeStyle = classProperties.clockface.stroke;
ctx.beginPath();
let rf = canvas.width / 2 - canvas.width / 60;
ctx.arc(c.x, c.y, rf, 0, Math.PI * 2);
ctx.stroke();

// Dashes
ctx.lineWidth = lwf;
for (let i = 0; i < 60; i++) {
let l = canvas.width / 80,
r = rf - l;
ctx.strokeStyle = classProperties.clockface.stroke;
if (i % 5 === 0)
l *= 2.5,
r = rf - l,
ctx.strokeStyle = classProperties.clockface.stroke;
let v = new Vector(r, Math.PI * 2 * (i / 60) - Math.PI / 2);
ctx.beginPath();
ctx.moveTo(v.getX() + c.x, v.getY() + c.y);
v.setMag(r + l);
ctx.lineTo(v.getX() + c.x, v.getY() + c.y);
ctx.stroke();
}

// Numbers
ctx.font = classProperties.clockface.font;
ctx.fillStyle = classProperties.clockface.color;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
for (let i = 1; i <= 12; i++) {
let v = new Vector(rf - canvas.width / 14, Math.PI * 2 * (i / 12) - Math.PI / 2);
ctx.fillText(i, v.getX() + c.x, v.getY() + c.y);
}

// Center button
ctx.beginPath();
ctx.arc(c.x, c.y, canvas.width / 130, 0, Math.PI * 2);
ctx.fillStyle = classProperties.clockface.fill;
ctx.strokeStyle = classProperties.clockface.second;
ctx.lineWidth = canvas.width / 180;
ctx.fill();
ctx.stroke();

}

function secondHand () {
ctx.lineWidth = canvas.width / 200;
ctx.strokeStyle = classProperties.clockface.second;
ctx.beginPath();
let a = Math.PI * 2 * (seconds / 60) - Math.PI / 2;
let v = new Vector(canvas.width / 2 - canvas.width / 6, a);
let v2 = new Vector(-canvas.width / 20, a);
ctx.moveTo(v2.getX() + c.x, v2.getY() + c.y);
ctx.lineTo(v.getX() + c.x, v.getY() + c.y);
ctx.stroke();
}

function minuteHand () {
ctx.lineWidth = canvas.width / 75;
ctx.strokeStyle = classProperties.clockface.stroke;
ctx.beginPath();
let a = Math.PI * 2 * (minutes / 60) - Math.PI / 2;
let v = new Vector(canvas.width / 2 - canvas.width / 6, a);
ctx.moveTo(c.x, c.y);
ctx.lineTo(v.getX() + c.x, v.getY() + c.y);
ctx.stroke();
}

function hourHand () {
ctx.lineWidth = canvas.width / 75;
ctx.strokeStyle = classProperties.clockface.stroke;
ctx.beginPath();
let a = Math.PI * 2 * (hours / 12) - Math.PI / 2;
let v = new Vector(canvas.width / 2 - canvas.width / 3.5, a);
ctx.moveTo(c.x, c.y);
ctx.lineTo(v.getX() + c.x, v.getY() + c.y);
ctx.stroke();
}
}

function init () {
canvas = document.getElementById('clock');
canvas.width = canvas.height = 300;
ctx = canvas.getContext('2d');

setInterval(draw, 10);
canvas = document.getElementById('clock');
canvas_bgr = document.getElementById('clock-background');

ctx = canvas.getContext('2d');
ctx_bgr = canvas_bgr.getContext('2d');

let canvasCSS = window.getComputedStyle(clock); // get current width of clock element in px, because CSS defined with 100% so that it is flexible to screensize
let blocksize = canvasCSS.width.slice(0, -2); // create out of canvas.width 1080px a string 1080
canvas.width = canvas.height = blocksize; // define canvas size based on current size of clock element shown on screen
canvas_bgr.width = canvas_bgr.height = blocksize;
getPropeties('clockface'); // get CSS properties for canvas

setInterval(draw, 1000); // draw the clock every second
}

init();
init();
73 changes: 73 additions & 0 deletions css/main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
html{
height: 100vh;
}

body {
background-color:#262A39;
color: black;
width:100%;
height: 100%;
margin:0;
padding:0;
display:flex;
}

main {
background-color: #8a8a8a;
width: 100%;
height: 100%;
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
align-content: flex-start;
align-items: stretch;
}

h1 {
color: navy;
text-align: center;
}

p {
font-family: verdana;
font-size: 20px;
}

#clock-section {
position: relative;
flex: 100vh; /*initial width of flexible item is 100% of viewport width*/
max-height: 100vw; /*maxium height is 100% of viewport width*/
max-width: 100vh; /*maxium width is 100% of viewport height*/
aspect-ratio: 1/1; /*in connection with max-height and max-width above - full screen quadrat */
display: flex; /* so child elements can use flexbox stuff too*/
justify-content: center;
align-items: center;
}

#weather-section {
flex: auto;
height: 100vh;
}
@media (max-width: 100vh){
#weather-section{
max-height: calc(100% - 100vw);
}
}

#clock, #clock-background {
position: absolute;
width: 100%;
height: 100%;
}

#clockface {
background-color: #faf0e6;
border-color: black;
outline-color: red; /*SecondHand*/
color: black;
font-family: Noto Sans;
}

#clock-functions {
position: absolute;
}
Loading