Spaces:
Running
Running
File size: 2,591 Bytes
3bcb678 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
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); |