@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,281 @@
|
|
|
1
|
+
// Port of component/Text.tsx — the SVG text renderer with word wrapping,
|
|
2
|
+
// maxLines binary-search truncation, scaleToFit, and rotation. Measurement
|
|
3
|
+
// runs through the vendored getStringSize (0×0 under SSR, so SSR renders the
|
|
4
|
+
// unwrapped single line — same as upstream).
|
|
5
|
+
import { useMemo } from 'octane';
|
|
6
|
+
import { clsx } from 'clsx';
|
|
7
|
+
import { isNullish, isNumber, isNumOrStr } from '../util/DataUtils';
|
|
8
|
+
import { Global } from '../util/Global';
|
|
9
|
+
import { getStringSize } from '../util/DOMUtils';
|
|
10
|
+
import { reduceCSSCalc } from '../util/ReduceCSSCalc';
|
|
11
|
+
import { svgPropertiesAndEvents } from '../util/svgPropertiesAndEvents.ts';
|
|
12
|
+
import { resolveDefaultProps } from '../util/resolveDefaultProps';
|
|
13
|
+
import { isWellBehavedNumber } from '../util/isWellBehavedNumber';
|
|
14
|
+
|
|
15
|
+
const BREAKING_SPACES = /[ \f\n\r\t\v\u2028\u2029]+/;
|
|
16
|
+
|
|
17
|
+
const calculateWordWidths = ({ children, breakAll, style }) => {
|
|
18
|
+
try {
|
|
19
|
+
let words = [];
|
|
20
|
+
if (!isNullish(children)) {
|
|
21
|
+
if (breakAll) {
|
|
22
|
+
words = children.toString().split('');
|
|
23
|
+
} else {
|
|
24
|
+
words = children.toString().split(BREAKING_SPACES);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const wordsWithComputedWidth = words.map(
|
|
28
|
+
(word) => ({
|
|
29
|
+
word,
|
|
30
|
+
width: getStringSize(word, style).width,
|
|
31
|
+
}),
|
|
32
|
+
);
|
|
33
|
+
const spaceWidth = breakAll ? 0 : getStringSize(' ', style).width;
|
|
34
|
+
return { wordsWithComputedWidth, spaceWidth };
|
|
35
|
+
} catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export function isValidTextAnchor(value) {
|
|
41
|
+
return value === 'start' || value === 'middle' || value === 'end' || value === 'inherit';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function isRenderableText(val) {
|
|
45
|
+
return isNullish(val) || typeof val === 'string' || typeof val === 'number' ||
|
|
46
|
+
typeof val === 'boolean';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const calculate = (words, lineWidth, spaceWidth, scaleToFit) => words.reduce((
|
|
50
|
+
result,
|
|
51
|
+
{ word, width },
|
|
52
|
+
) => {
|
|
53
|
+
const currentLine = result[result.length - 1];
|
|
54
|
+
if (
|
|
55
|
+
currentLine && width != null &&
|
|
56
|
+
(lineWidth == null || scaleToFit ||
|
|
57
|
+
currentLine.width + width + spaceWidth < Number(lineWidth))
|
|
58
|
+
) {
|
|
59
|
+
// Word can be added to an existing line
|
|
60
|
+
currentLine.words.push(word);
|
|
61
|
+
currentLine.width += width + spaceWidth;
|
|
62
|
+
} else {
|
|
63
|
+
// Add first word to line or word is too long to scaleToFit on existing line
|
|
64
|
+
result.push({ words: [word], width });
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}, []);
|
|
68
|
+
|
|
69
|
+
const findLongestLine = (words) => words.reduce((a, b) => (a.width > b.width ? a : b));
|
|
70
|
+
|
|
71
|
+
const suffix = '…';
|
|
72
|
+
|
|
73
|
+
const checkOverflow = (
|
|
74
|
+
text,
|
|
75
|
+
index,
|
|
76
|
+
breakAll,
|
|
77
|
+
style,
|
|
78
|
+
maxLines,
|
|
79
|
+
lineWidth,
|
|
80
|
+
spaceWidth,
|
|
81
|
+
scaleToFit,
|
|
82
|
+
) => {
|
|
83
|
+
const tempText = text.slice(0, index);
|
|
84
|
+
const words = calculateWordWidths({ breakAll, style, children: tempText + suffix });
|
|
85
|
+
if (!words) {
|
|
86
|
+
return [false, []];
|
|
87
|
+
}
|
|
88
|
+
const result = calculate(words.wordsWithComputedWidth, lineWidth, spaceWidth, scaleToFit);
|
|
89
|
+
const doesOverflow =
|
|
90
|
+
result.length > maxLines || findLongestLine(result).width > Number(lineWidth);
|
|
91
|
+
return [doesOverflow, result];
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const calculateWordsByLines = (
|
|
95
|
+
{ maxLines, children, style, breakAll },
|
|
96
|
+
initialWordsWithComputedWith,
|
|
97
|
+
spaceWidth,
|
|
98
|
+
lineWidth,
|
|
99
|
+
scaleToFit,
|
|
100
|
+
) => {
|
|
101
|
+
const shouldLimitLines = isNumber(maxLines);
|
|
102
|
+
const text = String(children);
|
|
103
|
+
const originalResult = calculate(initialWordsWithComputedWith, lineWidth, spaceWidth, scaleToFit);
|
|
104
|
+
if (!shouldLimitLines || scaleToFit) {
|
|
105
|
+
return originalResult;
|
|
106
|
+
}
|
|
107
|
+
const overflows =
|
|
108
|
+
originalResult.length > maxLines || findLongestLine(originalResult).width > Number(lineWidth);
|
|
109
|
+
if (!overflows) {
|
|
110
|
+
return originalResult;
|
|
111
|
+
}
|
|
112
|
+
let start = 0;
|
|
113
|
+
let end = text.length - 1;
|
|
114
|
+
let iterations = 0;
|
|
115
|
+
let trimmedResult;
|
|
116
|
+
while (start <= end && iterations <= text.length - 1) {
|
|
117
|
+
const middle = Math.floor((start + end) / 2);
|
|
118
|
+
const prev = middle - 1;
|
|
119
|
+
const [doesPrevOverflow, result] = checkOverflow(
|
|
120
|
+
text,
|
|
121
|
+
prev,
|
|
122
|
+
breakAll,
|
|
123
|
+
style,
|
|
124
|
+
maxLines,
|
|
125
|
+
lineWidth,
|
|
126
|
+
spaceWidth,
|
|
127
|
+
scaleToFit,
|
|
128
|
+
);
|
|
129
|
+
const [doesMiddleOverflow] = checkOverflow(
|
|
130
|
+
text,
|
|
131
|
+
middle,
|
|
132
|
+
breakAll,
|
|
133
|
+
style,
|
|
134
|
+
maxLines,
|
|
135
|
+
lineWidth,
|
|
136
|
+
spaceWidth,
|
|
137
|
+
scaleToFit,
|
|
138
|
+
);
|
|
139
|
+
if (!doesPrevOverflow && !doesMiddleOverflow) {
|
|
140
|
+
start = middle + 1;
|
|
141
|
+
}
|
|
142
|
+
if (doesPrevOverflow && doesMiddleOverflow) {
|
|
143
|
+
end = middle - 1;
|
|
144
|
+
}
|
|
145
|
+
if (!doesPrevOverflow && doesMiddleOverflow) {
|
|
146
|
+
trimmedResult = result;
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
iterations++;
|
|
150
|
+
}
|
|
151
|
+
// Fallback to originalResult (result without trimming) if we cannot find
|
|
152
|
+
// where to trim. This should not happen :tm:
|
|
153
|
+
return trimmedResult || originalResult;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const getWordsWithoutCalculate = (children) => {
|
|
157
|
+
const words =
|
|
158
|
+
!isNullish(children) ? children.toString().split(BREAKING_SPACES) : [];
|
|
159
|
+
return [
|
|
160
|
+
{ words, width: undefined },
|
|
161
|
+
];
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export const getWordsByLines = ({ width, scaleToFit, children, style, breakAll, maxLines }) => {
|
|
165
|
+
// Only perform calculations if using features that require them (multiline, scaleToFit)
|
|
166
|
+
if ((width || scaleToFit) && !Global.isSsr) {
|
|
167
|
+
const wordWidths = calculateWordWidths({ breakAll, children, style });
|
|
168
|
+
if (!wordWidths) {
|
|
169
|
+
return getWordsWithoutCalculate(children);
|
|
170
|
+
}
|
|
171
|
+
const { wordsWithComputedWidth, spaceWidth } = wordWidths;
|
|
172
|
+
return calculateWordsByLines(
|
|
173
|
+
{ breakAll, children, maxLines, style },
|
|
174
|
+
wordsWithComputedWidth,
|
|
175
|
+
spaceWidth,
|
|
176
|
+
width,
|
|
177
|
+
Boolean(scaleToFit),
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
return getWordsWithoutCalculate(children);
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const DEFAULT_FILL = '#808080';
|
|
184
|
+
|
|
185
|
+
export const textDefaultProps = {
|
|
186
|
+
angle: 0,
|
|
187
|
+
breakAll: false,
|
|
188
|
+
// Magic number from d3
|
|
189
|
+
capHeight: '0.71em',
|
|
190
|
+
fill: DEFAULT_FILL,
|
|
191
|
+
lineHeight: '1em',
|
|
192
|
+
scaleToFit: false,
|
|
193
|
+
textAnchor: 'start',
|
|
194
|
+
// Maintain compat with existing charts / default SVG behavior
|
|
195
|
+
verticalAnchor: 'end',
|
|
196
|
+
x: 0,
|
|
197
|
+
y: 0,
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
export function Text(outsideProps) @{
|
|
201
|
+
const {
|
|
202
|
+
x: propsX,
|
|
203
|
+
y: propsY,
|
|
204
|
+
lineHeight,
|
|
205
|
+
capHeight,
|
|
206
|
+
fill,
|
|
207
|
+
scaleToFit,
|
|
208
|
+
textAnchor,
|
|
209
|
+
verticalAnchor,
|
|
210
|
+
ref,
|
|
211
|
+
...props
|
|
212
|
+
} = resolveDefaultProps(outsideProps, textDefaultProps);
|
|
213
|
+
const wordsByLines = useMemo(() => {
|
|
214
|
+
return getWordsByLines({
|
|
215
|
+
breakAll: props.breakAll,
|
|
216
|
+
children: props.children,
|
|
217
|
+
maxLines: props.maxLines,
|
|
218
|
+
scaleToFit,
|
|
219
|
+
style: props.style,
|
|
220
|
+
width: props.width,
|
|
221
|
+
});
|
|
222
|
+
}, [props.breakAll, props.children, props.maxLines, scaleToFit, props.style, props.width]);
|
|
223
|
+
const { dx, dy, angle, className, breakAll, ...textProps } = props;
|
|
224
|
+
if (!isNumOrStr(propsX) || !isNumOrStr(propsY) || wordsByLines.length === 0) {
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
const x = Number(propsX) + (isNumber(dx) ? dx : 0);
|
|
228
|
+
const y = Number(propsY) + (isNumber(dy) ? dy : 0);
|
|
229
|
+
if (!isWellBehavedNumber(x) || !isWellBehavedNumber(y)) {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
let startDy;
|
|
233
|
+
switch (verticalAnchor) {
|
|
234
|
+
case 'start':
|
|
235
|
+
startDy = reduceCSSCalc('calc(' + capHeight + ')');
|
|
236
|
+
break;
|
|
237
|
+
case 'middle':
|
|
238
|
+
startDy = reduceCSSCalc(
|
|
239
|
+
'calc(' + (wordsByLines.length - 1) / 2 + ' * -' + lineHeight + ' + (' + capHeight +
|
|
240
|
+
' / 2))',
|
|
241
|
+
);
|
|
242
|
+
break;
|
|
243
|
+
default:
|
|
244
|
+
startDy = reduceCSSCalc('calc(' + (wordsByLines.length - 1) + ' * -' + lineHeight + ')');
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
const transforms = [];
|
|
248
|
+
const firstLine = wordsByLines[0];
|
|
249
|
+
if (scaleToFit && firstLine != null) {
|
|
250
|
+
const lineWidth = firstLine.width;
|
|
251
|
+
const { width } = props;
|
|
252
|
+
transforms.push(
|
|
253
|
+
'scale(' + (isNumber(width) && isNumber(lineWidth) ? width / lineWidth : 1) + ')',
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
if (angle) {
|
|
257
|
+
transforms.push('rotate(' + angle + ', ' + x + ', ' + y + ')');
|
|
258
|
+
}
|
|
259
|
+
if (transforms.length) {
|
|
260
|
+
textProps.transform = transforms.join(' ');
|
|
261
|
+
}
|
|
262
|
+
<text
|
|
263
|
+
{...svgPropertiesAndEvents(textProps)}
|
|
264
|
+
ref={ref}
|
|
265
|
+
x={x}
|
|
266
|
+
y={y}
|
|
267
|
+
class={clsx('recharts-text', className)}
|
|
268
|
+
textAnchor={textAnchor}
|
|
269
|
+
fill={fill.includes('url') ? DEFAULT_FILL : fill}
|
|
270
|
+
>{wordsByLines.map((line, index) => {
|
|
271
|
+
const words = line.words.join(breakAll ? '' : ' ');
|
|
272
|
+
// duplicate words would cause duplicate keys — the index disambiguates
|
|
273
|
+
return <tspan
|
|
274
|
+
x={x}
|
|
275
|
+
dy={index === 0 ? startDy : lineHeight}
|
|
276
|
+
key={words + '-' + index}
|
|
277
|
+
>{words}</tspan>;
|
|
278
|
+
})}</text>
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
Text.displayName = 'Text';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Type declaration for the .tsrx component (resolved by relative path).
|
|
2
|
+
export declare const textDefaultProps: Record<string, unknown>;
|
|
3
|
+
export declare const Text: {
|
|
4
|
+
(props: Record<string, unknown>): unknown;
|
|
5
|
+
displayName: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function isValidTextAnchor(value: unknown): boolean;
|
|
8
|
+
export declare function isRenderableText(val: unknown): boolean;
|
|
9
|
+
export declare const getWordsByLines: (input: Record<string, unknown>) => unknown[];
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// Vendored verbatim from recharts@3.9.2 es6/component/responsiveContainerUtils.js (framework-agnostic).
|
|
2
|
+
// Do not edit — update by re-vendoring when the recharts devDependency moves.
|
|
3
|
+
import { isPercent } from '../util/DataUtils';
|
|
4
|
+
export var defaultResponsiveContainerProps = {
|
|
5
|
+
width: '100%',
|
|
6
|
+
height: '100%',
|
|
7
|
+
debounce: 0,
|
|
8
|
+
minWidth: 0,
|
|
9
|
+
initialDimension: {
|
|
10
|
+
width: -1,
|
|
11
|
+
height: -1,
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
export var calculateChartDimensions = (containerWidth, containerHeight, props) => {
|
|
15
|
+
var _props$width = props.width,
|
|
16
|
+
width = _props$width === void 0 ? defaultResponsiveContainerProps.width : _props$width,
|
|
17
|
+
_props$height = props.height,
|
|
18
|
+
height = _props$height === void 0 ? defaultResponsiveContainerProps.height : _props$height,
|
|
19
|
+
aspect = props.aspect,
|
|
20
|
+
maxHeight = props.maxHeight;
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* The containerWidth and containerHeight are already percentage based because it's set as that percentage in CSS.
|
|
24
|
+
* Means we don't have to calculate percentages here.
|
|
25
|
+
*/
|
|
26
|
+
var calculatedWidth = isPercent(width) ? containerWidth : Number(width);
|
|
27
|
+
var calculatedHeight = isPercent(height) ? containerHeight : Number(height);
|
|
28
|
+
if (aspect && aspect > 0) {
|
|
29
|
+
// Preserve the desired aspect ratio
|
|
30
|
+
if (calculatedWidth) {
|
|
31
|
+
// Will default to using width for aspect ratio
|
|
32
|
+
calculatedHeight = calculatedWidth / aspect;
|
|
33
|
+
} else if (calculatedHeight) {
|
|
34
|
+
// But we should also take height into consideration
|
|
35
|
+
calculatedWidth = calculatedHeight * aspect;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// if maxHeight is set, overwrite if calculatedHeight is greater than maxHeight
|
|
39
|
+
if (maxHeight && calculatedHeight != null && calculatedHeight > maxHeight) {
|
|
40
|
+
calculatedHeight = maxHeight;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
calculatedWidth,
|
|
45
|
+
calculatedHeight,
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
var bothOverflow = {
|
|
49
|
+
width: 0,
|
|
50
|
+
height: 0,
|
|
51
|
+
overflow: 'visible',
|
|
52
|
+
};
|
|
53
|
+
var overflowX = {
|
|
54
|
+
width: 0,
|
|
55
|
+
overflowX: 'visible',
|
|
56
|
+
};
|
|
57
|
+
var overflowY = {
|
|
58
|
+
height: 0,
|
|
59
|
+
overflowY: 'visible',
|
|
60
|
+
};
|
|
61
|
+
var noStyle = {};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* This zero-size, overflow-visible is required to allow the chart to shrink.
|
|
65
|
+
* Without it, the chart itself will fill the ResponsiveContainer, and while it allows the chart to grow,
|
|
66
|
+
* it would always keep the container at the size of the chart,
|
|
67
|
+
* and ResizeObserver would never fire.
|
|
68
|
+
* With this zero-size element, the chart itself never actually fills the container,
|
|
69
|
+
* it just so happens that it is visible because it overflows.
|
|
70
|
+
* I learned this trick from the `react-virtualized` library: https://github.com/bvaughn/react-virtualized-auto-sizer/blob/master/src/AutoSizer.ts
|
|
71
|
+
* See https://github.com/recharts/recharts/issues/172 and also https://github.com/bvaughn/react-virtualized/issues/68
|
|
72
|
+
*
|
|
73
|
+
* Also, we don't need to apply the zero-size style if the dimension is a fixed number (or undefined),
|
|
74
|
+
* because in that case the chart can't shrink in that dimension anyway.
|
|
75
|
+
* This fixes defining the dimensions using aspect ratio: https://github.com/recharts/recharts/issues/6245
|
|
76
|
+
*/
|
|
77
|
+
export var getInnerDivStyle = (props) => {
|
|
78
|
+
var width = props.width,
|
|
79
|
+
height = props.height;
|
|
80
|
+
var isWidthPercent = isPercent(width);
|
|
81
|
+
var isHeightPercent = isPercent(height);
|
|
82
|
+
if (isWidthPercent && isHeightPercent) {
|
|
83
|
+
return bothOverflow;
|
|
84
|
+
}
|
|
85
|
+
if (isWidthPercent) {
|
|
86
|
+
return overflowX;
|
|
87
|
+
}
|
|
88
|
+
if (isHeightPercent) {
|
|
89
|
+
return overflowY;
|
|
90
|
+
}
|
|
91
|
+
return noStyle;
|
|
92
|
+
};
|
|
93
|
+
export function getDefaultWidthAndHeight(_ref) {
|
|
94
|
+
var width = _ref.width,
|
|
95
|
+
height = _ref.height,
|
|
96
|
+
aspect = _ref.aspect;
|
|
97
|
+
var calculatedWidth = width;
|
|
98
|
+
var calculatedHeight = height;
|
|
99
|
+
if (calculatedWidth === undefined && calculatedHeight === undefined) {
|
|
100
|
+
calculatedWidth = defaultResponsiveContainerProps.width;
|
|
101
|
+
calculatedHeight = defaultResponsiveContainerProps.height;
|
|
102
|
+
} else if (calculatedWidth === undefined) {
|
|
103
|
+
calculatedWidth = aspect && aspect > 0 ? undefined : defaultResponsiveContainerProps.width;
|
|
104
|
+
} else if (calculatedHeight === undefined) {
|
|
105
|
+
calculatedHeight = aspect && aspect > 0 ? undefined : defaultResponsiveContainerProps.height;
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
width: calculatedWidth,
|
|
109
|
+
height: calculatedHeight,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Port of container/ClipPathProvider.tsx — mints the chart's clip path id,
|
|
2
|
+
// renders the <defs><clipPath> sized to the plot area, and provides the id.
|
|
3
|
+
import { createContext, useContext, useState } from 'octane';
|
|
4
|
+
import { uniqueId } from '../util/DataUtils';
|
|
5
|
+
import { usePlotArea } from '../hooks';
|
|
6
|
+
|
|
7
|
+
const ClipPathIdContext = createContext(undefined);
|
|
8
|
+
|
|
9
|
+
export function ClipPathProvider(props) @{
|
|
10
|
+
const { children } = props;
|
|
11
|
+
const [clipPathId] = useState(uniqueId('recharts') + '-clip');
|
|
12
|
+
const plotArea = usePlotArea();
|
|
13
|
+
if (plotArea == null) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const { x, y, width, height } = plotArea;
|
|
17
|
+
<ClipPathIdContext.Provider value={clipPathId}>
|
|
18
|
+
<defs>
|
|
19
|
+
<clipPath id={clipPathId}>
|
|
20
|
+
<rect x={x} y={y} height={height} width={width} />
|
|
21
|
+
</clipPath>
|
|
22
|
+
</defs>
|
|
23
|
+
{children}
|
|
24
|
+
</ClipPathIdContext.Provider>
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const useClipPathId = () => {
|
|
28
|
+
return useContext(ClipPathIdContext);
|
|
29
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Port of container/Layer.tsx — an SVG <g> group. Ref is a plain prop.
|
|
2
|
+
import { clsx } from 'clsx';
|
|
3
|
+
import { svgPropertiesAndEvents } from '../util/svgPropertiesAndEvents.ts';
|
|
4
|
+
|
|
5
|
+
export function Layer(props) {
|
|
6
|
+
const { children, className, ref, ...others } = props;
|
|
7
|
+
const layerClass = clsx('recharts-layer', className);
|
|
8
|
+
return <g className={layerClass} {...svgPropertiesAndEvents(others)} ref={ref}>{children}</g>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Port of container/RootSurface.tsx — the chart's outer <svg> (via Surface),
|
|
2
|
+
// sized from the store, with the zIndex portal <g>s wrapped around children.
|
|
3
|
+
// A panorama (Brush preview) renders a nested, brush-sized Surface instead.
|
|
4
|
+
import { useChartHeight, useChartWidth } from '../context/chartLayoutContext.ts';
|
|
5
|
+
import { useAccessibilityLayer } from '../context/accessibilityContext';
|
|
6
|
+
import { useIsPanorama } from '../context/PanoramaContext.ts';
|
|
7
|
+
import { Surface } from './Surface.tsrx';
|
|
8
|
+
import { useAppSelector } from '../state/hooks';
|
|
9
|
+
import { selectBrushDimensions } from '../state/selectors/brushSelectors';
|
|
10
|
+
import { isPositiveNumber } from '../util/isWellBehavedNumber';
|
|
11
|
+
import { AllZIndexPortals } from '../zIndex/ZIndexPortal.tsrx';
|
|
12
|
+
|
|
13
|
+
const FULL_WIDTH_AND_HEIGHT = {
|
|
14
|
+
width: '100%',
|
|
15
|
+
height: '100%',
|
|
16
|
+
// display:block — the default inline SVG reserves descender space in some
|
|
17
|
+
// browsers, which inflates height measurement under responsive containers.
|
|
18
|
+
display: 'block',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function MainChartSurface(props) {
|
|
22
|
+
const width = useChartWidth();
|
|
23
|
+
const height = useChartHeight();
|
|
24
|
+
const hasAccessibilityLayer = useAccessibilityLayer();
|
|
25
|
+
if (!isPositiveNumber(width) || !isPositiveNumber(height)) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const { children, otherAttributes, title, desc, ref } = props;
|
|
29
|
+
let tabIndex, role;
|
|
30
|
+
if (otherAttributes != null) {
|
|
31
|
+
if (typeof otherAttributes.tabIndex === 'number') {
|
|
32
|
+
tabIndex = otherAttributes.tabIndex;
|
|
33
|
+
} else {
|
|
34
|
+
tabIndex = hasAccessibilityLayer ? 0 : undefined;
|
|
35
|
+
}
|
|
36
|
+
if (typeof otherAttributes.role === 'string') {
|
|
37
|
+
role = otherAttributes.role;
|
|
38
|
+
} else {
|
|
39
|
+
role = hasAccessibilityLayer ? 'application' : undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return <Surface
|
|
43
|
+
{...otherAttributes}
|
|
44
|
+
title={title}
|
|
45
|
+
desc={desc}
|
|
46
|
+
role={role}
|
|
47
|
+
tabIndex={tabIndex}
|
|
48
|
+
width={width}
|
|
49
|
+
height={height}
|
|
50
|
+
style={FULL_WIDTH_AND_HEIGHT}
|
|
51
|
+
ref={ref}
|
|
52
|
+
>{children}</Surface>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function BrushPanoramaSurface(props) {
|
|
56
|
+
const { children } = props;
|
|
57
|
+
const brushDimensions = useAppSelector(selectBrushDimensions);
|
|
58
|
+
if (!brushDimensions) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const { width, height, y, x } = brushDimensions;
|
|
62
|
+
return <Surface width={width} height={height} x={x} y={y}>{children}</Surface>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function RootSurface(props) {
|
|
66
|
+
const { children, ref, ...rest } = props;
|
|
67
|
+
const isPanorama = useIsPanorama();
|
|
68
|
+
if (isPanorama) {
|
|
69
|
+
return <BrushPanoramaSurface>
|
|
70
|
+
<AllZIndexPortals isPanorama={true}>{children}</AllZIndexPortals>
|
|
71
|
+
</BrushPanoramaSurface>;
|
|
72
|
+
}
|
|
73
|
+
return <MainChartSurface ref={ref} {...rest}>
|
|
74
|
+
<AllZIndexPortals isPanorama={false}>{children}</AllZIndexPortals>
|
|
75
|
+
</MainChartSurface>;
|
|
76
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Port of container/Surface.tsx — the root <svg> element every chart renders
|
|
2
|
+
// into. Ref is a plain prop (octane model, no forwardRef).
|
|
3
|
+
import { clsx } from 'clsx';
|
|
4
|
+
import { svgPropertiesAndEvents } from '../util/svgPropertiesAndEvents.ts';
|
|
5
|
+
|
|
6
|
+
export function Surface(props) {
|
|
7
|
+
const { children, width, height, viewBox, className, style, title, desc, ref, ...others } = props;
|
|
8
|
+
const svgView = viewBox || { width, height, x: 0, y: 0 };
|
|
9
|
+
const layerClass = clsx('recharts-surface', className);
|
|
10
|
+
return <svg
|
|
11
|
+
{...svgPropertiesAndEvents(others)}
|
|
12
|
+
className={layerClass}
|
|
13
|
+
width={width}
|
|
14
|
+
height={height}
|
|
15
|
+
style={style}
|
|
16
|
+
viewBox={svgView.x + ' ' + svgView.y + ' ' + svgView.width + ' ' + svgView.height}
|
|
17
|
+
ref={ref}
|
|
18
|
+
>
|
|
19
|
+
<title>{title}</title>
|
|
20
|
+
<desc>{desc}</desc>
|
|
21
|
+
{children}
|
|
22
|
+
</svg>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Type declaration for the .tsrx component (resolved by relative path).
|
|
2
|
+
export declare const Surface: (props: {
|
|
3
|
+
width: number;
|
|
4
|
+
height: number;
|
|
5
|
+
viewBox?: { x?: number; y?: number; width?: number; height?: number };
|
|
6
|
+
className?: unknown;
|
|
7
|
+
style?: unknown;
|
|
8
|
+
title?: string;
|
|
9
|
+
desc?: string;
|
|
10
|
+
children?: unknown;
|
|
11
|
+
[key: string]: unknown;
|
|
12
|
+
}) => unknown;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// octane-only (no upstream counterpart): Cell props collection by
|
|
2
|
+
// REGISTRATION. React recharts reads `<Cell>` children via findAllByType —
|
|
3
|
+
// element introspection that octane's compiled children (opaque block
|
|
4
|
+
// functions) cannot support. Instead, octane Cells REGISTER their props into
|
|
5
|
+
// this collector when rendered, mirroring the redux-registration pattern
|
|
6
|
+
// recharts v3 itself adopted for every other child type. Registration order is
|
|
7
|
+
// mount order, which octane guarantees follows tree order (sibling layout
|
|
8
|
+
// effects run in order), so indexes line up with data indexes exactly like the
|
|
9
|
+
// upstream element order did.
|
|
10
|
+
import { createContext, useContext, useMemo, useState } from 'octane';
|
|
11
|
+
import { splitSlot, subSlot } from '../internal';
|
|
12
|
+
|
|
13
|
+
export interface CellRegistry {
|
|
14
|
+
register(token: object, props: unknown): void;
|
|
15
|
+
unregister(token: object): void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** The shape upstream's `cells[index].props` access expects. */
|
|
19
|
+
export interface RegisteredCell {
|
|
20
|
+
props: unknown;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const CellsContext = createContext<CellRegistry | null>(null);
|
|
24
|
+
|
|
25
|
+
function toCellArray(map: Map<object, unknown>): RegisteredCell[] | undefined {
|
|
26
|
+
if (map.size === 0) {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
return Array.from(map.values(), (props) => ({ props }));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Owns the collected cells state. Returns `[cells, registry]`; provide the
|
|
34
|
+
* registry via `<CellsContext.Provider value={registry}>` around the item's
|
|
35
|
+
* children, and pass `cells` wherever upstream passed findAllByType's result.
|
|
36
|
+
* `cells` is `undefined` until the first Cell registers — matching upstream,
|
|
37
|
+
* where a childless item passes an empty find result whose `cells[index]`
|
|
38
|
+
* lookups are all undefined.
|
|
39
|
+
*/
|
|
40
|
+
export function useCellRegistry(...rest: any[]): [RegisteredCell[] | undefined, CellRegistry] {
|
|
41
|
+
const [, slot] = splitSlot(rest);
|
|
42
|
+
const [cells, setCells] = useState<RegisteredCell[] | undefined>(
|
|
43
|
+
undefined,
|
|
44
|
+
subSlot(slot, 'cr:s'),
|
|
45
|
+
);
|
|
46
|
+
const registry = useMemo(
|
|
47
|
+
() => {
|
|
48
|
+
const entries = new Map<object, unknown>();
|
|
49
|
+
let scheduled = false;
|
|
50
|
+
const publish = () => {
|
|
51
|
+
if (scheduled) return;
|
|
52
|
+
scheduled = true;
|
|
53
|
+
// One state update per commit no matter how many cells registered.
|
|
54
|
+
queueMicrotask(() => {
|
|
55
|
+
scheduled = false;
|
|
56
|
+
setCells(toCellArray(entries));
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
return {
|
|
60
|
+
register(token: object, props: unknown) {
|
|
61
|
+
entries.set(token, props);
|
|
62
|
+
publish();
|
|
63
|
+
},
|
|
64
|
+
unregister(token: object) {
|
|
65
|
+
entries.delete(token);
|
|
66
|
+
publish();
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
[],
|
|
71
|
+
subSlot(slot, 'cr:m'),
|
|
72
|
+
);
|
|
73
|
+
return [cells, registry];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Read the ambient registry (null outside a cell-collecting graphical item). */
|
|
77
|
+
export function useCellsRegistry(): CellRegistry | null {
|
|
78
|
+
// Context reads resolve by walking the block tree — no slot needed.
|
|
79
|
+
return useContext(CellsContext);
|
|
80
|
+
}
|