058
Circular Progress with Value in Pure JavaScript Class
Svg-based circular progress indicator with value in pure JavaScript class.
Demo
0%
Source Code
Javascript
class CircularProgress {
width = 0;
height = 0;
cx = 0;
cy = 0;
r = 0;
namespace = "http://www.w3.org/2000/svg";
options = {
stroke: "DodgerBlue",
strokeWidth: 4,
strokeLineCap: "round",
hasTrack: true,
trackBackgroundColor: "WhiteSmoke",
};
constructor(selectorOrElement, options) {
this.svg = this.getSvgElement(selectorOrElement);
if (selectorOrElement === null) return;
if (options !== undefined && typeof options === "object") {
this.options = { ...this.options, ...options };
}
this.width = parseInt(this.svg.getAttribute("width"));
this.height = parseInt(this.svg.getAttribute("height"));
this.cx = this.width / 2;
this.cy = this.height / 2;
this.r = (this.width - this.options.strokeWidth) / 2;
this.svg.setAttribute("xmlns", this.namespace);
this.svg.setAttribute("x", "0");
this.svg.setAttribute("y", "0");
this.svg.setAttribute("viewBox", "0 0 " + this.width + " " + this.height);
this.svg.style.transform = "rotate(270deg)";
if (this.options.hasTrack) this.addTrack();
this.addBar();
}
isSVG(element) {
if (typeof element !== "object") return false;
if (!(element instanceof HTMLElement)) return false;
return element.tagName === "SVG";
}
getSvgElement(selectorOrElement) {
if (typeof selectorOrElement === "string") {
return document.querySelector(selectorOrElement);
}
if (this.isSVG(selectorOrElement)) {
return selectorOrElement;
}
return null
}
createBaseCircle() {
const circle = document.createElementNS(this.namespace, "circle");
circle.setAttribute("cx", this.cx.toString());
circle.setAttribute("cy", this.cy.toString());
circle.setAttribute("r", this.r.toString());
circle.setAttribute("fill", "none");
circle.setAttribute("stroke-width", this.options.strokeWidth.toString());
return circle;
}
addTrack() {
this.track = this.createBaseCircle();
this.track.setAttribute("stroke", this.options.trackBackgroundColor);
this.svg.appendChild(this.track);
}
addBar() {
this.bar = this.createBaseCircle();
this.bar.style.transition = "stroke-dashoffset 500ms";
this.bar.setAttribute("pathLength", "100");
this.bar.setAttribute("stroke", this.options.stroke);
this.bar.setAttribute("stroke-linecap", this.options.strokeLineCap);
this.bar.setAttribute("stroke-dasharray", "100");
this.bar.setAttribute("stroke-dashoffset", "100");
this.svg.appendChild(this.bar);
}
reset() {
this.bar.style.transition = "";
this.bar.setAttribute("stroke-dashoffset", "100");
setTimeout(() => {
this.bar.style.transition = "stroke-dashoffset 500ms";
})
}
set value(x) {
this.bar.setAttribute("stroke-dashoffset", (100 - x).toString());
}
}
HTML
This is how to use CircularProgress class along with HTML.
<svg width="64" height="64"></svg>
<div><span id="circular-progress-text">0</span>%</div>
<button id="load-button" type="button">Load</button>
<button id="cancel-button" type="button">Cancel</button>
<script src="./circular-progress.js"></script>
<script>
let timer;
let loaded = 0;
const circularProgress = new CircularProgress("svg");
const circularProgressText = document.getElementById("circular-progress-text");
const loadButton = document.getElementById("load-button");
const cancelButton = document.getElementById("cancel-button");
function fakeLoad() {
loaded += Math.round(Math.random() * 20);
loaded = Math.min(loaded, 100);
circularProgress.value = loaded;
circularProgressText.innerHTML = loaded.toString();
if (loaded < 100) {
timer = setTimeout(fakeLoad, Math.round(Math.random() * 500));
}
}
loadButton.onclick = function() {
loaded = 0;
circularProgress.reset();
setTimeout(fakeLoad);
}
cancelButton.onclick = function() {
clearTimeout(timer);
}
</script>
Download
You can download the sample code at: