@robosystems/report-components 0.2.10 → 0.3.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/index.js
CHANGED
|
@@ -1,9 +1,109 @@
|
|
|
1
|
-
import { formatDate, BLOCK_TITLES, numericKindOf, humanizeDuration, formatValue, formatPeriod, isExternalFactUrl, BLOCK_ORDER, humanize, qname, currencySymbolFor } from './chunk-
|
|
2
|
-
export { BLOCK_ORDER, BLOCK_TITLES, NS, currencySymbolFor, cypherAdapter, fetchSecReportShell, fetchSecSection, formatDate, formatMoney, formatPeriod, formatValue, humanize, humanizeDuration, isExternalFactUrl, jsonldFileAdapter, mergeSecSections, numericKindOf, parseJsonld, parseStore, parseStructureDefinition, parseStructureName, qname, stripRoleSuffix } from './chunk-
|
|
1
|
+
import { formatMoney, formatDate, BLOCK_TITLES, numericKindOf, humanizeDuration, formatValue, formatPeriod, isExternalFactUrl, BLOCK_ORDER, humanize, qname, currencySymbolFor } from './chunk-ZTYXTMAT.js';
|
|
2
|
+
export { BLOCK_ORDER, BLOCK_TITLES, NS, currencySymbolFor, cypherAdapter, fetchSecReportShell, fetchSecSection, formatDate, formatMoney, formatPeriod, formatValue, humanize, humanizeDuration, isExternalFactUrl, jsonldFileAdapter, mergeSecSections, numericKindOf, parseJsonld, parseStore, parseStructureDefinition, parseStructureName, qname, stripRoleSuffix } from './chunk-ZTYXTMAT.js';
|
|
3
3
|
import { marked } from 'marked';
|
|
4
|
-
import { useState, useEffect, useMemo, useRef } from 'react';
|
|
4
|
+
import { useState, useEffect, useMemo, useRef, useId } from 'react';
|
|
5
5
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
6
|
|
|
7
|
+
// src/chart/format.ts
|
|
8
|
+
var DASH = "\u2014";
|
|
9
|
+
function formatMetricValue(itemType, value) {
|
|
10
|
+
if (value === null || value === void 0 || Number.isNaN(value)) return DASH;
|
|
11
|
+
switch (itemType) {
|
|
12
|
+
case "monetary":
|
|
13
|
+
return formatMoney(value);
|
|
14
|
+
case "percent":
|
|
15
|
+
return `${(value * 100).toLocaleString("en-US", { maximumFractionDigits: 2 })}%`;
|
|
16
|
+
case "multiple":
|
|
17
|
+
return `${value.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}\xD7`;
|
|
18
|
+
case "days":
|
|
19
|
+
return value.toLocaleString("en-US", { maximumFractionDigits: 0 });
|
|
20
|
+
case "ratio":
|
|
21
|
+
return value.toLocaleString("en-US", {
|
|
22
|
+
minimumFractionDigits: 2,
|
|
23
|
+
maximumFractionDigits: 2
|
|
24
|
+
});
|
|
25
|
+
default:
|
|
26
|
+
return value.toLocaleString("en-US", { maximumFractionDigits: 4 });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function formatMetricCompact(itemType, value) {
|
|
30
|
+
if (value === null || value === void 0 || Number.isNaN(value)) return "";
|
|
31
|
+
if (itemType === "monetary") {
|
|
32
|
+
const abs = Math.abs(value);
|
|
33
|
+
const sign = value < 0 ? "-" : "";
|
|
34
|
+
if (abs >= 1e9) return `${sign}$${(abs / 1e9).toFixed(abs >= 1e10 ? 0 : 1)}B`;
|
|
35
|
+
if (abs >= 1e6) return `${sign}$${(abs / 1e6).toFixed(abs >= 1e7 ? 0 : 1)}M`;
|
|
36
|
+
if (abs >= 1e3) return `${sign}$${(abs / 1e3).toFixed(abs >= 1e4 ? 0 : 1)}K`;
|
|
37
|
+
return `${sign}$${abs.toFixed(0)}`;
|
|
38
|
+
}
|
|
39
|
+
if (itemType === "percent") {
|
|
40
|
+
return `${(value * 100).toLocaleString("en-US", { maximumFractionDigits: 1 })}%`;
|
|
41
|
+
}
|
|
42
|
+
if (itemType === "multiple") {
|
|
43
|
+
return `${value.toLocaleString("en-US", { maximumFractionDigits: 1 })}\xD7`;
|
|
44
|
+
}
|
|
45
|
+
if (itemType === "days") {
|
|
46
|
+
return value.toLocaleString("en-US", { maximumFractionDigits: 0 });
|
|
47
|
+
}
|
|
48
|
+
return value.toLocaleString("en-US", { maximumFractionDigits: 2 });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// src/chart/join.ts
|
|
52
|
+
function joinChartSeries(panel, rendering) {
|
|
53
|
+
const rowByElement = new Map(rendering.rows.map((r) => [r.elementId, r]));
|
|
54
|
+
const periods = rendering.periods;
|
|
55
|
+
const out = [];
|
|
56
|
+
for (const series of panel.series) {
|
|
57
|
+
const row = rowByElement.get(series.elementId);
|
|
58
|
+
if (!row) continue;
|
|
59
|
+
const points = periods.map((p, i) => ({
|
|
60
|
+
x: p.end,
|
|
61
|
+
y: i < row.values.length ? row.values[i] : null
|
|
62
|
+
}));
|
|
63
|
+
out.push({
|
|
64
|
+
key: series.key,
|
|
65
|
+
label: series.label,
|
|
66
|
+
itemType: panel.itemType,
|
|
67
|
+
points
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/chart/palette.ts
|
|
74
|
+
var SERIES_COLORS_LIGHT = [
|
|
75
|
+
"#2a78d6",
|
|
76
|
+
// 1 blue
|
|
77
|
+
"#eb6834",
|
|
78
|
+
// 2 orange
|
|
79
|
+
"#1baf7a",
|
|
80
|
+
// 3 aqua
|
|
81
|
+
"#eda100",
|
|
82
|
+
// 4 yellow
|
|
83
|
+
"#e87ba4",
|
|
84
|
+
// 5 magenta
|
|
85
|
+
"#008300",
|
|
86
|
+
// 6 green
|
|
87
|
+
"#4a3aa7",
|
|
88
|
+
// 7 violet
|
|
89
|
+
"#e34948"
|
|
90
|
+
// 8 red
|
|
91
|
+
];
|
|
92
|
+
var SERIES_COLORS_DARK = [
|
|
93
|
+
"#3987e5",
|
|
94
|
+
"#d95926",
|
|
95
|
+
"#199e70",
|
|
96
|
+
"#c98500",
|
|
97
|
+
"#d55181",
|
|
98
|
+
"#008300",
|
|
99
|
+
"#9085e9",
|
|
100
|
+
"#e66767"
|
|
101
|
+
];
|
|
102
|
+
function seriesColor(index) {
|
|
103
|
+
const slot = Math.min(index, SERIES_COLORS_LIGHT.length - 1);
|
|
104
|
+
return `var(--rs-chart-series-${slot + 1}, ${SERIES_COLORS_LIGHT[slot]})`;
|
|
105
|
+
}
|
|
106
|
+
|
|
7
107
|
// src/project.ts
|
|
8
108
|
function fallbackElement(id) {
|
|
9
109
|
return {
|
|
@@ -102,8 +202,11 @@ function memberByAxis(fact) {
|
|
|
102
202
|
for (const d of fact.dimensions ?? []) m.set(d.axis, d);
|
|
103
203
|
return m;
|
|
104
204
|
}
|
|
205
|
+
function memberKey(d) {
|
|
206
|
+
return d?.member ?? d?.typedValue ?? DOMAIN;
|
|
207
|
+
}
|
|
105
208
|
function coordinate(byAxis, axes) {
|
|
106
|
-
return axes.map((a) => `${a}=${
|
|
209
|
+
return axes.map((a) => `${a}=${memberKey(byAxis.get(a))}`).join("|");
|
|
107
210
|
}
|
|
108
211
|
function sectionFacts(model, ib) {
|
|
109
212
|
const target = ib.factSet;
|
|
@@ -362,7 +465,7 @@ function resolveScale(facts, model, requested) {
|
|
|
362
465
|
}
|
|
363
466
|
return { factor, label, caption };
|
|
364
467
|
}
|
|
365
|
-
function buildSlicers(model,
|
|
468
|
+
function buildSlicers(model, config, diced) {
|
|
366
469
|
const slicers = [];
|
|
367
470
|
for (const key of config.slicers) {
|
|
368
471
|
if (key === "entity") {
|
|
@@ -377,14 +480,7 @@ function buildSlicers(model, facts, config) {
|
|
|
377
480
|
}
|
|
378
481
|
const axis = axisOf(key);
|
|
379
482
|
if (!axis) continue;
|
|
380
|
-
|
|
381
|
-
for (const f of facts) {
|
|
382
|
-
const d = (f.dimensions ?? []).find((x) => x.axis === axis);
|
|
383
|
-
if (d) {
|
|
384
|
-
qual = d;
|
|
385
|
-
break;
|
|
386
|
-
}
|
|
387
|
-
}
|
|
483
|
+
const qual = diced.get(axis) ?? null;
|
|
388
484
|
const axisLabel = qual?.axisLabel ?? humanize(axis);
|
|
389
485
|
slicers.push({
|
|
390
486
|
aspect: key,
|
|
@@ -404,14 +500,25 @@ function buildPivot(model, ib, config = defaultPivotConfig(model, ib)) {
|
|
|
404
500
|
const facts = sectionFacts(model, ib).filter(
|
|
405
501
|
(f) => (f.dimensions ?? []).every((d) => allowedAxes.has(d.axis) && dimensionInScope(scope, d))
|
|
406
502
|
);
|
|
503
|
+
const dicedSlicers = /* @__PURE__ */ new Map();
|
|
504
|
+
for (const axis of dimAxes(config.slicers)) {
|
|
505
|
+
const qual = facts.flatMap((f) => f.dimensions ?? []).find((d) => d.axis === axis) ?? null;
|
|
506
|
+
dicedSlicers.set(axis, qual);
|
|
507
|
+
}
|
|
508
|
+
const shownAxes = /* @__PURE__ */ new Set([...rowDimAxes, ...colDimAxes]);
|
|
509
|
+
const tableFacts = facts.filter(
|
|
510
|
+
(f) => (f.dimensions ?? []).every(
|
|
511
|
+
(d) => shownAxes.has(d.axis) || dicedSlicers.has(d.axis) && memberKey(d) === memberKey(dicedSlicers.get(d.axis))
|
|
512
|
+
)
|
|
513
|
+
);
|
|
407
514
|
const periodOnColumns = config.columns.includes("period");
|
|
408
|
-
let periods = periodOnColumns ? derivePeriods(model,
|
|
515
|
+
let periods = periodOnColumns ? derivePeriods(model, tableFacts) : [];
|
|
409
516
|
if (periodOnColumns && config.dropSparsePeriods !== false) {
|
|
410
|
-
periods = pruneSparsePeriods(model,
|
|
517
|
+
periods = pruneSparsePeriods(model, tableFacts, periods);
|
|
411
518
|
}
|
|
412
|
-
const colCombos = memberCombos(
|
|
519
|
+
const colCombos = memberCombos(tableFacts, colDimAxes, tree.indexOf);
|
|
413
520
|
const occupiedCols = /* @__PURE__ */ new Set();
|
|
414
|
-
for (const f of
|
|
521
|
+
for (const f of tableFacts) {
|
|
415
522
|
const end = model.periods[f.period]?.end ?? "";
|
|
416
523
|
occupiedCols.add(`${end}#${coordinate(memberByAxis(f), colDimAxes)}`);
|
|
417
524
|
}
|
|
@@ -433,18 +540,17 @@ function buildPivot(model, ib, config = defaultPivotConfig(model, ib)) {
|
|
|
433
540
|
}
|
|
434
541
|
}
|
|
435
542
|
const columnHeaders = headerLevels(columnSegs);
|
|
436
|
-
const
|
|
543
|
+
const slicerSpecificity = (f) => (f.dimensions ?? []).filter((d) => !shownAxes.has(d.axis)).length;
|
|
437
544
|
const factIndex = /* @__PURE__ */ new Map();
|
|
438
|
-
for (const f of
|
|
545
|
+
for (const f of [...tableFacts].sort((a, b) => slicerSpecificity(a) - slicerSpecificity(b))) {
|
|
439
546
|
const byAxis = memberByAxis(f);
|
|
440
|
-
if ([...byAxis.keys()].some((axis) => !shownAxes.has(axis))) continue;
|
|
441
547
|
const end = model.periods[f.period]?.end ?? "";
|
|
442
548
|
const rowSig = coordinate(byAxis, rowDimAxes);
|
|
443
549
|
const colSig = coordinate(byAxis, colDimAxes);
|
|
444
550
|
factIndex.set(`${f.element}\u241F${rowSig}\u241F${end}\u241F${colSig}`, f);
|
|
445
551
|
}
|
|
446
|
-
const factfulConcepts = new Set(
|
|
447
|
-
const rowCombos = memberCombos(
|
|
552
|
+
const factfulConcepts = new Set(tableFacts.map((f) => f.element));
|
|
553
|
+
const rowCombos = memberCombos(tableFacts, rowDimAxes, tree.indexOf);
|
|
448
554
|
const combosForConcept = (element) => {
|
|
449
555
|
if (rowDimAxes.length === 0) return rowCombos;
|
|
450
556
|
return rowCombos.filter(
|
|
@@ -546,11 +652,11 @@ function buildPivot(model, ib, config = defaultPivotConfig(model, ib)) {
|
|
|
546
652
|
structureName: ib.structureId ? null : structure?.structureName ?? ib.label ?? null,
|
|
547
653
|
definition: structure?.definition ?? null,
|
|
548
654
|
kind: structure?.kind ?? null,
|
|
549
|
-
slicers: buildSlicers(model,
|
|
655
|
+
slicers: buildSlicers(model, config, dicedSlicers),
|
|
550
656
|
columnHeaders,
|
|
551
657
|
columns,
|
|
552
658
|
rows,
|
|
553
|
-
scale: resolveScale(
|
|
659
|
+
scale: resolveScale(tableFacts, model, config.scale),
|
|
554
660
|
config
|
|
555
661
|
};
|
|
556
662
|
}
|
|
@@ -1190,7 +1296,394 @@ function ReportView({ report, inspect = true, dimensionAxis = "rows" }) {
|
|
|
1190
1296
|
)
|
|
1191
1297
|
] });
|
|
1192
1298
|
}
|
|
1299
|
+
var MARGIN = { top: 16, right: 104, bottom: 30, left: 60 };
|
|
1300
|
+
var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
1301
|
+
function shortMonth(iso) {
|
|
1302
|
+
const m = /^(\d{4})-(\d{2})/.exec(iso);
|
|
1303
|
+
if (!m) return iso;
|
|
1304
|
+
return `${MONTHS[Number(m[2]) - 1] ?? m[2]} '${m[1].slice(2)}`;
|
|
1305
|
+
}
|
|
1306
|
+
function niceTicks(min, max, count = 4) {
|
|
1307
|
+
if (!(max > min)) return [min];
|
|
1308
|
+
const span = max - min;
|
|
1309
|
+
const step0 = span / count;
|
|
1310
|
+
const mag = Math.pow(10, Math.floor(Math.log10(step0)));
|
|
1311
|
+
const norm = step0 / mag;
|
|
1312
|
+
const step = (norm >= 5 ? 10 : norm >= 2 ? 5 : norm >= 1 ? 2 : 1) * mag;
|
|
1313
|
+
const start = Math.ceil(min / step) * step;
|
|
1314
|
+
const ticks = [];
|
|
1315
|
+
for (let v = start; v <= max + step * 1e-6; v += step) ticks.push(Number(v.toFixed(10)));
|
|
1316
|
+
return ticks;
|
|
1317
|
+
}
|
|
1318
|
+
var styles5 = {
|
|
1319
|
+
wrap: {
|
|
1320
|
+
fontFamily: "var(--rs-font-sans, ui-sans-serif, system-ui, sans-serif)",
|
|
1321
|
+
color: "var(--rs-text, #111827)"
|
|
1322
|
+
},
|
|
1323
|
+
title: {
|
|
1324
|
+
fontFamily: "var(--rs-font-heading, var(--rs-font-sans, sans-serif))",
|
|
1325
|
+
fontSize: "0.9rem",
|
|
1326
|
+
fontWeight: 600,
|
|
1327
|
+
margin: "0 0 0.5rem"
|
|
1328
|
+
},
|
|
1329
|
+
legend: {
|
|
1330
|
+
display: "flex",
|
|
1331
|
+
flexWrap: "wrap",
|
|
1332
|
+
gap: "0.25rem 1rem",
|
|
1333
|
+
marginBottom: "0.5rem",
|
|
1334
|
+
fontSize: "0.78rem",
|
|
1335
|
+
color: "var(--rs-muted, #6b7280)"
|
|
1336
|
+
},
|
|
1337
|
+
legendItem: { display: "inline-flex", alignItems: "center", gap: "0.4rem" },
|
|
1338
|
+
legendKey: { display: "inline-block", width: 16, height: 2, borderRadius: 1 },
|
|
1339
|
+
empty: {
|
|
1340
|
+
padding: "2rem",
|
|
1341
|
+
textAlign: "center",
|
|
1342
|
+
color: "var(--rs-muted, #6b7280)",
|
|
1343
|
+
fontSize: "0.85rem"
|
|
1344
|
+
}
|
|
1345
|
+
};
|
|
1346
|
+
function TimeSeriesChart({
|
|
1347
|
+
series,
|
|
1348
|
+
itemType,
|
|
1349
|
+
title,
|
|
1350
|
+
width = 720,
|
|
1351
|
+
height = 280
|
|
1352
|
+
}) {
|
|
1353
|
+
const svgRef = useRef(null);
|
|
1354
|
+
const [active, setActive] = useState(null);
|
|
1355
|
+
const clipId = useId();
|
|
1356
|
+
const family = itemType ?? series[0]?.itemType ?? null;
|
|
1357
|
+
const periodCount = series[0]?.points.length ?? 0;
|
|
1358
|
+
const model = useMemo(() => {
|
|
1359
|
+
const values = [];
|
|
1360
|
+
for (const s of series)
|
|
1361
|
+
for (const p of s.points) if (p.y !== null && !Number.isNaN(p.y)) values.push(p.y);
|
|
1362
|
+
if (!values.length) return null;
|
|
1363
|
+
let min2 = Math.min(...values);
|
|
1364
|
+
let max2 = Math.max(...values);
|
|
1365
|
+
if (min2 === max2) {
|
|
1366
|
+
const pad = Math.abs(min2) * 0.1 || 1;
|
|
1367
|
+
min2 -= pad;
|
|
1368
|
+
max2 += pad;
|
|
1369
|
+
} else {
|
|
1370
|
+
const pad = (max2 - min2) * 0.08;
|
|
1371
|
+
min2 -= pad;
|
|
1372
|
+
max2 += pad;
|
|
1373
|
+
}
|
|
1374
|
+
return { min: min2, max: max2 };
|
|
1375
|
+
}, [series]);
|
|
1376
|
+
if (!model || periodCount === 0) {
|
|
1377
|
+
return /* @__PURE__ */ jsxs("div", { style: styles5.wrap, children: [
|
|
1378
|
+
title && /* @__PURE__ */ jsx("p", { style: styles5.title, children: title }),
|
|
1379
|
+
/* @__PURE__ */ jsx("p", { style: styles5.empty, children: "No data to plot for this period range." })
|
|
1380
|
+
] });
|
|
1381
|
+
}
|
|
1382
|
+
const innerW = width - MARGIN.left - MARGIN.right;
|
|
1383
|
+
const innerH = height - MARGIN.top - MARGIN.bottom;
|
|
1384
|
+
const { min, max } = model;
|
|
1385
|
+
const xAt = (i) => periodCount === 1 ? MARGIN.left + innerW / 2 : MARGIN.left + i / (periodCount - 1) * innerW;
|
|
1386
|
+
const yAt = (v) => MARGIN.top + innerH - (v - min) / (max - min) * innerH;
|
|
1387
|
+
const yTicks = niceTicks(min, max, 4);
|
|
1388
|
+
const xEvery = Math.max(1, Math.ceil(periodCount / 6));
|
|
1389
|
+
const periods = series[0].points;
|
|
1390
|
+
const showEndLabels = series.length <= 4;
|
|
1391
|
+
const placedLabelY = [];
|
|
1392
|
+
const showLegend = series.length >= 2;
|
|
1393
|
+
const ariaLabel = `${title ? `${title} \u2014 ` : ""}line chart of ${series.length} metric${series.length === 1 ? "" : "s"} over ${periodCount} periods`;
|
|
1394
|
+
function handleMove(e) {
|
|
1395
|
+
const svg = svgRef.current;
|
|
1396
|
+
const ctm = svg?.getScreenCTM?.();
|
|
1397
|
+
if (!svg || !ctm) return;
|
|
1398
|
+
const pt = new DOMPoint(e.clientX, e.clientY).matrixTransform(ctm.inverse());
|
|
1399
|
+
if (periodCount === 1) {
|
|
1400
|
+
setActive(0);
|
|
1401
|
+
return;
|
|
1402
|
+
}
|
|
1403
|
+
const frac = (pt.x - MARGIN.left) / innerW;
|
|
1404
|
+
const idx = Math.round(frac * (periodCount - 1));
|
|
1405
|
+
setActive(Math.max(0, Math.min(periodCount - 1, idx)));
|
|
1406
|
+
}
|
|
1407
|
+
function handleKey(e) {
|
|
1408
|
+
if (e.key === "ArrowRight") {
|
|
1409
|
+
e.preventDefault();
|
|
1410
|
+
setActive((a) => Math.min(periodCount - 1, (a ?? -1) + 1));
|
|
1411
|
+
} else if (e.key === "ArrowLeft") {
|
|
1412
|
+
e.preventDefault();
|
|
1413
|
+
setActive((a) => Math.max(0, (a ?? periodCount) - 1));
|
|
1414
|
+
} else if (e.key === "Escape") {
|
|
1415
|
+
setActive(null);
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
return /* @__PURE__ */ jsxs("div", { style: styles5.wrap, children: [
|
|
1419
|
+
title && /* @__PURE__ */ jsx("p", { style: styles5.title, children: title }),
|
|
1420
|
+
showLegend && /* @__PURE__ */ jsx("div", { style: styles5.legend, children: series.map((s, i) => /* @__PURE__ */ jsxs("span", { style: styles5.legendItem, children: [
|
|
1421
|
+
/* @__PURE__ */ jsx("span", { style: { ...styles5.legendKey, background: seriesColor(i) } }),
|
|
1422
|
+
s.label
|
|
1423
|
+
] }, s.key)) }),
|
|
1424
|
+
/* @__PURE__ */ jsxs(
|
|
1425
|
+
"svg",
|
|
1426
|
+
{
|
|
1427
|
+
ref: svgRef,
|
|
1428
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
1429
|
+
width: "100%",
|
|
1430
|
+
role: "img",
|
|
1431
|
+
"aria-label": ariaLabel,
|
|
1432
|
+
tabIndex: 0,
|
|
1433
|
+
style: { display: "block", outline: "none", touchAction: "none" },
|
|
1434
|
+
onPointerMove: handleMove,
|
|
1435
|
+
onPointerLeave: () => setActive(null),
|
|
1436
|
+
onKeyDown: handleKey,
|
|
1437
|
+
children: [
|
|
1438
|
+
/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("clipPath", { id: clipId, children: /* @__PURE__ */ jsx("rect", { x: MARGIN.left, y: MARGIN.top, width: innerW, height: innerH }) }) }),
|
|
1439
|
+
yTicks.map((t) => /* @__PURE__ */ jsxs("g", { children: [
|
|
1440
|
+
/* @__PURE__ */ jsx(
|
|
1441
|
+
"line",
|
|
1442
|
+
{
|
|
1443
|
+
x1: MARGIN.left,
|
|
1444
|
+
x2: MARGIN.left + innerW,
|
|
1445
|
+
y1: yAt(t),
|
|
1446
|
+
y2: yAt(t),
|
|
1447
|
+
stroke: "var(--rs-border, #e5e7eb)",
|
|
1448
|
+
strokeWidth: 1
|
|
1449
|
+
}
|
|
1450
|
+
),
|
|
1451
|
+
/* @__PURE__ */ jsx(
|
|
1452
|
+
"text",
|
|
1453
|
+
{
|
|
1454
|
+
x: MARGIN.left - 8,
|
|
1455
|
+
y: yAt(t),
|
|
1456
|
+
textAnchor: "end",
|
|
1457
|
+
dominantBaseline: "middle",
|
|
1458
|
+
fontSize: 11,
|
|
1459
|
+
fill: "var(--rs-muted, #6b7280)",
|
|
1460
|
+
style: { fontVariantNumeric: "tabular-nums" },
|
|
1461
|
+
children: formatMetricCompact(family, t)
|
|
1462
|
+
}
|
|
1463
|
+
)
|
|
1464
|
+
] }, `y${t}`)),
|
|
1465
|
+
periods.map(
|
|
1466
|
+
(p, i) => i % xEvery === 0 || i === periodCount - 1 ? /* @__PURE__ */ jsx(
|
|
1467
|
+
"text",
|
|
1468
|
+
{
|
|
1469
|
+
x: xAt(i),
|
|
1470
|
+
y: height - MARGIN.bottom + 18,
|
|
1471
|
+
textAnchor: "middle",
|
|
1472
|
+
fontSize: 11,
|
|
1473
|
+
fill: "var(--rs-muted, #6b7280)",
|
|
1474
|
+
children: shortMonth(p.x)
|
|
1475
|
+
},
|
|
1476
|
+
`x${p.x}`
|
|
1477
|
+
) : null
|
|
1478
|
+
),
|
|
1479
|
+
/* @__PURE__ */ jsx(
|
|
1480
|
+
"line",
|
|
1481
|
+
{
|
|
1482
|
+
x1: MARGIN.left,
|
|
1483
|
+
x2: MARGIN.left + innerW,
|
|
1484
|
+
y1: MARGIN.top + innerH,
|
|
1485
|
+
y2: MARGIN.top + innerH,
|
|
1486
|
+
stroke: "var(--rs-border-strong, #9ca3af)",
|
|
1487
|
+
strokeWidth: 1
|
|
1488
|
+
}
|
|
1489
|
+
),
|
|
1490
|
+
active !== null && /* @__PURE__ */ jsx(
|
|
1491
|
+
"line",
|
|
1492
|
+
{
|
|
1493
|
+
x1: xAt(active),
|
|
1494
|
+
x2: xAt(active),
|
|
1495
|
+
y1: MARGIN.top,
|
|
1496
|
+
y2: MARGIN.top + innerH,
|
|
1497
|
+
stroke: "var(--rs-border-strong, #9ca3af)",
|
|
1498
|
+
strokeWidth: 1
|
|
1499
|
+
}
|
|
1500
|
+
),
|
|
1501
|
+
/* @__PURE__ */ jsx("g", { clipPath: `url(#${clipId})`, children: series.map((s, si) => {
|
|
1502
|
+
const color = seriesColor(si);
|
|
1503
|
+
const segs = [];
|
|
1504
|
+
let pen = false;
|
|
1505
|
+
s.points.forEach((pt, i) => {
|
|
1506
|
+
if (pt.y === null || Number.isNaN(pt.y)) {
|
|
1507
|
+
pen = false;
|
|
1508
|
+
return;
|
|
1509
|
+
}
|
|
1510
|
+
segs.push(`${pen ? "L" : "M"}${xAt(i)},${yAt(pt.y)}`);
|
|
1511
|
+
pen = true;
|
|
1512
|
+
});
|
|
1513
|
+
return /* @__PURE__ */ jsx(
|
|
1514
|
+
"path",
|
|
1515
|
+
{
|
|
1516
|
+
d: segs.join(" "),
|
|
1517
|
+
fill: "none",
|
|
1518
|
+
stroke: color,
|
|
1519
|
+
strokeWidth: 2,
|
|
1520
|
+
strokeLinejoin: "round",
|
|
1521
|
+
strokeLinecap: "round"
|
|
1522
|
+
},
|
|
1523
|
+
s.key
|
|
1524
|
+
);
|
|
1525
|
+
}) }),
|
|
1526
|
+
series.map((s, si) => {
|
|
1527
|
+
const color = seriesColor(si);
|
|
1528
|
+
let endIdx = -1;
|
|
1529
|
+
for (let i = s.points.length - 1; i >= 0; i--) {
|
|
1530
|
+
const y = s.points[i].y;
|
|
1531
|
+
if (y !== null && !Number.isNaN(y)) {
|
|
1532
|
+
endIdx = i;
|
|
1533
|
+
break;
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
if (endIdx < 0) return null;
|
|
1537
|
+
const ey = yAt(s.points[endIdx].y);
|
|
1538
|
+
const ex = xAt(endIdx);
|
|
1539
|
+
let label = null;
|
|
1540
|
+
if (showEndLabels && endIdx === periodCount - 1) {
|
|
1541
|
+
const collides = placedLabelY.some((py) => Math.abs(py - ey) < 13);
|
|
1542
|
+
if (!collides) {
|
|
1543
|
+
placedLabelY.push(ey);
|
|
1544
|
+
label = formatMetricValue(family, s.points[endIdx].y);
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
return /* @__PURE__ */ jsxs("g", { children: [
|
|
1548
|
+
/* @__PURE__ */ jsx(
|
|
1549
|
+
"circle",
|
|
1550
|
+
{
|
|
1551
|
+
cx: ex,
|
|
1552
|
+
cy: ey,
|
|
1553
|
+
r: 4,
|
|
1554
|
+
fill: color,
|
|
1555
|
+
stroke: "var(--rs-surface, #ffffff)",
|
|
1556
|
+
strokeWidth: 2
|
|
1557
|
+
}
|
|
1558
|
+
),
|
|
1559
|
+
label && /* @__PURE__ */ jsx(
|
|
1560
|
+
"text",
|
|
1561
|
+
{
|
|
1562
|
+
x: ex + 8,
|
|
1563
|
+
y: ey,
|
|
1564
|
+
dominantBaseline: "middle",
|
|
1565
|
+
fontSize: 11,
|
|
1566
|
+
fill: "var(--rs-text, #111827)",
|
|
1567
|
+
style: { fontVariantNumeric: "tabular-nums" },
|
|
1568
|
+
children: label
|
|
1569
|
+
}
|
|
1570
|
+
)
|
|
1571
|
+
] }, `end${s.key}`);
|
|
1572
|
+
}),
|
|
1573
|
+
active !== null && /* @__PURE__ */ jsx(
|
|
1574
|
+
ActiveReadout,
|
|
1575
|
+
{
|
|
1576
|
+
active,
|
|
1577
|
+
series,
|
|
1578
|
+
family,
|
|
1579
|
+
xAt,
|
|
1580
|
+
yAt,
|
|
1581
|
+
width,
|
|
1582
|
+
periodLabel: periods[active] ? shortMonth(periods[active].x) : "",
|
|
1583
|
+
plotTop: MARGIN.top
|
|
1584
|
+
}
|
|
1585
|
+
)
|
|
1586
|
+
]
|
|
1587
|
+
}
|
|
1588
|
+
)
|
|
1589
|
+
] });
|
|
1590
|
+
}
|
|
1591
|
+
function ActiveReadout({
|
|
1592
|
+
active,
|
|
1593
|
+
series,
|
|
1594
|
+
family,
|
|
1595
|
+
xAt,
|
|
1596
|
+
yAt,
|
|
1597
|
+
width,
|
|
1598
|
+
periodLabel,
|
|
1599
|
+
plotTop
|
|
1600
|
+
}) {
|
|
1601
|
+
const rows = series.map((s, i) => ({
|
|
1602
|
+
label: s.label,
|
|
1603
|
+
color: seriesColor(i),
|
|
1604
|
+
value: s.points[active]?.y ?? null,
|
|
1605
|
+
y: s.points[active]?.y
|
|
1606
|
+
}));
|
|
1607
|
+
const rowH = 16;
|
|
1608
|
+
const boxW = 176;
|
|
1609
|
+
const boxH = 22 + rows.length * rowH;
|
|
1610
|
+
const cx = xAt(active);
|
|
1611
|
+
const bx = cx + 12 + boxW > width ? cx - 12 - boxW : cx + 12;
|
|
1612
|
+
const by = plotTop + 4;
|
|
1613
|
+
return /* @__PURE__ */ jsxs("g", { pointerEvents: "none", children: [
|
|
1614
|
+
rows.map(
|
|
1615
|
+
(r) => r.y !== null && r.y !== void 0 && !Number.isNaN(r.y) ? /* @__PURE__ */ jsx(
|
|
1616
|
+
"circle",
|
|
1617
|
+
{
|
|
1618
|
+
cx,
|
|
1619
|
+
cy: yAt(r.y),
|
|
1620
|
+
r: 4,
|
|
1621
|
+
fill: r.color,
|
|
1622
|
+
stroke: "var(--rs-surface, #ffffff)",
|
|
1623
|
+
strokeWidth: 2
|
|
1624
|
+
},
|
|
1625
|
+
`ap${r.label}`
|
|
1626
|
+
) : null
|
|
1627
|
+
),
|
|
1628
|
+
/* @__PURE__ */ jsx(
|
|
1629
|
+
"rect",
|
|
1630
|
+
{
|
|
1631
|
+
x: bx,
|
|
1632
|
+
y: by,
|
|
1633
|
+
width: boxW,
|
|
1634
|
+
height: boxH,
|
|
1635
|
+
rx: 6,
|
|
1636
|
+
fill: "var(--rs-surface, #ffffff)",
|
|
1637
|
+
stroke: "var(--rs-border, #e5e7eb)",
|
|
1638
|
+
strokeWidth: 1
|
|
1639
|
+
}
|
|
1640
|
+
),
|
|
1641
|
+
/* @__PURE__ */ jsx("text", { x: bx + 10, y: by + 15, fontSize: 11, fontWeight: 600, fill: "var(--rs-muted, #6b7280)", children: periodLabel }),
|
|
1642
|
+
rows.map((r, i) => {
|
|
1643
|
+
const ry = by + 22 + i * rowH + 11;
|
|
1644
|
+
return /* @__PURE__ */ jsxs("g", { children: [
|
|
1645
|
+
/* @__PURE__ */ jsx(
|
|
1646
|
+
"line",
|
|
1647
|
+
{
|
|
1648
|
+
x1: bx + 10,
|
|
1649
|
+
x2: bx + 24,
|
|
1650
|
+
y1: ry,
|
|
1651
|
+
y2: ry,
|
|
1652
|
+
stroke: r.color,
|
|
1653
|
+
strokeWidth: 2,
|
|
1654
|
+
strokeLinecap: "round"
|
|
1655
|
+
}
|
|
1656
|
+
),
|
|
1657
|
+
/* @__PURE__ */ jsx(
|
|
1658
|
+
"text",
|
|
1659
|
+
{
|
|
1660
|
+
x: bx + 30,
|
|
1661
|
+
y: ry,
|
|
1662
|
+
dominantBaseline: "middle",
|
|
1663
|
+
fontSize: 11,
|
|
1664
|
+
fill: "var(--rs-muted, #6b7280)",
|
|
1665
|
+
children: r.label
|
|
1666
|
+
}
|
|
1667
|
+
),
|
|
1668
|
+
/* @__PURE__ */ jsx(
|
|
1669
|
+
"text",
|
|
1670
|
+
{
|
|
1671
|
+
x: bx + boxW - 10,
|
|
1672
|
+
y: ry,
|
|
1673
|
+
dominantBaseline: "middle",
|
|
1674
|
+
textAnchor: "end",
|
|
1675
|
+
fontSize: 11,
|
|
1676
|
+
fontWeight: 600,
|
|
1677
|
+
fill: "var(--rs-text, #111827)",
|
|
1678
|
+
style: { fontVariantNumeric: "tabular-nums" },
|
|
1679
|
+
children: formatMetricValue(family, r.value)
|
|
1680
|
+
}
|
|
1681
|
+
)
|
|
1682
|
+
] }, `tr${r.label}`);
|
|
1683
|
+
})
|
|
1684
|
+
] });
|
|
1685
|
+
}
|
|
1193
1686
|
|
|
1194
|
-
export { ExternalTextBlock, FactInspector, ReportView, StatementTable, buildPivot, buildPivots, calcSubtotals, defaultPivotConfig, footCheck, pivotDimensionsOn, presentationOrder, reportSections, sliceReportSection };
|
|
1687
|
+
export { ExternalTextBlock, FactInspector, ReportView, SERIES_COLORS_DARK, SERIES_COLORS_LIGHT, StatementTable, TimeSeriesChart, buildPivot, buildPivots, calcSubtotals, defaultPivotConfig, footCheck, formatMetricCompact, formatMetricValue, joinChartSeries, pivotDimensionsOn, presentationOrder, reportSections, seriesColor, sliceReportSection };
|
|
1195
1688
|
//# sourceMappingURL=index.js.map
|
|
1196
1689
|
//# sourceMappingURL=index.js.map
|