<svg
class="progress-circle"
width="256"
height="256">
<circle
class="circle-background"
stroke="#e5e2d7"
stroke-width="8"
fill="transparent"
r="110"
cx="128"
cy="128"/>
<circle
class="progress"
stroke="#a4bfb8"
stroke-width="8"
fill="transparent"
r="110"
cx="128"
cy="128"/>
<circle
class="handle"
stroke="#fff"
stroke-width="6"
fill="#a4bfb8"
r="15"
cx="128"
cy="128"/>
<line x1="155" y1="96" x2="96" y2="160" stroke="#e5e2d7" stroke-width="8" />
<text x="118" y="120"
class="user-score"
font-size="48"
font-family="futura-pt"
font-weight="bold"
fill="#a4bfb8"
text-anchor="end"
letter-spacing="-2"
alignment-baseline="bottom">
4.2
</text>
<text x="130" y="170"
font-size="48"
font-family="futura-pt"
font-weight="bold"
fill="#e5e2d7"
text-anchor="start"
alignment-baseline="top">
5
</text>
</svg>
<input
value="30"
type="number"
step="5"
min="0"
max="100"
placeholder="progress"
>
<div class="coords"></div>
html, body {
background-color: #fff;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
position: relative;
font-family: monospace;
}
circle.progress {
transform: rotate(-90deg);
transform-origin: 50% 50%;
}
input {
position: fixed;
top: 10px;
left: 10px;
width: 80px;
}
div.coords {
position: absolute;
left: 50%;
margin-left: 150px;
width: 200px;
}
// Get circle parameters
var circle = document.querySelector('circle.progress');
var radius = circle.r.baseVal.value;
var circumference = radius * 2 * Math.PI;
var originX = circle.cx.baseVal.value;
var originY = circle.cy.baseVal.value;
var user_score = document.querySelector('text.user-score');
var handle = document.querySelector('circle.handle');
var coords = document.querySelector('div.coords');
// Assign initial stroke settings based on the circumference
circle.style.strokeDasharray = `${circumference} ${circumference}`;
circle.style.strokeDashoffset = `${circumference}`;
// Change the progress amount between 0 to 100
// We reverse the percentage and subtract circumference to go counter-clockwise.
function setProgress(percent) {
// For debugging, adjust the number to match the percentage. In production the percentage is just based on the amount.
user_score.innerHTML = Math.round( ((percent/100) * 5) * 10 ) / 10;
var reverse_percent = 100 - percent;
const offset = reverse_percent / 100 * circumference;
circle.style.strokeDashoffset = -1 * offset;
setHandleRotation(percent);
}
// Position the handle at the end of the stroke
// Percent will be between 0 to 100.
function setHandleRotation(percent) {
// 0% = 90 degrees
// 25% = 180 degrees
// 50% = 270 degrees
// 75% = 360 degrees
// 100% = 90 degrees (same as 0%)
var angle = (180 + (percent*3.6) ) % 360;
// Convert degrees to radians
var angle_radians = angle * Math.PI / 180;
var xOffset = radius * ( Math.sin( angle_radians ) );
var yOffset = radius * ( Math.cos( angle_radians ) );
var x = originX + xOffset;
var y = originY + yOffset;
handle.attributes.cx.value = x;
handle.attributes.cy.value = y;
coords.innerHTML =
'Percent: ' + percent + '<br>' +
'Center X: ' + originX + '<br>' +
'Center Y: ' + originY + '<br>' +
'Angle (Degrees): ' + angle + '<br>' +
'Angle (Radians): ' + (Math.round(100*angle_radians)/100) + '<br>' +
'X: ' + (Math.round(100*x)/100) + '<br>' +
'Y: ' + (Math.round(100*y)/100) + '<br>'
;
console.log( angle, xOffset, yOffset );
}
// DEBUG: Use input to change value
const input = document.querySelector('input');
input.value = Math.round( Math.random() * 100 ); // initialize with random percentage
setProgress(input.value);
input.addEventListener('change', function(e) {
if (input.value < 101 && input.value > -1) {
setProgress(input.value);
}
})
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.