@octanejs/recharts 0.1.0
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/LICENSE +21 -0
- package/package.json +53 -0
- package/src/animation/AnimatedItems.tsrx +82 -0
- package/src/animation/AnimationControllerImpl.js +33 -0
- package/src/animation/AnimationHandle.js +291 -0
- package/src/animation/JavascriptAnimate.tsrx +81 -0
- package/src/animation/easing.js +193 -0
- package/src/animation/matchBy.js +279 -0
- package/src/animation/timeoutController.js +49 -0
- package/src/animation/useAnimationController.ts +22 -0
- package/src/animation/useAnimationStartSnapshot.ts +43 -0
- package/src/animation/util.js +11 -0
- package/src/cartesian/Bar.ts +4 -0
- package/src/cartesian/Bar.tsrx +716 -0
- package/src/cartesian/Bar.tsrx.d.ts +4 -0
- package/src/cartesian/BarStack.tsrx +97 -0
- package/src/cartesian/BarStack.tsrx.d.ts +6 -0
- package/src/cartesian/CartesianAxis.tsrx +413 -0
- package/src/cartesian/CartesianAxis.tsrx.d.ts +3 -0
- package/src/cartesian/GraphicalItemClipPath.tsrx +44 -0
- package/src/cartesian/Line.ts +4 -0
- package/src/cartesian/Line.tsrx +544 -0
- package/src/cartesian/Line.tsrx.d.ts +4 -0
- package/src/cartesian/LineDrawShape.tsrx +106 -0
- package/src/cartesian/LineDrawShape.tsrx.d.ts +2 -0
- package/src/cartesian/XAxis.tsrx +156 -0
- package/src/cartesian/XAxis.tsrx.d.ts +3 -0
- package/src/cartesian/YAxis.tsrx +183 -0
- package/src/cartesian/YAxis.tsrx.d.ts +3 -0
- package/src/cartesian/getCartesianPosition.js +277 -0
- package/src/cartesian/getEquidistantTicks.js +133 -0
- package/src/cartesian/getTicks.js +280 -0
- package/src/cartesian/useAnimatedLineLength.ts +33 -0
- package/src/chart/BarChart.tsrx +22 -0
- package/src/chart/BarChart.tsrx.d.ts +2 -0
- package/src/chart/CartesianChart.tsrx +76 -0
- package/src/chart/CartesianChart.tsrx.d.ts +10 -0
- package/src/chart/CategoricalChart.tsrx +54 -0
- package/src/chart/LineChart.tsrx +22 -0
- package/src/chart/LineChart.tsrx.d.ts +2 -0
- package/src/chart/RechartsWrapper.tsrx +294 -0
- package/src/component/ActivePoints.tsrx +76 -0
- package/src/component/Cell.ts +37 -0
- package/src/component/Dots.tsrx +74 -0
- package/src/component/Label.tsrx +309 -0
- package/src/component/Label.tsrx.d.ts +12 -0
- package/src/component/LabelList.tsrx +83 -0
- package/src/component/LabelList.tsrx.d.ts +8 -0
- package/src/component/ResponsiveContainer.ts +22 -0
- package/src/component/Text.tsrx +281 -0
- package/src/component/Text.tsrx.d.ts +9 -0
- package/src/component/responsiveContainerUtils.js +111 -0
- package/src/container/ClipPathProvider.tsrx +29 -0
- package/src/container/Layer.tsrx +9 -0
- package/src/container/Layer.tsrx.d.ts +6 -0
- package/src/container/RootSurface.tsrx +76 -0
- package/src/container/Surface.tsrx +23 -0
- package/src/container/Surface.tsrx.d.ts +12 -0
- package/src/context/CellsContext.ts +80 -0
- package/src/context/ErrorBarContext.tsrx +53 -0
- package/src/context/PanoramaContext.ts +10 -0
- package/src/context/RegisterGraphicalItemId.tsrx +19 -0
- package/src/context/accessibilityContext.js +10 -0
- package/src/context/chartDataContext.ts +57 -0
- package/src/context/chartLayoutContext.ts +171 -0
- package/src/context/legendPortalContext.ts +5 -0
- package/src/context/tooltipContext.js +55 -0
- package/src/context/tooltipPortalContext.ts +5 -0
- package/src/hooks.js +509 -0
- package/src/index.ts +64 -0
- package/src/internal.ts +37 -0
- package/src/polar/defaultPolarAngleAxisProps.js +27 -0
- package/src/polar/defaultPolarRadiusAxisProps.js +24 -0
- package/src/shape/Cross.tsrx +25 -0
- package/src/shape/Cross.tsrx.d.ts +12 -0
- package/src/shape/Curve.tsrx +132 -0
- package/src/shape/Curve.tsrx.d.ts +42 -0
- package/src/shape/Dot.tsrx +21 -0
- package/src/shape/Dot.tsrx.d.ts +9 -0
- package/src/shape/Polygon.tsrx +95 -0
- package/src/shape/Polygon.tsrx.d.ts +13 -0
- package/src/shape/Rectangle.tsrx +162 -0
- package/src/shape/Rectangle.tsrx.d.ts +31 -0
- package/src/shape/Sector.tsrx +219 -0
- package/src/shape/Sector.tsrx.d.ts +29 -0
- package/src/shape/Symbols.tsrx +95 -0
- package/src/shape/Symbols.tsrx.d.ts +15 -0
- package/src/shape/Trapezoid.tsrx +56 -0
- package/src/shape/Trapezoid.tsrx.d.ts +29 -0
- package/src/state/RechartsReduxContext.ts +7 -0
- package/src/state/RechartsStoreProvider.tsrx +24 -0
- package/src/state/ReportChartProps.ts +13 -0
- package/src/state/ReportEventSettings.ts +15 -0
- package/src/state/ReportMainChartProps.ts +22 -0
- package/src/state/SetGraphicalItem.ts +61 -0
- package/src/state/SetLegendPayload.ts +61 -0
- package/src/state/SetTooltipEntrySettings.ts +40 -0
- package/src/state/brushSlice.js +36 -0
- package/src/state/cartesianAxisSlice.js +256 -0
- package/src/state/chartDataSlice.js +67 -0
- package/src/state/errorBarSlice.js +53 -0
- package/src/state/eventSettingsSlice.js +25 -0
- package/src/state/externalEventsMiddleware.js +127 -0
- package/src/state/graphicalItemsSlice.js +91 -0
- package/src/state/hooks.ts +46 -0
- package/src/state/keyboardEventsMiddleware.js +226 -0
- package/src/state/layoutSlice.js +57 -0
- package/src/state/legendSlice.js +83 -0
- package/src/state/mouseEventsMiddleware.js +130 -0
- package/src/state/optionsSlice.js +45 -0
- package/src/state/polarAxisSlice.js +33 -0
- package/src/state/polarOptionsSlice.js +26 -0
- package/src/state/reduxDevtoolsJsonStringifyReplacer.js +14 -0
- package/src/state/referenceElementsSlice.js +51 -0
- package/src/state/renderedTicksSlice.js +41 -0
- package/src/state/rootPropsSlice.js +48 -0
- package/src/state/selectors/arrayEqualityCheck.js +32 -0
- package/src/state/selectors/axisSelectors.js +2113 -0
- package/src/state/selectors/barSelectors.js +263 -0
- package/src/state/selectors/barStackSelectors.js +65 -0
- package/src/state/selectors/brushSelectors.js +21 -0
- package/src/state/selectors/combiners/combineActiveLabel.js +18 -0
- package/src/state/selectors/combiners/combineActiveTooltipIndex.js +75 -0
- package/src/state/selectors/combiners/combineAllBarPositions.js +169 -0
- package/src/state/selectors/combiners/combineAxisRangeWithReverse.js +11 -0
- package/src/state/selectors/combiners/combineBarPosition.js +17 -0
- package/src/state/selectors/combiners/combineBarSizeList.js +115 -0
- package/src/state/selectors/combiners/combineCheckedDomain.js +44 -0
- package/src/state/selectors/combiners/combineConfiguredScale.js +46 -0
- package/src/state/selectors/combiners/combineCoordinateForDefaultIndex.js +48 -0
- package/src/state/selectors/combiners/combineDisplayedStackedData.js +54 -0
- package/src/state/selectors/combiners/combineInverseScaleFunction.js +12 -0
- package/src/state/selectors/combiners/combineRealScaleType.js +36 -0
- package/src/state/selectors/combiners/combineStackedData.js +22 -0
- package/src/state/selectors/combiners/combineTooltipInteractionState.js +121 -0
- package/src/state/selectors/combiners/combineTooltipPayload.js +248 -0
- package/src/state/selectors/combiners/combineTooltipPayloadConfigurations.js +59 -0
- package/src/state/selectors/containerSelectors.js +6 -0
- package/src/state/selectors/dataSelectors.js +97 -0
- package/src/state/selectors/graphicalItemSelectors.js +25 -0
- package/src/state/selectors/legendSelectors.js +18 -0
- package/src/state/selectors/lineSelectors.js +106 -0
- package/src/state/selectors/numberDomainEqualityCheck.js +11 -0
- package/src/state/selectors/pickAxisId.js +3 -0
- package/src/state/selectors/pickAxisType.js +3 -0
- package/src/state/selectors/polarAxisSelectors.js +237 -0
- package/src/state/selectors/rootPropsSelectors.js +13 -0
- package/src/state/selectors/selectActivePropsFromChartPointer.js +23 -0
- package/src/state/selectors/selectAllAxes.js +15 -0
- package/src/state/selectors/selectChartOffset.js +12 -0
- package/src/state/selectors/selectChartOffsetInternal.js +174 -0
- package/src/state/selectors/selectPlotArea.js +19 -0
- package/src/state/selectors/selectTooltipAxisId.js +3 -0
- package/src/state/selectors/selectTooltipAxisType.js +25 -0
- package/src/state/selectors/selectTooltipEventType.js +27 -0
- package/src/state/selectors/selectTooltipPayloadSearcher.js +3 -0
- package/src/state/selectors/selectTooltipSettings.js +3 -0
- package/src/state/selectors/selectTooltipState.js +3 -0
- package/src/state/selectors/selectors.js +222 -0
- package/src/state/selectors/tooltipSelectors.js +471 -0
- package/src/state/selectors/touchSelectors.js +31 -0
- package/src/state/store.js +101 -0
- package/src/state/tooltipSlice.js +237 -0
- package/src/state/touchEventsMiddleware.js +140 -0
- package/src/state/types/StackedGraphicalItem.js +18 -0
- package/src/state/zIndexSlice.js +167 -0
- package/src/synchronisation/syncSelectors.js +5 -0
- package/src/synchronisation/useChartSynchronisation.tsrx +285 -0
- package/src/util/ActiveShapeUtils.tsrx +62 -0
- package/src/util/BarUtils.tsrx +35 -0
- package/src/util/CartesianUtils.js +66 -0
- package/src/util/ChartUtils.js +630 -0
- package/src/util/Constants.js +42 -0
- package/src/util/DOMUtils.js +180 -0
- package/src/util/DataUtils.js +199 -0
- package/src/util/Events.js +7 -0
- package/src/util/Global.js +13 -0
- package/src/util/LRUCache.js +58 -0
- package/src/util/LogUtils.js +29 -0
- package/src/util/PolarUtils.js +190 -0
- package/src/util/ReactUtils.ts +94 -0
- package/src/util/ReduceCSSCalc.js +260 -0
- package/src/util/TickUtils.js +43 -0
- package/src/util/YAxisUtils.js +43 -0
- package/src/util/axisPropsAreEqual.js +63 -0
- package/src/util/createEventProxy.js +18 -0
- package/src/util/excludeEventProps.js +172 -0
- package/src/util/getActiveCoordinate.js +253 -0
- package/src/util/getAxisTypeBasedOnLayout.js +17 -0
- package/src/util/getClassNameFromUnknown.js +8 -0
- package/src/util/getEveryNth.js +29 -0
- package/src/util/getRadiusAndStrokeWidthFromDot.js +28 -0
- package/src/util/getRelativeCoordinate.js +96 -0
- package/src/util/getSliced.js +11 -0
- package/src/util/isDomainSpecifiedByUser.js +255 -0
- package/src/util/isWellBehavedNumber.js +8 -0
- package/src/util/propsAreEqual.js +96 -0
- package/src/util/resolveDefaultProps.js +131 -0
- package/src/util/round.js +39 -0
- package/src/util/scale/RechartsScale.js +68 -0
- package/src/util/scale/createCategoricalInverse.js +77 -0
- package/src/util/scale/getNiceTickValues.js +354 -0
- package/src/util/scale/index.js +3 -0
- package/src/util/scale/util/arithmetic.js +51 -0
- package/src/util/stacks/getStackSeriesIdentifier.js +10 -0
- package/src/util/svgPropertiesAndEvents.ts +29 -0
- package/src/util/svgPropertiesNoEvents.js +383 -0
- package/src/util/types.ts +59 -0
- package/src/util/useAnimationId.ts +14 -0
- package/src/util/useId.ts +13 -0
- package/src/util/usePrefersReducedMotion.ts +30 -0
- package/src/util/useReportScale.ts +26 -0
- package/src/util/useUniqueId.js +34 -0
- package/src/zIndex/DefaultZIndexes.js +75 -0
- package/src/zIndex/ZIndexLayer.tsrx +80 -0
- package/src/zIndex/ZIndexLayer.tsrx.d.ts +2 -0
- package/src/zIndex/ZIndexPortal.tsrx +43 -0
- package/src/zIndex/getZIndexFromUnknown.js +15 -0
- package/src/zIndex/zIndexSelectors.js +45 -0
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
// Port of cartesian/Line.tsx — the line graphical item: redux registration,
|
|
2
|
+
// store-computed points, the draw-in curve, dots, labels, active points.
|
|
3
|
+
// `computeLinePoints` stays here (vendored lineSelectors imports it through
|
|
4
|
+
// cartesian/Line.ts).
|
|
5
|
+
import { memo, useCallback, useMemo, useRef } from 'octane';
|
|
6
|
+
import { clsx } from 'clsx';
|
|
7
|
+
import { Layer } from '../container/Layer.tsrx';
|
|
8
|
+
import { LineDrawShape } from './LineDrawShape.tsrx';
|
|
9
|
+
import { useAnimatedLineLength } from './useAnimatedLineLength.ts';
|
|
10
|
+
import {
|
|
11
|
+
CartesianLabelListContextProvider,
|
|
12
|
+
LabelListFromLabelProp,
|
|
13
|
+
} from '../component/LabelList.tsrx';
|
|
14
|
+
import { interpolate, isNullish, noop } from '../util/DataUtils';
|
|
15
|
+
import { isClipDot } from '../util/ReactUtils.ts';
|
|
16
|
+
import { getCateCoordinateOfLine, getTooltipNameProp, getValueByDataKey } from '../util/ChartUtils';
|
|
17
|
+
import { ActivePoints } from '../component/ActivePoints.tsrx';
|
|
18
|
+
import { SetTooltipEntrySettings } from '../state/SetTooltipEntrySettings';
|
|
19
|
+
import { SetErrorBarContext } from '../context/ErrorBarContext.tsrx';
|
|
20
|
+
import { GraphicalItemClipPath, useNeedsClip } from './GraphicalItemClipPath.tsrx';
|
|
21
|
+
import { useChartLayout } from '../context/chartLayoutContext.ts';
|
|
22
|
+
import { useIsPanorama } from '../context/PanoramaContext.ts';
|
|
23
|
+
import { selectLinePoints } from '../state/selectors/lineSelectors';
|
|
24
|
+
import { useAppSelector } from '../state/hooks';
|
|
25
|
+
import { SetLegendPayload } from '../state/SetLegendPayload';
|
|
26
|
+
import { AnimatedItems, useAnimationCallbacks } from '../animation/AnimatedItems.tsrx';
|
|
27
|
+
import { matchByIndex } from '../animation/matchBy';
|
|
28
|
+
import { resolveDefaultProps } from '../util/resolveDefaultProps';
|
|
29
|
+
import { usePlotArea } from '../hooks';
|
|
30
|
+
import { RegisterGraphicalItemId } from '../context/RegisterGraphicalItemId.tsrx';
|
|
31
|
+
import { SetCartesianGraphicalItem } from '../state/SetGraphicalItem';
|
|
32
|
+
import { svgPropertiesNoEvents } from '../util/svgPropertiesNoEvents';
|
|
33
|
+
import { svgPropertiesAndEvents } from '../util/svgPropertiesAndEvents.ts';
|
|
34
|
+
import { getRadiusAndStrokeWidthFromDot } from '../util/getRadiusAndStrokeWidthFromDot';
|
|
35
|
+
import { Shape } from '../util/ActiveShapeUtils.tsrx';
|
|
36
|
+
import { ZIndexLayer } from '../zIndex/ZIndexLayer.tsrx';
|
|
37
|
+
import { DefaultZIndexes } from '../zIndex/DefaultZIndexes';
|
|
38
|
+
import { propsAreEqual } from '../util/propsAreEqual';
|
|
39
|
+
import { Dots } from '../component/Dots.tsrx';
|
|
40
|
+
|
|
41
|
+
function getTotalLength(mainCurve) {
|
|
42
|
+
try {
|
|
43
|
+
return mainCurve && mainCurve.getTotalLength && mainCurve.getTotalLength() || 0;
|
|
44
|
+
} catch {
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Average x-shift between matched pairs — the overall direction/magnitude of
|
|
51
|
+
* data movement, used to extrapolate enter/exit positions.
|
|
52
|
+
*/
|
|
53
|
+
function averageShift(items) {
|
|
54
|
+
let total = 0;
|
|
55
|
+
let count = 0;
|
|
56
|
+
for (const item of items) {
|
|
57
|
+
if (item.status === 'matched' && item.prev.x != null && item.next.x != null) {
|
|
58
|
+
total += item.next.x - item.prev.x;
|
|
59
|
+
count++;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return count > 0 ? total / count : 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const defaultLineAnimateItems = (items, animationElapsedTime) => {
|
|
66
|
+
if (items == null) {
|
|
67
|
+
// First render: return empty, stroke-dasharray handles the reveal
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
// At animationElapsedTime=1 return only the non-removed items
|
|
71
|
+
if (animationElapsedTime === 1) {
|
|
72
|
+
return items.flatMap((item) => (item.status === 'removed' ? [] : [item.next]));
|
|
73
|
+
}
|
|
74
|
+
const shift = averageShift(items);
|
|
75
|
+
const result = [];
|
|
76
|
+
for (const item of items) {
|
|
77
|
+
if (item.status === 'matched') {
|
|
78
|
+
result.push({
|
|
79
|
+
...item.next,
|
|
80
|
+
x: interpolate(item.prev.x, item.next.x, animationElapsedTime),
|
|
81
|
+
y: interpolate(item.prev.y, item.next.y, animationElapsedTime),
|
|
82
|
+
});
|
|
83
|
+
} else if (item.status === 'added') {
|
|
84
|
+
if (item.next.x != null) {
|
|
85
|
+
// Extrapolate entry position: the point starts where it "would have been"
|
|
86
|
+
const entryX = item.next.x - shift;
|
|
87
|
+
result.push({
|
|
88
|
+
...item.next,
|
|
89
|
+
x: interpolate(entryX, item.next.x, animationElapsedTime),
|
|
90
|
+
y: item.next.y,
|
|
91
|
+
});
|
|
92
|
+
} else {
|
|
93
|
+
result.push(item.next);
|
|
94
|
+
}
|
|
95
|
+
} else if (item.status === 'removed') {
|
|
96
|
+
if (item.prev.x != null) {
|
|
97
|
+
const exitX = item.prev.x + shift;
|
|
98
|
+
result.push({
|
|
99
|
+
...item.prev,
|
|
100
|
+
x: interpolate(item.prev.x, exitX, animationElapsedTime),
|
|
101
|
+
y: item.prev.y,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
// else: removed items are simply dropped
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return result;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export const defaultLineProps = {
|
|
111
|
+
activeDot: true,
|
|
112
|
+
animateNewValues: true,
|
|
113
|
+
animationBegin: 0,
|
|
114
|
+
animationDuration: 1500,
|
|
115
|
+
animationEasing: 'ease',
|
|
116
|
+
animationInterpolateFn: defaultLineAnimateItems,
|
|
117
|
+
animationMatchBy: matchByIndex,
|
|
118
|
+
connectNulls: false,
|
|
119
|
+
dot: true,
|
|
120
|
+
fill: '#fff',
|
|
121
|
+
hide: false,
|
|
122
|
+
isAnimationActive: 'auto',
|
|
123
|
+
label: false,
|
|
124
|
+
legendType: 'line',
|
|
125
|
+
shape: LineDrawShape,
|
|
126
|
+
stroke: '#3182bd',
|
|
127
|
+
strokeWidth: 1,
|
|
128
|
+
xAxisId: 0,
|
|
129
|
+
yAxisId: 0,
|
|
130
|
+
zIndex: DefaultZIndexes.line,
|
|
131
|
+
type: 'linear',
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const computeLegendPayloadFromAreaData = (props) => {
|
|
135
|
+
const { dataKey, name, stroke, legendType, hide } = props;
|
|
136
|
+
return [
|
|
137
|
+
{
|
|
138
|
+
inactive: hide,
|
|
139
|
+
dataKey,
|
|
140
|
+
type: legendType,
|
|
141
|
+
color: stroke,
|
|
142
|
+
value: getTooltipNameProp(name, dataKey),
|
|
143
|
+
payload: props,
|
|
144
|
+
},
|
|
145
|
+
];
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const SetLineTooltipEntrySettings = memo((props) => {
|
|
149
|
+
const {
|
|
150
|
+
dataKey,
|
|
151
|
+
data,
|
|
152
|
+
stroke,
|
|
153
|
+
strokeWidth,
|
|
154
|
+
fill,
|
|
155
|
+
name,
|
|
156
|
+
hide,
|
|
157
|
+
unit,
|
|
158
|
+
formatter,
|
|
159
|
+
tooltipType,
|
|
160
|
+
id,
|
|
161
|
+
} = props;
|
|
162
|
+
const tooltipEntrySettings = {
|
|
163
|
+
dataDefinedOnItem: data,
|
|
164
|
+
getPosition: noop,
|
|
165
|
+
settings: {
|
|
166
|
+
stroke,
|
|
167
|
+
strokeWidth,
|
|
168
|
+
fill,
|
|
169
|
+
dataKey,
|
|
170
|
+
nameKey: undefined,
|
|
171
|
+
name: getTooltipNameProp(name, dataKey),
|
|
172
|
+
hide,
|
|
173
|
+
type: tooltipType,
|
|
174
|
+
color: stroke,
|
|
175
|
+
unit,
|
|
176
|
+
formatter,
|
|
177
|
+
graphicalItemId: id,
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
return <SetTooltipEntrySettings tooltipEntrySettings={tooltipEntrySettings} />;
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
function LineDotsWrapper(props) {
|
|
184
|
+
const { clipPathId, points } = props;
|
|
185
|
+
const { dot, dataKey, needClip } = props.props;
|
|
186
|
+
// Exclude ID so it isn't duplicated across every dot.
|
|
187
|
+
const { id, ...propsWithoutId } = props.props;
|
|
188
|
+
const lineProps = svgPropertiesNoEvents(propsWithoutId);
|
|
189
|
+
return <Dots
|
|
190
|
+
points={points}
|
|
191
|
+
dot={dot}
|
|
192
|
+
className="recharts-line-dots"
|
|
193
|
+
dotClassName="recharts-line-dot"
|
|
194
|
+
dataKey={dataKey}
|
|
195
|
+
baseProps={lineProps}
|
|
196
|
+
needClip={needClip}
|
|
197
|
+
clipPathId={clipPathId}
|
|
198
|
+
/>;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function LineLabelListProvider(props) @{
|
|
202
|
+
const { showLabels, children, points } = props;
|
|
203
|
+
const labelListEntries = useMemo(() => {
|
|
204
|
+
return points?.map((point) => {
|
|
205
|
+
const viewBox = {
|
|
206
|
+
x: point.x ?? 0,
|
|
207
|
+
y: point.y ?? 0,
|
|
208
|
+
width: 0,
|
|
209
|
+
lowerWidth: 0,
|
|
210
|
+
upperWidth: 0,
|
|
211
|
+
height: 0,
|
|
212
|
+
};
|
|
213
|
+
return {
|
|
214
|
+
...viewBox,
|
|
215
|
+
value: point.value,
|
|
216
|
+
payload: point.payload,
|
|
217
|
+
viewBox,
|
|
218
|
+
parentViewBox: undefined,
|
|
219
|
+
fill: undefined,
|
|
220
|
+
};
|
|
221
|
+
});
|
|
222
|
+
}, [points]);
|
|
223
|
+
<CartesianLabelListContextProvider
|
|
224
|
+
value={showLabels ? labelListEntries : undefined}
|
|
225
|
+
>{children}</CartesianLabelListContextProvider>
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function StaticCurve(staticCurveProps) {
|
|
229
|
+
const {
|
|
230
|
+
clipPathId,
|
|
231
|
+
pathRef,
|
|
232
|
+
points,
|
|
233
|
+
props,
|
|
234
|
+
animationElapsedTime,
|
|
235
|
+
isAnimating,
|
|
236
|
+
isEntrance,
|
|
237
|
+
visibleLength,
|
|
238
|
+
} = staticCurveProps;
|
|
239
|
+
const { type, layout, connectNulls, needClip, shape, strokeDasharray, ...others } = props;
|
|
240
|
+
const curveProps = {
|
|
241
|
+
...svgPropertiesAndEvents(others),
|
|
242
|
+
fill: 'none',
|
|
243
|
+
className: 'recharts-line-curve',
|
|
244
|
+
clipPath: needClip ? 'url(#clipPath-' + clipPathId + ')' : undefined,
|
|
245
|
+
points,
|
|
246
|
+
type,
|
|
247
|
+
layout,
|
|
248
|
+
connectNulls,
|
|
249
|
+
strokeDasharray: strokeDasharray ?? props.strokeDasharray,
|
|
250
|
+
pathRef,
|
|
251
|
+
animationElapsedTime,
|
|
252
|
+
isAnimating,
|
|
253
|
+
isEntrance: props.animateNewValues ? isEntrance : false,
|
|
254
|
+
visibleLength,
|
|
255
|
+
};
|
|
256
|
+
return <>
|
|
257
|
+
{points?.length > 1 &&
|
|
258
|
+
<Shape option={shape} DefaultShape={defaultLineProps.shape} shapeProps={curveProps} />}
|
|
259
|
+
<LineDotsWrapper points={points} clipPathId={clipPathId} props={props} />
|
|
260
|
+
</>;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function CurveWithAnimation(curveWithAnimationProps) {
|
|
264
|
+
const { clipPathId, props, pathRef, previousPointsRef } = curveWithAnimationProps;
|
|
265
|
+
const {
|
|
266
|
+
points,
|
|
267
|
+
isAnimationActive,
|
|
268
|
+
animationBegin,
|
|
269
|
+
animationDuration,
|
|
270
|
+
animationEasing,
|
|
271
|
+
animationMatchBy,
|
|
272
|
+
animationInterpolateFn,
|
|
273
|
+
layout,
|
|
274
|
+
} = props;
|
|
275
|
+
const totalLength = getTotalLength(pathRef.current);
|
|
276
|
+
const { isAnimating, handleAnimationStart, handleAnimationEnd } = useAnimationCallbacks(
|
|
277
|
+
props.onAnimationStart,
|
|
278
|
+
props.onAnimationEnd,
|
|
279
|
+
);
|
|
280
|
+
const showLabels = !isAnimating;
|
|
281
|
+
const getVisibleLength = useAnimatedLineLength(points);
|
|
282
|
+
// Don't update previousPointsRef before the SVG path is measured.
|
|
283
|
+
const shouldUpdatePreviousRef = useCallback(
|
|
284
|
+
(animationElapsedTime) => animationElapsedTime > 0 && totalLength > 0,
|
|
285
|
+
[totalLength],
|
|
286
|
+
);
|
|
287
|
+
return <LineLabelListProvider points={points} showLabels={showLabels}>
|
|
288
|
+
{props.children}
|
|
289
|
+
<AnimatedItems
|
|
290
|
+
animationInput={points}
|
|
291
|
+
animationIdPrefix="recharts-line-"
|
|
292
|
+
items={points}
|
|
293
|
+
previousItemsRef={previousPointsRef}
|
|
294
|
+
isAnimationActive={isAnimationActive}
|
|
295
|
+
animationBegin={animationBegin}
|
|
296
|
+
animationDuration={animationDuration}
|
|
297
|
+
animationEasing={animationEasing}
|
|
298
|
+
onAnimationStart={handleAnimationStart}
|
|
299
|
+
onAnimationEnd={handleAnimationEnd}
|
|
300
|
+
animationInterpolateFn={animationInterpolateFn}
|
|
301
|
+
animationMatchBy={animationMatchBy}
|
|
302
|
+
shouldUpdatePreviousRef={shouldUpdatePreviousRef}
|
|
303
|
+
layout={layout}
|
|
304
|
+
>
|
|
305
|
+
{(stepData, animationElapsedTime, isEntrance) => {
|
|
306
|
+
const animationActive = isAnimating || animationElapsedTime < 1;
|
|
307
|
+
const visibleLength =
|
|
308
|
+
animationActive ? getVisibleLength(animationElapsedTime, totalLength) : null;
|
|
309
|
+
return <StaticCurve
|
|
310
|
+
props={props}
|
|
311
|
+
points={stepData}
|
|
312
|
+
clipPathId={clipPathId}
|
|
313
|
+
pathRef={pathRef}
|
|
314
|
+
animationElapsedTime={animationElapsedTime}
|
|
315
|
+
isAnimating={animationActive}
|
|
316
|
+
isEntrance={isEntrance}
|
|
317
|
+
visibleLength={visibleLength}
|
|
318
|
+
/>;
|
|
319
|
+
}}
|
|
320
|
+
</AnimatedItems>
|
|
321
|
+
<LabelListFromLabelProp label={props.label} />
|
|
322
|
+
</LineLabelListProvider>;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function RenderCurve(props) {
|
|
326
|
+
const { clipPathId } = props;
|
|
327
|
+
const previousPointsRef = useRef(null);
|
|
328
|
+
const pathRef = useRef(null);
|
|
329
|
+
return <CurveWithAnimation
|
|
330
|
+
props={props.props}
|
|
331
|
+
clipPathId={clipPathId}
|
|
332
|
+
previousPointsRef={previousPointsRef}
|
|
333
|
+
pathRef={pathRef}
|
|
334
|
+
/>;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const errorBarDataPointFormatter = (dataPoint, dataKey) => {
|
|
338
|
+
return {
|
|
339
|
+
x: dataPoint.x ?? undefined,
|
|
340
|
+
y: dataPoint.y ?? undefined,
|
|
341
|
+
value: dataPoint.value,
|
|
342
|
+
// getValueByDataKey does not validate the output type
|
|
343
|
+
errorVal: getValueByDataKey(dataPoint.payload, dataKey),
|
|
344
|
+
};
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
function LineWithState(props) @{
|
|
348
|
+
const {
|
|
349
|
+
hide,
|
|
350
|
+
dot,
|
|
351
|
+
points,
|
|
352
|
+
className,
|
|
353
|
+
xAxisId,
|
|
354
|
+
yAxisId,
|
|
355
|
+
top,
|
|
356
|
+
left,
|
|
357
|
+
width,
|
|
358
|
+
height,
|
|
359
|
+
id,
|
|
360
|
+
needClip,
|
|
361
|
+
zIndex,
|
|
362
|
+
} = props;
|
|
363
|
+
if (hide) {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
const layerClass = clsx('recharts-line', className);
|
|
367
|
+
const clipPathId = id;
|
|
368
|
+
const { r, strokeWidth } = getRadiusAndStrokeWidthFromDot(dot);
|
|
369
|
+
const clipDot = isClipDot(dot);
|
|
370
|
+
const dotSize = r * 2 + strokeWidth;
|
|
371
|
+
const activePointsClipPath = needClip
|
|
372
|
+
? 'url(#clipPath-' + (clipDot ? '' : 'dots-') + clipPathId + ')'
|
|
373
|
+
: undefined;
|
|
374
|
+
<>
|
|
375
|
+
<ZIndexLayer zIndex={zIndex}>
|
|
376
|
+
<Layer className={layerClass}>
|
|
377
|
+
@if (needClip) {
|
|
378
|
+
<defs>
|
|
379
|
+
<GraphicalItemClipPath clipPathId={clipPathId} xAxisId={xAxisId} yAxisId={yAxisId} />
|
|
380
|
+
@if (!clipDot) {
|
|
381
|
+
<clipPath id={'clipPath-dots-' + clipPathId}>
|
|
382
|
+
<rect
|
|
383
|
+
x={left - dotSize / 2}
|
|
384
|
+
y={top - dotSize / 2}
|
|
385
|
+
width={width + dotSize}
|
|
386
|
+
height={height + dotSize}
|
|
387
|
+
/>
|
|
388
|
+
</clipPath>
|
|
389
|
+
}
|
|
390
|
+
</defs>
|
|
391
|
+
}
|
|
392
|
+
<SetErrorBarContext
|
|
393
|
+
xAxisId={xAxisId}
|
|
394
|
+
yAxisId={yAxisId}
|
|
395
|
+
data={points}
|
|
396
|
+
dataPointFormatter={errorBarDataPointFormatter}
|
|
397
|
+
errorBarOffset={0}
|
|
398
|
+
>
|
|
399
|
+
<RenderCurve props={props} clipPathId={clipPathId} />
|
|
400
|
+
</SetErrorBarContext>
|
|
401
|
+
</Layer>
|
|
402
|
+
</ZIndexLayer>
|
|
403
|
+
<ActivePoints
|
|
404
|
+
activeDot={props.activeDot}
|
|
405
|
+
points={points}
|
|
406
|
+
mainColor={props.stroke}
|
|
407
|
+
itemDataKey={props.dataKey}
|
|
408
|
+
clipPath={activePointsClipPath}
|
|
409
|
+
/>
|
|
410
|
+
</>
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function LineImpl(props) {
|
|
414
|
+
const {
|
|
415
|
+
activeDot,
|
|
416
|
+
animateNewValues,
|
|
417
|
+
animationBegin,
|
|
418
|
+
animationDuration,
|
|
419
|
+
animationEasing,
|
|
420
|
+
connectNulls,
|
|
421
|
+
dot,
|
|
422
|
+
hide,
|
|
423
|
+
isAnimationActive,
|
|
424
|
+
label,
|
|
425
|
+
legendType,
|
|
426
|
+
xAxisId,
|
|
427
|
+
yAxisId,
|
|
428
|
+
id,
|
|
429
|
+
...everythingElse
|
|
430
|
+
} = resolveDefaultProps(props, defaultLineProps);
|
|
431
|
+
const { needClip } = useNeedsClip(xAxisId, yAxisId);
|
|
432
|
+
const plotArea = usePlotArea();
|
|
433
|
+
const layout = useChartLayout();
|
|
434
|
+
const isPanorama = useIsPanorama();
|
|
435
|
+
const points = useAppSelector(
|
|
436
|
+
(state) => selectLinePoints(state, xAxisId, yAxisId, isPanorama, id),
|
|
437
|
+
);
|
|
438
|
+
if (layout !== 'horizontal' && layout !== 'vertical' || points == null || plotArea == null) {
|
|
439
|
+
// Cannot render Line in an unsupported layout
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
const { height, width, x: left, y: top } = plotArea;
|
|
443
|
+
return <LineWithState
|
|
444
|
+
{...everythingElse}
|
|
445
|
+
id={id}
|
|
446
|
+
connectNulls={connectNulls}
|
|
447
|
+
dot={dot}
|
|
448
|
+
activeDot={activeDot}
|
|
449
|
+
animateNewValues={animateNewValues}
|
|
450
|
+
animationBegin={animationBegin}
|
|
451
|
+
animationDuration={animationDuration}
|
|
452
|
+
animationEasing={animationEasing}
|
|
453
|
+
isAnimationActive={isAnimationActive}
|
|
454
|
+
hide={hide}
|
|
455
|
+
label={label}
|
|
456
|
+
legendType={legendType}
|
|
457
|
+
xAxisId={xAxisId}
|
|
458
|
+
yAxisId={yAxisId}
|
|
459
|
+
points={points}
|
|
460
|
+
layout={layout}
|
|
461
|
+
height={height}
|
|
462
|
+
width={width}
|
|
463
|
+
left={left}
|
|
464
|
+
top={top}
|
|
465
|
+
needClip={needClip}
|
|
466
|
+
/>;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
export function computeLinePoints({
|
|
470
|
+
layout,
|
|
471
|
+
xAxis,
|
|
472
|
+
yAxis,
|
|
473
|
+
xAxisTicks,
|
|
474
|
+
yAxisTicks,
|
|
475
|
+
dataKey,
|
|
476
|
+
bandSize,
|
|
477
|
+
displayedData,
|
|
478
|
+
}) {
|
|
479
|
+
return displayedData.map((entry, index) => {
|
|
480
|
+
// getValueByDataKey does not validate the output type
|
|
481
|
+
const value = getValueByDataKey(entry, dataKey);
|
|
482
|
+
if (layout === 'horizontal') {
|
|
483
|
+
const x = getCateCoordinateOfLine({ axis: xAxis, ticks: xAxisTicks, bandSize, entry, index });
|
|
484
|
+
const y =
|
|
485
|
+
isNullish(value) ? null : yAxis.scale.map(value);
|
|
486
|
+
return {
|
|
487
|
+
x,
|
|
488
|
+
y: y ?? null,
|
|
489
|
+
value,
|
|
490
|
+
payload: entry,
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
const x =
|
|
494
|
+
isNullish(value) ? null : xAxis.scale.map(value);
|
|
495
|
+
const y = getCateCoordinateOfLine({ axis: yAxis, ticks: yAxisTicks, bandSize, entry, index });
|
|
496
|
+
if (x == null || y == null) {
|
|
497
|
+
return null;
|
|
498
|
+
}
|
|
499
|
+
return { x, y, value, payload: entry };
|
|
500
|
+
}).filter(Boolean);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function LineFn(outsideProps) {
|
|
504
|
+
const props = resolveDefaultProps(outsideProps, defaultLineProps);
|
|
505
|
+
const isPanorama = useIsPanorama();
|
|
506
|
+
return <RegisterGraphicalItemId id={props.id} type="line">
|
|
507
|
+
{(id) => <>
|
|
508
|
+
<SetLegendPayload legendPayload={computeLegendPayloadFromAreaData(props)} />
|
|
509
|
+
<SetLineTooltipEntrySettings
|
|
510
|
+
dataKey={props.dataKey}
|
|
511
|
+
data={props.data}
|
|
512
|
+
stroke={props.stroke}
|
|
513
|
+
strokeWidth={props.strokeWidth}
|
|
514
|
+
fill={props.fill}
|
|
515
|
+
name={props.name}
|
|
516
|
+
hide={props.hide}
|
|
517
|
+
unit={props.unit}
|
|
518
|
+
formatter={props.formatter}
|
|
519
|
+
tooltipType={props.tooltipType}
|
|
520
|
+
id={id}
|
|
521
|
+
/>
|
|
522
|
+
<SetCartesianGraphicalItem
|
|
523
|
+
type="line"
|
|
524
|
+
id={id}
|
|
525
|
+
data={props.data}
|
|
526
|
+
xAxisId={props.xAxisId}
|
|
527
|
+
yAxisId={props.yAxisId}
|
|
528
|
+
zAxisId={0}
|
|
529
|
+
dataKey={props.dataKey}
|
|
530
|
+
hide={props.hide}
|
|
531
|
+
isPanorama={isPanorama}
|
|
532
|
+
/>
|
|
533
|
+
<LineImpl {...props} id={id} />
|
|
534
|
+
</>}
|
|
535
|
+
</RegisterGraphicalItemId>;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* @provides LabelListContext
|
|
540
|
+
* @provides ErrorBarContext
|
|
541
|
+
* @consumes CartesianChartContext
|
|
542
|
+
*/
|
|
543
|
+
export const Line = memo(LineFn, propsAreEqual);
|
|
544
|
+
Line.displayName = 'Line';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Type declaration for the .tsrx component (resolved by relative path).
|
|
2
|
+
export declare const defaultLineProps: Record<string, unknown>;
|
|
3
|
+
export declare const Line: (props: Record<string, unknown>) => unknown;
|
|
4
|
+
export declare function computeLinePoints(input: Record<string, unknown>): unknown[];
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// Port of cartesian/LineDrawShape.tsx — the default Line shape: the entrance
|
|
2
|
+
// animation progressively reveals the path via stroke-dasharray.
|
|
3
|
+
import { Curve } from '../shape/Curve.tsrx';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Reads the total length of an SVG path element, returning 0 if the element
|
|
7
|
+
* is null or the measurement fails (e.g. in JSDOM).
|
|
8
|
+
*/
|
|
9
|
+
function getTotalLength(path) {
|
|
10
|
+
try {
|
|
11
|
+
return path && path.getTotalLength && path.getTotalLength() || 0;
|
|
12
|
+
} catch {
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Uses `totalLength` as the gap (not totalLength - length) to dodge a
|
|
18
|
+
// float-serialization artifact that paints a phantom endpoint dot with
|
|
19
|
+
// round/square linecaps.
|
|
20
|
+
function generateSimpleStrokeDasharray(totalLength, length) {
|
|
21
|
+
return length + 'px ' + totalLength + 'px';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Odd-length stroke-dasharray values repeat once ("5" behaves like "5 5").
|
|
25
|
+
function normalizeDashPattern(lines) {
|
|
26
|
+
return lines.length % 2 !== 0 ? [...lines, ...lines] : lines;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function repeat(lines, count) {
|
|
30
|
+
const result = [];
|
|
31
|
+
for (let i = 0; i < count; ++i) {
|
|
32
|
+
result.push(...lines);
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Builds a dasharray that reveals exactly `length` pixels of the user's dash
|
|
39
|
+
* pattern, followed by a `totalLength` gap hiding the rest.
|
|
40
|
+
*/
|
|
41
|
+
function getStrokeDasharray(length, totalLength, lines) {
|
|
42
|
+
const normalizedLines = normalizeDashPattern(lines);
|
|
43
|
+
const lineLength = normalizedLines.reduce((pre, next) => pre + next, 0);
|
|
44
|
+
// if lineLength is 0 return the default when no strokeDasharray is provided
|
|
45
|
+
if (!lineLength) {
|
|
46
|
+
return generateSimpleStrokeDasharray(totalLength, length);
|
|
47
|
+
}
|
|
48
|
+
const count = Math.floor(length / lineLength);
|
|
49
|
+
const remainLength = length % lineLength;
|
|
50
|
+
let remainLines = [];
|
|
51
|
+
for (let i = 0, sum = 0; i < normalizedLines.length; (sum += normalizedLines[i] ?? 0, ++i)) {
|
|
52
|
+
const lineValue = normalizedLines[i];
|
|
53
|
+
if (lineValue != null && sum + lineValue > remainLength) {
|
|
54
|
+
remainLines = [...normalizedLines.slice(0, i), remainLength - sum];
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const emptyLines =
|
|
59
|
+
remainLines.length % 2 === 0 ? [0, totalLength] : [totalLength];
|
|
60
|
+
return [...repeat(normalizedLines, count), ...remainLines, ...emptyLines].map(
|
|
61
|
+
(line) => line + 'px',
|
|
62
|
+
).join(', ');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function computeAnimatedStrokeDasharray(userStrokeDasharray, totalLength, visibleLength) {
|
|
66
|
+
if (userStrokeDasharray) {
|
|
67
|
+
const lines = String(userStrokeDasharray).split(/[,\s]+/gim).map((num) => parseFloat(num));
|
|
68
|
+
return getStrokeDasharray(visibleLength, totalLength, lines);
|
|
69
|
+
}
|
|
70
|
+
return generateSimpleStrokeDasharray(totalLength, visibleLength);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* The default shape for Line: the entrance animation reveals the path through
|
|
75
|
+
* `strokeDasharray` as animationElapsedTime goes 0 → 1.
|
|
76
|
+
* @since 3.9
|
|
77
|
+
*/
|
|
78
|
+
export function LineDrawShape(props) {
|
|
79
|
+
const {
|
|
80
|
+
animationElapsedTime,
|
|
81
|
+
isAnimating,
|
|
82
|
+
isEntrance,
|
|
83
|
+
visibleLength,
|
|
84
|
+
strokeDasharray: userStrokeDasharray,
|
|
85
|
+
connectNulls,
|
|
86
|
+
...curveProps
|
|
87
|
+
} = props;
|
|
88
|
+
const finalConnectNulls = connectNulls ?? false;
|
|
89
|
+
let strokeDasharray;
|
|
90
|
+
if (visibleLength != null) {
|
|
91
|
+
const { pathRef } = curveProps;
|
|
92
|
+
const totalLength = getTotalLength(pathRef?.current ?? null);
|
|
93
|
+
strokeDasharray = computeAnimatedStrokeDasharray(
|
|
94
|
+
userStrokeDasharray,
|
|
95
|
+
totalLength,
|
|
96
|
+
visibleLength,
|
|
97
|
+
);
|
|
98
|
+
} else if (userStrokeDasharray != null) {
|
|
99
|
+
strokeDasharray = String(userStrokeDasharray);
|
|
100
|
+
}
|
|
101
|
+
return <Curve
|
|
102
|
+
{...curveProps}
|
|
103
|
+
connectNulls={finalConnectNulls}
|
|
104
|
+
strokeDasharray={strokeDasharray}
|
|
105
|
+
/>;
|
|
106
|
+
}
|