@zumer/orbit 1.4.10 → 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 +15 -0
- package/dist/orbit.js +114 -26
- 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):**
|
|
@@ -158,8 +160,21 @@ Browse examples on the [Orbit docs site](https://zumerlab.github.io/orbit-docs):
|
|
|
158
160
|
|
|
159
161
|
---
|
|
160
162
|
|
|
163
|
+
## Using Orbit with AI / LLMs
|
|
164
|
+
|
|
165
|
+
Orbit's radial model is unlike the box-flow layouts most models were trained on,
|
|
166
|
+
so an assistant generating Orbit markup from scratch will struggle. Give it the
|
|
167
|
+
reference first — these files are written for that purpose:
|
|
168
|
+
|
|
169
|
+
- **[llms.txt](https://zumerlab.github.io/orbit-docs/llms.txt)** — concise overview, structure rules, quick recipes.
|
|
170
|
+
- **[llms-full.txt](https://zumerlab.github.io/orbit-docs/llms-full.txt)** — complete reference: every class, custom property, web component, and copy-paste pattern.
|
|
171
|
+
|
|
172
|
+
Paste the relevant one into your prompt (or your tool's context/rules) before
|
|
173
|
+
asking the model to build a radial UI.
|
|
174
|
+
|
|
161
175
|
## Resources
|
|
162
176
|
|
|
177
|
+
- [orbit-kit](https://zumerlab.com/orbit-kit) — ready-made radial components built on Orbit
|
|
163
178
|
- [Full documentation](https://zumerlab.github.io/orbit-docs) — elements, tools, advanced examples
|
|
164
179
|
- [Contributing](CONTRIBUTING.md)
|
|
165
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
|
*/
|
|
@@ -84,13 +84,19 @@
|
|
|
84
84
|
const upperArcEnd = this.arcPoint(bigRadius, upperAngleEnd);
|
|
85
85
|
const innerArcStart = this.arcPoint(smallRadius, innerAngleStart);
|
|
86
86
|
const innerArcEnd = this.arcPoint(smallRadius, innerAngleEnd);
|
|
87
|
-
const
|
|
87
|
+
const upperSweep = upperAngleEnd - upperAngleStart;
|
|
88
|
+
const innerSweep = innerAngleEnd - innerAngleStart;
|
|
89
|
+
const largeArcFlagUpper = upperSweep > Math.PI ? 1 : 0;
|
|
90
|
+
const largeArcFlagInner = innerSweep > Math.PI ? 1 : 0;
|
|
88
91
|
return {
|
|
89
92
|
upperArcStart,
|
|
90
93
|
upperArcEnd,
|
|
91
94
|
innerArcStart,
|
|
92
95
|
innerArcEnd,
|
|
93
|
-
largeArcFlag,
|
|
96
|
+
largeArcFlag: largeArcFlagUpper,
|
|
97
|
+
// back-compat alias; prefer the two below
|
|
98
|
+
largeArcFlagUpper,
|
|
99
|
+
largeArcFlagInner,
|
|
94
100
|
bigRadius,
|
|
95
101
|
smallRadius,
|
|
96
102
|
radius,
|
|
@@ -130,8 +136,11 @@
|
|
|
130
136
|
return d;
|
|
131
137
|
}
|
|
132
138
|
generateRoundedPath(params, arcHeight, orbitNumber) {
|
|
133
|
-
const {
|
|
139
|
+
const { bigRadius, smallRadius } = params;
|
|
134
140
|
const curve = arcHeight < 10 ? 5 : arcHeight < 5 ? 2.5 : 10;
|
|
141
|
+
const capRad = curve / orbitNumber * Math.PI / 180;
|
|
142
|
+
const flagU = params.upperAngleEnd - params.upperAngleStart - 2 * capRad > Math.PI ? 1 : 0;
|
|
143
|
+
const flagI = params.innerAngleEnd - params.innerAngleStart - 2 * capRad > Math.PI ? 1 : 0;
|
|
135
144
|
const newUpperStart = this.arcPoint(bigRadius, params.upperAngleStart, 0, curve / orbitNumber);
|
|
136
145
|
const newUpperEnd = this.arcPoint(bigRadius, params.upperAngleEnd, 0, -curve / orbitNumber);
|
|
137
146
|
const newInnerStart = this.arcPoint(smallRadius, params.innerAngleStart, 0, curve / orbitNumber);
|
|
@@ -144,10 +153,10 @@
|
|
|
144
153
|
const Q1 = this.getControlPoint(innerPointEnd.x, innerPointEnd.y, newInnerEnd.x, newInnerEnd.y);
|
|
145
154
|
const Q2 = this.getControlPoint(newInnerStart.x, newInnerStart.y, innerPointStart.x, innerPointStart.y);
|
|
146
155
|
const Q3 = this.getControlPoint(upperPointStart.x, upperPointStart.y, newUpperStart.x, newUpperStart.y);
|
|
147
|
-
let d = `M ${newUpperStart.x},${newUpperStart.y} A ${bigRadius},${bigRadius} 0 ${
|
|
156
|
+
let d = `M ${newUpperStart.x},${newUpperStart.y} A ${bigRadius},${bigRadius} 0 ${flagU} 1 ${newUpperEnd.x},${newUpperEnd.y}`;
|
|
148
157
|
d += `Q ${Q.xc},${Q.yc} ${upperPointEnd.x},${upperPointEnd.y} L ${innerPointEnd.x},${innerPointEnd.y}`;
|
|
149
158
|
d += `Q ${Q1.xc},${Q1.yc} ${newInnerEnd.x},${newInnerEnd.y}`;
|
|
150
|
-
d += `A ${smallRadius},${smallRadius} 0 ${
|
|
159
|
+
d += `A ${smallRadius},${smallRadius} 0 ${flagI} 0 ${newInnerStart.x},${newInnerStart.y}`;
|
|
151
160
|
d += `Q ${Q2.xc},${Q2.yc} ${innerPointStart.x},${innerPointStart.y} L ${upperPointStart.x},${upperPointStart.y}`;
|
|
152
161
|
d += ` Q ${Q3.xc},${Q3.yc} ${newUpperStart.x},${newUpperStart.y}`;
|
|
153
162
|
d += ` Z`;
|
|
@@ -155,54 +164,57 @@
|
|
|
155
164
|
}
|
|
156
165
|
// Dentro de la clase OrbitCommon en orbit-common.js
|
|
157
166
|
generateCirclePath(params, shape) {
|
|
158
|
-
const { upperArcStart, upperArcEnd, innerArcStart, innerArcEnd, bigRadius, smallRadius,
|
|
159
|
-
let d = `M ${upperArcStart.x},${upperArcStart.y} A ${bigRadius},${bigRadius} 0 ${
|
|
167
|
+
const { upperArcStart, upperArcEnd, innerArcStart, innerArcEnd, bigRadius, smallRadius, largeArcFlagUpper, largeArcFlagInner } = params;
|
|
168
|
+
let d = `M ${upperArcStart.x},${upperArcStart.y} A ${bigRadius},${bigRadius} 0 ${largeArcFlagUpper} 1 ${upperArcEnd.x},${upperArcEnd.y}`;
|
|
160
169
|
d += ` A 1,1 0 0 1 ${innerArcEnd.x},${innerArcEnd.y} `;
|
|
161
|
-
d += ` A ${smallRadius},${smallRadius} 0 ${
|
|
170
|
+
d += ` A ${smallRadius},${smallRadius} 0 ${largeArcFlagInner} 0 ${innerArcStart.x},${innerArcStart.y}`;
|
|
162
171
|
d += ` A 1,1 0 0 ${shape === "circle" || shape === "circle-a" ? 1 : 0} ${upperArcStart.x},${upperArcStart.y} `;
|
|
163
172
|
d += ` Z`;
|
|
164
173
|
return d;
|
|
165
174
|
}
|
|
166
175
|
generateCircleBPath(params, arcHeight, orbitNumber) {
|
|
167
|
-
const { upperAngleStart, upperAngleEnd, innerAngleStart, innerAngleEnd, bigRadius, smallRadius
|
|
176
|
+
const { upperAngleStart, upperAngleEnd, innerAngleStart, innerAngleEnd, bigRadius, smallRadius } = params;
|
|
168
177
|
const segment = arcHeight * 1.36;
|
|
178
|
+
const capRad = segment / orbitNumber * Math.PI / 180;
|
|
179
|
+
const flagU = upperAngleEnd - upperAngleStart - 2 * capRad > Math.PI ? 1 : 0;
|
|
180
|
+
const flagI = innerAngleEnd - innerAngleStart - 2 * capRad > Math.PI ? 1 : 0;
|
|
169
181
|
const newUpperStart = this.arcPoint(bigRadius, upperAngleStart, 0, segment / orbitNumber);
|
|
170
182
|
const newUpperEnd = this.arcPoint(bigRadius, upperAngleEnd, 0, -segment / orbitNumber);
|
|
171
183
|
const newInnerStart = this.arcPoint(smallRadius, innerAngleStart, 0, segment / orbitNumber);
|
|
172
184
|
const newInnerEnd = this.arcPoint(smallRadius, innerAngleEnd, 0, -segment / orbitNumber);
|
|
173
|
-
let d = `M ${newUpperStart.x},${newUpperStart.y} A ${bigRadius},${bigRadius} 0 ${
|
|
185
|
+
let d = `M ${newUpperStart.x},${newUpperStart.y} A ${bigRadius},${bigRadius} 0 ${flagU} 1 ${newUpperEnd.x},${newUpperEnd.y}`;
|
|
174
186
|
d += ` A 1,1 0 0 1 ${newInnerEnd.x},${newInnerEnd.y} `;
|
|
175
|
-
d += ` A ${smallRadius},${smallRadius} 0 ${
|
|
187
|
+
d += ` A ${smallRadius},${smallRadius} 0 ${flagI} 0 ${newInnerStart.x},${newInnerStart.y}`;
|
|
176
188
|
d += ` A 1,1 0 0 1 ${newUpperStart.x},${newUpperStart.y} `;
|
|
177
189
|
d += ` Z`;
|
|
178
190
|
return d;
|
|
179
191
|
}
|
|
180
192
|
generateArrowPath(params, orbitNumber) {
|
|
181
|
-
const { upperArcStart, upperArcEnd, innerArcStart, innerArcEnd, bigRadius, smallRadius,
|
|
193
|
+
const { upperArcStart, upperArcEnd, innerArcStart, innerArcEnd, bigRadius, smallRadius, largeArcFlagUpper, largeArcFlagInner, radius } = params;
|
|
182
194
|
const middleEnd = this.arcPoint(radius, params.upperAngleEnd, 0, 24 / orbitNumber / 2);
|
|
183
195
|
const middleStart = this.arcPoint(radius, params.upperAngleStart, 0, 24 / orbitNumber / 2);
|
|
184
|
-
let d = `M ${upperArcStart.x},${upperArcStart.y} A ${bigRadius},${bigRadius} 0 ${
|
|
196
|
+
let d = `M ${upperArcStart.x},${upperArcStart.y} A ${bigRadius},${bigRadius} 0 ${largeArcFlagUpper} 1 ${upperArcEnd.x},${upperArcEnd.y}`;
|
|
185
197
|
d += `L ${middleEnd.x} ${middleEnd.y}`;
|
|
186
198
|
d += `L ${innerArcEnd.x} ${innerArcEnd.y}`;
|
|
187
|
-
d += `A ${smallRadius},${smallRadius} 0 ${
|
|
199
|
+
d += `A ${smallRadius},${smallRadius} 0 ${largeArcFlagInner} 0 ${innerArcStart.x}, ${innerArcStart.y}`;
|
|
188
200
|
d += `L ${middleStart.x} ${middleStart.y}`;
|
|
189
201
|
d += `Z`;
|
|
190
202
|
return d;
|
|
191
203
|
}
|
|
192
204
|
generateSlashPath(params, shape, orbitNumber) {
|
|
193
|
-
const { upperAngleStart, upperAngleEnd, innerAngleStart, innerAngleEnd, bigRadius, smallRadius,
|
|
205
|
+
const { upperAngleStart, upperAngleEnd, innerAngleStart, innerAngleEnd, bigRadius, smallRadius, largeArcFlagUpper, largeArcFlagInner } = params;
|
|
194
206
|
const newUpperStart = this.arcPoint(bigRadius, upperAngleStart, 0, shape === "backslash" ? 0 : 24 / orbitNumber / 2);
|
|
195
207
|
const newUpperEnd = this.arcPoint(bigRadius, upperAngleEnd, 0, shape === "backslash" ? 0 : 24 / orbitNumber / 2);
|
|
196
208
|
const newInnerStart = this.arcPoint(smallRadius, innerAngleStart, 0, shape === "backslash" ? 24 / orbitNumber / 2 : 0);
|
|
197
209
|
const newInnerEnd = this.arcPoint(smallRadius, innerAngleEnd, 0, shape === "backslash" ? 24 / orbitNumber / 2 : 0);
|
|
198
|
-
let d = `M ${newUpperStart.x},${newUpperStart.y} A ${bigRadius},${bigRadius} 0 ${
|
|
210
|
+
let d = `M ${newUpperStart.x},${newUpperStart.y} A ${bigRadius},${bigRadius} 0 ${largeArcFlagUpper} 1 ${newUpperEnd.x},${newUpperEnd.y}`;
|
|
199
211
|
d += `L ${newInnerEnd.x} ${newInnerEnd.y}`;
|
|
200
|
-
d += `A ${smallRadius},${smallRadius} 0 ${
|
|
212
|
+
d += `A ${smallRadius},${smallRadius} 0 ${largeArcFlagInner} 0 ${newInnerStart.x}, ${newInnerStart.y}`;
|
|
201
213
|
d += `Z`;
|
|
202
214
|
return d;
|
|
203
215
|
}
|
|
204
216
|
generateZigzagPath(params, arcHeight, orbitNumber) {
|
|
205
|
-
const { upperArcStart, upperArcEnd, innerArcStart, innerArcEnd, bigRadius, smallRadius,
|
|
217
|
+
const { upperArcStart, upperArcEnd, innerArcStart, innerArcEnd, bigRadius, smallRadius, largeArcFlagUpper, largeArcFlagInner, radius } = params;
|
|
206
218
|
const h2 = arcHeight / orbitNumber / 2;
|
|
207
219
|
const s2 = this.arcPoint(radius, params.upperAngleStart, -h2, 3);
|
|
208
220
|
const s3 = this.arcPoint(radius, params.upperAngleStart, 0, 0);
|
|
@@ -210,12 +222,12 @@
|
|
|
210
222
|
const e2 = this.arcPoint(radius, params.innerAngleEnd, h2, 3);
|
|
211
223
|
const e3 = this.arcPoint(radius, params.innerAngleEnd, 0, 0);
|
|
212
224
|
const e4 = this.arcPoint(radius, params.innerAngleEnd, -h2, 3);
|
|
213
|
-
let d = `M ${upperArcStart.x},${upperArcStart.y} A ${bigRadius},${bigRadius} 0 ${
|
|
225
|
+
let d = `M ${upperArcStart.x},${upperArcStart.y} A ${bigRadius},${bigRadius} 0 ${largeArcFlagUpper} 1 ${upperArcEnd.x},${upperArcEnd.y}`;
|
|
214
226
|
d += `L ${e2.x} ${e2.y}`;
|
|
215
227
|
d += `L ${e3.x} ${e3.y}`;
|
|
216
228
|
d += `L ${e4.x} ${e4.y}`;
|
|
217
229
|
d += `L ${innerArcEnd.x} ${innerArcEnd.y}`;
|
|
218
|
-
d += `A ${smallRadius},${smallRadius} 0 ${
|
|
230
|
+
d += `A ${smallRadius},${smallRadius} 0 ${largeArcFlagInner} 0 ${innerArcStart.x}, ${innerArcStart.y}`;
|
|
219
231
|
d += `L ${s2.x} ${s2.y}`;
|
|
220
232
|
d += `L ${s3.x} ${s3.y}`;
|
|
221
233
|
d += `L ${s4.x} ${s4.y}`;
|
|
@@ -223,10 +235,10 @@
|
|
|
223
235
|
return d;
|
|
224
236
|
}
|
|
225
237
|
generateDefaultPath(params) {
|
|
226
|
-
const { upperArcStart, upperArcEnd, innerArcStart, innerArcEnd, bigRadius, smallRadius,
|
|
227
|
-
let d = `M ${upperArcStart.x},${upperArcStart.y} A ${bigRadius},${bigRadius} 0 ${
|
|
238
|
+
const { upperArcStart, upperArcEnd, innerArcStart, innerArcEnd, bigRadius, smallRadius, largeArcFlagUpper, largeArcFlagInner } = params;
|
|
239
|
+
let d = `M ${upperArcStart.x},${upperArcStart.y} A ${bigRadius},${bigRadius} 0 ${largeArcFlagUpper} 1 ${upperArcEnd.x},${upperArcEnd.y}`;
|
|
228
240
|
d += `L ${innerArcEnd.x} ${innerArcEnd.y}`;
|
|
229
|
-
d += `A ${smallRadius},${smallRadius} 0 ${
|
|
241
|
+
d += `A ${smallRadius},${smallRadius} 0 ${largeArcFlagInner} 0 ${innerArcStart.x}, ${innerArcStart.y}`;
|
|
230
242
|
d += `Z`;
|
|
231
243
|
return d;
|
|
232
244
|
}
|
|
@@ -261,9 +273,17 @@
|
|
|
261
273
|
overflow: visible;
|
|
262
274
|
pointer-events: none;
|
|
263
275
|
}
|
|
276
|
+
/* Display element by default: never steals clicks (see orbit-arc).
|
|
277
|
+
Interaction is opt-in via the "interactive" attribute. */
|
|
264
278
|
svg * {
|
|
279
|
+
pointer-events: none;
|
|
280
|
+
}
|
|
281
|
+
:host([interactive]) svg * {
|
|
265
282
|
pointer-events: visiblePainted;
|
|
266
283
|
}
|
|
284
|
+
:host([interactive]) {
|
|
285
|
+
cursor: pointer;
|
|
286
|
+
}
|
|
267
287
|
.progress-bar {
|
|
268
288
|
fill: var(--o-fill);
|
|
269
289
|
stroke: var(--o-stroke);
|
|
@@ -276,6 +296,23 @@
|
|
|
276
296
|
stroke: var(--o-back-stroke);
|
|
277
297
|
stroke-width: var(--o-back-stroke-width);
|
|
278
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
|
+
}
|
|
279
316
|
</style>
|
|
280
317
|
<svg viewBox="0 0 100 100">
|
|
281
318
|
<path class="progress-bg" shape-rendering="geometricPrecision" vector-effect="non-scaling-stroke"></path>
|
|
@@ -297,11 +334,28 @@
|
|
|
297
334
|
}
|
|
298
335
|
update() {
|
|
299
336
|
const attrs = this.getAttributes();
|
|
300
|
-
const
|
|
301
|
-
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);
|
|
302
340
|
this.shadowRoot.querySelector(".progress-bg").setAttribute("d", dBg);
|
|
303
341
|
this.shadowRoot.querySelector(".progress-bar").setAttribute("d", dBar);
|
|
304
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
|
+
}
|
|
305
359
|
getAttributes() {
|
|
306
360
|
const common = super.getCommonAttributes(this);
|
|
307
361
|
const range = parseFloat(getComputedStyle(this).getPropertyValue("--o-range") || 360);
|
|
@@ -356,9 +410,19 @@
|
|
|
356
410
|
overflow: visible;
|
|
357
411
|
pointer-events: none;
|
|
358
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. */
|
|
359
417
|
svg * {
|
|
418
|
+
pointer-events: none;
|
|
419
|
+
}
|
|
420
|
+
:host([interactive]) svg * {
|
|
360
421
|
pointer-events: visiblePainted;
|
|
361
422
|
}
|
|
423
|
+
:host([interactive]) {
|
|
424
|
+
cursor: pointer;
|
|
425
|
+
}
|
|
362
426
|
#orbitShape {
|
|
363
427
|
fill: var(--o-fill);
|
|
364
428
|
stroke: var(--o-stroke);
|
|
@@ -432,6 +496,30 @@
|
|
|
432
496
|
}
|
|
433
497
|
textPath.parentElement.style.fontSize = `calc(${fontSize} * (100 / (${length}) * (12 / var(--o-orbit-number)))`;
|
|
434
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
|
+
});
|
|
435
523
|
}
|
|
436
524
|
getAttributes() {
|
|
437
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
|
|
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
|
|
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;})();
|