@tangle-network/charts 0.12.0 → 0.12.1
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/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +50 -17
- package/package.json +1 -1
package/dist/react/index.d.ts
CHANGED
|
@@ -77,7 +77,7 @@ interface StackedBarChartProps {
|
|
|
77
77
|
label: string;
|
|
78
78
|
series: readonly StackedBarSeries[];
|
|
79
79
|
buckets: readonly StackedBarBucket[];
|
|
80
|
-
/**
|
|
80
|
+
/** Values must lie in [0, maxValue]; the axis extends to the next round tick. Zero is valid only for zero-valued data. */
|
|
81
81
|
maxValue: number;
|
|
82
82
|
formatValue: (value: number) => string;
|
|
83
83
|
selectedBucketId: string | null;
|
package/dist/react/index.js
CHANGED
|
@@ -217,6 +217,41 @@ function validate({ series, buckets, maxValue }) {
|
|
|
217
217
|
}
|
|
218
218
|
}
|
|
219
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* Round axis ticks covering [0, max]: three to six steps of 1, 2, 2.5 or 5
|
|
222
|
+
* times a power of ten, so labels read $0.003 rather than $0.0028. The
|
|
223
|
+
* tightest top wins, then the fewest steps, so bars keep their height.
|
|
224
|
+
*/
|
|
225
|
+
function niceTicks(max) {
|
|
226
|
+
if (!(max > 0)) return [0];
|
|
227
|
+
const magnitude = 10 ** Math.floor(Math.log10(max));
|
|
228
|
+
let best = {
|
|
229
|
+
top: Infinity,
|
|
230
|
+
step: 0,
|
|
231
|
+
count: 0
|
|
232
|
+
};
|
|
233
|
+
for (const scale of [
|
|
234
|
+
1,
|
|
235
|
+
.1,
|
|
236
|
+
.01
|
|
237
|
+
]) for (const multiple of [
|
|
238
|
+
1,
|
|
239
|
+
2,
|
|
240
|
+
2.5,
|
|
241
|
+
5
|
|
242
|
+
]) {
|
|
243
|
+
const step = multiple * magnitude * scale;
|
|
244
|
+
const count = Math.ceil(max / step - 1e-9);
|
|
245
|
+
const top = count * step;
|
|
246
|
+
if (count < 3 || count > 6) continue;
|
|
247
|
+
if (top < best.top - 1e-12 * top || Math.abs(top - best.top) <= 1e-12 * top && count < best.count) best = {
|
|
248
|
+
top,
|
|
249
|
+
step,
|
|
250
|
+
count
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
return Array.from({ length: best.count + 1 }, (_, i) => Number((i * best.step).toPrecision(12)));
|
|
254
|
+
}
|
|
220
255
|
function StackedBarChart(props) {
|
|
221
256
|
const { label, series, buckets, maxValue, formatValue, selectedBucketId, onSelectionChange, emptyLabel = "No data yet", unavailableLabel = "Not available", className } = props;
|
|
222
257
|
const readoutId = useId();
|
|
@@ -249,13 +284,16 @@ function StackedBarChart(props) {
|
|
|
249
284
|
const formatted = (value) => isValue(value) ? formatValue(value) : unavailableLabel;
|
|
250
285
|
const summary = (bucket) => `${bucket.label}: total ${formatted(bucket.total)}` + (hasGap(bucket) ? ` — ${unavailableLabel}` : "") + (bucket.segments.length ? ` — ${bucket.segments.map((segment) => `${bySeries.get(segment.seriesId).label} ${formatted(segment.value)}`).join(", ")}` : "") + (bucket.description ? ` — ${bucket.description}` : "");
|
|
251
286
|
const activeIndex = selectedBucketId === null ? -1 : buckets.findIndex(({ id }) => id === selectedBucketId);
|
|
252
|
-
const activeBucket = activeIndex >= 0 ? buckets[activeIndex] : null, marginTop = 12, marginRight =
|
|
287
|
+
const activeBucket = activeIndex >= 0 ? buckets[activeIndex] : null, marginTop = 12, marginRight = 24, marginLeft = 56;
|
|
253
288
|
const chartHeight = 220;
|
|
254
289
|
const innerHeight = 176;
|
|
255
290
|
const barGap = 6;
|
|
256
|
-
const barWidth = Math.max(8, Math.min(36,
|
|
291
|
+
const barWidth = Math.max(8, Math.min(36, 640 / Math.max(1, buckets.length) - barGap));
|
|
257
292
|
const viewWidth = Math.max(buckets.length * (barWidth + barGap) + marginLeft + marginRight, 400);
|
|
258
|
-
const
|
|
293
|
+
const ticks = niceTicks(maxValue);
|
|
294
|
+
const scaleMax = ticks[ticks.length - 1];
|
|
295
|
+
const labelWidth = Math.max(0, ...buckets.map((bucket) => bucket.label.length)) * 6 + 8;
|
|
296
|
+
const labelStride = Math.max(1, Math.ceil(labelWidth / (barWidth + barGap)));
|
|
259
297
|
if (buckets.length === 0) return /* @__PURE__ */ jsxs("p", {
|
|
260
298
|
className,
|
|
261
299
|
children: [
|
|
@@ -284,16 +322,12 @@ function StackedBarChart(props) {
|
|
|
284
322
|
maxHeight: 300
|
|
285
323
|
},
|
|
286
324
|
preserveAspectRatio: "xMinYMin meet",
|
|
287
|
-
children: [
|
|
288
|
-
0
|
|
289
|
-
.25,
|
|
290
|
-
.5,
|
|
291
|
-
.75,
|
|
292
|
-
1
|
|
293
|
-
].map((fraction) => {
|
|
325
|
+
children: [ticks.map((tick) => {
|
|
326
|
+
const fraction = scaleMax > 0 ? tick / scaleMax : 0;
|
|
294
327
|
const y = 188 - fraction * innerHeight;
|
|
295
328
|
return /* @__PURE__ */ jsxs("g", {
|
|
296
329
|
"aria-hidden": "true",
|
|
330
|
+
"data-tick": "",
|
|
297
331
|
children: [/* @__PURE__ */ jsx("line", {
|
|
298
332
|
x1: marginLeft,
|
|
299
333
|
y1: y,
|
|
@@ -310,14 +344,14 @@ function StackedBarChart(props) {
|
|
|
310
344
|
fontSize: "11",
|
|
311
345
|
fill: "currentColor",
|
|
312
346
|
fontFamily: "inherit",
|
|
313
|
-
children: formatValue(
|
|
347
|
+
children: formatValue(tick)
|
|
314
348
|
})]
|
|
315
|
-
},
|
|
349
|
+
}, tick);
|
|
316
350
|
}), buckets.map((bucket, index) => {
|
|
317
351
|
const x = marginLeft + index * (barWidth + barGap) + barGap / 2;
|
|
318
352
|
const isActive = index === activeIndex;
|
|
319
353
|
const gap = hasGap(bucket);
|
|
320
|
-
const stackHeight = !gap &&
|
|
354
|
+
const stackHeight = !gap && scaleMax > 0 ? bucket.total / scaleMax * innerHeight : 0;
|
|
321
355
|
let yOffset = 0;
|
|
322
356
|
const select = () => onSelectionChange(bucket.id);
|
|
323
357
|
const clear = () => {
|
|
@@ -398,7 +432,7 @@ function StackedBarChart(props) {
|
|
|
398
432
|
rx: 3
|
|
399
433
|
}),
|
|
400
434
|
!gap && bucket.segments.map((segment, segmentIndex) => {
|
|
401
|
-
const height =
|
|
435
|
+
const height = scaleMax > 0 ? segment.value / scaleMax * innerHeight : 0;
|
|
402
436
|
const y = 188 - yOffset - height;
|
|
403
437
|
yOffset += height;
|
|
404
438
|
return /* @__PURE__ */ jsx("rect", {
|
|
@@ -434,16 +468,15 @@ function StackedBarChart(props) {
|
|
|
434
468
|
rx: 3,
|
|
435
469
|
pointerEvents: "none"
|
|
436
470
|
}),
|
|
437
|
-
/* @__PURE__ */ jsx("text", {
|
|
471
|
+
index % labelStride === 0 && /* @__PURE__ */ jsx("text", {
|
|
438
472
|
x: x + barWidth / 2,
|
|
439
473
|
y: 204,
|
|
440
|
-
textAnchor:
|
|
474
|
+
textAnchor: "middle",
|
|
441
475
|
fontSize: "10",
|
|
442
476
|
fill: "currentColor",
|
|
443
477
|
fontFamily: "inherit",
|
|
444
478
|
pointerEvents: "none",
|
|
445
479
|
"aria-hidden": "true",
|
|
446
|
-
transform: denseLabels ? `rotate(-40, ${x + barWidth / 2}, 204)` : void 0,
|
|
447
480
|
children: bucket.label
|
|
448
481
|
})
|
|
449
482
|
]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/charts",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"description": "Static SVG and HTML figures for benchmarks and operational timing. Draws from producer data and refuses what it cannot draw honestly.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|