omniloop-ai / components /progress-ring.js
00Boobs00's picture
Review revise and update with refactoring, refinement and optimization expanding this out to at least 4 times its origional size and magnitude.
3bcb678 verified
class ProgressRing extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
static get observedAttributes() {
return ['value', 'color', 'size'];
}
connectedCallback() {
this.animateValue();
}
attributeChangedCallback(name, oldValue, newValue) {
if (oldValue !== newValue && this.shadowRoot) {
this.render();
this.animateValue();
}
}
render() {
const value = this.getAttribute('value') || 0;
const color = this.getAttribute('color') || '#10b981';
const size = this.getAttribute('size') || 150;
this.shadowRoot.innerHTML = `
<style>
:host {
display: inline-block;
}
.progress-ring {
transform: rotate(-90deg);
}
.progress-ring__circle {
transition: stroke-dashoffset 0.5s ease-in-out;
transform-origin: 50% 50%;
}
</style>
<svg class="progress-ring" width="${size}" height="${size}">
<circle
class="progress-ring__circle-bg"
stroke="#1e293b"
stroke-width="12"
fill="transparent"
r="${size/2 - 12}"
cx="${size/2}"
cy="${size/2}"
/>
<circle
class="progress-ring__circle"
stroke="${color}"
stroke-width="12"
stroke-linecap="round"
fill="transparent"
r="${size/2 - 12}"
cx="${size/2}"
cy="${size/2}"
style="stroke-dasharray: ${2 * Math.PI * (size/2 - 12)}; stroke-dashoffset: ${2 * Math.PI * (size/2 - 12)}"
/>
</svg>
`;
}
animateValue() {
const circle = this.shadowRoot.querySelector('.progress-ring__circle');
const value = parseInt(this.getAttribute('value') || 0);
const radius = circle.r.baseVal.value;
const circumference = radius * 2 * Math.PI;
circle.style.strokeDasharray = `${circumference} ${circumference}`;
const offset = circumference - (value / 100) * circumference;
setTimeout(() => {
circle.style.strokeDashoffset = offset;
}, 100);
}
}
customElements.define('progress-ring', ProgressRing);