@zumer/orbit 1.4.11 → 1.4.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/orbit.js +79 -3
- package/dist/orbit.min.js +39 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
|
|
19
19
|
Radial UIs usually need JavaScript to compute angles, radii, and positions. **Orbit** handles all of that with CSS classes and a couple of Web Components. Drop in two files and start building.
|
|
20
20
|
|
|
21
|
+
> **Want ready-made components?** [**orbit-kit**](https://zumerlab.com/orbit-kit) wraps the common Orbit patterns into one-line custom elements — gauges, charts, activity rings, knobs, pie menus, cockpit instruments, analog clocks, compasses and radars.
|
|
22
|
+
|
|
21
23
|
## Installation
|
|
22
24
|
|
|
23
25
|
**CDN (fastest):**
|
|
@@ -172,6 +174,7 @@ asking the model to build a radial UI.
|
|
|
172
174
|
|
|
173
175
|
## Resources
|
|
174
176
|
|
|
177
|
+
- [orbit-kit](https://zumerlab.com/orbit-kit) — ready-made radial components built on Orbit
|
|
175
178
|
- [Full documentation](https://zumerlab.github.io/orbit-docs) — elements, tools, advanced examples
|
|
176
179
|
- [Contributing](CONTRIBUTING.md)
|
|
177
180
|
- [GitHub Discussions](https://github.com/zumerlab/orbit/discussions)
|
package/dist/orbit.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* orbit
|
|
3
|
-
* v.1.4.
|
|
3
|
+
* v.1.4.12
|
|
4
4
|
* Author Juan Martin Muda - Zumerlab
|
|
5
5
|
* License MIT
|
|
6
6
|
*/
|
|
@@ -273,9 +273,17 @@
|
|
|
273
273
|
overflow: visible;
|
|
274
274
|
pointer-events: none;
|
|
275
275
|
}
|
|
276
|
+
/* Display element by default: never steals clicks (see orbit-arc).
|
|
277
|
+
Interaction is opt-in via the "interactive" attribute. */
|
|
276
278
|
svg * {
|
|
279
|
+
pointer-events: none;
|
|
280
|
+
}
|
|
281
|
+
:host([interactive]) svg * {
|
|
277
282
|
pointer-events: visiblePainted;
|
|
278
283
|
}
|
|
284
|
+
:host([interactive]) {
|
|
285
|
+
cursor: pointer;
|
|
286
|
+
}
|
|
279
287
|
.progress-bar {
|
|
280
288
|
fill: var(--o-fill);
|
|
281
289
|
stroke: var(--o-stroke);
|
|
@@ -288,6 +296,23 @@
|
|
|
288
296
|
stroke: var(--o-back-stroke);
|
|
289
297
|
stroke-width: var(--o-back-stroke-width);
|
|
290
298
|
}
|
|
299
|
+
/* variant="stroke": the thin, legible gauge (registro "medidor").
|
|
300
|
+
The default band is a FILLED donut wedge, so everyone building a
|
|
301
|
+
thin gauge tripped on --o-fill/--o-back-fill. With this variant the
|
|
302
|
+
paths are open arcs and the data color lives where you expect it:
|
|
303
|
+
--o-stroke for the bar, --o-back-stroke for the track. */
|
|
304
|
+
:host([variant="stroke"]) .progress-bar {
|
|
305
|
+
fill: none;
|
|
306
|
+
stroke: var(--o-stroke);
|
|
307
|
+
stroke-width: var(--o-stroke-width, 2);
|
|
308
|
+
stroke-linecap: round;
|
|
309
|
+
}
|
|
310
|
+
:host([variant="stroke"]) .progress-bg {
|
|
311
|
+
fill: none;
|
|
312
|
+
stroke: var(--o-back-stroke, var(--o-gray-light));
|
|
313
|
+
stroke-width: var(--o-back-stroke-width, 1);
|
|
314
|
+
stroke-linecap: round;
|
|
315
|
+
}
|
|
291
316
|
</style>
|
|
292
317
|
<svg viewBox="0 0 100 100">
|
|
293
318
|
<path class="progress-bg" shape-rendering="geometricPrecision" vector-effect="non-scaling-stroke"></path>
|
|
@@ -309,11 +334,28 @@
|
|
|
309
334
|
}
|
|
310
335
|
update() {
|
|
311
336
|
const attrs = this.getAttributes();
|
|
312
|
-
const
|
|
313
|
-
const
|
|
337
|
+
const isStroke = this.getAttribute("variant") === "stroke";
|
|
338
|
+
const dBg = isStroke ? this.calculateStrokeArc(attrs, true) : this.calculateArcParameters(attrs, true);
|
|
339
|
+
const dBar = isStroke ? this.calculateStrokeArc(attrs, false) : this.calculateArcParameters(attrs, false);
|
|
314
340
|
this.shadowRoot.querySelector(".progress-bg").setAttribute("d", dBg);
|
|
315
341
|
this.shadowRoot.querySelector(".progress-bar").setAttribute("d", dBar);
|
|
316
342
|
}
|
|
343
|
+
/**
|
|
344
|
+
* variant="stroke": open arc along the orbit radius (no closed band),
|
|
345
|
+
* stroked by CSS. Same progress math as the band variant.
|
|
346
|
+
*/
|
|
347
|
+
calculateStrokeArc(attrs, full) {
|
|
348
|
+
const { realRadius } = attrs;
|
|
349
|
+
const arcAngle = Math.max(0, Math.min(this.getProgressAngle(attrs, full), 359.99));
|
|
350
|
+
const a0 = -90 * (Math.PI / 180);
|
|
351
|
+
const a1 = (-90 + arcAngle) * (Math.PI / 180);
|
|
352
|
+
const x0 = 50 + realRadius * Math.cos(a0);
|
|
353
|
+
const y0 = 50 + realRadius * Math.sin(a0);
|
|
354
|
+
const x1 = 50 + realRadius * Math.cos(a1);
|
|
355
|
+
const y1 = 50 + realRadius * Math.sin(a1);
|
|
356
|
+
const largeArcFlag = arcAngle > 180 ? 1 : 0;
|
|
357
|
+
return `M ${x0},${y0} A ${realRadius},${realRadius} 0 ${largeArcFlag} 1 ${x1},${y1}`;
|
|
358
|
+
}
|
|
317
359
|
getAttributes() {
|
|
318
360
|
const common = super.getCommonAttributes(this);
|
|
319
361
|
const range = parseFloat(getComputedStyle(this).getPropertyValue("--o-range") || 360);
|
|
@@ -368,9 +410,19 @@
|
|
|
368
410
|
overflow: visible;
|
|
369
411
|
pointer-events: none;
|
|
370
412
|
}
|
|
413
|
+
/* Arcs are display elements by default: they must NOT steal clicks from
|
|
414
|
+
satellites/controls nearby (a painted arc used to capture clicks even
|
|
415
|
+
at opacity 0, and pointer-events:none on the host could not pierce the
|
|
416
|
+
shadow). Interaction is opt-in via the "interactive" attribute. */
|
|
371
417
|
svg * {
|
|
418
|
+
pointer-events: none;
|
|
419
|
+
}
|
|
420
|
+
:host([interactive]) svg * {
|
|
372
421
|
pointer-events: visiblePainted;
|
|
373
422
|
}
|
|
423
|
+
:host([interactive]) {
|
|
424
|
+
cursor: pointer;
|
|
425
|
+
}
|
|
374
426
|
#orbitShape {
|
|
375
427
|
fill: var(--o-fill);
|
|
376
428
|
stroke: var(--o-stroke);
|
|
@@ -444,6 +496,30 @@
|
|
|
444
496
|
}
|
|
445
497
|
textPath.parentElement.style.fontSize = `calc(${fontSize} * (100 / (${length}) * (12 / var(--o-orbit-number)))`;
|
|
446
498
|
textPath.textContent = this.textContent;
|
|
499
|
+
this.warnIfTextOverflows(orbitPath, textPath, fitRange);
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Curved text has an explicit angular budget: glyphs past the end of the
|
|
503
|
+
* arc path are clipped SILENTLY by SVG. Measure and warn so nobody loses
|
|
504
|
+
* time to invisible truncation (~20 chars in 96° at default sizes).
|
|
505
|
+
* fit-range squeezes the text to the path via textLength, so it never clips.
|
|
506
|
+
*/
|
|
507
|
+
warnIfTextOverflows(orbitPath, textPath, fitRange) {
|
|
508
|
+
const raw = (this.textContent || "").trim();
|
|
509
|
+
if (!raw || fitRange || !this.isConnected) return;
|
|
510
|
+
requestAnimationFrame(() => {
|
|
511
|
+
try {
|
|
512
|
+
const pathLen = orbitPath.getTotalLength();
|
|
513
|
+
const textLen = textPath.parentElement.getComputedTextLength();
|
|
514
|
+
if (pathLen > 0 && textLen > pathLen && this._truncWarned !== raw) {
|
|
515
|
+
this._truncWarned = raw;
|
|
516
|
+
console.warn(
|
|
517
|
+
`[orbit] <o-arc> text "${raw.length > 34 ? raw.slice(0, 34) + "\u2026" : raw}" overflows its arc (${Math.round(textLen)} > ${Math.round(pathLen)} units) and will clip. Shorten the text, widen --o-range, or use fit-range to squeeze it.`
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
} catch (e) {
|
|
521
|
+
}
|
|
522
|
+
});
|
|
447
523
|
}
|
|
448
524
|
getAttributes() {
|
|
449
525
|
const common = super.getCommonAttributes(this);
|
package/dist/orbit.min.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* orbit
|
|
3
|
-
* v.1.4.
|
|
3
|
+
* v.1.4.12
|
|
4
4
|
* Author Juan Martin Muda - Zumerlab
|
|
5
5
|
* License MIT
|
|
6
6
|
*/
|
|
7
|
-
(()=>{var b=class extends HTMLElement{constructor(){super()}getCommonAttributes(t){let r=parseFloat(getComputedStyle(t).getPropertyValue("r")||0),e=parseFloat(getComputedStyle(t).getPropertyValue("--o-orbit-number")||1),s=parseFloat(getComputedStyle(t).getPropertyValue("--o-size-ratio")||1),n=parseFloat(getComputedStyle(t).getPropertyValue("--o-stroke-width")||1),o=t.getAttribute("shape")||"none",l=r/e*s-n+.3,a=r>0?l/2*100/r/2:0,i=0;t.classList.contains("outer-orbit")?i=a:t.classList.contains("quarter-outer-orbit")?i=a*-.5:t.classList.contains("inner-orbit")?i=a*-1:t.classList.contains("quarter-inner-orbit")&&(i=a*.5);let c=50+i;return{orbitRadius:r,arcHeight:l,realRadius:c,arcAngle:0,shape:o,arcHeightPercentage:a,orbitNumber:e,size:s,strokeWidth:n}}getProgressAngle(t,r,e=100){return r/e*t}getControlPoint(t,r,e,s,n="clockwise"){let o=(t+e)/2,l=(r+s)/2,a=e-t,i=s-r;return n==="clockwise"?{xc:o+i*.4,yc:l-a*.4}:{xc:o-i*.4,yc:l+a*.4}}arcPoint(t,r,e=0,s=0){let n=t+e,o=r+s*Math.PI/180;return{x:50+n*Math.cos(o),y:50+n*Math.sin(o)}}calculateCommonArcParameters(t,r,e,s,n,o,l,a=0){let i=Math.PI/2,c=t*Math.PI/180,h=r+e,g=r-e!==0?r-e:r,u=(a+o*1.25)/s/h,d=(a+o*1.25)/s/g,$=u-i,p=c-u-i,A=d-i,P=c-d-i,
|
|
7
|
+
(()=>{var b=class extends HTMLElement{constructor(){super()}getCommonAttributes(t){let r=parseFloat(getComputedStyle(t).getPropertyValue("r")||0),e=parseFloat(getComputedStyle(t).getPropertyValue("--o-orbit-number")||1),s=parseFloat(getComputedStyle(t).getPropertyValue("--o-size-ratio")||1),n=parseFloat(getComputedStyle(t).getPropertyValue("--o-stroke-width")||1),o=t.getAttribute("shape")||"none",l=r/e*s-n+.3,a=r>0?l/2*100/r/2:0,i=0;t.classList.contains("outer-orbit")?i=a:t.classList.contains("quarter-outer-orbit")?i=a*-.5:t.classList.contains("inner-orbit")?i=a*-1:t.classList.contains("quarter-inner-orbit")&&(i=a*.5);let c=50+i;return{orbitRadius:r,arcHeight:l,realRadius:c,arcAngle:0,shape:o,arcHeightPercentage:a,orbitNumber:e,size:s,strokeWidth:n}}getProgressAngle(t,r,e=100){return r/e*t}getControlPoint(t,r,e,s,n="clockwise"){let o=(t+e)/2,l=(r+s)/2,a=e-t,i=s-r;return n==="clockwise"?{xc:o+i*.4,yc:l-a*.4}:{xc:o-i*.4,yc:l+a*.4}}arcPoint(t,r,e=0,s=0){let n=t+e,o=r+s*Math.PI/180;return{x:50+n*Math.cos(o),y:50+n*Math.sin(o)}}calculateCommonArcParameters(t,r,e,s,n,o,l,a=0){let i=Math.PI/2,c=t*Math.PI/180,h=r+e,g=r-e!==0?r-e:r,u=(a+o*1.25)/s/h,d=(a+o*1.25)/s/g,$=u-i,p=c-u-i,A=d-i,P=c-d-i,v=this.arcPoint(h,$),f=this.arcPoint(h,p),k=this.arcPoint(g,A),y=this.arcPoint(g,P),C=p-$,R=P-A,m=C>Math.PI?1:0,I=R>Math.PI?1:0;return{upperArcStart:v,upperArcEnd:f,innerArcStart:k,innerArcEnd:y,largeArcFlag:m,largeArcFlagUpper:m,largeArcFlagInner:I,bigRadius:h,smallRadius:g,radius:r,upperAngleStart:$,upperAngleEnd:p,innerAngleStart:A,innerAngleEnd:P}}generatePathData(t,r,e,s){let n="";switch(t){case"rounded":n=this.generateRoundedPath(r,e,s);break;case"circle":case"circle-a":case"bullet":n=this.generateCirclePath(r,t);break;case"circle-b":n=this.generateCircleBPath(r,e,s);break;case"arrow":n=this.generateArrowPath(r,s);break;case"backslash":case"slash":n=this.generateSlashPath(r,t,s);break;case"zigzag":n=this.generateZigzagPath(r,e,s);break;default:n=this.generateDefaultPath(r)}return n}generateRoundedPath(t,r,e){let{bigRadius:s,smallRadius:n}=t,o=r<10?5:r<5?2.5:10,l=o/e*Math.PI/180,a=t.upperAngleEnd-t.upperAngleStart-2*l>Math.PI?1:0,i=t.innerAngleEnd-t.innerAngleStart-2*l>Math.PI?1:0,c=this.arcPoint(s,t.upperAngleStart,0,o/e),h=this.arcPoint(s,t.upperAngleEnd,0,-o/e),g=this.arcPoint(n,t.innerAngleStart,0,o/e),u=this.arcPoint(n,t.innerAngleEnd,0,-o/e),d=this.arcPoint(s,t.upperAngleStart,-(o/2)/e,0),$=this.arcPoint(s,t.upperAngleEnd,-(o/2)/e,0),p=this.arcPoint(n,t.innerAngleStart,o/2/e,0),A=this.arcPoint(n,t.innerAngleEnd,o/2/e,0),P=this.getControlPoint(h.x,h.y,$.x,$.y),v=this.getControlPoint(A.x,A.y,u.x,u.y),f=this.getControlPoint(g.x,g.y,p.x,p.y),k=this.getControlPoint(d.x,d.y,c.x,c.y),y=`M ${c.x},${c.y} A ${s},${s} 0 ${a} 1 ${h.x},${h.y}`;return y+=`Q ${P.xc},${P.yc} ${$.x},${$.y} L ${A.x},${A.y}`,y+=`Q ${v.xc},${v.yc} ${u.x},${u.y}`,y+=`A ${n},${n} 0 ${i} 0 ${g.x},${g.y}`,y+=`Q ${f.xc},${f.yc} ${p.x},${p.y} L ${d.x},${d.y}`,y+=` Q ${k.xc},${k.yc} ${c.x},${c.y}`,y+=" Z",y}generateCirclePath(t,r){let{upperArcStart:e,upperArcEnd:s,innerArcStart:n,innerArcEnd:o,bigRadius:l,smallRadius:a,largeArcFlagUpper:i,largeArcFlagInner:c}=t,h=`M ${e.x},${e.y} A ${l},${l} 0 ${i} 1 ${s.x},${s.y}`;return h+=` A 1,1 0 0 1 ${o.x},${o.y} `,h+=` A ${a},${a} 0 ${c} 0 ${n.x},${n.y}`,h+=` A 1,1 0 0 ${r==="circle"||r==="circle-a"?1:0} ${e.x},${e.y} `,h+=" Z",h}generateCircleBPath(t,r,e){let{upperAngleStart:s,upperAngleEnd:n,innerAngleStart:o,innerAngleEnd:l,bigRadius:a,smallRadius:i}=t,c=r*1.36,h=c/e*Math.PI/180,g=n-s-2*h>Math.PI?1:0,u=l-o-2*h>Math.PI?1:0,d=this.arcPoint(a,s,0,c/e),$=this.arcPoint(a,n,0,-c/e),p=this.arcPoint(i,o,0,c/e),A=this.arcPoint(i,l,0,-c/e),P=`M ${d.x},${d.y} A ${a},${a} 0 ${g} 1 ${$.x},${$.y}`;return P+=` A 1,1 0 0 1 ${A.x},${A.y} `,P+=` A ${i},${i} 0 ${u} 0 ${p.x},${p.y}`,P+=` A 1,1 0 0 1 ${d.x},${d.y} `,P+=" Z",P}generateArrowPath(t,r){let{upperArcStart:e,upperArcEnd:s,innerArcStart:n,innerArcEnd:o,bigRadius:l,smallRadius:a,largeArcFlagUpper:i,largeArcFlagInner:c,radius:h}=t,g=this.arcPoint(h,t.upperAngleEnd,0,24/r/2),u=this.arcPoint(h,t.upperAngleStart,0,24/r/2),d=`M ${e.x},${e.y} A ${l},${l} 0 ${i} 1 ${s.x},${s.y}`;return d+=`L ${g.x} ${g.y}`,d+=`L ${o.x} ${o.y}`,d+=`A ${a},${a} 0 ${c} 0 ${n.x}, ${n.y}`,d+=`L ${u.x} ${u.y}`,d+="Z",d}generateSlashPath(t,r,e){let{upperAngleStart:s,upperAngleEnd:n,innerAngleStart:o,innerAngleEnd:l,bigRadius:a,smallRadius:i,largeArcFlagUpper:c,largeArcFlagInner:h}=t,g=this.arcPoint(a,s,0,r==="backslash"?0:24/e/2),u=this.arcPoint(a,n,0,r==="backslash"?0:24/e/2),d=this.arcPoint(i,o,0,r==="backslash"?24/e/2:0),$=this.arcPoint(i,l,0,r==="backslash"?24/e/2:0),p=`M ${g.x},${g.y} A ${a},${a} 0 ${c} 1 ${u.x},${u.y}`;return p+=`L ${$.x} ${$.y}`,p+=`A ${i},${i} 0 ${h} 0 ${d.x}, ${d.y}`,p+="Z",p}generateZigzagPath(t,r,e){let{upperArcStart:s,upperArcEnd:n,innerArcStart:o,innerArcEnd:l,bigRadius:a,smallRadius:i,largeArcFlagUpper:c,largeArcFlagInner:h,radius:g}=t,u=r/e/2,d=this.arcPoint(g,t.upperAngleStart,-u,3),$=this.arcPoint(g,t.upperAngleStart,0,0),p=this.arcPoint(g,t.upperAngleStart,u,3),A=this.arcPoint(g,t.innerAngleEnd,u,3),P=this.arcPoint(g,t.innerAngleEnd,0,0),v=this.arcPoint(g,t.innerAngleEnd,-u,3),f=`M ${s.x},${s.y} A ${a},${a} 0 ${c} 1 ${n.x},${n.y}`;return f+=`L ${A.x} ${A.y}`,f+=`L ${P.x} ${P.y}`,f+=`L ${v.x} ${v.y}`,f+=`L ${l.x} ${l.y}`,f+=`A ${i},${i} 0 ${h} 0 ${o.x}, ${o.y}`,f+=`L ${d.x} ${d.y}`,f+=`L ${$.x} ${$.y}`,f+=`L ${p.x} ${p.y}`,f+="Z",f}generateDefaultPath(t){let{upperArcStart:r,upperArcEnd:e,innerArcStart:s,innerArcEnd:n,bigRadius:o,smallRadius:l,largeArcFlagUpper:a,largeArcFlagInner:i}=t,c=`M ${r.x},${r.y} A ${o},${o} 0 ${a} 1 ${e.x},${e.y}`;return c+=`L ${n.x} ${n.y}`,c+=`A ${l},${l} 0 ${i} 0 ${s.x}, ${s.y}`,c+="Z",c}};var S=class extends b{constructor(){super(),this.attachShadow({mode:"open"}),this.shadowRoot.innerHTML=`
|
|
8
8
|
<style>
|
|
9
9
|
:host {
|
|
10
10
|
--o-fill: var(--o-gray-light);
|
|
@@ -28,9 +28,17 @@
|
|
|
28
28
|
overflow: visible;
|
|
29
29
|
pointer-events: none;
|
|
30
30
|
}
|
|
31
|
+
/* Display element by default: never steals clicks (see orbit-arc).
|
|
32
|
+
Interaction is opt-in via the "interactive" attribute. */
|
|
31
33
|
svg * {
|
|
34
|
+
pointer-events: none;
|
|
35
|
+
}
|
|
36
|
+
:host([interactive]) svg * {
|
|
32
37
|
pointer-events: visiblePainted;
|
|
33
38
|
}
|
|
39
|
+
:host([interactive]) {
|
|
40
|
+
cursor: pointer;
|
|
41
|
+
}
|
|
34
42
|
.progress-bar {
|
|
35
43
|
fill: var(--o-fill);
|
|
36
44
|
stroke: var(--o-stroke);
|
|
@@ -43,12 +51,29 @@
|
|
|
43
51
|
stroke: var(--o-back-stroke);
|
|
44
52
|
stroke-width: var(--o-back-stroke-width);
|
|
45
53
|
}
|
|
54
|
+
/* variant="stroke": the thin, legible gauge (registro "medidor").
|
|
55
|
+
The default band is a FILLED donut wedge, so everyone building a
|
|
56
|
+
thin gauge tripped on --o-fill/--o-back-fill. With this variant the
|
|
57
|
+
paths are open arcs and the data color lives where you expect it:
|
|
58
|
+
--o-stroke for the bar, --o-back-stroke for the track. */
|
|
59
|
+
:host([variant="stroke"]) .progress-bar {
|
|
60
|
+
fill: none;
|
|
61
|
+
stroke: var(--o-stroke);
|
|
62
|
+
stroke-width: var(--o-stroke-width, 2);
|
|
63
|
+
stroke-linecap: round;
|
|
64
|
+
}
|
|
65
|
+
:host([variant="stroke"]) .progress-bg {
|
|
66
|
+
fill: none;
|
|
67
|
+
stroke: var(--o-back-stroke, var(--o-gray-light));
|
|
68
|
+
stroke-width: var(--o-back-stroke-width, 1);
|
|
69
|
+
stroke-linecap: round;
|
|
70
|
+
}
|
|
46
71
|
</style>
|
|
47
72
|
<svg viewBox="0 0 100 100">
|
|
48
73
|
<path class="progress-bg" shape-rendering="geometricPrecision" vector-effect="non-scaling-stroke"></path>
|
|
49
74
|
<path class="progress-bar" shape-rendering="geometricPrecision" vector-effect="non-scaling-stroke"></path>
|
|
50
75
|
</svg>
|
|
51
|
-
`}connectedCallback(){this.update(),this.setupObserver()}setupObserver(){this.observer=new MutationObserver(t=>{this.observer.disconnect(),t.forEach(()=>this.update()),this.observer.observe(this,{attributes:!0,childList:!0})}),this.observer.observe(this,{attributes:!0,childList:!0})}update(){let t=this.getAttributes(),r=this.calculateArcParameters(t,!0),
|
|
76
|
+
`}connectedCallback(){this.update(),this.setupObserver()}setupObserver(){this.observer=new MutationObserver(t=>{this.observer.disconnect(),t.forEach(()=>this.update()),this.observer.observe(this,{attributes:!0,childList:!0})}),this.observer.observe(this,{attributes:!0,childList:!0})}update(){let t=this.getAttributes(),r=this.getAttribute("variant")==="stroke",e=r?this.calculateStrokeArc(t,!0):this.calculateArcParameters(t,!0),s=r?this.calculateStrokeArc(t,!1):this.calculateArcParameters(t,!1);this.shadowRoot.querySelector(".progress-bg").setAttribute("d",e),this.shadowRoot.querySelector(".progress-bar").setAttribute("d",s)}calculateStrokeArc(t,r){let{realRadius:e}=t,s=Math.max(0,Math.min(this.getProgressAngle(t,r),359.99)),n=-90*(Math.PI/180),o=(-90+s)*(Math.PI/180),l=50+e*Math.cos(n),a=50+e*Math.sin(n),i=50+e*Math.cos(o),c=50+e*Math.sin(o),h=s>180?1:0;return`M ${l},${a} A ${e},${e} 0 ${h} 1 ${i},${c}`}getAttributes(){let t=super.getCommonAttributes(this),r=parseFloat(getComputedStyle(this).getPropertyValue("--o-range")||360),e=parseFloat(getComputedStyle(this).getPropertyValue("--o-progress")||this.getAttribute("value")||0),s=parseFloat(this.getAttribute("max"))||100;return{...t,range:r,progress:e,maxValue:s}}getProgressAngle(t,r){let{range:e,progress:s,maxValue:n}=t;return r?(n-1e-5)/n*e:s/n*e}calculateArcParameters(t,r){let{shape:e,realRadius:s,arcHeightPercentage:n,orbitNumber:o,strokeWidth:l,arcHeight:a}=t,i=this.getProgressAngle(t,r),c=super.calculateCommonArcParameters(i,s,n,o,e,l,a);return super.generatePathData(e,c,a,o)}};var E=document.createElement("template");E.innerHTML=`
|
|
52
77
|
<style>
|
|
53
78
|
:host {
|
|
54
79
|
--o-fill: var(--o-gray-light);
|
|
@@ -68,9 +93,19 @@
|
|
|
68
93
|
overflow: visible;
|
|
69
94
|
pointer-events: none;
|
|
70
95
|
}
|
|
96
|
+
/* Arcs are display elements by default: they must NOT steal clicks from
|
|
97
|
+
satellites/controls nearby (a painted arc used to capture clicks even
|
|
98
|
+
at opacity 0, and pointer-events:none on the host could not pierce the
|
|
99
|
+
shadow). Interaction is opt-in via the "interactive" attribute. */
|
|
71
100
|
svg * {
|
|
101
|
+
pointer-events: none;
|
|
102
|
+
}
|
|
103
|
+
:host([interactive]) svg * {
|
|
72
104
|
pointer-events: visiblePainted;
|
|
73
105
|
}
|
|
106
|
+
:host([interactive]) {
|
|
107
|
+
cursor: pointer;
|
|
108
|
+
}
|
|
74
109
|
#orbitShape {
|
|
75
110
|
fill: var(--o-fill);
|
|
76
111
|
stroke: var(--o-stroke);
|
|
@@ -93,4 +128,4 @@
|
|
|
93
128
|
<textPath href="#orbitPath" alignment-baseline="middle"></textPath>
|
|
94
129
|
</text>
|
|
95
130
|
</svg>
|
|
96
|
-
`;var w=class extends b{constructor(){super(),this.attachShadow({mode:"open"}),this.shadowRoot.appendChild(E.content.cloneNode(!0))}connectedCallback(){this.update(),this.setupObservers()}disconnectedCallback(){this.observer&&this.observer.disconnect(),this.textObserver&&this.textObserver.disconnect()}setupObservers(){this.observer=new MutationObserver(t=>{this.observer.disconnect(),t.forEach(()=>this.update()),this.observer.observe(this,{attributes:!0,childList:!0})}),this.observer.observe(this,{attributes:!0,childList:!0}),this.textObserver=new MutationObserver(()=>{let t=this.shadowRoot.querySelector("textPath");t.textContent=this.textContent}),this.textObserver.observe(this,{characterData:!0,subtree:!0})}update(){let t=this.getAttributes(),{length:r,fontSize:e,textAnchor:s,fitRange:n}=t,o=this.shadowRoot.querySelector("#orbitPath"),l=this.shadowRoot.querySelector("#orbitShape"),a=this.shadowRoot.querySelector("textPath");l.setAttribute("d",this.calculateArcParameters(t).dShape),o.setAttribute("d",this.calculateTextArcParameters(t).dPath),s==="start"?(a.setAttribute("startOffset","0%"),a.setAttribute("text-anchor","start")):s==="middle"?(a.setAttribute("startOffset","50%"),a.setAttribute("text-anchor","middle")):s==="end"&&(a.setAttribute("startOffset","100%"),a.setAttribute("text-anchor","end")),n&&a.parentElement.setAttribute("textLength",o.getTotalLength()),a.parentElement.style.fontSize=`calc(${e} * (100 / (${r}) * (12 / var(--o-orbit-number)))`,a.textContent=this.textContent}getAttributes(){let t=super.getCommonAttributes(this),r,e=this.hasAttribute("flip")||this.classList.contains("flip"),s=this.hasAttribute("fit-range")||this.classList.contains("fit-range")||!1,n=parseFloat(getComputedStyle(this).getPropertyValue("--o-force"))||100,o=this.getAttribute("text-anchor")||"middle",l=getComputedStyle(this).getPropertyValue("font-size")||getComputedStyle(this).getPropertyValue("--font-size"),a=parseFloat(getComputedStyle(this).getPropertyValue("--o-range")||360),i=parseFloat(this.getAttribute("value")),c=parseFloat(getComputedStyle(this).getPropertyValue("--o-gap"))||1;if(i){r=super.getProgressAngle(a,i);let h=this.previousElementSibling,g=h?parseFloat(getComputedStyle(h).getPropertyValue("--o_stack")):0;this.style.setProperty("--o_stack",g+r),g>=0&&e&&this.style.setProperty("--o-angle-composite",parseFloat(g)+"deg"),g>0&&!e&&this.style.setProperty("--o-angle-composite",parseFloat(g)+"deg")}else{let h=getComputedStyle(this).getPropertyValue("--o-angle");r=this.calcularExpresionCSS(h)}return{...t,gap:c,arcAngle:r,flip:e,fitRange:s,length:n,fontSize:l,textAnchor:o}}calculateArcParameters(t){let{arcAngle:r,realRadius:e,arcHeightPercentage:s,orbitNumber:n,shape:o,strokeWidth:l,arcHeight:a,gap:i}=t,c=super.calculateCommonArcParameters(r,e,s,n,o,l,a,i);return{dShape:super.generatePathData(o,c,a,n)}}calculateTextArcParameters(t){let{arcAngle:r,realRadius:e,gap:s,flip:n}=t,o=s*.5,l=n?0:1,a=r<=180?0:1,i=50+e*Math.cos((-90+o)*(Math.PI/180)),c=50+e*Math.sin((-90+o)*(Math.PI/180)),h=50+e*Math.cos((r-90-o)*Math.PI/180),g=50+e*Math.sin((r-90-o)*Math.PI/180),[u,d,$,p]=n?[h,g,i,c]:[i,c,h,g];return{dPath:`M ${u},${d} A ${e},${e} 0 ${a} ${l} ${$},${p}`}}calcularExpresionCSS(t){let r=t.match(/calc\(\s*([\d.]+)deg\s*\/\s*\(\s*(\d+)\s*-\s*(\d+)\s*\)\s*\)/);if(r){let e=parseFloat(r[1]),s=parseInt(r[2])-parseInt(r[3]);if(!isNaN(e)&&!isNaN(s)&&s!==0)return e/s}return 0}};var
|
|
131
|
+
`;var w=class extends b{constructor(){super(),this.attachShadow({mode:"open"}),this.shadowRoot.appendChild(E.content.cloneNode(!0))}connectedCallback(){this.update(),this.setupObservers()}disconnectedCallback(){this.observer&&this.observer.disconnect(),this.textObserver&&this.textObserver.disconnect()}setupObservers(){this.observer=new MutationObserver(t=>{this.observer.disconnect(),t.forEach(()=>this.update()),this.observer.observe(this,{attributes:!0,childList:!0})}),this.observer.observe(this,{attributes:!0,childList:!0}),this.textObserver=new MutationObserver(()=>{let t=this.shadowRoot.querySelector("textPath");t.textContent=this.textContent}),this.textObserver.observe(this,{characterData:!0,subtree:!0})}update(){let t=this.getAttributes(),{length:r,fontSize:e,textAnchor:s,fitRange:n}=t,o=this.shadowRoot.querySelector("#orbitPath"),l=this.shadowRoot.querySelector("#orbitShape"),a=this.shadowRoot.querySelector("textPath");l.setAttribute("d",this.calculateArcParameters(t).dShape),o.setAttribute("d",this.calculateTextArcParameters(t).dPath),s==="start"?(a.setAttribute("startOffset","0%"),a.setAttribute("text-anchor","start")):s==="middle"?(a.setAttribute("startOffset","50%"),a.setAttribute("text-anchor","middle")):s==="end"&&(a.setAttribute("startOffset","100%"),a.setAttribute("text-anchor","end")),n&&a.parentElement.setAttribute("textLength",o.getTotalLength()),a.parentElement.style.fontSize=`calc(${e} * (100 / (${r}) * (12 / var(--o-orbit-number)))`,a.textContent=this.textContent,this.warnIfTextOverflows(o,a,n)}warnIfTextOverflows(t,r,e){let s=(this.textContent||"").trim();!s||e||!this.isConnected||requestAnimationFrame(()=>{try{let n=t.getTotalLength(),o=r.parentElement.getComputedTextLength();n>0&&o>n&&this._truncWarned!==s&&(this._truncWarned=s,console.warn(`[orbit] <o-arc> text "${s.length>34?s.slice(0,34)+"\u2026":s}" overflows its arc (${Math.round(o)} > ${Math.round(n)} units) and will clip. Shorten the text, widen --o-range, or use fit-range to squeeze it.`))}catch(n){}})}getAttributes(){let t=super.getCommonAttributes(this),r,e=this.hasAttribute("flip")||this.classList.contains("flip"),s=this.hasAttribute("fit-range")||this.classList.contains("fit-range")||!1,n=parseFloat(getComputedStyle(this).getPropertyValue("--o-force"))||100,o=this.getAttribute("text-anchor")||"middle",l=getComputedStyle(this).getPropertyValue("font-size")||getComputedStyle(this).getPropertyValue("--font-size"),a=parseFloat(getComputedStyle(this).getPropertyValue("--o-range")||360),i=parseFloat(this.getAttribute("value")),c=parseFloat(getComputedStyle(this).getPropertyValue("--o-gap"))||1;if(i){r=super.getProgressAngle(a,i);let h=this.previousElementSibling,g=h?parseFloat(getComputedStyle(h).getPropertyValue("--o_stack")):0;this.style.setProperty("--o_stack",g+r),g>=0&&e&&this.style.setProperty("--o-angle-composite",parseFloat(g)+"deg"),g>0&&!e&&this.style.setProperty("--o-angle-composite",parseFloat(g)+"deg")}else{let h=getComputedStyle(this).getPropertyValue("--o-angle");r=this.calcularExpresionCSS(h)}return{...t,gap:c,arcAngle:r,flip:e,fitRange:s,length:n,fontSize:l,textAnchor:o}}calculateArcParameters(t){let{arcAngle:r,realRadius:e,arcHeightPercentage:s,orbitNumber:n,shape:o,strokeWidth:l,arcHeight:a,gap:i}=t,c=super.calculateCommonArcParameters(r,e,s,n,o,l,a,i);return{dShape:super.generatePathData(o,c,a,n)}}calculateTextArcParameters(t){let{arcAngle:r,realRadius:e,gap:s,flip:n}=t,o=s*.5,l=n?0:1,a=r<=180?0:1,i=50+e*Math.cos((-90+o)*(Math.PI/180)),c=50+e*Math.sin((-90+o)*(Math.PI/180)),h=50+e*Math.cos((r-90-o)*Math.PI/180),g=50+e*Math.sin((r-90-o)*Math.PI/180),[u,d,$,p]=n?[h,g,i,c]:[i,c,h,g];return{dPath:`M ${u},${d} A ${e},${e} 0 ${a} ${l} ${$},${p}`}}calcularExpresionCSS(t){let r=t.match(/calc\(\s*([\d.]+)deg\s*\/\s*\(\s*(\d+)\s*-\s*(\d+)\s*\)\s*\)/);if(r){let e=parseFloat(r[1]),s=parseInt(r[2])-parseInt(r[3]);if(!isNaN(e)&&!isNaN(s)&&s!==0)return e/s}return 0}};var M={resize(x){let t=document.querySelector(x);if(!t){console.error("Orbit.resize: element not found:",x);return}let r=n=>{t.querySelectorAll(".gravity-spot").forEach(o=>{o.style.setProperty("--o-force-ratio",String(n/500))})},e=t.offsetWidth||t.getBoundingClientRect().width;e>0?r(e):requestAnimationFrame(()=>{e=t.offsetWidth||t.getBoundingClientRect().width,e>0&&r(e)}),new ResizeObserver(n=>{for(let o of n)o.contentRect.width>0&&r(o.contentRect.width)}).observe(t)}};customElements.get("o-progress")||customElements.define("o-progress",S);customElements.get("o-arc")||customElements.define("o-arc",w);window.Orbit=M;})();
|