Skip to content

Commit

Permalink
It's alive!
Browse files Browse the repository at this point in the history
  • Loading branch information
dkallen78 committed Dec 26, 2023
1 parent e1bda2f commit 8760d5d
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 109 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ I like making clocks with web technology

[Balanced Ternary Clock](https://github.com/dkallen78/clocks/tree/master/balanced-ternary-clock)

[Seven-Segment Display Clock](https://github.com/dkallen78/clocks/tree/master/seven-segment-clock)

## Other Clocks

[Ternary Clock](https://github.com/dkallen78/clocks/tree/master/ternary-clock)
6 changes: 4 additions & 2 deletions seven-segment-clock/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Seven-Segment Display Clock
# [Seven-Segment Display Clock](https://dkallen78.github.io/clocks/seven-segment-clock/seven-segment-clock.html)

The first challenge I overcame with this clock was putting together the segments. My options were either using `<div>`s with `clip-path` or `<path>` SVG elements. I went with SVG because I like its versatility compared to HTML when it comes to looking pretty. Since I like to make my clocks responsive to the size of the window, I can't use "normal" units when laying out my paths. Instead, I define all my points as percentages of the width and height. This preloads me with a bit of math but once I've crunched my numbers, it makes inputting everything into the path pretty easy.
The first challenge I overcame with this clock was putting together the segments. My options were either using `<div>`s with `clip-path` or `<path>` SVG elements. I went with SVG because I like its versatility compared to HTML when it comes to looking pretty. Since I like to make my clocks responsive to the size of the window, I can't use "normal" units when laying out my paths. Instead, I define all my points as percentages of the width and height. This preloads me with a bit of math but once I've crunched my numbers, it makes inputting everything into the path pretty easy.

Turning the segments on and off is done by running `childNodes.forEach` on the `<svg>` with the `<path>` elements to be modified: `fill-opacity = "0"` for off, `fill-opacity = "1"` for on. I also have an array of 10 elements (corresponding to the numbers 0 - 9) which have letter codes indicating which segments to display for which number.
14 changes: 13 additions & 1 deletion seven-segment-clock/seven-segment-clock.css
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
body {
background-color: black;
}

.digits {
width: 15svw;
height: 24svw;
opacity: 0;
fill-opacity: 0;
}

.colon {
width: 3svw;
height: 24svw;
}

.digits, .colon {
fill: lime;
}

.digits path, .colon path {
filter: drop-shadow(0 0 1svh lime);
}
256 changes: 150 additions & 106 deletions seven-segment-clock/seven-segment-clock.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,3 @@
class Point {
//----------------------------------------------------//
//A data structure to make managing and representing //
// Cartesian points easier //
//----------------------------------------------------//
//x(float): x coordinate of the point //
//y(float): y coordinate of the point //
//----------------------------------------------------//

constructor(x, y) {
this.x = x;
this.y = y;
}

static center(p1, p2) {
//----------------------------------------------------//
//Finds the center point between p1 and p2 //
//----------------------------------------------------//
//p1, p2(Point): points to find the center of //
//----------------------------------------------------//
//return(Point): the point at the midpoint between the//
// original two points //
//----------------------------------------------------//

const midX = (p1.x + p2.x) / 2;
const midY = (p1.y + p2.y) / 2;
const newCenter = new Point(midX, midY);
return newCenter;
}

static vector(p1, p2) {
//----------------------------------------------------//
//Finds the vector from p1 to p2 //
//----------------------------------------------------//
//p1, p2(Point): points on the vector to be found //
//----------------------------------------------------//
//return(Point): the vector from p1 to p2 //
//----------------------------------------------------//

const vecX = (p1.x - p2.x);
const vecY = (p1.y - p2.y);
const newVector = new Point(vecX, vecY);
return newVector;
}
}

function makeSVG(type, id, ...classes) {
//----------------------------------------------------//
//Makes an SVG element of the type specified //
Expand All @@ -61,8 +15,31 @@ function makeSVG(type, id, ...classes) {
return svg;
}

function makeSegments(svg) {
function makeSVGcircle(x, y, r) {
//----------------------------------------------------//
//Makes an SVG <circle> element //
//----------------------------------------------------//
//x(float): the x coordinate of the circle's center //
//y(float): the y coordinate of the circle's center //
//r(float): the radius of the circle //
//----------------------------------------------------//
//return(element): SVG <circle> element //
//----------------------------------------------------//

let circle = makeSVG("circle");
circle.setAttribute("cx", x);
circle.setAttribute("cy", y);
circle.setAttribute("r", r);
return circle;
}

function makeSegments(svg) {
//----------------------------------------------------//
//Makes the seven segments for the display //
//----------------------------------------------------//
//svg(DOM element): the <svg> element into which the //
// segments will be appended //
//----------------------------------------------------//

const svgBox = document.getElementById(svg.id);
const box = svgBox.getBoundingClientRect();
Expand All @@ -71,104 +48,101 @@ function makeSegments(svg) {
const xMod = xBias * box.width;
const yMod = yBias * box.height;

let path1 = makeSVG("path", "a");
let path1 = makeSVG("path", "a", "segment");
path1.setAttribute("d", `
M ${5 * xMod} ${4 * yMod}
L ${7 * xMod} ${2 * yMod}
L ${13 * xMod} ${2 * yMod}
L ${15 * xMod} ${4 * yMod}
L ${13 * xMod} ${6 * yMod}
L ${7 * xMod} ${6 * yMod}
M ${4.5 * xMod} ${4 * yMod}
L ${6.5 * xMod} ${2 * yMod}
L ${13.5 * xMod} ${2 * yMod}
L ${15.5 * xMod} ${4 * yMod}
L ${13.5 * xMod} ${6 * yMod}
L ${6.5 * xMod} ${6 * yMod}
Z
`);
svg.appendChild(path1);

let path2 = makeSVG("path", "b");
let path2 = makeSVG("path", "b", "segment");
path2.setAttribute("d", `
M ${16 * xMod} ${5 * yMod}
L ${18 * xMod} ${7 * yMod}
L ${18 * xMod} ${13 * yMod}
L ${16 * xMod} ${15 * yMod}
L ${14 * xMod} ${13 * yMod}
L ${14 * xMod} ${7 * yMod}
M ${16 * xMod} ${4.5 * yMod}
L ${18 * xMod} ${6.5 * yMod}
L ${18 * xMod} ${13.5 * yMod}
L ${16 * xMod} ${15.5 * yMod}
L ${14 * xMod} ${13.5 * yMod}
L ${14 * xMod} ${6.5 * yMod}
Z
`);
svg.appendChild(path2);

let path3 = makeSVG("path", "c");
let path3 = makeSVG("path", "c", "segment");
path3.setAttribute("d", `
M ${16 * xMod} ${17 * yMod}
L ${18 * xMod} ${19 * yMod}
L ${18 * xMod} ${25 * yMod}
L ${16 * xMod} ${27 * yMod}
L ${14 * xMod} ${25 * yMod}
L ${14 * xMod} ${19 * yMod}
M ${16 * xMod} ${16.5 * yMod}
L ${18 * xMod} ${18.5 * yMod}
L ${18 * xMod} ${25.5 * yMod}
L ${16 * xMod} ${27.5 * yMod}
L ${14 * xMod} ${25.5 * yMod}
L ${14 * xMod} ${18.5 * yMod}
Z
`);
svg.appendChild(path3);

let path4 = makeSVG("path", "d");
let path4 = makeSVG("path", "d", "segment");
path4.setAttribute("d", `
M ${5 * xMod} ${28 * yMod}
L ${7 * xMod} ${26 * yMod}
L ${13 * xMod} ${26 * yMod}
L ${15 * xMod} ${28 * yMod}
L ${13 * xMod} ${30 * yMod}
L ${7 * xMod} ${30 * yMod}
M ${4.5 * xMod} ${28 * yMod}
L ${6.5 * xMod} ${26 * yMod}
L ${13.5 * xMod} ${26 * yMod}
L ${15.5 * xMod} ${28 * yMod}
L ${13.5 * xMod} ${30 * yMod}
L ${6.5 * xMod} ${30 * yMod}
Z
`);
svg.appendChild(path4);

let path5 = makeSVG("path", "e");
let path5 = makeSVG("path", "e", "segment");
path5.setAttribute("d", `
M ${4 * xMod} ${17 * yMod}
L ${6 * xMod} ${19 * yMod}
L ${6 * xMod} ${25 * yMod}
L ${4 * xMod} ${27 * yMod}
L ${2 * xMod} ${25 * yMod}
L ${2 * xMod} ${19 * yMod}
M ${4 * xMod} ${16.5 * yMod}
L ${6 * xMod} ${18.5 * yMod}
L ${6 * xMod} ${25.5 * yMod}
L ${4 * xMod} ${27.5 * yMod}
L ${2 * xMod} ${25.5 * yMod}
L ${2 * xMod} ${18.5 * yMod}
Z
`);
svg.appendChild(path5);

let path6 = makeSVG("path", "f");
let path6 = makeSVG("path", "f", "segment");
path6.setAttribute("d", `
M ${4 * xMod} ${5 * yMod}
L ${6 * xMod} ${7 * yMod}
L ${6 * xMod} ${13 * yMod}
L ${4 * xMod} ${15 * yMod}
L ${2 * xMod} ${13 * yMod}
L ${2 * xMod} ${7 * yMod}
M ${4 * xMod} ${4.5 * yMod}
L ${6 * xMod} ${6.5 * yMod}
L ${6 * xMod} ${13.5 * yMod}
L ${4 * xMod} ${15.5 * yMod}
L ${2 * xMod} ${13.5 * yMod}
L ${2 * xMod} ${6.5 * yMod}
Z
`);
svg.appendChild(path6);

let path7 = makeSVG("path", "g");
let path7 = makeSVG("path", "g", "segment");
path7.setAttribute("d", `
M ${5 * xMod} ${16 * yMod}
L ${7 * xMod} ${14 * yMod}
L ${13 * xMod} ${14 * yMod}
L ${15 * xMod} ${16 * yMod}
L ${13 * xMod} ${18 * yMod}
L ${7 * xMod} ${18 * yMod}
M ${4.5 * xMod} ${16 * yMod}
L ${6.5 * xMod} ${14 * yMod}
L ${13.5 * xMod} ${14 * yMod}
L ${15.5 * xMod} ${16 * yMod}
L ${13.5 * xMod} ${18 * yMod}
L ${6.5 * xMod} ${18 * yMod}
Z
`);
svg.appendChild(path7);
}

function makeSVGcircle(x, y, r) {
let circle = makeSVG("circle");
circle.setAttribute("cx", x);
circle.setAttribute("cy", y);
circle.setAttribute("r", r);
return circle;
}

function buildFace() {
//----------------------------------------------------//
//Builds the face of the clock by inserting the <svg> //
// elements and adding the segment <path> elements //
//----------------------------------------------------//

const clockFace = document.getElementById("clock-face");

for (let i = 0; i < 6; i++) {

if ((i > 0) && ((i % 2) === 0)) {
let colon = makeSVG("svg", `sep${i}`, "colon");
clockFace.appendChild(colon);
Expand All @@ -185,11 +159,81 @@ function buildFace() {
let circle2 = makeSVGcircle(x1, y2, r);
colon.appendChild(circle2);
}
let display = makeSVG("svg", i.toString(10), "digits");
let display = makeSVG("svg", `d${i.toString(10)}`, "digits");
clockFace.appendChild(display);
makeSegments(display);

}

let second = "";
let minute = "";
let hour = "";

let startClock = setInterval(() => {
const time = new Date();

const secNow = time.getSeconds().toString(10).padStart(2, "0");

if (secNow !== second) {

const minNow = time.getMinutes().toString(10).padStart(2, "0");

if (minNow !== minute) {

const hourNow = time.getHours().toString(10).padStart(2, "0");

if (hourNow !== hour) {
hour = hourNow;
setDigit("0", hour[0]);
setDigit("1", hour[1]);
}

minute = minNow;
setDigit("2", minute[0]);
setDigit("3", minute[1]);
}

second = secNow;
setDigit("4", second[0]);
setDigit("5", second[1]);
}

}, 100);
}

function setDigit(target, digit) {
//----------------------------------------------------//
//Modifies the fill-opacity attributes of the segments//
// to display the proper digit //
//----------------------------------------------------//
//target(string): the ID of the <svg> whose <path> //
// elements are to be changed //
//digit(string): the digit to to be displayed on the //
// seven-segment display //
//----------------------------------------------------//

let targ = document.getElementById(`d${target}`);

targ.childNodes.forEach((x) => {
if (digitSegments[digit].includes(x.id)) {
x.setAttribute("fill-opacity", "1");
} else {
x.setAttribute("fill-opacity", "0");
}
})
}

const digitSegments = [
"abcdef",
"bc",
"abdeg",
"abcdg",
"bcfg",
"acdfg",
"acdefg",
"abc",
"abcdefg",
"abcdfg"
];

document.body.onload = buildFace;

0 comments on commit 8760d5d

Please sign in to comment.