@cdx-ui/components 0.3.5 → 0.3.6
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 +1 -1
- package/coverage.svg +1 -1
- package/docs/components/bar-chart/content.md +703 -0
- package/docs/components/content.md +9 -1
- package/docs/components/line-chart/content.md +567 -0
- package/docs/components/pie-chart/content.md +493 -0
- package/docs/components/progress-segmented/content.md +1 -1
- package/docs/components/stepper/content.md +599 -0
- package/docs/components/system-alert/content.md +533 -0
- package/docs/foundations/styles/tokens/all-tokens/content.md +2 -1
- package/docs/llms.txt +9 -0
- package/docs/patterns/content.md +1 -0
- package/docs/patterns/dashboard/content.md +423 -19
- package/docs/patterns/insights/content.md +590 -0
- package/docs/resources/release-notes/0.3.5/content.md +7 -0
- package/docs/resources/release-notes/content.md +1 -0
- package/lib/commonjs/components/BarChart/geometry.js +1130 -0
- package/lib/commonjs/components/BarChart/geometry.js.map +1 -0
- package/lib/commonjs/components/BarChart/index.js +942 -0
- package/lib/commonjs/components/BarChart/index.js.map +1 -0
- package/lib/commonjs/components/BarChart/styles.js +26 -0
- package/lib/commonjs/components/BarChart/styles.js.map +1 -0
- package/lib/commonjs/components/Button/index.js +2 -2
- package/lib/commonjs/components/Button/index.js.map +1 -1
- package/lib/commonjs/components/LineChart/geometry.js +698 -0
- package/lib/commonjs/components/LineChart/geometry.js.map +1 -0
- package/lib/commonjs/components/LineChart/index.js +747 -0
- package/lib/commonjs/components/LineChart/index.js.map +1 -0
- package/lib/commonjs/components/LineChart/styles.js +25 -0
- package/lib/commonjs/components/LineChart/styles.js.map +1 -0
- package/lib/commonjs/components/PieChart/geometry.js +216 -0
- package/lib/commonjs/components/PieChart/geometry.js.map +1 -0
- package/lib/commonjs/components/PieChart/index.js +476 -0
- package/lib/commonjs/components/PieChart/index.js.map +1 -0
- package/lib/commonjs/components/PieChart/styles.js +88 -0
- package/lib/commonjs/components/PieChart/styles.js.map +1 -0
- package/lib/commonjs/components/ProgressCircle/ProgressCircleRing.js +9 -31
- package/lib/commonjs/components/ProgressCircle/ProgressCircleRing.js.map +1 -1
- package/lib/commonjs/components/ProgressCircle/ProgressRing.js +52 -0
- package/lib/commonjs/components/ProgressCircle/ProgressRing.js.map +1 -0
- package/lib/commonjs/components/ScrollShadow/useScrollShadow.js +8 -7
- package/lib/commonjs/components/ScrollShadow/useScrollShadow.js.map +1 -1
- package/lib/commonjs/components/Stepper/index.js +369 -0
- package/lib/commonjs/components/Stepper/index.js.map +1 -0
- package/lib/commonjs/components/Stepper/styles.js +211 -0
- package/lib/commonjs/components/Stepper/styles.js.map +1 -0
- package/lib/commonjs/components/Stepper/useStepperLabelFit.js +22 -0
- package/lib/commonjs/components/Stepper/useStepperLabelFit.js.map +1 -0
- package/lib/commonjs/components/Stepper/useStepperLabelFit.web.js +52 -0
- package/lib/commonjs/components/Stepper/useStepperLabelFit.web.js.map +1 -0
- package/lib/commonjs/components/Stepper/useStepperRingColors.js +31 -0
- package/lib/commonjs/components/Stepper/useStepperRingColors.js.map +1 -0
- package/lib/commonjs/components/SystemAlert/animation.js +218 -0
- package/lib/commonjs/components/SystemAlert/animation.js.map +1 -0
- package/lib/commonjs/components/SystemAlert/index.js +525 -0
- package/lib/commonjs/components/SystemAlert/index.js.map +1 -0
- package/lib/commonjs/components/SystemAlert/styles.js +178 -0
- package/lib/commonjs/components/SystemAlert/styles.js.map +1 -0
- package/lib/commonjs/components/SystemAlert/useSystemAlertStatusBarStyle.js +53 -0
- package/lib/commonjs/components/SystemAlert/useSystemAlertStatusBarStyle.js.map +1 -0
- package/lib/commonjs/components/Tabs/index.js +4 -0
- package/lib/commonjs/components/Tabs/index.js.map +1 -1
- package/lib/commonjs/components/Tabs/styles.js +1 -1
- package/lib/commonjs/components/Tabs/styles.js.map +1 -1
- package/lib/commonjs/components/chart/ChartInspector.js +610 -0
- package/lib/commonjs/components/chart/ChartInspector.js.map +1 -0
- package/lib/commonjs/components/chart/format.js +93 -0
- package/lib/commonjs/components/chart/format.js.map +1 -0
- package/lib/commonjs/components/chart/index.js +2 -0
- package/lib/commonjs/components/chart/index.js.map +1 -0
- package/lib/commonjs/components/chart/motion.js +97 -0
- package/lib/commonjs/components/chart/motion.js.map +1 -0
- package/lib/commonjs/components/chart/palette.js +178 -0
- package/lib/commonjs/components/chart/palette.js.map +1 -0
- package/lib/commonjs/components/chart/size.js +34 -0
- package/lib/commonjs/components/chart/size.js.map +1 -0
- package/lib/commonjs/components/chart/ticks.js +59 -0
- package/lib/commonjs/components/chart/ticks.js.map +1 -0
- package/lib/commonjs/components/chart/types.js +6 -0
- package/lib/commonjs/components/chart/types.js.map +1 -0
- package/lib/commonjs/components/chart/useChartHostWidth.js +27 -0
- package/lib/commonjs/components/chart/useChartHostWidth.js.map +1 -0
- package/lib/commonjs/components/index.js +60 -0
- package/lib/commonjs/components/index.js.map +1 -1
- package/lib/commonjs/figma/SystemAlert.Button.figma.js +28 -0
- package/lib/commonjs/figma/SystemAlert.Button.figma.js.map +1 -0
- package/lib/commonjs/figma/SystemAlert.Close.figma.js +22 -0
- package/lib/commonjs/figma/SystemAlert.Close.figma.js.map +1 -0
- package/lib/commonjs/figma/SystemAlert.Description.figma.js +20 -0
- package/lib/commonjs/figma/SystemAlert.Description.figma.js.map +1 -0
- package/lib/commonjs/figma/SystemAlert.IconButton.figma.js +31 -0
- package/lib/commonjs/figma/SystemAlert.IconButton.figma.js.map +1 -0
- package/lib/commonjs/figma/SystemAlert.figma.js +48 -0
- package/lib/commonjs/figma/SystemAlert.figma.js.map +1 -0
- package/lib/module/components/BarChart/geometry.js +1110 -0
- package/lib/module/components/BarChart/geometry.js.map +1 -0
- package/lib/module/components/BarChart/index.js +936 -0
- package/lib/module/components/BarChart/index.js.map +1 -0
- package/lib/module/components/BarChart/styles.js +22 -0
- package/lib/module/components/BarChart/styles.js.map +1 -0
- package/lib/module/components/Button/index.js +2 -2
- package/lib/module/components/Button/index.js.map +1 -1
- package/lib/module/components/LineChart/geometry.js +685 -0
- package/lib/module/components/LineChart/geometry.js.map +1 -0
- package/lib/module/components/LineChart/index.js +741 -0
- package/lib/module/components/LineChart/index.js.map +1 -0
- package/lib/module/components/LineChart/styles.js +21 -0
- package/lib/module/components/LineChart/styles.js.map +1 -0
- package/lib/module/components/PieChart/geometry.js +209 -0
- package/lib/module/components/PieChart/geometry.js.map +1 -0
- package/lib/module/components/PieChart/index.js +471 -0
- package/lib/module/components/PieChart/index.js.map +1 -0
- package/lib/module/components/PieChart/styles.js +84 -0
- package/lib/module/components/PieChart/styles.js.map +1 -0
- package/lib/module/components/ProgressCircle/ProgressCircleRing.js +10 -32
- package/lib/module/components/ProgressCircle/ProgressCircleRing.js.map +1 -1
- package/lib/module/components/ProgressCircle/ProgressRing.js +48 -0
- package/lib/module/components/ProgressCircle/ProgressRing.js.map +1 -0
- package/lib/module/components/ScrollShadow/useScrollShadow.js +8 -7
- package/lib/module/components/ScrollShadow/useScrollShadow.js.map +1 -1
- package/lib/module/components/Stepper/index.js +360 -0
- package/lib/module/components/Stepper/index.js.map +1 -0
- package/lib/module/components/Stepper/styles.js +206 -0
- package/lib/module/components/Stepper/styles.js.map +1 -0
- package/lib/module/components/Stepper/useStepperLabelFit.js +18 -0
- package/lib/module/components/Stepper/useStepperLabelFit.js.map +1 -0
- package/lib/module/components/Stepper/useStepperLabelFit.web.js +48 -0
- package/lib/module/components/Stepper/useStepperLabelFit.web.js.map +1 -0
- package/lib/module/components/Stepper/useStepperRingColors.js +28 -0
- package/lib/module/components/Stepper/useStepperRingColors.js.map +1 -0
- package/lib/module/components/SystemAlert/animation.js +213 -0
- package/lib/module/components/SystemAlert/animation.js.map +1 -0
- package/lib/module/components/SystemAlert/index.js +515 -0
- package/lib/module/components/SystemAlert/index.js.map +1 -0
- package/lib/module/components/SystemAlert/styles.js +174 -0
- package/lib/module/components/SystemAlert/styles.js.map +1 -0
- package/lib/module/components/SystemAlert/useSystemAlertStatusBarStyle.js +49 -0
- package/lib/module/components/SystemAlert/useSystemAlertStatusBarStyle.js.map +1 -0
- package/lib/module/components/Tabs/index.js +4 -0
- package/lib/module/components/Tabs/index.js.map +1 -1
- package/lib/module/components/Tabs/styles.js +1 -1
- package/lib/module/components/Tabs/styles.js.map +1 -1
- package/lib/module/components/chart/ChartInspector.js +600 -0
- package/lib/module/components/chart/ChartInspector.js.map +1 -0
- package/lib/module/components/chart/format.js +84 -0
- package/lib/module/components/chart/format.js.map +1 -0
- package/lib/module/components/chart/index.js +2 -0
- package/lib/module/components/chart/index.js.map +1 -0
- package/lib/module/components/chart/motion.js +89 -0
- package/lib/module/components/chart/motion.js.map +1 -0
- package/lib/module/components/chart/palette.js +168 -0
- package/lib/module/components/chart/palette.js.map +1 -0
- package/lib/module/components/chart/size.js +29 -0
- package/lib/module/components/chart/size.js.map +1 -0
- package/lib/module/components/chart/ticks.js +55 -0
- package/lib/module/components/chart/ticks.js.map +1 -0
- package/lib/module/components/chart/types.js +4 -0
- package/lib/module/components/chart/types.js.map +1 -0
- package/lib/module/components/chart/useChartHostWidth.js +23 -0
- package/lib/module/components/chart/useChartHostWidth.js.map +1 -0
- package/lib/module/components/index.js +5 -0
- package/lib/module/components/index.js.map +1 -1
- package/lib/module/figma/SystemAlert.Button.figma.js +22 -0
- package/lib/module/figma/SystemAlert.Button.figma.js.map +1 -0
- package/lib/module/figma/SystemAlert.Close.figma.js +18 -0
- package/lib/module/figma/SystemAlert.Close.figma.js.map +1 -0
- package/lib/module/figma/SystemAlert.Description.figma.js +14 -0
- package/lib/module/figma/SystemAlert.Description.figma.js.map +1 -0
- package/lib/module/figma/SystemAlert.IconButton.figma.js +25 -0
- package/lib/module/figma/SystemAlert.IconButton.figma.js.map +1 -0
- package/lib/module/figma/SystemAlert.figma.js +42 -0
- package/lib/module/figma/SystemAlert.figma.js.map +1 -0
- package/lib/typescript/components/BarChart/geometry.d.ts +236 -0
- package/lib/typescript/components/BarChart/geometry.d.ts.map +1 -0
- package/lib/typescript/components/BarChart/index.d.ts +193 -0
- package/lib/typescript/components/BarChart/index.d.ts.map +1 -0
- package/lib/typescript/components/BarChart/styles.d.ts +32 -0
- package/lib/typescript/components/BarChart/styles.d.ts.map +1 -0
- package/lib/typescript/components/LineChart/geometry.d.ts +248 -0
- package/lib/typescript/components/LineChart/geometry.d.ts.map +1 -0
- package/lib/typescript/components/LineChart/index.d.ts +105 -0
- package/lib/typescript/components/LineChart/index.d.ts.map +1 -0
- package/lib/typescript/components/LineChart/styles.d.ts +12 -0
- package/lib/typescript/components/LineChart/styles.d.ts.map +1 -0
- package/lib/typescript/components/PieChart/geometry.d.ts +43 -0
- package/lib/typescript/components/PieChart/geometry.d.ts.map +1 -0
- package/lib/typescript/components/PieChart/index.d.ts +147 -0
- package/lib/typescript/components/PieChart/index.d.ts.map +1 -0
- package/lib/typescript/components/PieChart/styles.d.ts +27 -0
- package/lib/typescript/components/PieChart/styles.d.ts.map +1 -0
- package/lib/typescript/components/ProgressCircle/ProgressCircleRing.d.ts.map +1 -1
- package/lib/typescript/components/ProgressCircle/ProgressRing.d.ts +17 -0
- package/lib/typescript/components/ProgressCircle/ProgressRing.d.ts.map +1 -0
- package/lib/typescript/components/ScrollShadow/useScrollShadow.d.ts.map +1 -1
- package/lib/typescript/components/Stepper/index.d.ts +68 -0
- package/lib/typescript/components/Stepper/index.d.ts.map +1 -0
- package/lib/typescript/components/Stepper/styles.d.ts +46 -0
- package/lib/typescript/components/Stepper/styles.d.ts.map +1 -0
- package/lib/typescript/components/Stepper/useStepperLabelFit.d.ts +15 -0
- package/lib/typescript/components/Stepper/useStepperLabelFit.d.ts.map +1 -0
- package/lib/typescript/components/Stepper/useStepperLabelFit.web.d.ts +10 -0
- package/lib/typescript/components/Stepper/useStepperLabelFit.web.d.ts.map +1 -0
- package/lib/typescript/components/Stepper/useStepperRingColors.d.ts +6 -0
- package/lib/typescript/components/Stepper/useStepperRingColors.d.ts.map +1 -0
- package/lib/typescript/components/SystemAlert/animation.d.ts +56 -0
- package/lib/typescript/components/SystemAlert/animation.d.ts.map +1 -0
- package/lib/typescript/components/SystemAlert/index.d.ts +110 -0
- package/lib/typescript/components/SystemAlert/index.d.ts.map +1 -0
- package/lib/typescript/components/SystemAlert/styles.d.ts +38 -0
- package/lib/typescript/components/SystemAlert/styles.d.ts.map +1 -0
- package/lib/typescript/components/SystemAlert/useSystemAlertStatusBarStyle.d.ts +14 -0
- package/lib/typescript/components/SystemAlert/useSystemAlertStatusBarStyle.d.ts.map +1 -0
- package/lib/typescript/components/Tabs/index.d.ts.map +1 -1
- package/lib/typescript/components/chart/ChartInspector.d.ts +101 -0
- package/lib/typescript/components/chart/ChartInspector.d.ts.map +1 -0
- package/lib/typescript/components/chart/format.d.ts +16 -0
- package/lib/typescript/components/chart/format.d.ts.map +1 -0
- package/lib/typescript/components/chart/index.d.ts +3 -0
- package/lib/typescript/components/chart/index.d.ts.map +1 -0
- package/lib/typescript/components/chart/motion.d.ts +27 -0
- package/lib/typescript/components/chart/motion.d.ts.map +1 -0
- package/lib/typescript/components/chart/palette.d.ts +44 -0
- package/lib/typescript/components/chart/palette.d.ts.map +1 -0
- package/lib/typescript/components/chart/size.d.ts +25 -0
- package/lib/typescript/components/chart/size.d.ts.map +1 -0
- package/lib/typescript/components/chart/ticks.d.ts +3 -0
- package/lib/typescript/components/chart/ticks.d.ts.map +1 -0
- package/lib/typescript/components/chart/types.d.ts +163 -0
- package/lib/typescript/components/chart/types.d.ts.map +1 -0
- package/lib/typescript/components/chart/useChartHostWidth.d.ts +9 -0
- package/lib/typescript/components/chart/useChartHostWidth.d.ts.map +1 -0
- package/lib/typescript/components/index.d.ts +5 -0
- package/lib/typescript/components/index.d.ts.map +1 -1
- package/lib/typescript/figma/SystemAlert.Button.figma.d.ts +11 -0
- package/lib/typescript/figma/SystemAlert.Button.figma.d.ts.map +1 -0
- package/lib/typescript/figma/SystemAlert.Close.figma.d.ts +11 -0
- package/lib/typescript/figma/SystemAlert.Close.figma.d.ts.map +1 -0
- package/lib/typescript/figma/SystemAlert.Description.figma.d.ts +8 -0
- package/lib/typescript/figma/SystemAlert.Description.figma.d.ts.map +1 -0
- package/lib/typescript/figma/SystemAlert.IconButton.figma.d.ts +11 -0
- package/lib/typescript/figma/SystemAlert.IconButton.figma.d.ts.map +1 -0
- package/lib/typescript/figma/SystemAlert.figma.d.ts +8 -0
- package/lib/typescript/figma/SystemAlert.figma.d.ts.map +1 -0
- package/package.json +5 -5
- package/src/components/BarChart/geometry.ts +1469 -0
- package/src/components/BarChart/index.tsx +1424 -0
- package/src/components/BarChart/styles.ts +31 -0
- package/src/components/Button/index.tsx +1 -1
- package/src/components/LineChart/geometry.ts +957 -0
- package/src/components/LineChart/index.tsx +1109 -0
- package/src/components/LineChart/styles.ts +26 -0
- package/src/components/PieChart/geometry.ts +295 -0
- package/src/components/PieChart/index.tsx +715 -0
- package/src/components/PieChart/styles.ts +101 -0
- package/src/components/ProgressCircle/ProgressCircleRing.tsx +10 -39
- package/src/components/ProgressCircle/ProgressRing.tsx +60 -0
- package/src/components/ScrollShadow/useScrollShadow.ts +12 -11
- package/src/components/Stepper/index.tsx +452 -0
- package/src/components/Stepper/styles.ts +234 -0
- package/src/components/Stepper/useStepperLabelFit.ts +21 -0
- package/src/components/Stepper/useStepperLabelFit.web.ts +53 -0
- package/src/components/Stepper/useStepperRingColors.ts +29 -0
- package/src/components/SystemAlert/animation.ts +252 -0
- package/src/components/SystemAlert/index.tsx +684 -0
- package/src/components/SystemAlert/styles.ts +212 -0
- package/src/components/SystemAlert/useSystemAlertStatusBarStyle.ts +57 -0
- package/src/components/Tabs/index.tsx +4 -0
- package/src/components/Tabs/styles.ts +1 -1
- package/src/components/chart/ChartInspector.tsx +726 -0
- package/src/components/chart/format.ts +95 -0
- package/src/components/chart/index.ts +24 -0
- package/src/components/chart/motion.ts +98 -0
- package/src/components/chart/palette.tsx +247 -0
- package/src/components/chart/size.ts +21 -0
- package/src/components/chart/ticks.ts +53 -0
- package/src/components/chart/types.ts +183 -0
- package/src/components/chart/useChartHostWidth.ts +26 -0
- package/src/components/index.ts +5 -0
|
@@ -0,0 +1,685 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { niceTicks } from '../chart/ticks';
|
|
4
|
+
|
|
5
|
+
/** How points connect. Names match MUI X `curve`. */
|
|
6
|
+
|
|
7
|
+
export const MIN_LINE_POINT_BAND = 32;
|
|
8
|
+
/** Max distance from a series stroke (overlay px) that still counts as hovering the line. */
|
|
9
|
+
export const LINE_POINTER_HIT_PX = 20;
|
|
10
|
+
/** Extra radius around a plotted point (dots / markers) so a valley like Lowest is easy to hit. */
|
|
11
|
+
export const LINE_POINT_HIT_PX = 28;
|
|
12
|
+
/** Extra plot padding when a marker draws a caption or value. */
|
|
13
|
+
export const LINE_MARKER_PADDING_TOP = 28;
|
|
14
|
+
export const LINE_MARKER_PADDING_RIGHT = 36;
|
|
15
|
+
export const DEFAULT_LINE_TICK_NUMBER = 4;
|
|
16
|
+
const VALUE_TICK_LEFT = 40;
|
|
17
|
+
const VALUE_TICK_END = 28;
|
|
18
|
+
const TIGHT_GUTTER = 8;
|
|
19
|
+
const PLOT_END_GUTTER = 20;
|
|
20
|
+
const CATEGORY_GUTTER = 28;
|
|
21
|
+
function round2(value) {
|
|
22
|
+
'worklet';
|
|
23
|
+
|
|
24
|
+
const rounded = Math.round(value * 100) / 100;
|
|
25
|
+
return Object.is(rounded, -0) ? 0 : rounded;
|
|
26
|
+
}
|
|
27
|
+
function readNumber(row, key) {
|
|
28
|
+
const raw = row[key];
|
|
29
|
+
if (typeof raw !== 'number' || !Number.isFinite(raw)) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return raw;
|
|
33
|
+
}
|
|
34
|
+
function rawCategory(row, key, index) {
|
|
35
|
+
if (key === undefined || row === undefined) {
|
|
36
|
+
return index;
|
|
37
|
+
}
|
|
38
|
+
return row[key];
|
|
39
|
+
}
|
|
40
|
+
function categoryText(raw, index, location, axis) {
|
|
41
|
+
if (typeof raw === 'string') {
|
|
42
|
+
return raw;
|
|
43
|
+
}
|
|
44
|
+
if (typeof raw === 'number') {
|
|
45
|
+
return axis?.valueFormatter?.(raw, {
|
|
46
|
+
location,
|
|
47
|
+
dataIndex: index
|
|
48
|
+
}) ?? String(raw);
|
|
49
|
+
}
|
|
50
|
+
if (raw === null || raw === undefined) {
|
|
51
|
+
return '';
|
|
52
|
+
}
|
|
53
|
+
return String(raw);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Maps the public `dataset` + `series` + `xAxis` props onto geometry inputs. Row keys are read
|
|
58
|
+
* only through `dataKey`, so no key is reserved.
|
|
59
|
+
*/
|
|
60
|
+
export function resolveLineChartData({
|
|
61
|
+
dataset,
|
|
62
|
+
series,
|
|
63
|
+
xAxis
|
|
64
|
+
}) {
|
|
65
|
+
const axis = xAxis;
|
|
66
|
+
const interval = axis?.tickLabelInterval;
|
|
67
|
+
const hidden = axis?.position === 'none';
|
|
68
|
+
const categories = dataset.map((row, index) => {
|
|
69
|
+
const raw = rawCategory(row, axis?.dataKey, index);
|
|
70
|
+
const label = categoryText(raw, index, 'tick', axis);
|
|
71
|
+
const shown = typeof interval === 'function' ? interval(raw, index) : true;
|
|
72
|
+
return {
|
|
73
|
+
label,
|
|
74
|
+
title: categoryText(raw, index, 'tooltip', axis),
|
|
75
|
+
tick: !hidden && shown && label.length > 0
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
const inputs = series.map(item => {
|
|
79
|
+
const dashed = item.dashed === true;
|
|
80
|
+
const dashAt = dashed || item.dashedFrom === undefined || !Number.isInteger(item.dashedFrom) ? -1 : item.dashedFrom;
|
|
81
|
+
return {
|
|
82
|
+
id: item.id,
|
|
83
|
+
label: item.label ?? '',
|
|
84
|
+
curve: item.curve ?? 'monotoneX',
|
|
85
|
+
area: item.area === true,
|
|
86
|
+
dashed,
|
|
87
|
+
dashAt,
|
|
88
|
+
values: dataset.map(row => readNumber(row, item.dataKey))
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
return {
|
|
92
|
+
categories,
|
|
93
|
+
series: inputs
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export function lineChartGutters({
|
|
97
|
+
showValueTicks = true,
|
|
98
|
+
showCategoryLabels = true
|
|
99
|
+
} = {}) {
|
|
100
|
+
return {
|
|
101
|
+
paddingLeft: showValueTicks ? VALUE_TICK_LEFT : TIGHT_GUTTER,
|
|
102
|
+
paddingRight: showValueTicks ? VALUE_TICK_END : PLOT_END_GUTTER,
|
|
103
|
+
paddingTop: TIGHT_GUTTER,
|
|
104
|
+
paddingBottom: showCategoryLabels ? CATEGORY_GUTTER : TIGHT_GUTTER
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
export function resolveLineChartContentSize({
|
|
108
|
+
viewportWidth,
|
|
109
|
+
viewportHeight,
|
|
110
|
+
categoryCount,
|
|
111
|
+
gutters,
|
|
112
|
+
scrollable,
|
|
113
|
+
visiblePoints
|
|
114
|
+
}) {
|
|
115
|
+
if (!scrollable || categoryCount <= 0) {
|
|
116
|
+
return {
|
|
117
|
+
width: viewportWidth,
|
|
118
|
+
height: viewportHeight
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
const plotWidth = Math.max(viewportWidth - gutters.paddingLeft - gutters.paddingRight, 0);
|
|
122
|
+
const band = visiblePoints !== undefined && visiblePoints > 0 ? plotWidth / Math.max(visiblePoints - 1, 1) : MIN_LINE_POINT_BAND;
|
|
123
|
+
const contentPlot = Math.max(plotWidth, Math.max(categoryCount - 1, 1) * band);
|
|
124
|
+
return {
|
|
125
|
+
width: contentPlot + gutters.paddingLeft + gutters.paddingRight,
|
|
126
|
+
height: viewportHeight
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Value domain and ticks. `min` / `max` pin that end exactly; an open end rounds to a readable
|
|
132
|
+
* tick. `tickNumber` is approximate.
|
|
133
|
+
*/
|
|
134
|
+
export function lineValueDomain(values, {
|
|
135
|
+
min: minOption,
|
|
136
|
+
max: maxOption,
|
|
137
|
+
tickNumber = DEFAULT_LINE_TICK_NUMBER
|
|
138
|
+
} = {}) {
|
|
139
|
+
const min = minOption !== undefined && Number.isFinite(minOption) ? minOption : undefined;
|
|
140
|
+
const max = maxOption !== undefined && Number.isFinite(maxOption) ? maxOption : undefined;
|
|
141
|
+
let low = min ?? (values.length > 0 ? Math.min(...values) : 0);
|
|
142
|
+
let high = max ?? (values.length > 0 ? Math.max(...values) : 1);
|
|
143
|
+
if (low > high) {
|
|
144
|
+
[low, high] = [high, low];
|
|
145
|
+
}
|
|
146
|
+
if (low === high) {
|
|
147
|
+
if (min === undefined) {
|
|
148
|
+
low -= 1;
|
|
149
|
+
}
|
|
150
|
+
if (max === undefined || min !== undefined) {
|
|
151
|
+
high += 1;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const nice = niceTicks(low, high, tickNumber);
|
|
155
|
+
const domainMin = min ?? nice[0] ?? low;
|
|
156
|
+
const domainMax = max ?? nice[nice.length - 1] ?? high;
|
|
157
|
+
const epsilon = (domainMax - domainMin) * 1e-9;
|
|
158
|
+
const ticks = nice.filter(tick => tick >= domainMin - epsilon && tick <= domainMax + epsilon);
|
|
159
|
+
return {
|
|
160
|
+
min: domainMin,
|
|
161
|
+
max: domainMax,
|
|
162
|
+
ticks
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function coord(x, y) {
|
|
166
|
+
'worklet';
|
|
167
|
+
|
|
168
|
+
return `${String(round2(x))} ${String(round2(y))}`;
|
|
169
|
+
}
|
|
170
|
+
function linearPath(points) {
|
|
171
|
+
'worklet';
|
|
172
|
+
|
|
173
|
+
return points.map((point, index) => `${index === 0 ? 'M' : 'L'} ${coord(point.x, point.y)}`).join(' ');
|
|
174
|
+
}
|
|
175
|
+
function stepPath(points) {
|
|
176
|
+
'worklet';
|
|
177
|
+
|
|
178
|
+
if (points.length === 0) {
|
|
179
|
+
return '';
|
|
180
|
+
}
|
|
181
|
+
const parts = [`M ${coord(points[0].x, points[0].y)}`];
|
|
182
|
+
for (let index = 1; index < points.length; index += 1) {
|
|
183
|
+
const prev = points[index - 1];
|
|
184
|
+
const point = points[index];
|
|
185
|
+
parts.push(`L ${coord(point.x, prev.y)}`, `L ${coord(point.x, point.y)}`);
|
|
186
|
+
}
|
|
187
|
+
return parts.join(' ');
|
|
188
|
+
}
|
|
189
|
+
function monotoneControls(points) {
|
|
190
|
+
'worklet';
|
|
191
|
+
|
|
192
|
+
const count = points.length;
|
|
193
|
+
const dx = [];
|
|
194
|
+
const slope = [];
|
|
195
|
+
for (let index = 0; index < count - 1; index += 1) {
|
|
196
|
+
const deltaX = points[index + 1].x - points[index].x;
|
|
197
|
+
dx.push(deltaX);
|
|
198
|
+
slope.push(deltaX === 0 ? 0 : (points[index + 1].y - points[index].y) / deltaX);
|
|
199
|
+
}
|
|
200
|
+
const tangent = [slope[0]];
|
|
201
|
+
for (let index = 1; index < count - 1; index += 1) {
|
|
202
|
+
tangent.push(slope[index - 1] * slope[index] <= 0 ? 0 : (slope[index - 1] + slope[index]) / 2);
|
|
203
|
+
}
|
|
204
|
+
tangent.push(slope[count - 2]);
|
|
205
|
+
for (let index = 0; index < count - 1; index += 1) {
|
|
206
|
+
if (Math.abs(slope[index]) < 1e-8) {
|
|
207
|
+
tangent[index] = 0;
|
|
208
|
+
tangent[index + 1] = 0;
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
const alpha = tangent[index] / slope[index];
|
|
212
|
+
const beta = tangent[index + 1] / slope[index];
|
|
213
|
+
const magnitude = alpha * alpha + beta * beta;
|
|
214
|
+
if (magnitude > 9) {
|
|
215
|
+
const scale = 3 / Math.sqrt(magnitude);
|
|
216
|
+
tangent[index] = scale * alpha * slope[index];
|
|
217
|
+
tangent[index + 1] = scale * beta * slope[index];
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
dx,
|
|
222
|
+
tangent
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
function monotonePathSlice(points, from, to) {
|
|
226
|
+
'worklet';
|
|
227
|
+
|
|
228
|
+
const count = points.length;
|
|
229
|
+
if (count === 0 || to < from || from < 0 || to > count - 1) {
|
|
230
|
+
return '';
|
|
231
|
+
}
|
|
232
|
+
if (from === to) {
|
|
233
|
+
return `M ${coord(points[from].x, points[from].y)}`;
|
|
234
|
+
}
|
|
235
|
+
if (count === 2) {
|
|
236
|
+
return linearPath(points.slice(from, to + 1));
|
|
237
|
+
}
|
|
238
|
+
const {
|
|
239
|
+
dx,
|
|
240
|
+
tangent
|
|
241
|
+
} = monotoneControls(points);
|
|
242
|
+
const parts = [`M ${coord(points[from].x, points[from].y)}`];
|
|
243
|
+
for (let index = from; index < to; index += 1) {
|
|
244
|
+
const start = points[index];
|
|
245
|
+
const end = points[index + 1];
|
|
246
|
+
const handle = dx[index] / 3;
|
|
247
|
+
parts.push(`C ${coord(start.x + handle, start.y + tangent[index] * handle)} ${coord(end.x - handle, end.y - tangent[index + 1] * handle)} ${coord(end.x, end.y)}`);
|
|
248
|
+
}
|
|
249
|
+
return parts.join(' ');
|
|
250
|
+
}
|
|
251
|
+
function monotonePath(points) {
|
|
252
|
+
'worklet';
|
|
253
|
+
|
|
254
|
+
if (points.length === 0) {
|
|
255
|
+
return '';
|
|
256
|
+
}
|
|
257
|
+
return monotonePathSlice(points, 0, points.length - 1);
|
|
258
|
+
}
|
|
259
|
+
function pathForCurve(points, curve) {
|
|
260
|
+
'worklet';
|
|
261
|
+
|
|
262
|
+
if (curve === 'stepAfter') {
|
|
263
|
+
return stepPath(points);
|
|
264
|
+
}
|
|
265
|
+
if (curve === 'monotoneX') {
|
|
266
|
+
return monotonePath(points);
|
|
267
|
+
}
|
|
268
|
+
return linearPath(points);
|
|
269
|
+
}
|
|
270
|
+
function pathSlice(points, curve, from, to) {
|
|
271
|
+
'worklet';
|
|
272
|
+
|
|
273
|
+
if (to <= from) {
|
|
274
|
+
return '';
|
|
275
|
+
}
|
|
276
|
+
if (curve === 'monotoneX') {
|
|
277
|
+
return monotonePathSlice(points, from, to);
|
|
278
|
+
}
|
|
279
|
+
return pathForCurve(points.slice(from, to + 1), curve);
|
|
280
|
+
}
|
|
281
|
+
function areaFromLine(linePath, run, baselineY) {
|
|
282
|
+
'worklet';
|
|
283
|
+
|
|
284
|
+
if (linePath.length === 0 || run.length === 0) {
|
|
285
|
+
return '';
|
|
286
|
+
}
|
|
287
|
+
const first = run[0];
|
|
288
|
+
const last = run[run.length - 1];
|
|
289
|
+
return `${linePath} L ${coord(last.x, baselineY)} L ${coord(first.x, baselineY)} Z`;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Line and area paths for one series. `ys` uses `NaN` for missing values, which
|
|
294
|
+
* open a gap. Runs on the UI thread while a chart animates.
|
|
295
|
+
* `dashAt` is a category index; cubics before it stay solid, after it dashed,
|
|
296
|
+
* using the same monotone tangents so the join stays round.
|
|
297
|
+
*/
|
|
298
|
+
export function lineSeriesPaths(xs, ys, curve, baselineY, dashAt = -1) {
|
|
299
|
+
'worklet';
|
|
300
|
+
|
|
301
|
+
const runs = [];
|
|
302
|
+
let current = [];
|
|
303
|
+
for (let index = 0; index < ys.length; index += 1) {
|
|
304
|
+
const y = ys[index];
|
|
305
|
+
if (!Number.isFinite(y)) {
|
|
306
|
+
if (current.length > 0) {
|
|
307
|
+
runs.push(current);
|
|
308
|
+
current = [];
|
|
309
|
+
}
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
current.push({
|
|
313
|
+
x: xs[index] ?? 0,
|
|
314
|
+
y,
|
|
315
|
+
index
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
if (current.length > 0) {
|
|
319
|
+
runs.push(current);
|
|
320
|
+
}
|
|
321
|
+
const solids = [];
|
|
322
|
+
const dashes = [];
|
|
323
|
+
const areas = [];
|
|
324
|
+
for (const run of runs) {
|
|
325
|
+
const line = pathForCurve(run, curve);
|
|
326
|
+
areas.push(areaFromLine(line, run, baselineY));
|
|
327
|
+
const first = run[0]?.index ?? -1;
|
|
328
|
+
const last = run[run.length - 1]?.index ?? -1;
|
|
329
|
+
if (dashAt < 0 || dashAt <= first || dashAt >= last) {
|
|
330
|
+
if (dashAt >= 0 && dashAt <= first) {
|
|
331
|
+
dashes.push(line);
|
|
332
|
+
} else {
|
|
333
|
+
solids.push(line);
|
|
334
|
+
}
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
const split = run.findIndex(point => point.index === dashAt);
|
|
338
|
+
if (split <= 0) {
|
|
339
|
+
solids.push(line);
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
solids.push(pathSlice(run, curve, 0, split));
|
|
343
|
+
dashes.push(pathSlice(run, curve, split, run.length - 1));
|
|
344
|
+
}
|
|
345
|
+
return {
|
|
346
|
+
path: solids.join(' '),
|
|
347
|
+
dashedPath: dashes.join(' '),
|
|
348
|
+
areaPath: areas.join(' ')
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/** Pins each marker to its `dataIndex` row; markers that cannot resolve are dropped. */
|
|
353
|
+
export function layoutLineChartMarkers(markers, series) {
|
|
354
|
+
return markers.flatMap((marker, markerIndex) => {
|
|
355
|
+
const index = marker.dataIndex;
|
|
356
|
+
if (!Number.isInteger(index)) {
|
|
357
|
+
return [];
|
|
358
|
+
}
|
|
359
|
+
const seriesItem = marker.seriesId !== undefined ? series.find(item => item.key === marker.seriesId) : series.find(item => item.points[index]?.y != null);
|
|
360
|
+
const point = seriesItem?.points[index];
|
|
361
|
+
if (seriesItem === undefined || point?.y == null || point.value == null) {
|
|
362
|
+
return [];
|
|
363
|
+
}
|
|
364
|
+
return [{
|
|
365
|
+
key: `${seriesItem.key}-${String(index)}-${String(markerIndex)}`,
|
|
366
|
+
index,
|
|
367
|
+
seriesIndex: series.indexOf(seriesItem),
|
|
368
|
+
seriesId: seriesItem.key,
|
|
369
|
+
x: point.x,
|
|
370
|
+
y: point.y,
|
|
371
|
+
value: point.value,
|
|
372
|
+
label: marker.label,
|
|
373
|
+
showValue: marker.showValue === true,
|
|
374
|
+
color: marker.color,
|
|
375
|
+
legend: marker.legend,
|
|
376
|
+
guide: marker.guide !== false,
|
|
377
|
+
dot: marker.dot !== false
|
|
378
|
+
}];
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
function distanceToSegment(px, py, ax, ay, bx, by) {
|
|
382
|
+
const dx = bx - ax;
|
|
383
|
+
const dy = by - ay;
|
|
384
|
+
const length = dx * dx + dy * dy;
|
|
385
|
+
if (length === 0) {
|
|
386
|
+
return Math.hypot(px - ax, py - ay);
|
|
387
|
+
}
|
|
388
|
+
const t = Math.max(0, Math.min(1, ((px - ax) * dx + (py - ay) * dy) / length));
|
|
389
|
+
return Math.hypot(px - (ax + t * dx), py - (ay + t * dy));
|
|
390
|
+
}
|
|
391
|
+
function cubicPoint(t, p0, p1, p2, p3) {
|
|
392
|
+
const u = 1 - t;
|
|
393
|
+
const a = u * u * u;
|
|
394
|
+
const b = 3 * u * u * t;
|
|
395
|
+
const c = 3 * u * t * t;
|
|
396
|
+
const d = t * t * t;
|
|
397
|
+
return {
|
|
398
|
+
x: a * p0.x + b * p1.x + c * p2.x + d * p3.x,
|
|
399
|
+
y: a * p0.y + b * p1.y + c * p2.y + d * p3.y
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
function sampleMonotoneRun(points) {
|
|
403
|
+
if (points.length < 3) {
|
|
404
|
+
return [...points];
|
|
405
|
+
}
|
|
406
|
+
const count = points.length;
|
|
407
|
+
const dx = [];
|
|
408
|
+
const slope = [];
|
|
409
|
+
for (let index = 0; index < count - 1; index += 1) {
|
|
410
|
+
const from = points[index];
|
|
411
|
+
const to = points[index + 1];
|
|
412
|
+
if (from === undefined || to === undefined) {
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
const deltaX = to.x - from.x;
|
|
416
|
+
dx.push(deltaX);
|
|
417
|
+
slope.push(deltaX === 0 ? 0 : (to.y - from.y) / deltaX);
|
|
418
|
+
}
|
|
419
|
+
const tangent = [slope[0] ?? 0];
|
|
420
|
+
for (let index = 1; index < count - 1; index += 1) {
|
|
421
|
+
tangent.push((slope[index - 1] ?? 0) * (slope[index] ?? 0) <= 0 ? 0 : ((slope[index - 1] ?? 0) + (slope[index] ?? 0)) / 2);
|
|
422
|
+
}
|
|
423
|
+
tangent.push(slope[count - 2] ?? 0);
|
|
424
|
+
for (let index = 0; index < count - 1; index += 1) {
|
|
425
|
+
if (Math.abs(slope[index] ?? 0) < 1e-8) {
|
|
426
|
+
tangent[index] = 0;
|
|
427
|
+
tangent[index + 1] = 0;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
const sampled = [];
|
|
431
|
+
const steps = 8;
|
|
432
|
+
for (let index = 0; index < count - 1; index += 1) {
|
|
433
|
+
const start = points[index];
|
|
434
|
+
const end = points[index + 1];
|
|
435
|
+
if (start === undefined || end === undefined) {
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
const handle = (dx[index] ?? 0) / 3;
|
|
439
|
+
const c1 = {
|
|
440
|
+
x: start.x + handle,
|
|
441
|
+
y: start.y + (tangent[index] ?? 0) * handle
|
|
442
|
+
};
|
|
443
|
+
const c2 = {
|
|
444
|
+
x: end.x - handle,
|
|
445
|
+
y: end.y - (tangent[index + 1] ?? 0) * handle
|
|
446
|
+
};
|
|
447
|
+
for (let step = 0; step < steps; step += 1) {
|
|
448
|
+
const t = step / steps;
|
|
449
|
+
const point = cubicPoint(t, start, c1, c2, end);
|
|
450
|
+
sampled.push({
|
|
451
|
+
x: point.x,
|
|
452
|
+
y: point.y,
|
|
453
|
+
index: t < 0.5 ? start.index : end.index
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
const last = points[count - 1];
|
|
458
|
+
if (last !== undefined) {
|
|
459
|
+
sampled.push(last);
|
|
460
|
+
}
|
|
461
|
+
return sampled;
|
|
462
|
+
}
|
|
463
|
+
function strokeSamples(points, curve) {
|
|
464
|
+
if (curve === 'monotoneX') {
|
|
465
|
+
return sampleMonotoneRun(points);
|
|
466
|
+
}
|
|
467
|
+
if (curve === 'stepAfter') {
|
|
468
|
+
const sampled = [];
|
|
469
|
+
for (let index = 0; index < points.length; index += 1) {
|
|
470
|
+
const from = points[index];
|
|
471
|
+
const to = points[index + 1];
|
|
472
|
+
if (from === undefined) {
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
sampled.push(from);
|
|
476
|
+
if (to !== undefined) {
|
|
477
|
+
sampled.push({
|
|
478
|
+
x: to.x,
|
|
479
|
+
y: from.y,
|
|
480
|
+
index: from.index
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
return sampled;
|
|
485
|
+
}
|
|
486
|
+
return [...points];
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Category index of the closest point on any series stroke, or `null` when the pointer is
|
|
491
|
+
* farther than `maxDistance` from every line. Overlay coordinates (`plot.x` already subtracted).
|
|
492
|
+
* Uses the same monotone cubics as the painted path so a valley (Lowest) still hits.
|
|
493
|
+
*/
|
|
494
|
+
export function nearestCategoryOnLines(series, overlayX, overlayY, plotOffsetX, maxDistance, pointDistance = maxDistance) {
|
|
495
|
+
let bestDistance = Math.max(maxDistance, pointDistance);
|
|
496
|
+
let bestIndex = null;
|
|
497
|
+
for (const item of series) {
|
|
498
|
+
const points = item.points.flatMap(point => point.y == null ? [] : [{
|
|
499
|
+
x: point.x - plotOffsetX,
|
|
500
|
+
y: point.y,
|
|
501
|
+
index: point.index
|
|
502
|
+
}]);
|
|
503
|
+
for (const point of points) {
|
|
504
|
+
const distance = Math.hypot(overlayX - point.x, overlayY - point.y);
|
|
505
|
+
if (distance <= pointDistance && distance <= bestDistance) {
|
|
506
|
+
bestDistance = distance;
|
|
507
|
+
bestIndex = point.index;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
const sampled = strokeSamples(points, item.curve);
|
|
511
|
+
for (let i = 0; i < sampled.length; i += 1) {
|
|
512
|
+
const from = sampled[i];
|
|
513
|
+
const to = sampled[i + 1];
|
|
514
|
+
if (from === undefined) {
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
const distance = to === undefined ? Math.hypot(overlayX - from.x, overlayY - from.y) : distanceToSegment(overlayX, overlayY, from.x, from.y, to.x, to.y);
|
|
518
|
+
if (distance > maxDistance || distance > bestDistance) {
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
521
|
+
bestDistance = distance;
|
|
522
|
+
if (to === undefined) {
|
|
523
|
+
bestIndex = from.index;
|
|
524
|
+
} else {
|
|
525
|
+
const closerToStart = Math.hypot(overlayX - from.x, overlayY - from.y) <= Math.hypot(overlayX - to.x, overlayY - to.y);
|
|
526
|
+
bestIndex = closerToStart ? from.index : to.index;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
return bestIndex;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Category under the pointer when it is inside the plot box. Snaps to the nearest category on X.
|
|
535
|
+
* Overlay coordinates (`plot.x` already subtracted).
|
|
536
|
+
*/
|
|
537
|
+
export function nearestCategoryInPlot(labels, plot, overlayX, overlayY, plotOffsetX) {
|
|
538
|
+
if (labels.length === 0) {
|
|
539
|
+
return null;
|
|
540
|
+
}
|
|
541
|
+
if (overlayY < plot.y || overlayY > plot.y + plot.height) {
|
|
542
|
+
return null;
|
|
543
|
+
}
|
|
544
|
+
if (overlayX < 0 || overlayX > plot.width) {
|
|
545
|
+
return null;
|
|
546
|
+
}
|
|
547
|
+
let bestIndex = 0;
|
|
548
|
+
let bestDist = Number.POSITIVE_INFINITY;
|
|
549
|
+
labels.forEach((item, index) => {
|
|
550
|
+
const dist = Math.abs(item.x - plotOffsetX - overlayX);
|
|
551
|
+
if (dist < bestDist) {
|
|
552
|
+
bestDist = dist;
|
|
553
|
+
bestIndex = index;
|
|
554
|
+
}
|
|
555
|
+
});
|
|
556
|
+
return bestIndex;
|
|
557
|
+
}
|
|
558
|
+
export function lineChartMarkerGutters(categoryCount, markers, base = lineChartGutters()) {
|
|
559
|
+
if (markers === undefined || markers.length === 0) {
|
|
560
|
+
return base;
|
|
561
|
+
}
|
|
562
|
+
const hasCaption = markers.some(marker => marker.label !== undefined && marker.label.length > 0 || marker.showValue === true);
|
|
563
|
+
const hasEndValue = markers.some(marker => marker.showValue === true && marker.dataIndex === categoryCount - 1);
|
|
564
|
+
return {
|
|
565
|
+
...base,
|
|
566
|
+
paddingTop: hasCaption ? LINE_MARKER_PADDING_TOP : base.paddingTop,
|
|
567
|
+
paddingRight: hasEndValue ? LINE_MARKER_PADDING_RIGHT : base.paddingRight
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
export function layoutLineChart({
|
|
571
|
+
categories,
|
|
572
|
+
series,
|
|
573
|
+
width,
|
|
574
|
+
height,
|
|
575
|
+
referenceLines = [],
|
|
576
|
+
yAxis,
|
|
577
|
+
formatTick = String,
|
|
578
|
+
gutters: guttersProp
|
|
579
|
+
}) {
|
|
580
|
+
const empty = {
|
|
581
|
+
series: [],
|
|
582
|
+
categoryLabels: [],
|
|
583
|
+
valueTicks: [],
|
|
584
|
+
gridLines: [],
|
|
585
|
+
referenceLines: [],
|
|
586
|
+
baselineY: 0,
|
|
587
|
+
plot: {
|
|
588
|
+
x: 0,
|
|
589
|
+
y: 0,
|
|
590
|
+
width: 0,
|
|
591
|
+
height: 0
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
if (width <= 0 || height <= 0 || categories.length === 0 || series.length === 0) {
|
|
595
|
+
return empty;
|
|
596
|
+
}
|
|
597
|
+
const gutters = guttersProp ?? lineChartGutters();
|
|
598
|
+
const plot = {
|
|
599
|
+
x: gutters.paddingLeft,
|
|
600
|
+
y: gutters.paddingTop,
|
|
601
|
+
width: Math.max(width - gutters.paddingLeft - gutters.paddingRight, 0),
|
|
602
|
+
height: Math.max(height - gutters.paddingTop - gutters.paddingBottom, 0)
|
|
603
|
+
};
|
|
604
|
+
const values = [...series.flatMap(item => item.values.filter(value => value !== null)), ...referenceLines.flatMap(line => Number.isFinite(line.value) ? [line.value] : [])];
|
|
605
|
+
const domain = lineValueDomain(values, yAxis);
|
|
606
|
+
const span = domain.max - domain.min || 1;
|
|
607
|
+
const lastIndex = Math.max(categories.length - 1, 1);
|
|
608
|
+
const valueToY = value => plot.y + plot.height * (1 - (value - domain.min) / span);
|
|
609
|
+
const indexToX = index => categories.length === 1 ? plot.x + plot.width / 2 : plot.x + index / lastIndex * plot.width;
|
|
610
|
+
const baselineY = valueToY(Math.min(Math.max(0, domain.min), domain.max));
|
|
611
|
+
const categoryLabels = categories.map((category, index) => ({
|
|
612
|
+
label: category.label,
|
|
613
|
+
title: category.title,
|
|
614
|
+
x: round2(indexToX(index)),
|
|
615
|
+
y: round2(height - 8),
|
|
616
|
+
tick: category.tick
|
|
617
|
+
}));
|
|
618
|
+
const seriesLayouts = series.map(item => {
|
|
619
|
+
const points = categories.map((_, index) => {
|
|
620
|
+
const value = item.values[index] ?? null;
|
|
621
|
+
return {
|
|
622
|
+
index,
|
|
623
|
+
value,
|
|
624
|
+
x: round2(indexToX(index)),
|
|
625
|
+
y: value === null ? null : round2(valueToY(value))
|
|
626
|
+
};
|
|
627
|
+
});
|
|
628
|
+
const dashAt = item.dashAt < categories.length ? item.dashAt : -1;
|
|
629
|
+
const {
|
|
630
|
+
path,
|
|
631
|
+
dashedPath,
|
|
632
|
+
areaPath
|
|
633
|
+
} = lineSeriesPaths(points.map(point => point.x), points.map(point => point.y ?? Number.NaN), item.curve, baselineY, dashAt);
|
|
634
|
+
return {
|
|
635
|
+
key: item.id,
|
|
636
|
+
label: item.label,
|
|
637
|
+
curve: item.curve,
|
|
638
|
+
area: item.area,
|
|
639
|
+
dashed: item.dashed,
|
|
640
|
+
path,
|
|
641
|
+
dashedPath,
|
|
642
|
+
dashAt,
|
|
643
|
+
areaPath,
|
|
644
|
+
points
|
|
645
|
+
};
|
|
646
|
+
});
|
|
647
|
+
const valueTicks = domain.ticks.map(value => ({
|
|
648
|
+
value,
|
|
649
|
+
x: round2(plot.x - 8),
|
|
650
|
+
y: round2(valueToY(value)),
|
|
651
|
+
text: formatTick(value)
|
|
652
|
+
}));
|
|
653
|
+
const gridLines = domain.ticks.map(value => {
|
|
654
|
+
const y = round2(valueToY(value));
|
|
655
|
+
return {
|
|
656
|
+
x1: round2(plot.x),
|
|
657
|
+
y1: y,
|
|
658
|
+
x2: round2(plot.x + plot.width),
|
|
659
|
+
y2: y
|
|
660
|
+
};
|
|
661
|
+
});
|
|
662
|
+
const laidReference = referenceLines.flatMap(line => {
|
|
663
|
+
if (!Number.isFinite(line.value)) {
|
|
664
|
+
return [];
|
|
665
|
+
}
|
|
666
|
+
const y = round2(valueToY(line.value));
|
|
667
|
+
return [{
|
|
668
|
+
x1: round2(plot.x),
|
|
669
|
+
y1: y,
|
|
670
|
+
x2: round2(plot.x + plot.width),
|
|
671
|
+
y2: y,
|
|
672
|
+
label: line.label
|
|
673
|
+
}];
|
|
674
|
+
});
|
|
675
|
+
return {
|
|
676
|
+
series: seriesLayouts,
|
|
677
|
+
categoryLabels,
|
|
678
|
+
valueTicks,
|
|
679
|
+
gridLines,
|
|
680
|
+
referenceLines: laidReference,
|
|
681
|
+
baselineY: round2(baselineY),
|
|
682
|
+
plot
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
//# sourceMappingURL=geometry.js.map
|