この記事を読むのに必要な時間は約 23 分です。
JavaScriptでデジタル時計を実装する上でセグメントの仕様について以下の画像で簡単に説明します。

基本的にシンプルな作りになっています。
setInterval(clock, 1000);
最終的な仕組みとして、1秒間隔で更新される時間情報の反映にsetIntervalを用います。ここでのsetIntervalは、1000ms(ミリ秒)おきにclock関数を実行させるシンプルなものです。
function clock() {
const now = new Date();
const hours = now.getHours();
const mins = now.getMinutes();
const seconds = now.getSeconds();
const time = [
formatTime(hours),
formatTime(mins),
formatTime(seconds)
];
};
現在時刻の取得は、Dateオブジェクトを使い、それぞれ「hours = 時間」、「mins = 分」、「seconds = 秒」に振り分け、
formatTime関数で整形した値を配列timeにセットしています。
function formatTime(cnt) {
return cnt < 10 ? `0${cnt}` : cnt.toString();
};
formatTimeは引数に数値を持ち、与えられた値が10(2ケタ)に満たない値に対しては’0’を前に付与した文字列に整形し、2ケタの値に対しても数値から文字列へと整形する仕組みです。
ここまでに、配列timeには2ケタずつの文字列に整形された[‘時間’,’分’,’秒’]構造の値がセットされており、例えば(AM)7時21分56秒 = [’07’,’21’,’56’]のようになっています。
function clock() {
const splitTimes = time.join('').split('');
const splitNums = splitTimes.map((val) => { return val = nums[val];});
const segmentNums = splitNums.join('').split('');
};
配列timeにセットされている要素を1ケタずつになるようにバラした配列(splitTimes)に対してmap関数を適応し、値とnumsのインデックスに対応する値を新たな配列splitNumsにセット。
そして、splitNumsの要素をバラした後に1ケタずつにした「1 or 0」 のどちらかを持つ要素数42の配列がsegmentNumsです。
function clock() {
const nums = ['1111110','0110000','1101101','1111001','0110011','1011011','0011111','1110010','1111111','1110011'];
}
clock関数に定義されている配列numsについて。
例えば、nums[0]には’1111110’の値がセットされており、この7桁から構成される「1,0」の羅列を利用して各セグメント要素に対する条件分岐を用いた背景色の変更処理を施します。
JavaScriptでは条件式において数値の1は「true」を意味し、数値の0は「false」と暗黙的な型変換が行われます。
function segmentBlink(ary) {
const segments = document.getElementsByClassName('seg');
for (let i = 0; i < ary.length; i++) {
if (!Number(ary[i])) {
segments.item(i).classList.add('inactive');
segments.item(i).classList.remove('active');
} else {
segments.item(i).classList.add('active');
segments.item(i).classList.remove('inactive');
}
}
};
実際にsegmentBlink関数が各セグメントの背景色の変更(クラスの着脱)処理を管理しています。
<h1>Seven Segment Clock</h1>
<div class="clock-container">
<div class="clock-item">
<span class="seg one"></span>
<span class="seg two"></span>
<span class="seg three"></span>
<span class="seg four"></span>
<span class="seg five"></span>
<span class="seg six"></span>
<span class="seg seven"></span>
</div>
<div class="clock-item">
<span class="seg one"></span>
<span class="seg two"></span>
<span class="seg three"></span>
<span class="seg four"></span>
<span class="seg five"></span>
<span class="seg six"></span>
<span class="seg seven"></span>
</div>
<div class="clock-space">
<span class="d1 lamp active"></span>
<span class="d2 lamp active"></span>
</div>
<div class="clock-item">
<span class="seg one"></span>
<span class="seg two"></span>
<span class="seg three"></span>
<span class="seg four"></span>
<span class="seg five"></span>
<span class="seg six"></span>
<span class="seg seven"></span>
</div>
<div class="clock-item">
<span class="seg one"></span>
<span class="seg two"></span>
<span class="seg three"></span>
<span class="seg four"></span>
<span class="seg five"></span>
<span class="seg six"></span>
<span class="seg seven"></span>
</div>
<div class="clock-space">
<span class="d1 lamp active"></span>
<span class="d2 lamp active"></span>
</div>
<div class="clock-item">
<span class="seg one"></span>
<span class="seg two"></span>
<span class="seg three"></span>
<span class="seg four"></span>
<span class="seg five"></span>
<span class="seg six"></span>
<span class="seg seven"></span>
</div>
<div class="clock-item">
<span class="seg one"></span>
<span class="seg two"></span>
<span class="seg three"></span>
<span class="seg four"></span>
<span class="seg five"></span>
<span class="seg six"></span>
<span class="seg seven"></span>
</div>
</div>
@import url("https://fonts.googleapis.com/css2?family=Oswald:wght@200;400;600&display=swap");
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
min-height: 100vh;
color: #161e29;
font-size: 1rem;
font-family: "Oswald", sans-serif;
font-weight: 200;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
h1 {
font-size: 3rem;
font-weight: 600;
margin-bottom: 1rem;
}
.clock-container {
padding: 0.5rem 0;
min-width: 320px;
background-color: #161e29;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
border-radius: 6px;
}
.clock-item {
position: relative;
margin: 0.1rem;
min-width: 70px;
height: 110px;
background-color: #161e29;
}
.clock-item .seg {
position: absolute;
content: "";
top: 0;
left: 0;
display: inline-block;
width: 68px;
height: 10px;
clip-path: polygon(25% 0%, 75% 0%, 83% 50%, 75% 100%, 25% 100%, 18% 50%);
transform: translateX(-50%) translateY(0%);
}
.clock-item .one {
top: 3%;
left: 50%;
}
.clock-item .two {
top: 24%;
left: 35%;
transform: rotate(90deg);
z-index: 99;
}
.clock-item .three {
top: 66%;
left: 35%;
transform: rotate(90deg);
z-index: 98;
}
.clock-item .four {
top: 88%;
left: 50%;
z-index: 97;
}
.clock-item .five {
top: 66%;
left: -31%;
transform: rotate(-90deg);
z-index: 96;
}
.clock-item .six {
top: 24%;
left: -31%;
transform: rotate(-90deg);
z-index: 95;
}
.clock-item .seven {
top: 45%;
left: 50%;
z-index: 94;
}
.clock-space {
position: relative;
margin: 0.1rem;
min-width: 20px;
height: 110px;
background-color: #161e29;
}
.clock-space .d1,
.clock-space .d2 {
position: absolute;
content: "";
width: 12px;
height: 12px;
transform: translate(-50%, 0%);
}
.clock-space .d1,
.clock-space .d2 {
left: 50%;
transform: translateX(-50%) rotate(45deg);
}
.clock-space .d1 {
top: 25%;
}
.clock-space .d2 {
top: 65%;
}
.active {
background-color: #5ac54f;
}
.inactive {
background-color: #282f3d;
}
function clock() {
const nums = ['1111110','0110000','1101101','1111001','0110011','1011011','0011111','1110010','1111111','1110011'];
const now = new Date();
const hours = now.getHours();
const mins = now.getMinutes();
const seconds = now.getSeconds();
const time = [
formatTime(hours),
formatTime(mins),
formatTime(seconds)
];
const splitTimes = time.join('').split('');
const splitNums = splitTimes.map((val) => { return val = nums[val];});
const segmentNums = splitNums.join('').split('');
console.log(segmentNums);
segmentBlink(segmentNums);
lampAnimation();
};
function segmentBlink(ary) {
const segments = document.getElementsByClassName('seg');
for (let i = 0; i < ary.length; i++) {
if (!Number(ary[i])) {
segments.item(i).classList.add('inactive');
segments.item(i).classList.remove('active');
} else {
segments.item(i).classList.add('active');
segments.item(i).classList.remove('inactive');
}
}
};
function lampAnimation() {
const lamp = document.getElementsByClassName('lamp');
for (let i = 0; i < lamp.length; i++) {
lamp.item(i).classList.toggle('active');
lamp.item(i).classList.toggle('inactive');
}
};
function formatTime(cnt) {
return cnt < 10 ? `0${cnt}` : cnt.toString();
};
setInterval(clock, 1000);