<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Note Display</title>
<link rel="stylesheet" href="./styles.css">
</head>
<body>
<ul class="display-container">
<li class="note-display" data-note="7.50">
<div class="circle">
<svg width="84" height="84" class="circle-svg">
<circle cx="41" cy="41" r="38" class="progress path"></circle>
<circle cx="41" cy="41" r="38" stroke-linejoin="round" stroke-linecap="round" class="progress fill"></circle>
</svg>
<div class="percent">
<span class="int"></span>
<span class="dec"></span>
</div>
</div>
<span class="subtitle">Transparent</span>
</li>
<li class="note-display" data-note="9.50">
<div class="circle">
<svg width="84" height="84" class="circle-svg">
<circle cx="41" cy="41" r="38" class="progress path"></circle>
<circle cx="41" cy="41" r="38" stroke-linejoin="round" stroke-linecap="round" class="progress fill"></circle>
</svg>
<div class="percent">
<span class="int"></span>
<span class="dec"></span>
</div>
</div>
<span class="subtitle">Reasonable</span>
</li>
<li class="note-display" data-note="6.37">
<div class="circle">
<svg width="84" height="84" class="circle-svg">
<circle cx="41" cy="41" r="38" class="progress path"></circle>
<circle cx="41" cy="41" r="38" stroke-linejoin="round" stroke-linecap="round" class="progress fill"></circle>
</svg>
<div class="percent">
<span class="int"></span>
<span class="dec"></span>
</div>
</div>
<span class="subtitle">Usable</span>
</li>
<li class="note-display" data-note="8.72">
<div class="circle">
<svg width="84" height="84" class="circle-svg">
<circle cx="41" cy="41" r="38" class="progress path"></circle>
<circle cx="41" cy="41" r="38" stroke-linejoin="round" stroke-linecap="round" class="progress fill"></circle>
</svg>
<div class="percent">
<span class="int"></span>
<span class="dec"></span>
</div>
</div>
<span class="subtitle">Exemplary</span>
</li>
</ul>
<script src="./scripts.js"></script>
</body>
</html>
@import url('https://fonts.googleapis.com/css?family=Nixie+One|Raleway:200');
:root {
--initialStroke;
--animationDuration;
}
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
height: 100vh;
color: #fff;
display: flex;
background: #3E423A;
font-family: 'Nixie One', cursive;
}
.display-container {
margin: auto;
display: flex;
}
.note-display {
display: flex;
flex-direction: column;
align-items: center;
margin: 0 25px;
}
.circle {
position: relative;
}
.circle-svg {
transform: rotate(-90deg);
}
.progress {
fill: none;
stroke-width: 3;
stroke-opacity: 0.3;
}
.note-display:nth-child(1) .progress { stroke: #AAFF00; }
.note-display:nth-child(2) .progress { stroke: #FF00AA; }
.note-display:nth-child(3) .progress { stroke: #AA00FF; }
.note-display:nth-child(4) .progress { stroke: #00AAFF; }
.progress.fill {
stroke-dasharray: var(--initialStroke);
stroke-dashoffset: var(--initialStroke);
stroke-opacity: 1;
transition: all var(--animationDuration) ease;
}
.percent {
width: 100%;
top: 50%;
left: 50%;
position: absolute;
font-weight: bold;
text-align: center;
line-height: 28px;
transform: translate(-50%, -50%);
}
.int { font-size: 28px; }
.dec { font-size: 12px; }
.subtitle {
font-family: 'Raleway', serif;
font-size: 14px;
text-transform: uppercase;
margin-top: 15px;
}
const displays = document.querySelectorAll('.note-display');
const animationDuration = 900;
displays.forEach((circle, index) => {
let note = parseFloat(circle.dataset.note),
int = Math.floor(note),
dec = getDecimals(note);
increaseNumber(circle, int, 'int');
increaseNumber(circle, dec, 'dec');
animateStroke(circle, note);
});
function increaseNumber(circle, number, className) {
let element = circle.querySelector(`.${className}`),
decPoint = className === 'int' ? '.' : '',
interval = animationDuration / number,
counter = 0;
let increaseInterval = setInterval(() => {
if (counter === number) { window.clearInterval(increaseInterval); }
element.textContent = counter + decPoint;
counter++;
}, interval);
}
function animateStroke(circle, note) {
let progress = circle.querySelector(".progress.fill"),
radius = progress.r.baseVal.value,
circ = 2 * Math.PI * radius,
offset = circ * (10 - note) / 10;
progress.style.setProperty(`--animationDuration`, `${animationDuration}ms`);
progress.style.setProperty(`--initialStroke`, circ);
setTimeout(() => progress.style.strokeDashoffset = offset, 0);
}
function getDecimals(note) {
let dec = note - Math.floor(note);
return Math.round(dec * 100);
}