@solidports/recharts 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (304) hide show
  1. package/dist/index.d.ts +40 -2
  2. package/dist/index.js +14238 -7174
  3. package/dist/{dev.js → index.jsx} +18367 -15900
  4. package/dist/server.js +48178 -0
  5. package/package.json +36 -19
  6. package/src/animation/AnimatedItems.tsx +0 -183
  7. package/src/animation/AnimationController.ts +0 -33
  8. package/src/animation/AnimationControllerImpl.ts +0 -36
  9. package/src/animation/AnimationHandle.ts +0 -307
  10. package/src/animation/CSSTransitionAnimate.tsx +0 -170
  11. package/src/animation/JavascriptAnimate.tsx +0 -119
  12. package/src/animation/easing.ts +0 -221
  13. package/src/animation/matchBy.ts +0 -164
  14. package/src/animation/timeoutController.ts +0 -70
  15. package/src/animation/useAnimationController.tsx +0 -34
  16. package/src/animation/useAnimationStartSnapshot.ts +0 -118
  17. package/src/animation/util.ts +0 -41
  18. package/src/cartesian/Area.tsx +0 -915
  19. package/src/cartesian/AreaRevealShape.tsx +0 -190
  20. package/src/cartesian/Bar.tsx +0 -1369
  21. package/src/cartesian/BarStack.tsx +0 -152
  22. package/src/cartesian/Brush.tsx +0 -951
  23. package/src/cartesian/CartesianAxis.tsx +0 -722
  24. package/src/cartesian/CartesianGrid.tsx +0 -711
  25. package/src/cartesian/ErrorBar.tsx +0 -361
  26. package/src/cartesian/Funnel.tsx +0 -803
  27. package/src/cartesian/GraphicalItemClipPath.tsx +0 -67
  28. package/src/cartesian/Line.tsx +0 -863
  29. package/src/cartesian/LineDrawShape.tsx +0 -89
  30. package/src/cartesian/ReferenceArea.tsx +0 -331
  31. package/src/cartesian/ReferenceDot.tsx +0 -304
  32. package/src/cartesian/ReferenceLine.tsx +0 -474
  33. package/src/cartesian/Scatter.tsx +0 -888
  34. package/src/cartesian/XAxis.tsx +0 -433
  35. package/src/cartesian/YAxis.tsx +0 -443
  36. package/src/cartesian/ZAxis.tsx +0 -155
  37. package/src/cartesian/cartesianPositionToCSSTranslate.tsx +0 -29
  38. package/src/cartesian/cartesianViewBoxToTrapezoid.tsx +0 -21
  39. package/src/cartesian/getCartesianPosition.tsx +0 -267
  40. package/src/cartesian/getEquidistantTicks.ts +0 -144
  41. package/src/cartesian/getTicks.ts +0 -225
  42. package/src/cartesian/isOutsidePosition.ts +0 -15
  43. package/src/cartesian/useAnimatedLineLength.ts +0 -54
  44. package/src/chart/AreaChart.tsx +0 -29
  45. package/src/chart/BarChart.tsx +0 -29
  46. package/src/chart/CartesianChart.tsx +0 -131
  47. package/src/chart/CategoricalChart.tsx +0 -94
  48. package/src/chart/ComposedChart.tsx +0 -29
  49. package/src/chart/FunnelChart.tsx +0 -29
  50. package/src/chart/LineChart.tsx +0 -29
  51. package/src/chart/PieChart.tsx +0 -50
  52. package/src/chart/PolarChart.tsx +0 -164
  53. package/src/chart/RadarChart.tsx +0 -70
  54. package/src/chart/RadialBarChart.tsx +0 -46
  55. package/src/chart/RechartsWrapper.tsx +0 -551
  56. package/src/chart/Sankey.tsx +0 -1534
  57. package/src/chart/ScatterChart.tsx +0 -29
  58. package/src/chart/SunburstChart.tsx +0 -504
  59. package/src/chart/Treemap.tsx +0 -1223
  60. package/src/chart/createInitialRootProps.ts +0 -24
  61. package/src/chart/types.ts +0 -53
  62. package/src/component/ActivePoints.tsx +0 -144
  63. package/src/component/Cell.tsx +0 -37
  64. package/src/component/Cursor.tsx +0 -185
  65. package/src/component/Customized.tsx +0 -50
  66. package/src/component/DefaultLegendContent.tsx +0 -348
  67. package/src/component/DefaultTooltipContent.tsx +0 -224
  68. package/src/component/Dots.tsx +0 -157
  69. package/src/component/Label.tsx +0 -636
  70. package/src/component/LabelList.tsx +0 -375
  71. package/src/component/Legend.tsx +0 -512
  72. package/src/component/ResponsiveContainer.tsx +0 -348
  73. package/src/component/Text.tsx +0 -541
  74. package/src/component/Tooltip.tsx +0 -470
  75. package/src/component/TooltipBoundingBox.tsx +0 -146
  76. package/src/component/responsiveContainerUtils.ts +0 -134
  77. package/src/container/ClipPathProvider.tsx +0 -51
  78. package/src/container/Layer.tsx +0 -38
  79. package/src/container/RootSurface.tsx +0 -120
  80. package/src/container/Surface.tsx +0 -61
  81. package/src/context/CellsContext.tsx +0 -54
  82. package/src/context/ErrorBarContext.tsx +0 -146
  83. package/src/context/GraphicalItemChildrenScope.tsx +0 -18
  84. package/src/context/PanoramaContext.tsx +0 -9
  85. package/src/context/RegisterGraphicalItemId.tsx +0 -30
  86. package/src/context/accessibilityContext.tsx +0 -6
  87. package/src/context/brushUpdateContext.tsx +0 -9
  88. package/src/context/chartDataContext.tsx +0 -97
  89. package/src/context/chartLayoutContext.tsx +0 -201
  90. package/src/context/legendPayloadContext.tsx +0 -20
  91. package/src/context/legendPortalContext.tsx +0 -12
  92. package/src/context/tooltipContext.tsx +0 -89
  93. package/src/context/tooltipPortalContext.tsx +0 -12
  94. package/src/context/useTooltipAxis.ts +0 -22
  95. package/src/hooks.ts +0 -476
  96. package/src/index.ts +0 -280
  97. package/src/polar/Pie.tsx +0 -1360
  98. package/src/polar/PolarAngleAxis.tsx +0 -616
  99. package/src/polar/PolarGrid.tsx +0 -312
  100. package/src/polar/PolarRadiusAxis.tsx +0 -547
  101. package/src/polar/Radar.tsx +0 -734
  102. package/src/polar/RadialBar.tsx +0 -917
  103. package/src/polar/defaultPolarAngleAxisProps.tsx +0 -27
  104. package/src/polar/defaultPolarRadiusAxisProps.tsx +0 -25
  105. package/src/shape/Cross.tsx +0 -89
  106. package/src/shape/Curve.tsx +0 -343
  107. package/src/shape/Dot.tsx +0 -70
  108. package/src/shape/Polygon.tsx +0 -195
  109. package/src/shape/Rectangle.tsx +0 -470
  110. package/src/shape/Sector.tsx +0 -347
  111. package/src/shape/Symbols.tsx +0 -139
  112. package/src/shape/Trapezoid.tsx +0 -280
  113. package/src/state/RechartsStateContext.tsx +0 -12
  114. package/src/state/RechartsStateProvider.tsx +0 -87
  115. package/src/state/RechartsStoreContext.tsx +0 -25
  116. package/src/state/RechartsStoreProvider.tsx +0 -35
  117. package/src/state/ReportChartProps.tsx +0 -40
  118. package/src/state/ReportEventSettings.tsx +0 -30
  119. package/src/state/ReportMainChartProps.tsx +0 -61
  120. package/src/state/ReportPolarOptions.tsx +0 -35
  121. package/src/state/SetGraphicalItem.ts +0 -79
  122. package/src/state/SetLegendPayload.ts +0 -134
  123. package/src/state/SetTooltipEntrySettings.tsx +0 -72
  124. package/src/state/actions.ts +0 -464
  125. package/src/state/brushSlice.ts +0 -13
  126. package/src/state/cartesianAxisSlice.ts +0 -141
  127. package/src/state/chartDataSlice.ts +0 -50
  128. package/src/state/chartState.ts +0 -297
  129. package/src/state/errorBarSlice.ts +0 -29
  130. package/src/state/eventSettingsSlice.ts +0 -8
  131. package/src/state/events.ts +0 -76
  132. package/src/state/externalEventsMiddleware.ts +0 -255
  133. package/src/state/graphicalItemsSlice.ts +0 -74
  134. package/src/state/hooks/useChartSelectors.tsx +0 -45
  135. package/src/state/keyboardEventsMiddleware.ts +0 -228
  136. package/src/state/layoutSlice.ts +0 -21
  137. package/src/state/legendSlice.ts +0 -57
  138. package/src/state/mouseEventsMiddleware.ts +0 -185
  139. package/src/state/optionsSlice.ts +0 -47
  140. package/src/state/polarAxisSlice.ts +0 -10
  141. package/src/state/polarOptionsSlice.ts +0 -12
  142. package/src/state/rawData.ts +0 -26
  143. package/src/state/referenceElementsSlice.ts +0 -40
  144. package/src/state/renderedTicksSlice.ts +0 -15
  145. package/src/state/rootPropsSlice.ts +0 -47
  146. package/src/state/selectors/areaSelectors.ts +0 -240
  147. package/src/state/selectors/arrayEqualityCheck.ts +0 -29
  148. package/src/state/selectors/axisSelectors.ts +0 -2157
  149. package/src/state/selectors/barSelectors.ts +0 -310
  150. package/src/state/selectors/barStackSelectors.ts +0 -77
  151. package/src/state/selectors/brushSelectors.ts +0 -33
  152. package/src/state/selectors/chartSelector.ts +0 -185
  153. package/src/state/selectors/combiners/combineActiveLabel.ts +0 -16
  154. package/src/state/selectors/combiners/combineActiveTooltipIndex.ts +0 -95
  155. package/src/state/selectors/combiners/combineAllBarPositions.ts +0 -122
  156. package/src/state/selectors/combiners/combineAxisRangeWithReverse.ts +0 -16
  157. package/src/state/selectors/combiners/combineBarPosition.ts +0 -23
  158. package/src/state/selectors/combiners/combineBarSizeList.ts +0 -80
  159. package/src/state/selectors/combiners/combineCheckedDomain.ts +0 -48
  160. package/src/state/selectors/combiners/combineConfiguredScale.ts +0 -111
  161. package/src/state/selectors/combiners/combineCoordinateForDefaultIndex.ts +0 -45
  162. package/src/state/selectors/combiners/combineDisplayedStackedData.ts +0 -50
  163. package/src/state/selectors/combiners/combineInverseScaleFunction.ts +0 -16
  164. package/src/state/selectors/combiners/combineRealScaleType.ts +0 -44
  165. package/src/state/selectors/combiners/combineStackedData.ts +0 -27
  166. package/src/state/selectors/combiners/combineTooltipInteractionState.ts +0 -86
  167. package/src/state/selectors/combiners/combineTooltipPayload.ts +0 -205
  168. package/src/state/selectors/combiners/combineTooltipPayloadConfigurations.ts +0 -58
  169. package/src/state/selectors/containerSelectors.ts +0 -12
  170. package/src/state/selectors/dataSelectors.ts +0 -88
  171. package/src/state/selectors/funnelSelectors.ts +0 -75
  172. package/src/state/selectors/graphicalItemSelectors.ts +0 -30
  173. package/src/state/selectors/legendSelectors.ts +0 -29
  174. package/src/state/selectors/lineSelectors.ts +0 -134
  175. package/src/state/selectors/numberDomainEqualityCheck.ts +0 -14
  176. package/src/state/selectors/pickAxisId.ts +0 -5
  177. package/src/state/selectors/pickAxisType.ts +0 -3
  178. package/src/state/selectors/pieSelectors.ts +0 -97
  179. package/src/state/selectors/polarAxisSelectors.ts +0 -201
  180. package/src/state/selectors/polarGridSelectors.ts +0 -28
  181. package/src/state/selectors/polarScaleSelectors.ts +0 -133
  182. package/src/state/selectors/polarSelectors.ts +0 -219
  183. package/src/state/selectors/radarSelectors.ts +0 -191
  184. package/src/state/selectors/radialBarSelectors.ts +0 -435
  185. package/src/state/selectors/rootPropsSelectors.ts +0 -25
  186. package/src/state/selectors/scatterSelectors.ts +0 -96
  187. package/src/state/selectors/selectActivePropsFromChartPointer.ts +0 -26
  188. package/src/state/selectors/selectAllAxes.ts +0 -17
  189. package/src/state/selectors/selectChartOffset.ts +0 -16
  190. package/src/state/selectors/selectChartOffsetInternal.ts +0 -136
  191. package/src/state/selectors/selectLegendArea.ts +0 -20
  192. package/src/state/selectors/selectPlotArea.ts +0 -22
  193. package/src/state/selectors/selectTooltipAxisId.ts +0 -7
  194. package/src/state/selectors/selectTooltipAxisType.ts +0 -32
  195. package/src/state/selectors/selectTooltipEventType.ts +0 -48
  196. package/src/state/selectors/selectTooltipPayloadSearcher.ts +0 -6
  197. package/src/state/selectors/selectTooltipSettings.ts +0 -39
  198. package/src/state/selectors/selectTooltipState.ts +0 -8
  199. package/src/state/selectors/selectors.ts +0 -271
  200. package/src/state/selectors/tooltipSelectors.ts +0 -578
  201. package/src/state/selectors/touchSelectors.ts +0 -31
  202. package/src/state/store.ts +0 -29
  203. package/src/state/storeIdentity.ts +0 -9
  204. package/src/state/teardownWrite.ts +0 -10
  205. package/src/state/tooltipInteraction.ts +0 -23
  206. package/src/state/tooltipSlice.ts +0 -334
  207. package/src/state/touchEventsMiddleware.ts +0 -214
  208. package/src/state/types/AnimationSettings.ts +0 -20
  209. package/src/state/types/AreaSettings.ts +0 -14
  210. package/src/state/types/BarSettings.ts +0 -15
  211. package/src/state/types/LineSettings.ts +0 -9
  212. package/src/state/types/PieSettings.ts +0 -34
  213. package/src/state/types/RadarSettings.ts +0 -5
  214. package/src/state/types/RadialBarSettings.ts +0 -10
  215. package/src/state/types/ScatterSettings.ts +0 -12
  216. package/src/state/types/StackedGraphicalItem.ts +0 -34
  217. package/src/state/useChartState.ts +0 -17
  218. package/src/state/zIndexSlice.ts +0 -39
  219. package/src/synchronisation/syncSelectors.ts +0 -7
  220. package/src/synchronisation/types.ts +0 -44
  221. package/src/synchronisation/useChartSynchronisation.tsx +0 -404
  222. package/src/theme/RechartsTheme.ts +0 -16
  223. package/src/theme/RechartsThemeContext.ts +0 -19
  224. package/src/theme/darkTheme.ts +0 -13
  225. package/src/theme/graphicalItemIdentity.ts +0 -70
  226. package/src/theme/legacyTheme.ts +0 -17
  227. package/src/theme/lightTheme.ts +0 -13
  228. package/src/types.ts +0 -54
  229. package/src/util/ActiveShapeUtils.tsx +0 -162
  230. package/src/util/BarUtils.tsx +0 -62
  231. package/src/util/BarePortal.tsx +0 -50
  232. package/src/util/CamelCaseSVGAttrs.ts +0 -34
  233. package/src/util/CartesianUtils.ts +0 -48
  234. package/src/util/ChartUtils.ts +0 -802
  235. package/src/util/Constants.ts +0 -42
  236. package/src/util/CssPrefixUtils.ts +0 -20
  237. package/src/util/DOMUtils.ts +0 -129
  238. package/src/util/DataUtils.ts +0 -216
  239. package/src/util/Events.ts +0 -16
  240. package/src/util/FunnelUtils.tsx +0 -15
  241. package/src/util/Global.ts +0 -12
  242. package/src/util/IfOverflow.ts +0 -15
  243. package/src/util/LRUCache.ts +0 -41
  244. package/src/util/LogUtils.ts +0 -22
  245. package/src/util/PolarUtils.ts +0 -132
  246. package/src/util/RadialBarUtils.tsx +0 -24
  247. package/src/util/ReactUtils.ts +0 -95
  248. package/src/util/ReduceCSSCalc.ts +0 -187
  249. package/src/util/ScatterUtils.tsx +0 -52
  250. package/src/util/ShapeElementProps.tsx +0 -87
  251. package/src/util/TickUtils.ts +0 -60
  252. package/src/util/XAxisUtils.ts +0 -48
  253. package/src/util/YAxisUtils.ts +0 -48
  254. package/src/util/axisPropsAreEqual.ts +0 -48
  255. package/src/util/createCartesianCharts.tsx +0 -150
  256. package/src/util/createEventProxy.ts +0 -20
  257. package/src/util/createPolarCharts.tsx +0 -112
  258. package/src/util/cursor/getCursorPoints.ts +0 -46
  259. package/src/util/cursor/getCursorRectangle.ts +0 -28
  260. package/src/util/cursor/getRadialCursorPoints.ts +0 -32
  261. package/src/util/excludeEventProps.ts +0 -171
  262. package/src/util/getActiveCoordinate.ts +0 -213
  263. package/src/util/getAxisTypeBasedOnLayout.ts +0 -21
  264. package/src/util/getClassNameFromUnknown.ts +0 -6
  265. package/src/util/getEveryNth.ts +0 -27
  266. package/src/util/getRadiusAndStrokeWidthFromDot.ts +0 -35
  267. package/src/util/getRelativeCoordinate.ts +0 -80
  268. package/src/util/getSliced.ts +0 -13
  269. package/src/util/hoverDedupe.ts +0 -41
  270. package/src/util/isDomainSpecifiedByUser.ts +0 -219
  271. package/src/util/isWellBehavedNumber.ts +0 -7
  272. package/src/util/pathTotalLength.ts +0 -25
  273. package/src/util/payload/getUniqPayload.ts +0 -28
  274. package/src/util/propsAreEqual.ts +0 -121
  275. package/src/util/resolveDefaultProps.ts +0 -161
  276. package/src/util/round.ts +0 -32
  277. package/src/util/scale/CartesianScaleHelper.ts +0 -72
  278. package/src/util/scale/CustomScaleDefinition.ts +0 -81
  279. package/src/util/scale/RechartsScale.ts +0 -130
  280. package/src/util/scale/createCategoricalInverse.ts +0 -72
  281. package/src/util/scale/getNiceTickValues.ts +0 -311
  282. package/src/util/scale/index.ts +0 -2
  283. package/src/util/scale/util/arithmetic.ts +0 -54
  284. package/src/util/solid-1-compat.ts +0 -310
  285. package/src/util/solidJsxCamelAugment.d.ts +0 -84
  286. package/src/util/stacks/getStackSeriesIdentifier.ts +0 -21
  287. package/src/util/stacks/stackTypes.ts +0 -60
  288. package/src/util/structurallyEqual.ts +0 -31
  289. package/src/util/svgPropertiesAndEvents.ts +0 -53
  290. package/src/util/svgPropertiesNoEvents.ts +0 -571
  291. package/src/util/tooltip/translate.ts +0 -171
  292. package/src/util/typedDataKey.ts +0 -48
  293. package/src/util/types.ts +0 -1560
  294. package/src/util/useAnimationId.ts +0 -31
  295. package/src/util/useElementOffset.ts +0 -110
  296. package/src/util/useId.ts +0 -8
  297. package/src/util/usePrefersReducedMotion.ts +0 -48
  298. package/src/util/useReportScale.ts +0 -24
  299. package/src/util/useUniqueId.ts +0 -30
  300. package/src/zIndex/DefaultZIndexes.ts +0 -84
  301. package/src/zIndex/ZIndexLayer.tsx +0 -121
  302. package/src/zIndex/ZIndexPortal.tsx +0 -79
  303. package/src/zIndex/getZIndexFromUnknown.ts +0 -14
  304. package/src/zIndex/zIndexSelectors.ts +0 -48
@@ -1,2157 +0,0 @@
1
- /* eslint-disable import/no-cycle */
2
- import range from "es-toolkit/compat/range"
3
- import { markRawData } from "../rawData"
4
- import { selectChartLayout } from "../../context/chartLayoutContext"
5
- import {
6
- getDomainOfStackGroups,
7
- getStackedData,
8
- getValueByDataKey,
9
- isCategoricalAxis,
10
- type StackId,
11
- } from "../../util/ChartUtils"
12
- import type {
13
- AxisDomain,
14
- AxisTick,
15
- CartesianTickItem,
16
- CategoricalDomain,
17
- CategoricalDomainItem,
18
- ChartOffsetInternal,
19
- Coordinate,
20
- D3ScaleType,
21
- DataKey,
22
- LayoutType,
23
- NumberDomain,
24
- Size,
25
- StackOffsetType,
26
- TickItem,
27
- } from "../../util/types"
28
- import type {
29
- AxisId,
30
- BaseCartesianAxis,
31
- CartesianAxisSettings,
32
- XAxisOrientation,
33
- XAxisSettings,
34
- YAxisOrientation,
35
- YAxisSettings,
36
- ZAxisSettings,
37
- } from "../cartesianAxisSlice"
38
- import type { ChartState } from "../store"
39
- import {
40
- selectChartDataWithIndexes,
41
- selectChartDataWithIndexesIfNotInPanoramaPosition4,
42
- selectChartDataSliceIfNotInPanorama,
43
- } from "./dataSelectors"
44
- import {
45
- isWellFormedNumberDomain,
46
- numericalDomainSpecifiedWithoutRequiringData,
47
- parseNumericalUserDomain,
48
- } from "../../util/isDomainSpecifiedByUser"
49
- import type { AppliedChartData, ChartData, ChartDataState } from "../chartDataSlice"
50
- import {
51
- getPercentValue,
52
- hasDuplicate,
53
- isNan,
54
- isNotNil,
55
- isNumOrStr,
56
- mathSign,
57
- } from "../../util/DataUtils"
58
- import type {
59
- BaseCartesianGraphicalItemSettings,
60
- BasePolarGraphicalItemSettings,
61
- CartesianGraphicalItemSettings,
62
- GraphicalItemSettings,
63
- } from "../graphicalItemsSlice"
64
- import { readChartState } from "../chartState"
65
- import { isWellBehavedNumber } from "../../util/isWellBehavedNumber"
66
- import { getNiceTickValues, getTickValuesFixedDomain } from "../../util/scale"
67
- import type {
68
- ReferenceAreaSettings,
69
- ReferenceDotSettings,
70
- ReferenceElementSettings,
71
- ReferenceLineSettings,
72
- } from "../referenceElementsSlice"
73
- import { selectChartHeight, selectChartWidth } from "./containerSelectors"
74
- import { selectAllXAxes, selectAllYAxes } from "./selectAllAxes"
75
- import { selectChartOffsetInternal } from "./selectChartOffsetInternal"
76
- import type { AxisPropsForCartesianGridTicksGeneration } from "../../cartesian/CartesianGrid"
77
- import { selectBrushDimensions, selectBrushSettings } from "./brushSelectors"
78
- import {
79
- selectBarCategoryGap,
80
- selectChartName,
81
- selectReverseStackOrder,
82
- selectStackOffsetType,
83
- } from "./rootPropsSelectors"
84
- import {
85
- selectAngleAxis,
86
- selectAngleAxisRange,
87
- selectRadiusAxis,
88
- selectRadiusAxisRange,
89
- } from "./polarAxisSelectors"
90
- import type { AngleAxisSettings, RadiusAxisSettings } from "../polarAxisSlice"
91
- import { combineAxisRangeWithReverse } from "./combiners/combineAxisRangeWithReverse"
92
- import { DEFAULT_X_AXIS_HEIGHT, DEFAULT_Y_AXIS_WIDTH } from "../../util/Constants"
93
- import { getStackSeriesIdentifier } from "../../util/stacks/getStackSeriesIdentifier"
94
- import type { AllStackGroups, StackGroup } from "../../util/stacks/stackTypes"
95
- import {
96
- combineDisplayedStackedData,
97
- type DisplayedStackedData,
98
- } from "./combiners/combineDisplayedStackedData"
99
- import { type DefinitelyStackedGraphicalItem, isStacked } from "../types/StackedGraphicalItem"
100
- import type { ErrorBarsSettings, ErrorBarsState } from "../errorBarSlice"
101
- import type { AllAxisTypes, RenderableAxisType } from "./selectTooltipAxisType"
102
- import { selectTooltipAxisType } from "./selectTooltipAxisType"
103
- import { selectTooltipAxisId } from "./selectTooltipAxisId"
104
- import { type RechartsScale, rechartsScaleFactory } from "../../util/scale/RechartsScale"
105
- import { combineCheckedDomain } from "./combiners/combineCheckedDomain"
106
- import type { CustomScaleDefinition } from "../../util/scale/CustomScaleDefinition"
107
- import { combineConfiguredScale } from "./combiners/combineConfiguredScale"
108
- import { combineRealScaleType } from "./combiners/combineRealScaleType"
109
- import type { InverseScaleFunction } from "../../hooks"
110
- import { createCategoricalInverse } from "../../util/scale/createCategoricalInverse"
111
- import { chartSelector } from "./chartSelector"
112
- import { combineInverseScaleFunction } from "./combiners/combineInverseScaleFunction"
113
-
114
- export const defaultNumericDomain: AxisDomain = [0, "auto"]
115
-
116
- export type RenderableAxisSettings =
117
- | XAxisSettings
118
- | YAxisSettings
119
- | AngleAxisSettings
120
- | RadiusAxisSettings
121
-
122
- export type AllAxisSettings =
123
- | XAxisSettings
124
- | YAxisSettings
125
- | ZAxisSettings
126
- | AngleAxisSettings
127
- | RadiusAxisSettings
128
-
129
- /**
130
- * If an axis is not explicitly defined as an element,
131
- * we still need to render something in the chart and we need
132
- * some object to hold the domain and default settings.
133
- */
134
- export const implicitXAxis: XAxisSettings = {
135
- allowDataOverflow: false,
136
- allowDecimals: true,
137
- allowDuplicatedCategory: true,
138
- angle: 0,
139
- dataKey: undefined,
140
- domain: undefined,
141
- height: 30,
142
- hide: true,
143
- id: 0,
144
- includeHidden: false,
145
- interval: "preserveEnd",
146
- minTickGap: 5,
147
- mirror: false,
148
- name: undefined,
149
- niceTicks: "auto",
150
- orientation: "bottom",
151
- /* Shared default: served raw so it never ties a chart store to this module (see markRawData). */
152
- padding: markRawData({ left: 0, right: 0 }),
153
- reversed: false,
154
- scale: "auto",
155
- tick: true,
156
- tickCount: 5,
157
- tickFormatter: undefined,
158
- ticks: undefined,
159
- type: "category",
160
- unit: undefined,
161
- }
162
-
163
- export const selectXAxisSettingsNoDefaults = chartSelector((
164
- state: ChartState,
165
- axisId: AxisId,
166
- override?: XAxisSettings,
167
- ): XAxisSettings | undefined => {
168
- if (override !== undefined) return override
169
- return readChartState(state).cartesianAxes.xAxis?.[String(axisId)]?.settings
170
- })
171
-
172
- export const selectXAxisSettings = chartSelector((
173
- state: ChartState,
174
- axisId: AxisId,
175
- override?: XAxisSettings,
176
- ): XAxisSettings => {
177
- const axis = selectXAxisSettingsNoDefaults(state, axisId, override)
178
- if (axis == null) {
179
- return implicitXAxis
180
- }
181
- return axis
182
- })
183
-
184
- /**
185
- * If an axis is not explicitly defined as an element,
186
- * we still need to render something in the chart and we need
187
- * some object to hold the domain and default settings.
188
- */
189
- export const implicitYAxis: YAxisSettings = {
190
- allowDataOverflow: false,
191
- allowDecimals: true,
192
- allowDuplicatedCategory: true,
193
- angle: 0,
194
- dataKey: undefined,
195
- domain: defaultNumericDomain,
196
- hide: true,
197
- id: 0,
198
- includeHidden: false,
199
- interval: "preserveEnd",
200
- minTickGap: 5,
201
- mirror: false,
202
- name: undefined,
203
- niceTicks: "auto",
204
- orientation: "left",
205
- /* Shared default: served raw so it never ties a chart store to this module (see markRawData). */
206
- padding: markRawData({ bottom: 0, top: 0 }),
207
- reversed: false,
208
- scale: "auto",
209
- tick: true,
210
- tickCount: 5,
211
- tickFormatter: undefined,
212
- ticks: undefined,
213
- type: "number",
214
- unit: undefined,
215
- width: DEFAULT_Y_AXIS_WIDTH,
216
- }
217
-
218
- export const selectYAxisSettingsNoDefaults = chartSelector((
219
- state: ChartState,
220
- axisId: AxisId,
221
- override?: YAxisSettings,
222
- ): YAxisSettings | undefined => {
223
- if (override !== undefined) return override
224
- return readChartState(state).cartesianAxes.yAxis?.[String(axisId)]?.settings
225
- })
226
-
227
- export const selectYAxisSettings = chartSelector((
228
- state: ChartState,
229
- axisId: AxisId,
230
- override?: YAxisSettings,
231
- ): YAxisSettings => {
232
- const axis = selectYAxisSettingsNoDefaults(state, axisId, override)
233
- if (axis == null) {
234
- return implicitYAxis
235
- }
236
- return axis
237
- })
238
-
239
- export const implicitZAxis: ZAxisSettings = {
240
- allowDataOverflow: false,
241
- allowDuplicatedCategory: false,
242
- dataKey: undefined,
243
- domain: [0, "auto"],
244
- id: 0,
245
- includeHidden: false,
246
- name: "",
247
- range: [64, 64],
248
- reversed: false,
249
- scale: "auto",
250
- type: "number",
251
- unit: "",
252
- }
253
-
254
- export const selectZAxisSettings = chartSelector((
255
- state: ChartState,
256
- axisId: AxisId,
257
- override?: ZAxisSettings,
258
- ): ZAxisSettings => {
259
- if (override !== undefined) return override
260
- const solidEntry = readChartState(state).cartesianAxes.zAxis?.[String(axisId)]?.settings
261
- if (solidEntry != null) return solidEntry
262
- return implicitZAxis
263
- })
264
-
265
- export const selectBaseAxis = chartSelector((
266
- state: ChartState,
267
- axisType: AllAxisTypes,
268
- axisId: AxisId,
269
- ): AllAxisSettings => {
270
- switch (axisType) {
271
- case "xAxis": {
272
- return selectXAxisSettings(state, axisId)
273
- }
274
- case "yAxis": {
275
- return selectYAxisSettings(state, axisId)
276
- }
277
- case "zAxis": {
278
- return selectZAxisSettings(state, axisId)
279
- }
280
- case "angleAxis": {
281
- return selectAngleAxis(state, axisId)
282
- }
283
- case "radiusAxis": {
284
- return selectRadiusAxis(state, axisId)
285
- }
286
- default:
287
- throw new Error(`Unexpected axis type: ${axisType}`)
288
- }
289
- })
290
-
291
- const selectCartesianAxisSettings = chartSelector((
292
- state: ChartState,
293
- axisType: "xAxis" | "yAxis",
294
- axisId: AxisId,
295
- ): XAxisSettings | YAxisSettings => {
296
- switch (axisType) {
297
- case "xAxis": {
298
- return selectXAxisSettings(state, axisId)
299
- }
300
- case "yAxis": {
301
- return selectYAxisSettings(state, axisId)
302
- }
303
- default:
304
- throw new Error(`Unexpected axis type: ${axisType}`)
305
- }
306
- })
307
-
308
- /**
309
- * Selects either an X or Y axis. Doesn't work with Z axis - for that, instead use selectBaseAxis.
310
- * @param state Root state
311
- * @param axisType xAxis | yAxis
312
- * @param axisId xAxisId | yAxisId
313
- * @returns axis settings object
314
- */
315
- export const selectRenderableAxisSettings = chartSelector((
316
- state: ChartState,
317
- axisType: RenderableAxisType,
318
- axisId: AxisId,
319
- ): RenderableAxisSettings => {
320
- switch (axisType) {
321
- case "xAxis": {
322
- return selectXAxisSettings(state, axisId)
323
- }
324
- case "yAxis": {
325
- return selectYAxisSettings(state, axisId)
326
- }
327
- case "angleAxis": {
328
- return selectAngleAxis(state, axisId)
329
- }
330
- case "radiusAxis": {
331
- return selectRadiusAxis(state, axisId)
332
- }
333
- default:
334
- throw new Error(`Unexpected axis type: ${axisType}`)
335
- }
336
- })
337
-
338
- /**
339
- * @param state ChartState
340
- * @return boolean true if there is at least one Bar or RadialBar
341
- */
342
- export const selectHasBar = chartSelector((state: ChartState): boolean => {
343
- return Object.values(readChartState(state).graphicalItems).some(
344
- (item) =>
345
- item != null &&
346
- typeof item === "object" &&
347
- "type" in item &&
348
- (item.type === "bar" || item.type === "radialBar"),
349
- )
350
- })
351
-
352
- /**
353
- * Filters CartesianGraphicalItemSettings by the relevant axis ID
354
- * @param axisType 'xAxis' | 'yAxis' | 'zAxis' | 'radiusAxis' | 'angleAxis'
355
- * @param axisId from props, defaults to 0
356
- *
357
- * @returns Predicate function that return true for CartesianGraphicalItemSettings that are relevant to the specified axis
358
- */
359
- export function itemAxisPredicate(axisType: AllAxisTypes, axisId: AxisId) {
360
- return (item: BaseCartesianGraphicalItemSettings | BasePolarGraphicalItemSettings) => {
361
- switch (axisType) {
362
- case "xAxis":
363
- return "xAxisId" in item && item.xAxisId === axisId
364
- case "yAxis":
365
- return "yAxisId" in item && item.yAxisId === axisId
366
- case "zAxis":
367
- return "zAxisId" in item && item.zAxisId === axisId
368
- case "angleAxis":
369
- return "angleAxisId" in item && item.angleAxisId === axisId
370
- case "radiusAxis":
371
- return "radiusAxisId" in item && item.radiusAxisId === axisId
372
- default:
373
- return false
374
- }
375
- }
376
- }
377
-
378
- export const selectUnfilteredCartesianItems = chartSelector((
379
- state: ChartState,
380
- ): ReadonlyArray<CartesianGraphicalItemSettings> => {
381
- const graphicalItems = readChartState(state).graphicalItems
382
- const result: CartesianGraphicalItemSettings[] = []
383
- for (const id in graphicalItems) {
384
- const item = graphicalItems[id]
385
- if (
386
- item != null &&
387
- typeof item === "object" &&
388
- (item.type === "line" || item.type === "area" || item.type === "bar" || item.type === "scatter")
389
- ) {
390
- result.push(item.settings)
391
- }
392
- }
393
- return result
394
- })
395
-
396
- export const combineGraphicalItemsSettings = <T extends GraphicalItemSettings>(
397
- graphicalItems: ReadonlyArray<T>,
398
- axisSettings: BaseCartesianAxis,
399
- axisPredicate: (item: T) => boolean,
400
- ) =>
401
- graphicalItems.filter(axisPredicate).filter((item) => {
402
- if (axisSettings?.includeHidden === true) {
403
- return true
404
- }
405
- return !item.hide
406
- })
407
-
408
- export const selectCartesianItemsSettings = chartSelector(function selectCartesianItemsSettings(state: ChartState, axisType: AllAxisTypes, axisId: AxisId): ReadonlyArray<CartesianGraphicalItemSettings> {
409
- const graphicalItems = selectUnfilteredCartesianItems(state)
410
- const axisSettings = selectBaseAxis(state, axisType, axisId)
411
- const axisPredicate = itemAxisPredicate(axisType, axisId)
412
- return combineGraphicalItemsSettings(graphicalItems, axisSettings, axisPredicate)
413
- })
414
-
415
- export const selectStackedCartesianItemsSettings = chartSelector(function selectStackedCartesianItemsSettings(state: ChartState, axisType: AllAxisTypes, axisId: AxisId): ReadonlyArray<DefinitelyStackedGraphicalItem> {
416
- const cartesianItems = selectCartesianItemsSettings(state, axisType, axisId)
417
- return cartesianItems
418
- .filter((item) => item.type === "area" || item.type === "bar")
419
- .filter(isStacked)
420
- })
421
-
422
- export const filterGraphicalNotStackedItems = (
423
- cartesianItems: ReadonlyArray<GraphicalItemSettings>,
424
- ): ReadonlyArray<GraphicalItemSettings> =>
425
- cartesianItems.filter((item) => !("stackId" in item) || item.stackId === undefined)
426
-
427
- const selectCartesianItemsSettingsExceptStacked = chartSelector(function selectCartesianItemsSettingsExceptStacked(state: ChartState, axisType: AllAxisTypes, axisId: AxisId): ReadonlyArray<GraphicalItemSettings> {
428
- return filterGraphicalNotStackedItems(selectCartesianItemsSettings(state, axisType, axisId))
429
- })
430
-
431
- export const combineGraphicalItemsData = (cartesianItems: ReadonlyArray<GraphicalItemSettings>) =>
432
- cartesianItems
433
- .map((item) => item.data)
434
- .filter(Boolean)
435
- .flat(1)
436
-
437
- /**
438
- * This is a "cheap" selector - it returns the data but doesn't iterate them, so it is not sensitive on the array length.
439
- * Also does not apply dataKey yet.
440
- * @param state ChartState
441
- * @returns data defined on the chart graphical items, such as Line or Scatter or Pie, and filtered with appropriate dataKey
442
- */
443
- export const selectCartesianGraphicalItemsData = chartSelector(function selectCartesianGraphicalItemsData(state: ChartState, axisType: AllAxisTypes, axisId: AxisId): ChartData {
444
- return combineGraphicalItemsData(selectCartesianItemsSettings(state, axisType, axisId))
445
- })
446
-
447
- export const combineDisplayedData = (
448
- graphicalItemsData: ChartData,
449
- { chartData = [], dataStartIndex, dataEndIndex }: ChartDataState,
450
- ): ChartData => {
451
- if (graphicalItemsData.length > 0) {
452
- return graphicalItemsData
453
- }
454
- return chartData.slice(dataStartIndex, dataEndIndex + 1)
455
- }
456
-
457
- /**
458
- * This selector will return all data there is in the chart: graphical items, chart root, all together.
459
- * Useful for figuring out an axis domain (because that needs to know of everything),
460
- * not useful for rendering individual graphical elements (because they need to know which data is theirs and which is not).
461
- *
462
- * This function will discard the original indexes, so it is also not useful for anything that depends on ordering.
463
- */
464
- export const selectDisplayedData = chartSelector(function selectDisplayedData(state: ChartState, axisType: AllAxisTypes, axisId: AxisId, isPanorama: boolean): ChartData {
465
- return combineDisplayedData(
466
- selectCartesianGraphicalItemsData(state, axisType, axisId),
467
- selectChartDataWithIndexesIfNotInPanoramaPosition4(state, undefined, undefined, isPanorama),
468
- )
469
- })
470
-
471
- export const combineAppliedValues = (
472
- data: ChartData,
473
- axisSettings: BaseCartesianAxis,
474
- items: ReadonlyArray<GraphicalItemSettings>,
475
- ): AppliedChartData => {
476
- if (axisSettings?.dataKey != null) {
477
- return data.map((item) => ({ value: getValueByDataKey(item, axisSettings.dataKey) }))
478
- }
479
- if (items.length > 0) {
480
- return items
481
- .map((item) => item.dataKey)
482
- .flatMap((dataKey) => data.map((entry) => ({ value: getValueByDataKey(entry, dataKey) })))
483
- }
484
- return data.map((entry) => ({ value: entry }))
485
- }
486
-
487
- /**
488
- * This selector will return all values with the appropriate dataKey applied on them.
489
- * Which dataKey is appropriate depends on where it is defined.
490
- *
491
- * This is an expensive selector - it will iterate all data and compute their value using the provided dataKey.
492
- */
493
- /**
494
- * Computes applied values from graphical items data plus, when needed, chart-level data.
495
- *
496
- * When at least one graphical item has no own `data` (it relies on chart root data) AND the axis has a `dataKey`,
497
- * AND there are other items that do have their own data (meaning `displayedData` only contains graphical items data,
498
- * not chart root data), we also include chart root data values so the axis domain covers all categories,
499
- * including those only present in the chart root data but not in any graphical item's own data.
500
- *
501
- * Values from chart root data that don't match the axis dataKey (undefined) are excluded.
502
- */
503
- export const combineAllAppliedValues = (
504
- displayedData: ChartData,
505
- axisSettings: BaseCartesianAxis,
506
- items: ReadonlyArray<GraphicalItemSettings>,
507
- chartDataState: ChartDataState,
508
- anyItemUsesChartData: boolean,
509
- graphicalItemsData: ChartData,
510
- ): AppliedChartData => {
511
- const appliedValues = combineAppliedValues(displayedData, axisSettings, items)
512
- if (anyItemUsesChartData && axisSettings?.dataKey != null && graphicalItemsData.length > 0) {
513
- const { chartData = [], dataStartIndex, dataEndIndex } = chartDataState
514
- const chartDataSlice = chartData.slice(dataStartIndex, dataEndIndex + 1)
515
- const chartAppliedValues: AppliedChartData = chartDataSlice
516
- .map((item) => ({ value: getValueByDataKey(item, axisSettings.dataKey) }))
517
- .filter((av) => av.value != null)
518
- return [...chartAppliedValues, ...appliedValues]
519
- }
520
- return appliedValues
521
- }
522
-
523
- export const selectAnyCartesianItemsUsesChartData = chartSelector(function selectAnyCartesianItemsUsesChartData(state: ChartState, axisType: AllAxisTypes, axisId: AxisId): boolean {
524
- return selectCartesianItemsSettings(state, axisType, axisId).some(
525
- (item) => !(item as { data?: unknown }).data,
526
- )
527
- })
528
-
529
- export const selectAllAppliedValues = chartSelector(function selectAllAppliedValues(state: ChartState, axisType: AllAxisTypes, axisId: AxisId, isPanorama: boolean): AppliedChartData {
530
- return combineAllAppliedValues(
531
- selectDisplayedData(state, axisType, axisId, isPanorama),
532
- selectBaseAxis(state, axisType, axisId),
533
- selectCartesianItemsSettings(state, axisType, axisId),
534
- selectChartDataWithIndexesIfNotInPanoramaPosition4(state, undefined, undefined, isPanorama),
535
- selectAnyCartesianItemsUsesChartData(state, axisType, axisId),
536
- selectCartesianGraphicalItemsData(state, axisType, axisId),
537
- )
538
- })
539
-
540
- function makeNumber(val: unknown): number | undefined {
541
- if (isNumOrStr(val) || val instanceof Date) {
542
- const n = Number(val)
543
- if (isWellBehavedNumber(n)) {
544
- return n
545
- }
546
- }
547
- return undefined
548
- }
549
-
550
- function makeDomain(val: unknown): NumberDomain | undefined {
551
- if (Array.isArray(val)) {
552
- const attempt = [makeNumber(val[0]), makeNumber(val[1])]
553
- if (isWellFormedNumberDomain(attempt)) {
554
- return attempt
555
- }
556
- return undefined
557
- }
558
- const n = makeNumber(val)
559
- if (n == null) {
560
- return undefined
561
- }
562
- return [n, n]
563
- }
564
-
565
- function onlyAllowNumbers(data: ReadonlyArray<unknown>): ReadonlyArray<number> {
566
- return data.map(makeNumber).filter(isNotNil)
567
- }
568
-
569
- function sortBy(a: unknown, b: unknown): number {
570
- const aNum = makeNumber(a)
571
- const bNum = makeNumber(b)
572
- if (aNum == null && bNum == null) {
573
- return 0
574
- }
575
- if (aNum == null) {
576
- return -1
577
- }
578
- if (bNum == null) {
579
- return 1
580
- }
581
- return aNum - bNum
582
- }
583
-
584
- export const selectSortedDataPoints = chartSelector(function selectSortedDataPoints(state: ChartState, axisType: AllAxisTypes, axisId: AxisId, isPanorama: boolean): ReadonlyArray<unknown> | undefined {
585
- const appliedData = selectAllAppliedValues(state, axisType, axisId, isPanorama)
586
- return appliedData?.map((item) => item.value).sort(sortBy)
587
- })
588
-
589
- export function isErrorBarRelevantForAxisType(
590
- axisType: AllAxisTypes,
591
- errorBar: ErrorBarsSettings,
592
- ): boolean {
593
- switch (axisType) {
594
- case "xAxis":
595
- return errorBar.direction === "x"
596
- case "yAxis":
597
- return errorBar.direction === "y"
598
- default:
599
- return false
600
- }
601
- }
602
-
603
- export type AppliedChartDataWithErrorDomain = {
604
- /**
605
- * This is the value after the dataKey has been applied. Presumably a number? But no guarantees.
606
- */
607
- value: unknown
608
- /**
609
- * This is the error domain, if any, for the current value.
610
- * This may be either x or y direction, whatever is applicable.
611
- * Assumption is that we're looking at this data from the point of view of a single axis,
612
- * and that axis dictates the relevant direction.
613
- */
614
- errorDomain: ReadonlyArray<number> | undefined
615
- }
616
-
617
- /**
618
- * @param entry One item in the 'data' array. Could be anything really - this is defined externally. This is the raw, before dataKey application
619
- * @param appliedValue This is the result of applying the 'main' dataKey on the `entry`.
620
- * @param relevantErrorBars Error bars that are relevant for the current axis and layout and all that.
621
- * @return either undefined or an array of ErrorValue
622
- */
623
- export function getErrorDomainByDataKey(
624
- entry: unknown,
625
- appliedValue: unknown,
626
- relevantErrorBars: ReadonlyArray<ErrorBarsSettings> | undefined,
627
- ): ReadonlyArray<number> {
628
- if (!relevantErrorBars) {
629
- return []
630
- }
631
-
632
- if (!relevantErrorBars.length) {
633
- return []
634
- }
635
-
636
- /* Ranged values (e.g. a [low, high] bar) anchor the error bar at their upper end. */
637
- let appliedNumericValue: number | undefined
638
- if (typeof appliedValue === "number" && !isNan(appliedValue)) {
639
- appliedNumericValue = appliedValue
640
- } else if (Array.isArray(appliedValue)) {
641
- const numericRangeValues = onlyAllowNumbers(appliedValue)
642
- if (numericRangeValues.length > 0) {
643
- appliedNumericValue = Math.max(...numericRangeValues)
644
- }
645
- }
646
-
647
- if (appliedNumericValue == null) {
648
- return []
649
- }
650
- const anchor = appliedNumericValue
651
-
652
- return onlyAllowNumbers(
653
- relevantErrorBars.flatMap((eb) => {
654
- const errorValue = getValueByDataKey(entry, eb.dataKey)
655
- let lowBound: unknown
656
- let highBound: unknown
657
-
658
- if (Array.isArray(errorValue)) {
659
- ;[lowBound, highBound] = errorValue
660
- } else {
661
- lowBound = errorValue
662
- highBound = errorValue
663
- }
664
- if (!isWellBehavedNumber(lowBound) || !isWellBehavedNumber(highBound)) {
665
- return undefined
666
- }
667
- return [anchor - lowBound, anchor + highBound]
668
- }),
669
- )
670
- }
671
-
672
- export const selectTooltipAxis = chartSelector((state: ChartState): RenderableAxisSettings => {
673
- const axisType = selectTooltipAxisType(state)
674
- const axisId = selectTooltipAxisId(state)
675
- return selectRenderableAxisSettings(state, axisType, axisId)
676
- })
677
-
678
- export const selectTooltipAxisDataKey = chartSelector(function selectTooltipAxisDataKey(state: ChartState): DataKey<unknown> | undefined {
679
- const axis = selectTooltipAxis(state)
680
- return axis?.dataKey
681
- })
682
-
683
- export const selectDisplayedStackedData = chartSelector(function selectDisplayedStackedData(state: ChartState, axisType: AllAxisTypes, axisId: AxisId, isPanorama: boolean): DisplayedStackedData {
684
- return combineDisplayedStackedData(
685
- selectStackedCartesianItemsSettings(state, axisType, axisId),
686
- selectChartDataWithIndexesIfNotInPanoramaPosition4(state, undefined, undefined, isPanorama),
687
- selectTooltipAxis(state),
688
- )
689
- })
690
-
691
- export const combineStackGroups = (
692
- displayedData: DisplayedStackedData,
693
- items: ReadonlyArray<DefinitelyStackedGraphicalItem>,
694
- stackOffsetType: StackOffsetType,
695
- reverseStackOrder: boolean,
696
- ): AllStackGroups => {
697
- const initialItemsGroups: Record<StackId, Array<DefinitelyStackedGraphicalItem>> = {}
698
- const itemsGroup: Record<StackId, ReadonlyArray<DefinitelyStackedGraphicalItem>> = items.reduce(
699
- (
700
- acc: Record<StackId, Array<DefinitelyStackedGraphicalItem>>,
701
- item: DefinitelyStackedGraphicalItem,
702
- ) => {
703
- if (item.stackId == null) {
704
- return acc
705
- }
706
- let stack = acc[item.stackId]
707
- if (stack == null) {
708
- stack = []
709
- }
710
- stack.push(item)
711
- acc[item.stackId] = stack
712
- return acc
713
- },
714
- initialItemsGroups,
715
- )
716
-
717
- return Object.fromEntries(
718
- Object.entries(itemsGroup).map(([stackId, graphicalItems]): [StackId, StackGroup] => {
719
- const orderedGraphicalItems = reverseStackOrder
720
- ? [...graphicalItems].reverse()
721
- : graphicalItems
722
- const dataKeys = orderedGraphicalItems
723
- .map((item) => getStackSeriesIdentifier(item))
724
- .filter((k): k is string => k != null)
725
- return [
726
- stackId,
727
- {
728
- graphicalItems: orderedGraphicalItems,
729
- stackedData: getStackedData(
730
- displayedData as unknown as Array<Record<string, unknown>>,
731
- dataKeys,
732
- stackOffsetType,
733
- ),
734
- },
735
- ]
736
- }),
737
- )
738
- }
739
-
740
- /**
741
- * Stack groups are groups of graphical items that stack on each other.
742
- * Stack is a function of axis type (X, Y), axis ID, and stack ID.
743
- * Graphical items that do not have a stack ID are not going to be present in stack groups.
744
- */
745
- export const selectStackGroups = chartSelector(function selectStackGroups(state: ChartState, axisType: AllAxisTypes, axisId: AxisId, isPanorama: boolean): AllStackGroups | undefined {
746
- return combineStackGroups(
747
- selectDisplayedStackedData(state, axisType, axisId, isPanorama),
748
- selectStackedCartesianItemsSettings(state, axisType, axisId),
749
- selectStackOffsetType(state),
750
- selectReverseStackOrder(state),
751
- )
752
- })
753
-
754
- export const combineDomainOfStackGroups = (
755
- stackGroups: AllStackGroups | undefined,
756
- { dataStartIndex, dataEndIndex }: ChartDataState,
757
- axisType: AllAxisTypes,
758
- domainFromUserPreference: NumberDomain | undefined,
759
- ): NumberDomain | undefined => {
760
- if (domainFromUserPreference != null) {
761
- return undefined
762
- }
763
- if (axisType === "zAxis") {
764
- return undefined
765
- }
766
- return getDomainOfStackGroups(stackGroups, dataStartIndex, dataEndIndex)
767
- }
768
-
769
- function selectAllowsDataOverflow(
770
- state: ChartState,
771
- axisType: AllAxisTypes,
772
- axisId: AxisId,
773
- ): boolean {
774
- return selectBaseAxis(state, axisType, axisId).allowDataOverflow
775
- }
776
-
777
- export const getDomainDefinition = (axisSettings: AllAxisSettings): AxisDomain => {
778
- if (axisSettings == null || !("domain" in axisSettings)) {
779
- return defaultNumericDomain
780
- }
781
-
782
- if (axisSettings.domain != null) {
783
- return axisSettings.domain
784
- }
785
- if ("ticks" in axisSettings && axisSettings.ticks != null) {
786
- if (axisSettings.type === "number") {
787
- const allValues = onlyAllowNumbers(axisSettings.ticks)
788
- return [Math.min(...allValues), Math.max(...allValues)]
789
- }
790
- if (axisSettings.type === "category") {
791
- return axisSettings.ticks.map(String)
792
- }
793
- }
794
- return axisSettings?.domain ?? defaultNumericDomain
795
- }
796
-
797
- export const selectDomainDefinition = chartSelector(function selectDomainDefinition(state: ChartState, axisType: AllAxisTypes, axisId: AxisId): AxisDomain {
798
- return getDomainDefinition(selectBaseAxis(state, axisType, axisId))
799
- })
800
-
801
- /**
802
- * Under certain circumstances, we can determine the domain without looking at the data at all.
803
- * This is the case when the domain is explicitly specified as numbers, or when it is specified
804
- * as 'auto' or 'dataMin'/'dataMax' and data overflow is not allowed.
805
- *
806
- * In that case, this function will return the domain, otherwise it returns undefined.
807
- *
808
- * This is an optimization to avoid unnecessary data processing.
809
- */
810
- export const selectDomainFromUserPreference = chartSelector(function selectDomainFromUserPreference(state: ChartState, axisType: AllAxisTypes, axisId: AxisId): NumberDomain | undefined {
811
- return numericalDomainSpecifiedWithoutRequiringData(
812
- selectDomainDefinition(state, axisType, axisId),
813
- selectAllowsDataOverflow(state, axisType, axisId),
814
- )
815
- })
816
-
817
- export const selectDomainOfStackGroups = chartSelector(function selectDomainOfStackGroups(state: ChartState, axisType: AllAxisTypes, axisId: AxisId, isPanorama: boolean): NumberDomain | undefined {
818
- return combineDomainOfStackGroups(
819
- selectStackGroups(state, axisType, axisId, isPanorama),
820
- selectChartDataWithIndexes(state),
821
- axisType,
822
- selectDomainFromUserPreference(state, axisType, axisId),
823
- )
824
- })
825
-
826
- export const selectAllErrorBarSettings = (state: ChartState): ErrorBarsState =>
827
- state.errorBars
828
-
829
- const combineRelevantErrorBarSettings = (
830
- cartesianItemsSettings: ReadonlyArray<CartesianGraphicalItemSettings>,
831
- allErrorBarSettings: ErrorBarsState,
832
- axisType: RenderableAxisType,
833
- ): ReadonlyArray<ErrorBarsSettings> => {
834
- return cartesianItemsSettings
835
- .flatMap((item) => {
836
- return allErrorBarSettings[item.id]
837
- })
838
- .filter((e): e is ErrorBarsSettings => e != null)
839
- .filter((e) => {
840
- return isErrorBarRelevantForAxisType(axisType, e)
841
- })
842
- }
843
-
844
- export const mergeDomains = (
845
- ...domains: ReadonlyArray<ReadonlyArray<number> | undefined>
846
- ): NumberDomain | undefined => {
847
- const allDomains = domains.filter((d): d is ReadonlyArray<number> => d != null)
848
- if (allDomains.length === 0) {
849
- return undefined
850
- }
851
- const allValues = allDomains.flat()
852
- const min = Math.min(...allValues)
853
- const max = Math.max(...allValues)
854
- return [min, max]
855
- }
856
-
857
- export const combineDomainOfAllAppliedNumericalValuesIncludingErrorValues = (
858
- displayedData: ChartData,
859
- axisSettings: BaseCartesianAxis,
860
- items: ReadonlyArray<GraphicalItemSettings>,
861
- errorBars: ErrorBarsState,
862
- axisType: AllAxisTypes,
863
- chartDataSlice: ChartData = [],
864
- ): NumberDomain | undefined => {
865
- let lowerEnd: number | undefined
866
- let upperEnd: number | undefined
867
- if (items.length > 0) {
868
- /*
869
- * Iterate item-first so each item can use its own `data` prop when present,
870
- * falling back to the chart-level data slice for items that rely on it.
871
- * This ensures that mixing items with and without own data (e.g. Bar reading
872
- * chart-level data alongside a Scatter with its own outlier data) produces a
873
- * domain that covers all values from all sources.
874
- */
875
- items.forEach((item) => {
876
- const ownData = (item as { data?: ChartData }).data
877
- const itemData: ChartData = ownData != null ? [...ownData] : chartDataSlice
878
- const relevantErrorBars = errorBars[item.id]?.filter((errorBar) =>
879
- isErrorBarRelevantForAxisType(axisType, errorBar),
880
- )
881
- itemData.forEach((entry) => {
882
- const valueByDataKey = getValueByDataKey(entry, axisSettings.dataKey ?? item.dataKey)
883
- const errorDomain = getErrorDomainByDataKey(entry, valueByDataKey, relevantErrorBars)
884
- if (errorDomain.length >= 2) {
885
- const localLower = Math.min(...errorDomain)
886
- const localUpper = Math.max(...errorDomain)
887
- if (lowerEnd == null || localLower < lowerEnd) {
888
- lowerEnd = localLower
889
- }
890
- if (upperEnd == null || localUpper > upperEnd) {
891
- upperEnd = localUpper
892
- }
893
- }
894
- const dataValueDomain: NumberDomain | undefined = makeDomain(valueByDataKey)
895
- if (dataValueDomain != null) {
896
- lowerEnd = lowerEnd == null ? dataValueDomain[0] : Math.min(lowerEnd, dataValueDomain[0])
897
- upperEnd = upperEnd == null ? dataValueDomain[1] : Math.max(upperEnd, dataValueDomain[1])
898
- }
899
- })
900
- })
901
- }
902
- if (axisSettings?.dataKey != null && items.length === 0) {
903
- // When there are no items, fall back to the displayed data (chart-level or graphical item data).
904
- displayedData.forEach((item) => {
905
- const dataValueDomain: NumberDomain | undefined = makeDomain(
906
- getValueByDataKey(item, axisSettings.dataKey),
907
- )
908
- if (dataValueDomain != null) {
909
- lowerEnd = lowerEnd == null ? dataValueDomain[0] : Math.min(lowerEnd, dataValueDomain[0])
910
- upperEnd = upperEnd == null ? dataValueDomain[1] : Math.max(upperEnd, dataValueDomain[1])
911
- }
912
- })
913
- }
914
-
915
- if (isWellBehavedNumber(lowerEnd) && isWellBehavedNumber(upperEnd)) {
916
- return [lowerEnd, upperEnd]
917
- }
918
- return undefined
919
- }
920
-
921
- const selectDomainOfAllAppliedNumericalValuesIncludingErrorValues = chartSelector(function selectDomainOfAllAppliedNumericalValuesIncludingErrorValues(state: ChartState, axisType: AllAxisTypes, axisId: AxisId, isPanorama: boolean): NumberDomain | undefined {
922
- return combineDomainOfAllAppliedNumericalValuesIncludingErrorValues(
923
- selectDisplayedData(state, axisType, axisId, isPanorama),
924
- selectBaseAxis(state, axisType, axisId),
925
- selectCartesianItemsSettingsExceptStacked(state, axisType, axisId),
926
- selectAllErrorBarSettings(state),
927
- axisType,
928
- selectChartDataSliceIfNotInPanorama(state, undefined, undefined, isPanorama),
929
- )
930
- })
931
-
932
- function onlyAllowNumbersAndStringsAndDates(item: {
933
- value: unknown
934
- }): string | number | Date | undefined {
935
- const { value } = item
936
- if (isNumOrStr(value) || value instanceof Date) {
937
- return value
938
- }
939
- return undefined
940
- }
941
-
942
- const computeDomainOfTypeCategory = (
943
- allDataSquished: AppliedChartData,
944
- axisSettings: BaseCartesianAxis,
945
- isCategorical: boolean,
946
- ): CategoricalDomain => {
947
- const categoricalDomain = allDataSquished
948
- .map(onlyAllowNumbersAndStringsAndDates)
949
- .filter((v) => v != null)
950
- if (
951
- isCategorical &&
952
- (axisSettings.dataKey == null ||
953
- (axisSettings.allowDuplicatedCategory && hasDuplicate(categoricalDomain)))
954
- ) {
955
- return range(0, allDataSquished.length)
956
- }
957
- if (axisSettings.allowDuplicatedCategory) {
958
- return categoricalDomain
959
- }
960
- return Array.from(new Set(categoricalDomain))
961
- }
962
-
963
- export const selectReferenceDots = (
964
- state: ChartState,
965
- ): ReadonlyArray<ReferenceDotSettings> => state.referenceElements.dots
966
-
967
- export const filterReferenceElements = <T extends ReferenceElementSettings>(
968
- elements: ReadonlyArray<T>,
969
- axisType: AllAxisTypes,
970
- axisId: AxisId,
971
- ): ReadonlyArray<T> => {
972
- return elements
973
- .filter((el) => el.ifOverflow === "extendDomain")
974
- .filter((el) => {
975
- if (axisType === "xAxis") {
976
- return el.xAxisId === axisId
977
- }
978
- return el.yAxisId === axisId
979
- })
980
- }
981
-
982
- export const selectReferenceDotsByAxis = chartSelector(function selectReferenceDotsByAxis(state: ChartState, axisType: AllAxisTypes, axisId: AxisId): ReadonlyArray<ReferenceDotSettings> {
983
- return filterReferenceElements(selectReferenceDots(state), axisType, axisId)
984
- })
985
-
986
- export const selectReferenceAreas = (
987
- state: ChartState,
988
- ): ReadonlyArray<ReferenceAreaSettings> => state.referenceElements.areas
989
-
990
- export const selectReferenceAreasByAxis = chartSelector(function selectReferenceAreasByAxis(state: ChartState, axisType: AllAxisTypes, axisId: AxisId): ReadonlyArray<ReferenceAreaSettings> {
991
- return filterReferenceElements(selectReferenceAreas(state), axisType, axisId)
992
- })
993
-
994
- export const selectReferenceLines = (
995
- state: ChartState,
996
- ): ReadonlyArray<ReferenceLineSettings> => state.referenceElements.lines
997
-
998
- export const selectReferenceLinesByAxis = chartSelector(function selectReferenceLinesByAxis(state: ChartState, axisType: AllAxisTypes, axisId: AxisId): ReadonlyArray<ReferenceLineSettings> {
999
- return filterReferenceElements(selectReferenceLines(state), axisType, axisId)
1000
- })
1001
-
1002
- export const combineDotsDomain = (
1003
- dots: ReadonlyArray<ReferenceDotSettings> | undefined,
1004
- axisType: RenderableAxisType,
1005
- ): NumberDomain | undefined => {
1006
- if (dots == null) {
1007
- return undefined
1008
- }
1009
- const allCoords = onlyAllowNumbers(dots.map((dot) => (axisType === "xAxis" ? dot.x : dot.y)))
1010
- if (allCoords.length === 0) {
1011
- return undefined
1012
- }
1013
- return [Math.min(...allCoords), Math.max(...allCoords)]
1014
- }
1015
-
1016
- const selectReferenceDotsDomain = chartSelector(function selectReferenceDotsDomain(state: ChartState, axisType: AllAxisTypes, axisId: AxisId): NumberDomain | undefined {
1017
- return combineDotsDomain(
1018
- selectReferenceDotsByAxis(state, axisType, axisId),
1019
- axisType as RenderableAxisType,
1020
- )
1021
- })
1022
-
1023
- export const combineAreasDomain = (
1024
- areas: ReadonlyArray<ReferenceAreaSettings> | undefined,
1025
- axisType: RenderableAxisType,
1026
- ): NumberDomain | undefined => {
1027
- if (areas == null) {
1028
- return undefined
1029
- }
1030
- const allCoords = onlyAllowNumbers(
1031
- areas.flatMap((area) => [
1032
- axisType === "xAxis" ? area.x1 : area.y1,
1033
- axisType === "xAxis" ? area.x2 : area.y2,
1034
- ]),
1035
- )
1036
- if (allCoords.length === 0) {
1037
- return undefined
1038
- }
1039
- return [Math.min(...allCoords), Math.max(...allCoords)]
1040
- }
1041
-
1042
- const selectReferenceAreasDomain = chartSelector(function selectReferenceAreasDomain(state: ChartState, axisType: AllAxisTypes, axisId: AxisId): NumberDomain | undefined {
1043
- return combineAreasDomain(
1044
- selectReferenceAreasByAxis(state, axisType, axisId),
1045
- axisType as RenderableAxisType,
1046
- )
1047
- })
1048
-
1049
- function extractXCoordinates(line: ReferenceLineSettings): ReadonlyArray<number> {
1050
- if (line.x != null) {
1051
- return onlyAllowNumbers([line.x])
1052
- }
1053
- const segmentCoordinates: ReadonlyArray<string | number | undefined> | undefined =
1054
- line.segment?.map((s) => s.x)
1055
- if (segmentCoordinates == null || segmentCoordinates.length === 0) {
1056
- return []
1057
- }
1058
- return onlyAllowNumbers(segmentCoordinates)
1059
- }
1060
-
1061
- function extractYCoordinates(line: ReferenceLineSettings): ReadonlyArray<number> {
1062
- if (line.y != null) {
1063
- return onlyAllowNumbers([line.y])
1064
- }
1065
- const segmentCoordinates: ReadonlyArray<string | number | undefined> | undefined =
1066
- line.segment?.map((s) => s.y)
1067
- if (segmentCoordinates == null || segmentCoordinates.length === 0) {
1068
- return []
1069
- }
1070
- return onlyAllowNumbers(segmentCoordinates)
1071
- }
1072
-
1073
- export const combineLinesDomain = (
1074
- lines: ReadonlyArray<ReferenceLineSettings> | undefined,
1075
- axisType: RenderableAxisType,
1076
- ): NumberDomain | undefined => {
1077
- if (lines == null) {
1078
- return undefined
1079
- }
1080
- const allCoords: ReadonlyArray<number> = lines.flatMap((line) =>
1081
- axisType === "xAxis" ? extractXCoordinates(line) : extractYCoordinates(line),
1082
- )
1083
- if (allCoords.length === 0) {
1084
- return undefined
1085
- }
1086
- return [Math.min(...allCoords), Math.max(...allCoords)]
1087
- }
1088
-
1089
- const selectReferenceLinesDomain = chartSelector(function selectReferenceLinesDomain(state: ChartState, axisType: AllAxisTypes, axisId: AxisId): NumberDomain | undefined {
1090
- return combineLinesDomain(
1091
- selectReferenceLinesByAxis(state, axisType, axisId),
1092
- axisType as RenderableAxisType,
1093
- )
1094
- })
1095
-
1096
- const selectReferenceElementsDomain = chartSelector(function selectReferenceElementsDomain(state: ChartState, axisType: AllAxisTypes, axisId: AxisId): NumberDomain | undefined {
1097
- const dotsDomain = selectReferenceDotsDomain(state, axisType, axisId)
1098
- const linesDomain = selectReferenceLinesDomain(state, axisType, axisId)
1099
- const areasDomain = selectReferenceAreasDomain(state, axisType, axisId)
1100
- return mergeDomains(dotsDomain, areasDomain, linesDomain)
1101
- })
1102
-
1103
- export const combineNumericalDomain = (
1104
- axisSettings: BaseCartesianAxis,
1105
- domainDefinition: AxisDomain | undefined,
1106
- domainFromUserPreference: NumberDomain | undefined,
1107
- domainOfStackGroups: NumberDomain | undefined,
1108
- dataAndErrorBarsDomain: NumberDomain | undefined,
1109
- referenceElementsDomain: NumberDomain | undefined,
1110
- layout: LayoutType,
1111
- axisType: AllAxisTypes,
1112
- numericTicksDomain?: NumberDomain | undefined,
1113
- ): NumberDomain | undefined => {
1114
- if (domainFromUserPreference != null) {
1115
- return domainFromUserPreference
1116
- }
1117
-
1118
- const shouldIncludeDomainOfStackGroups =
1119
- (layout === "vertical" && axisType === "xAxis") ||
1120
- (layout === "horizontal" && axisType === "yAxis")
1121
-
1122
- const mergedDomains = shouldIncludeDomainOfStackGroups
1123
- ? mergeDomains(domainOfStackGroups, referenceElementsDomain, dataAndErrorBarsDomain)
1124
- : mergeDomains(referenceElementsDomain, dataAndErrorBarsDomain)
1125
-
1126
- const parsedDomain = parseNumericalUserDomain(domainDefinition, mergedDomains, axisSettings.allowDataOverflow)
1127
- if (parsedDomain != null) {
1128
- return parsedDomain
1129
- }
1130
-
1131
- /*
1132
- * https://github.com/recharts/recharts/issues/7362
1133
- * The user-provided domain could not be resolved without data - it's a function
1134
- * bound or one of 'auto'/'dataMin'/'dataMax' - and there is no data domain to
1135
- * resolve it from: empty or all-null data, and no domain-extending reference
1136
- * elements. If the axis opted into data overflow and supplied an explicit numeric
1137
- * `ticks` array, fall back to the ticks' [min, max] extent so the explicit tick
1138
- * ladder still renders, mirroring what a literal numeric domain already does.
1139
- */
1140
- if (axisSettings.allowDataOverflow && mergedDomains == null && numericTicksDomain != null) {
1141
- return numericTicksDomain
1142
- }
1143
-
1144
- return parsedDomain
1145
- }
1146
-
1147
- /**
1148
- * https://github.com/recharts/recharts/issues/7362
1149
- * Derives the [min, max] extent of an axis's explicit numeric `ticks`. Used by
1150
- * {@link combineNumericalDomain} as a last-resort domain when a non-literal domain
1151
- * cannot be resolved without data. Returns undefined for non-number axes, or when
1152
- * no numeric ticks were supplied.
1153
- */
1154
- export const combineNumericTicksDomain = (
1155
- axisSettings: BaseCartesianAxis | undefined,
1156
- ): NumberDomain | undefined => {
1157
- if (axisSettings == null || axisSettings.type !== "number" || !("ticks" in axisSettings)) {
1158
- return undefined
1159
- }
1160
- const ticks = (axisSettings as { ticks?: ReadonlyArray<unknown> }).ticks
1161
- if (ticks == null) {
1162
- return undefined
1163
- }
1164
- const numericTicks = onlyAllowNumbers(ticks)
1165
- if (numericTicks.length === 0) {
1166
- return undefined
1167
- }
1168
- return [Math.min(...numericTicks), Math.max(...numericTicks)]
1169
- }
1170
-
1171
- export const selectNumericTicksDomain = chartSelector(function selectNumericTicksDomain(state: ChartState, axisType: AllAxisTypes, axisId: AxisId): NumberDomain | undefined {
1172
- return combineNumericTicksDomain(selectBaseAxis(state, axisType, axisId))
1173
- })
1174
-
1175
- export const selectNumericalDomain = chartSelector(function selectNumericalDomain(state: ChartState, axisType: AllAxisTypes, axisId: AxisId, isPanorama: boolean): NumberDomain | undefined {
1176
- return combineNumericalDomain(
1177
- selectBaseAxis(state, axisType, axisId),
1178
- selectDomainDefinition(state, axisType, axisId),
1179
- selectDomainFromUserPreference(state, axisType, axisId),
1180
- selectDomainOfStackGroups(state, axisType, axisId, isPanorama),
1181
- selectDomainOfAllAppliedNumericalValuesIncludingErrorValues(
1182
- state,
1183
- axisType,
1184
- axisId,
1185
- isPanorama,
1186
- ),
1187
- selectReferenceElementsDomain(state, axisType, axisId),
1188
- selectChartLayout(state),
1189
- axisType,
1190
- selectNumericTicksDomain(state, axisType, axisId),
1191
- )
1192
- })
1193
-
1194
- /**
1195
- * Expand by design maps everything between 0 and 1,
1196
- * there is nothing to compute.
1197
- * See https://d3js.org/d3-shape/stack#stack-offsets
1198
- */
1199
- const expandDomain: NumberDomain = [0, 1]
1200
-
1201
- export const combineAxisDomain = (
1202
- axisSettings: BaseCartesianAxis,
1203
- layout: LayoutType,
1204
- displayedData: ChartData | undefined,
1205
- allAppliedValues: AppliedChartData,
1206
- stackOffsetType: StackOffsetType,
1207
- axisType: AllAxisTypes,
1208
- numericalDomain: NumberDomain | undefined,
1209
- ): NumberDomain | CategoricalDomain | undefined => {
1210
- if (
1211
- (axisSettings == null || displayedData == null || displayedData.length === 0) &&
1212
- numericalDomain === undefined
1213
- ) {
1214
- return undefined
1215
- }
1216
- const { dataKey, type } = axisSettings
1217
- const isCategorical = isCategoricalAxis(layout, axisType)
1218
-
1219
- if (isCategorical && dataKey == null) {
1220
- return range(0, displayedData?.length ?? 0)
1221
- }
1222
-
1223
- if (type === "category") {
1224
- return computeDomainOfTypeCategory(allAppliedValues, axisSettings, isCategorical)
1225
- }
1226
-
1227
- if (stackOffsetType === "expand" && !isCategorical) {
1228
- return expandDomain
1229
- }
1230
- return numericalDomain
1231
- }
1232
-
1233
- export const selectAxisDomain = chartSelector(function selectAxisDomain(state: ChartState, axisType: AllAxisTypes, axisId: AxisId, isPanorama: boolean): NumberDomain | CategoricalDomain | undefined {
1234
- return combineAxisDomain(
1235
- selectBaseAxis(state, axisType, axisId),
1236
- selectChartLayout(state),
1237
- selectDisplayedData(state, axisType, axisId, isPanorama),
1238
- selectAllAppliedValues(state, axisType, axisId, isPanorama),
1239
- selectStackOffsetType(state),
1240
- axisType,
1241
- selectNumericalDomain(state, axisType, axisId, isPanorama),
1242
- )
1243
- })
1244
-
1245
- export const selectRealScaleType = chartSelector(function selectRealScaleType(state: ChartState, axisType: AllAxisTypes, axisId: AxisId): D3ScaleType | undefined {
1246
- return combineRealScaleType(
1247
- selectBaseAxis(state, axisType, axisId),
1248
- selectHasBar(state),
1249
- selectChartName(state),
1250
- )
1251
- })
1252
-
1253
- export const combineNiceTicks = (
1254
- axisDomain: NumberDomain | CategoricalDomain | undefined,
1255
- axisSettings: RenderableAxisSettings,
1256
- realScaleType: string | undefined,
1257
- ): ReadonlyArray<number> | undefined => {
1258
- const niceTicks = axisSettings?.niceTicks
1259
-
1260
- if (niceTicks === "none") {
1261
- return undefined
1262
- }
1263
-
1264
- const domainDefinition: AxisDomain = getDomainDefinition(axisSettings)
1265
- const hasDomainAutoKeyword =
1266
- Array.isArray(domainDefinition) && (domainDefinition[0] === "auto" || domainDefinition[1] === "auto")
1267
-
1268
- if (
1269
- (niceTicks === "snap125" || niceTicks === "adaptive") &&
1270
- axisSettings != null &&
1271
- axisSettings.tickCount &&
1272
- isWellFormedNumberDomain(axisDomain)
1273
- ) {
1274
- if (hasDomainAutoKeyword) {
1275
- return getNiceTickValues(axisDomain, axisSettings.tickCount, axisSettings.allowDecimals, niceTicks)
1276
- }
1277
- if (axisSettings.type === "number") {
1278
- return getTickValuesFixedDomain(
1279
- axisDomain as NumberDomain,
1280
- axisSettings.tickCount,
1281
- axisSettings.allowDecimals,
1282
- niceTicks,
1283
- )
1284
- }
1285
- }
1286
-
1287
- if (niceTicks === "auto" && realScaleType === "linear" && axisSettings != null && axisSettings.tickCount) {
1288
- /* Apply nice ticks when the domain contains an 'auto' keyword (may extend the domain),
1289
- or for any fixed number-type axis. Always the space-efficient (adaptive) algorithm. */
1290
- if (hasDomainAutoKeyword && isWellFormedNumberDomain(axisDomain)) {
1291
- return getNiceTickValues(axisDomain, axisSettings.tickCount, axisSettings.allowDecimals, "adaptive")
1292
- }
1293
-
1294
- if (axisSettings.type === "number" && isWellFormedNumberDomain(axisDomain)) {
1295
- return getTickValuesFixedDomain(
1296
- axisDomain as NumberDomain,
1297
- axisSettings.tickCount,
1298
- axisSettings.allowDecimals,
1299
- "adaptive",
1300
- )
1301
- }
1302
- }
1303
-
1304
- return undefined
1305
- }
1306
-
1307
- export const selectNiceTicks = chartSelector(function selectNiceTicks(state: ChartState, axisType: RenderableAxisType, axisId: AxisId, isPanorama: boolean): ReadonlyArray<number> | undefined {
1308
- return combineNiceTicks(
1309
- selectAxisDomain(state, axisType, axisId, isPanorama),
1310
- selectRenderableAxisSettings(state, axisType, axisId),
1311
- selectRealScaleType(state, axisType, axisId),
1312
- )
1313
- })
1314
-
1315
- export const combineAxisDomainWithNiceTicks = (
1316
- axisSettings: BaseCartesianAxis,
1317
- domain: NumberDomain | CategoricalDomain | undefined,
1318
- niceTicks: ReadonlyArray<number> | undefined,
1319
- axisType: RenderableAxisType,
1320
- ): NumberDomain | CategoricalDomain | undefined => {
1321
- if (
1322
- axisType !== "angleAxis" &&
1323
- axisSettings?.type === "number" &&
1324
- isWellFormedNumberDomain(domain) &&
1325
- Array.isArray(niceTicks) &&
1326
- niceTicks.length > 0
1327
- ) {
1328
- const minFromDomain = domain[0]
1329
- const minFromTicks = niceTicks[0] ?? 0
1330
- const maxFromDomain = domain[1]
1331
- const maxFromTicks = niceTicks[niceTicks.length - 1] ?? 0
1332
- return [Math.min(minFromDomain, minFromTicks), Math.max(maxFromDomain, maxFromTicks)]
1333
- }
1334
- return domain
1335
- }
1336
-
1337
- export const selectAxisDomainIncludingNiceTicks = chartSelector(function selectAxisDomainIncludingNiceTicks(state: ChartState, axisType: RenderableAxisType, axisId: AxisId, isPanorama: boolean): NumberDomain | CategoricalDomain | undefined {
1338
- return combineAxisDomainWithNiceTicks(
1339
- selectBaseAxis(state, axisType, axisId),
1340
- selectAxisDomain(state, axisType, axisId, isPanorama),
1341
- selectNiceTicks(state, axisType, axisId, isPanorama),
1342
- axisType,
1343
- )
1344
- })
1345
-
1346
- /**
1347
- * Returns the smallest gap, between two numbers in the data, as a ratio of the whole range (max - min).
1348
- * Ignores domain provided by user and only considers domain from data.
1349
- *
1350
- * The result is a number between 0 and 1.
1351
- */
1352
- export const selectSmallestDistanceBetweenValues = chartSelector(function selectSmallestDistanceBetweenValues(state: ChartState, axisType: RenderableAxisType, axisId: AxisId, isPanorama: boolean): number | undefined {
1353
- const allDataSquished = selectAllAppliedValues(state, axisType, axisId, isPanorama)
1354
- const axisSettings = selectBaseAxis(state, axisType, axisId)
1355
- if (!axisSettings || axisSettings.type !== "number") {
1356
- return undefined
1357
- }
1358
- let smallestDistanceBetweenValues = Infinity
1359
- const sortedValues = Array.from(onlyAllowNumbers(allDataSquished.map((d) => d.value))).sort(
1360
- (a, b) => a - b,
1361
- )
1362
- const first = sortedValues[0]
1363
- const last = sortedValues[sortedValues.length - 1]
1364
- if (first == null || last == null) {
1365
- return Infinity
1366
- }
1367
- const diff = last - first
1368
- if (diff === 0) {
1369
- return Infinity
1370
- }
1371
- for (let i = 0; i < sortedValues.length - 1; i++) {
1372
- const curr = sortedValues[i]
1373
- const next = sortedValues[i + 1]
1374
- if (curr == null || next == null) {
1375
- continue
1376
- }
1377
- const distance = next - curr
1378
- smallestDistanceBetweenValues = Math.min(smallestDistanceBetweenValues, distance)
1379
- }
1380
- return smallestDistanceBetweenValues / diff
1381
- })
1382
-
1383
- const selectCalculatedPadding = chartSelector(function selectCalculatedPadding(state: ChartState, axisType: RenderableAxisType, axisId: AxisId, isPanorama: boolean, padding: string): number {
1384
- const smallestDistanceInPercent = selectSmallestDistanceBetweenValues(
1385
- state,
1386
- axisType,
1387
- axisId,
1388
- isPanorama,
1389
- )
1390
- const layout = selectChartLayout(state)
1391
- const barCategoryGap = selectBarCategoryGap(state)
1392
- const offset = selectChartOffsetInternal(state)
1393
-
1394
- if (!isWellBehavedNumber(smallestDistanceInPercent)) {
1395
- return 0
1396
- }
1397
- const rangeWidth = layout === "vertical" ? offset.height : offset.width
1398
-
1399
- if (padding === "gap") {
1400
- return (smallestDistanceInPercent * rangeWidth) / 2
1401
- }
1402
-
1403
- if (padding === "no-gap") {
1404
- const gap = getPercentValue(barCategoryGap, smallestDistanceInPercent * rangeWidth)
1405
- const halfBand = (smallestDistanceInPercent * rangeWidth) / 2
1406
- return halfBand - gap - ((halfBand - gap) / rangeWidth) * gap
1407
- }
1408
-
1409
- return 0
1410
- })
1411
-
1412
- export const selectCalculatedXAxisPadding = chartSelector((
1413
- state: ChartState,
1414
- axisId: AxisId,
1415
- isPanorama: boolean,
1416
- ): number => {
1417
- const xAxisSettings = selectXAxisSettings(state, axisId)
1418
- if (xAxisSettings == null || typeof xAxisSettings.padding !== "string") {
1419
- return 0
1420
- }
1421
- return selectCalculatedPadding(state, "xAxis", axisId, isPanorama, xAxisSettings.padding)
1422
- })
1423
-
1424
- export const selectCalculatedYAxisPadding = chartSelector((
1425
- state: ChartState,
1426
- axisId: AxisId,
1427
- isPanorama: boolean,
1428
- ): number => {
1429
- const yAxisSettings = selectYAxisSettings(state, axisId)
1430
- if (yAxisSettings == null || typeof yAxisSettings.padding !== "string") {
1431
- return 0
1432
- }
1433
- return selectCalculatedPadding(state, "yAxis", axisId, isPanorama, yAxisSettings.padding)
1434
- })
1435
-
1436
- const selectXAxisPadding = chartSelector(function selectXAxisPadding(state: ChartState, axisId: AxisId, isPanorama: boolean): { left: number; right: number } {
1437
- const xAxisSettings = selectXAxisSettings(state, axisId)
1438
- const calculated = selectCalculatedXAxisPadding(state, axisId, isPanorama)
1439
- if (xAxisSettings == null) {
1440
- return { left: 0, right: 0 }
1441
- }
1442
- const { padding } = xAxisSettings
1443
- if (typeof padding === "string") {
1444
- return { left: calculated, right: calculated }
1445
- }
1446
- return {
1447
- left: (padding.left ?? 0) + calculated,
1448
- right: (padding.right ?? 0) + calculated,
1449
- }
1450
- })
1451
-
1452
- const selectYAxisPadding = chartSelector(function selectYAxisPadding(state: ChartState, axisId: AxisId, isPanorama: boolean): { top: number; bottom: number } {
1453
- const yAxisSettings = selectYAxisSettings(state, axisId)
1454
- const calculated = selectCalculatedYAxisPadding(state, axisId, isPanorama)
1455
- if (yAxisSettings == null) {
1456
- return { bottom: 0, top: 0 }
1457
- }
1458
- const { padding } = yAxisSettings
1459
- if (typeof padding === "string") {
1460
- return { bottom: calculated, top: calculated }
1461
- }
1462
- return {
1463
- bottom: (padding.bottom ?? 0) + calculated,
1464
- top: (padding.top ?? 0) + calculated,
1465
- }
1466
- })
1467
-
1468
- export type AxisRange = readonly [number, number]
1469
-
1470
- export const selectXAxisRange = chartSelector(function selectXAxisRange(state: ChartState, axisId: AxisId, isPanorama: boolean): AxisRange | undefined {
1471
- const offset = selectChartOffsetInternal(state)
1472
- const padding = selectXAxisPadding(state, axisId, isPanorama)
1473
- const brushDimensions = selectBrushDimensions(state)
1474
- const { padding: brushPadding } = selectBrushSettings(state)
1475
- if (isPanorama) {
1476
- return [brushPadding.left, brushDimensions.width - brushPadding.right]
1477
- }
1478
- return [offset.left + padding.left, offset.left + offset.width - padding.right]
1479
- })
1480
-
1481
- export const selectYAxisRange = chartSelector(function selectYAxisRange(state: ChartState, axisId: AxisId, isPanorama: boolean): AxisRange | undefined {
1482
- const offset = selectChartOffsetInternal(state)
1483
- const layout = selectChartLayout(state)
1484
- const padding = selectYAxisPadding(state, axisId, isPanorama)
1485
- const brushDimensions = selectBrushDimensions(state)
1486
- const { padding: brushPadding } = selectBrushSettings(state)
1487
- if (isPanorama) {
1488
- return [brushDimensions.height - brushPadding.bottom, brushPadding.top]
1489
- }
1490
- if (layout === "horizontal") {
1491
- return [offset.top + offset.height - padding.bottom, offset.top + padding.top]
1492
- }
1493
- return [offset.top + padding.top, offset.top + offset.height - padding.bottom]
1494
- })
1495
-
1496
- export const selectAxisRange = chartSelector((
1497
- state: ChartState,
1498
- axisType: AllAxisTypes,
1499
- axisId: AxisId,
1500
- isPanorama: boolean,
1501
- ): AxisRange | undefined => {
1502
- switch (axisType) {
1503
- case "xAxis":
1504
- return selectXAxisRange(state, axisId, isPanorama)
1505
- case "yAxis":
1506
- return selectYAxisRange(state, axisId, isPanorama)
1507
- case "zAxis":
1508
- return selectZAxisSettings(state, axisId)?.range
1509
- case "angleAxis":
1510
- return selectAngleAxisRange(state)
1511
- case "radiusAxis":
1512
- return selectRadiusAxisRange(state, axisId)
1513
- default:
1514
- return undefined
1515
- }
1516
- })
1517
-
1518
- export const selectAxisRangeWithReverse = chartSelector(function selectAxisRangeWithReverse(state: ChartState, axisType: AllAxisTypes, axisId: AxisId, isPanorama: boolean): AxisRange | undefined {
1519
- return combineAxisRangeWithReverse(
1520
- selectBaseAxis(state, axisType, axisId),
1521
- selectAxisRange(state, axisType, axisId, isPanorama),
1522
- )
1523
- })
1524
-
1525
- export const selectCheckedAxisDomain = chartSelector(function selectCheckedAxisDomain(state: ChartState, axisType: RenderableAxisType, axisId: AxisId, isPanorama: boolean): NumberDomain | CategoricalDomain | undefined {
1526
- return combineCheckedDomain(
1527
- selectRealScaleType(state, axisType, axisId),
1528
- selectAxisDomainIncludingNiceTicks(state, axisType, axisId, isPanorama),
1529
- )
1530
- })
1531
-
1532
- const selectConfiguredScale = chartSelector(function selectConfiguredScale(state: ChartState, axisType: RenderableAxisType, axisId: AxisId, isPanorama: boolean): CustomScaleDefinition | undefined {
1533
- return combineConfiguredScale(
1534
- selectBaseAxis(state, axisType, axisId),
1535
- selectRealScaleType(state, axisType, axisId),
1536
- selectCheckedAxisDomain(state, axisType, axisId, isPanorama),
1537
- selectAxisRangeWithReverse(state, axisType, axisId, isPanorama),
1538
- )
1539
- })
1540
-
1541
- export const combineCategoricalDomain = (
1542
- layout: LayoutType,
1543
- appliedValues: AppliedChartData,
1544
- axis: RenderableAxisSettings,
1545
- axisType: RenderableAxisType,
1546
- ): ReadonlyArray<unknown> | undefined => {
1547
- if (axis == null || axis.dataKey == null) {
1548
- return undefined
1549
- }
1550
- const { type, scale } = axis
1551
- const isCategorical = isCategoricalAxis(layout, axisType)
1552
- if (isCategorical && (type === "number" || scale !== "auto")) {
1553
- return appliedValues.map((d) => d.value)
1554
- }
1555
- return undefined
1556
- }
1557
-
1558
- export const selectCategoricalDomain = chartSelector(function selectCategoricalDomain(state: ChartState, axisType: RenderableAxisType, axisId: AxisId, isPanorama: boolean): ReadonlyArray<unknown> | undefined {
1559
- return combineCategoricalDomain(
1560
- selectChartLayout(state),
1561
- selectAllAppliedValues(state, axisType, axisId, isPanorama),
1562
- selectRenderableAxisSettings(state, axisType, axisId),
1563
- axisType,
1564
- )
1565
- })
1566
-
1567
- export const selectAxisScale = chartSelector(function selectAxisScale(state: ChartState, axisType: RenderableAxisType, axisId: AxisId, isPanorama: boolean): RechartsScale | undefined {
1568
- return rechartsScaleFactory(selectConfiguredScale(state, axisType, axisId, isPanorama))
1569
- })
1570
-
1571
- export const selectAxisInverseScale = chartSelector(function selectAxisInverseScale(state: ChartState, axisType: RenderableAxisType, axisId: AxisId, isPanorama: boolean): InverseScaleFunction | undefined {
1572
- return combineInverseScaleFunction(selectConfiguredScale(state, axisType, axisId, isPanorama))
1573
- })
1574
-
1575
- export const selectAxisInverseDataSnapScale = chartSelector(function selectAxisInverseDataSnapScale(state: ChartState, axisType: RenderableAxisType, axisId: AxisId, isPanorama: boolean): InverseScaleFunction | undefined {
1576
- return createCategoricalInverse(
1577
- selectConfiguredScale(state, axisType, axisId, isPanorama),
1578
- selectSortedDataPoints(state, axisType, axisId, isPanorama),
1579
- )
1580
- })
1581
-
1582
- export const selectErrorBarsSettings = chartSelector(function selectErrorBarsSettings(state: ChartState, axisType: AllAxisTypes, axisId: AxisId): ReadonlyArray<ErrorBarsSettings> {
1583
- return combineRelevantErrorBarSettings(
1584
- selectCartesianItemsSettings(state, axisType, axisId),
1585
- selectAllErrorBarSettings(state),
1586
- axisType as RenderableAxisType,
1587
- )
1588
- })
1589
-
1590
- function compareIds(a: CartesianAxisSettings, b: CartesianAxisSettings) {
1591
- if (a.id < b.id) {
1592
- return -1
1593
- }
1594
- if (a.id > b.id) {
1595
- return 1
1596
- }
1597
- return 0
1598
- }
1599
-
1600
- const selectAllXAxesWithOffsetType = chartSelector(function selectAllXAxesWithOffsetType(state: ChartState, orientation: XAxisOrientation, mirror: boolean): ReadonlyArray<XAxisSettings> {
1601
- return selectAllXAxes(state)
1602
- .filter((axis) => axis.orientation === orientation)
1603
- .filter((axis) => axis.mirror === mirror)
1604
- .sort(compareIds)
1605
- })
1606
-
1607
- const selectAllYAxesWithOffsetType = chartSelector(function selectAllYAxesWithOffsetType(state: ChartState, orientation: YAxisOrientation, mirror: boolean): ReadonlyArray<YAxisSettings> {
1608
- return selectAllYAxes(state)
1609
- .filter((axis) => axis.orientation === orientation)
1610
- .filter((axis) => axis.mirror === mirror)
1611
- .sort(compareIds)
1612
- })
1613
-
1614
- const getXAxisSize = (offset: ChartOffsetInternal, axisSettings: XAxisSettings): Size => {
1615
- const height = typeof axisSettings.height === "number" ? axisSettings.height : DEFAULT_X_AXIS_HEIGHT
1616
- return {
1617
- height,
1618
- width: offset.width,
1619
- }
1620
- }
1621
-
1622
- const getYAxisSize = (offset: ChartOffsetInternal, axisSettings: YAxisSettings): Size => {
1623
- const width = typeof axisSettings.width === "number" ? axisSettings.width : DEFAULT_Y_AXIS_WIDTH
1624
- return {
1625
- height: offset.height,
1626
- width,
1627
- }
1628
- }
1629
-
1630
- export const selectXAxisSize = chartSelector(function selectXAxisSize(state: ChartState, xAxisId: AxisId): Size {
1631
- return getXAxisSize(selectChartOffsetInternal(state), selectXAxisSettings(state, xAxisId))
1632
- })
1633
-
1634
- type AxisOffsetSteps = Record<AxisId, number>
1635
-
1636
- const combineXAxisPositionStartingPoint = (
1637
- offset: ChartOffsetInternal,
1638
- orientation: XAxisOrientation,
1639
- chartHeight: number,
1640
- ) => {
1641
- switch (orientation) {
1642
- case "top":
1643
- return offset.top
1644
- case "bottom":
1645
- return chartHeight - offset.bottom
1646
- default:
1647
- return 0
1648
- }
1649
- }
1650
-
1651
- const combineYAxisPositionStartingPoint = (
1652
- offset: ChartOffsetInternal,
1653
- orientation: YAxisOrientation,
1654
- chartWidth: number,
1655
- ) => {
1656
- switch (orientation) {
1657
- case "left":
1658
- return offset.left
1659
- case "right":
1660
- return chartWidth - offset.right
1661
- default:
1662
- return 0
1663
- }
1664
- }
1665
-
1666
- export const selectAllXAxesOffsetSteps = chartSelector(function selectAllXAxesOffsetSteps(state: ChartState, orientation: XAxisOrientation, mirror: boolean): AxisOffsetSteps {
1667
- const chartHeight = selectChartHeight(state)
1668
- const offset = selectChartOffsetInternal(state)
1669
- const allAxesWithSameOffsetType = selectAllXAxesWithOffsetType(state, orientation, mirror)
1670
-
1671
- const steps: AxisOffsetSteps = {}
1672
- let position: number | undefined
1673
- allAxesWithSameOffsetType.forEach((axis) => {
1674
- const axisSize = getXAxisSize(offset, axis)
1675
- if (position == null) {
1676
- position = combineXAxisPositionStartingPoint(offset, orientation, chartHeight)
1677
- }
1678
- const needSpace = (orientation === "top" && !mirror) || (orientation === "bottom" && mirror)
1679
- steps[axis.id] = position - Number(needSpace) * axisSize.height
1680
- position += (needSpace ? -1 : 1) * axisSize.height
1681
- })
1682
- return steps
1683
- })
1684
-
1685
- export const selectAllYAxesOffsetSteps = chartSelector(function selectAllYAxesOffsetSteps(state: ChartState, orientation: YAxisOrientation, mirror: boolean): AxisOffsetSteps {
1686
- const chartWidth = selectChartWidth(state)
1687
- const offset = selectChartOffsetInternal(state)
1688
- const allAxesWithSameOffsetType = selectAllYAxesWithOffsetType(state, orientation, mirror)
1689
-
1690
- const steps: AxisOffsetSteps = {}
1691
- let position: number | undefined
1692
- allAxesWithSameOffsetType.forEach((axis) => {
1693
- const axisSize = getYAxisSize(offset, axis)
1694
- if (position == null) {
1695
- position = combineYAxisPositionStartingPoint(offset, orientation, chartWidth)
1696
- }
1697
- const needSpace = (orientation === "left" && !mirror) || (orientation === "right" && mirror)
1698
- steps[axis.id] = position - Number(needSpace) * axisSize.width
1699
- position += (needSpace ? -1 : 1) * axisSize.width
1700
- })
1701
- return steps
1702
- })
1703
-
1704
- const selectXAxisOffsetSteps = chartSelector((state: ChartState, axisId: AxisId) => {
1705
- const axisSettings = selectXAxisSettings(state, axisId)
1706
- if (axisSettings == null) {
1707
- return undefined
1708
- }
1709
- return selectAllXAxesOffsetSteps(state, axisSettings.orientation, axisSettings.mirror)
1710
- })
1711
-
1712
- export const selectXAxisPosition = chartSelector(function selectXAxisPosition(state: ChartState, axisId: AxisId): Coordinate | undefined {
1713
- const offset = selectChartOffsetInternal(state)
1714
- const axisSettings = selectXAxisSettings(state, axisId)
1715
- const allSteps = selectXAxisOffsetSteps(state, axisId)
1716
- if (axisSettings == null) {
1717
- return undefined
1718
- }
1719
- const stepOfThisAxis = allSteps?.[axisId]
1720
- if (stepOfThisAxis == null) {
1721
- return { x: offset.left, y: 0 }
1722
- }
1723
- return { x: offset.left, y: stepOfThisAxis }
1724
- })
1725
-
1726
- const selectYAxisOffsetSteps = chartSelector((state: ChartState, axisId: AxisId) => {
1727
- const axisSettings = selectYAxisSettings(state, axisId)
1728
- if (axisSettings == null) {
1729
- return undefined
1730
- }
1731
- return selectAllYAxesOffsetSteps(state, axisSettings.orientation, axisSettings.mirror)
1732
- })
1733
-
1734
- export const selectYAxisPosition = chartSelector(function selectYAxisPosition(state: ChartState, axisId: AxisId): Coordinate | undefined {
1735
- const offset = selectChartOffsetInternal(state)
1736
- const axisSettings = selectYAxisSettings(state, axisId)
1737
- const allSteps = selectYAxisOffsetSteps(state, axisId)
1738
- if (axisSettings == null) {
1739
- return undefined
1740
- }
1741
- const stepOfThisAxis = allSteps?.[axisId]
1742
- if (stepOfThisAxis == null) {
1743
- return { x: 0, y: offset.top }
1744
- }
1745
- return { x: stepOfThisAxis, y: offset.top }
1746
- })
1747
-
1748
- export const selectYAxisSize = chartSelector(function selectYAxisSize(state: ChartState, yAxisId: AxisId): Size {
1749
- const offset = selectChartOffsetInternal(state)
1750
- const axisSettings = selectYAxisSettings(state, yAxisId)
1751
- const width = typeof axisSettings.width === "number" ? axisSettings.width : DEFAULT_Y_AXIS_WIDTH
1752
- return {
1753
- height: offset.height,
1754
- width,
1755
- }
1756
- })
1757
-
1758
- export const selectCartesianAxisSize = chartSelector((
1759
- state: ChartState,
1760
- axisType: RenderableAxisType,
1761
- axisId: AxisId,
1762
- ): number | undefined => {
1763
- switch (axisType) {
1764
- case "xAxis": {
1765
- return selectXAxisSize(state, axisId).width
1766
- }
1767
- case "yAxis": {
1768
- return selectYAxisSize(state, axisId).height
1769
- }
1770
- default: {
1771
- return undefined
1772
- }
1773
- }
1774
- })
1775
-
1776
- export const combineDuplicateDomain = (
1777
- chartLayout: LayoutType,
1778
- appliedValues: AppliedChartData,
1779
- axis: BaseCartesianAxis,
1780
- axisType: AllAxisTypes,
1781
- ): ReadonlyArray<unknown> | undefined => {
1782
- if (axis == null) {
1783
- return undefined
1784
- }
1785
- const { allowDuplicatedCategory, type, dataKey } = axis
1786
- const isCategorical = isCategoricalAxis(chartLayout, axisType)
1787
- const allData = appliedValues.map((av) => av.value)
1788
- if (
1789
- dataKey &&
1790
- isCategorical &&
1791
- type === "category" &&
1792
- allowDuplicatedCategory &&
1793
- hasDuplicate(allData)
1794
- ) {
1795
- return allData
1796
- }
1797
- return undefined
1798
- }
1799
-
1800
- export const selectDuplicateDomain = chartSelector(function selectDuplicateDomain(state: ChartState, axisType: AllAxisTypes, axisId: AxisId, isPanorama: boolean): ReadonlyArray<unknown> | undefined {
1801
- return combineDuplicateDomain(
1802
- selectChartLayout(state),
1803
- selectAllAppliedValues(state, axisType, axisId, isPanorama),
1804
- selectBaseAxis(state, axisType, axisId),
1805
- axisType,
1806
- )
1807
- })
1808
-
1809
- export const selectAxisPropsNeededForCartesianGridTicksGenerator = chartSelector(function selectAxisPropsNeededForCartesianGridTicksGenerator(state: ChartState, axisType: "xAxis" | "yAxis", axisId: AxisId, isPanorama: boolean): AxisPropsForCartesianGridTicksGeneration | undefined {
1810
- const layout = selectChartLayout(state)
1811
- const axis = selectCartesianAxisSettings(state, axisType, axisId)
1812
- const realScaleType = selectRealScaleType(state, axisType, axisId)
1813
- const scale = selectAxisScale(state, axisType, axisId, isPanorama)
1814
- const duplicateDomain = selectDuplicateDomain(state, axisType, axisId, isPanorama)
1815
- const categoricalDomain = selectCategoricalDomain(state, axisType, axisId, isPanorama)
1816
- const axisRange = selectAxisRange(state, axisType, axisId, isPanorama)
1817
- const niceTicks = selectNiceTicks(state, axisType, axisId, isPanorama)
1818
-
1819
- if (axis == null) {
1820
- return undefined
1821
- }
1822
- const isCategorical = isCategoricalAxis(layout, axisType)
1823
- return {
1824
- angle: axis.angle,
1825
- axisType,
1826
- categoricalDomain,
1827
- duplicateDomain,
1828
- interval: axis.interval,
1829
- isCategorical,
1830
- minTickGap: axis.minTickGap,
1831
- niceTicks,
1832
- orientation: axis.orientation,
1833
- range: axisRange,
1834
- realScaleType,
1835
- scale,
1836
- tick: axis.tick,
1837
- tickCount: axis.tickCount,
1838
- tickFormatter: axis.tickFormatter,
1839
- ticks: axis.ticks,
1840
- type: axis.type,
1841
- unit: axis.unit,
1842
- }
1843
- })
1844
-
1845
- /**
1846
- * Of on four almost identical implementations of tick generation.
1847
- * The four horsemen of tick generation are:
1848
- * - {@link selectTooltipAxisTicks}
1849
- * - {@link combineAxisTicks}
1850
- * - {@link getTicksOfAxis}.
1851
- * - {@link combineGraphicalItemTicks}
1852
- */
1853
- export const combineAxisTicks = (
1854
- layout: LayoutType,
1855
- axis: RenderableAxisSettings,
1856
- realScaleType: D3ScaleType | undefined,
1857
- scale: RechartsScale | undefined,
1858
- niceTicks: ReadonlyArray<number> | undefined,
1859
- axisRange: AxisRange | undefined,
1860
- duplicateDomain: ReadonlyArray<unknown> | undefined,
1861
- categoricalDomain: ReadonlyArray<unknown> | undefined,
1862
- axisType: RenderableAxisType,
1863
- ): ReadonlyArray<TickItem> | undefined => {
1864
- if (axis == null || scale == null) {
1865
- return undefined
1866
- }
1867
-
1868
- const isCategorical = isCategoricalAxis(layout, axisType)
1869
-
1870
- const { type, ticks, tickCount } = axis
1871
-
1872
- /* mirror upstream dead-code: comparison against "scaleBand" never matches
1873
- (combineRealScaleType returns "band" instead). Branch is intentionally
1874
- always-false, so offsetForBand resolves to 2 and the final offset becomes
1875
- bandwidth/2 — the centered-tick coordinate. Do not "fix" the literal to
1876
- "band" — that inverts the offset and breaks every band axis. */
1877
- const offsetForBand =
1878
- // @ts-expect-error see comment above — intentional always-false comparison
1879
- realScaleType === "scaleBand" && typeof scale.bandwidth === "function"
1880
- ? scale.bandwidth() / 2
1881
- : 2
1882
-
1883
- let offset = type === "category" && scale.bandwidth ? scale.bandwidth() / offsetForBand : 0
1884
-
1885
- offset =
1886
- axisType === "angleAxis" && axisRange != null && axisRange.length >= 2
1887
- ? mathSign(axisRange[0] - axisRange[1]) * 2 * offset
1888
- : offset
1889
-
1890
- const ticksOrNiceTicks = ticks || niceTicks
1891
- if (ticksOrNiceTicks) {
1892
- return ticksOrNiceTicks
1893
- .map((entry: AxisTick, index: number): TickItem | null => {
1894
- const scaleContent = duplicateDomain ? duplicateDomain.indexOf(entry) : entry
1895
-
1896
- const scaled = scale.map(scaleContent)
1897
- if (!isWellBehavedNumber(scaled)) {
1898
- return null
1899
- }
1900
- return {
1901
- coordinate: scaled + offset,
1902
- index,
1903
- offset,
1904
- value: entry,
1905
- }
1906
- })
1907
- .filter(isNotNil)
1908
- }
1909
-
1910
- if (isCategorical && categoricalDomain) {
1911
- return categoricalDomain
1912
- .map((entry: unknown, index: number): TickItem | null => {
1913
- const scaled = scale.map(entry)
1914
- if (!isWellBehavedNumber(scaled)) {
1915
- return null
1916
- }
1917
- return {
1918
- coordinate: scaled + offset,
1919
- index,
1920
- offset,
1921
- value: entry,
1922
- }
1923
- })
1924
- .filter(isNotNil)
1925
- }
1926
-
1927
- if (scale.ticks) {
1928
- return scale
1929
- .ticks(tickCount)
1930
- .map((entry: number, index: number): TickItem | null => {
1931
- const scaled = scale.map(entry)
1932
- if (!isWellBehavedNumber(scaled)) {
1933
- return null
1934
- }
1935
- return { coordinate: scaled + offset, index, offset, value: entry }
1936
- })
1937
- .filter(isNotNil)
1938
- }
1939
-
1940
- return scale
1941
- .domain()
1942
- .map((entry: CategoricalDomainItem, index: number): TickItem | null => {
1943
- const scaled = scale.map(entry)
1944
- if (!isWellBehavedNumber(scaled)) {
1945
- return null
1946
- }
1947
- return {
1948
- coordinate: scaled + offset,
1949
- index,
1950
- offset,
1951
- value: duplicateDomain ? duplicateDomain[entry as unknown as number] : entry,
1952
- }
1953
- })
1954
- .filter(isNotNil)
1955
- }
1956
-
1957
- export const selectTicksOfAxis = chartSelector(function selectTicksOfAxis(state: ChartState, axisType: RenderableAxisType, axisId: AxisId, isPanorama: boolean): ReadonlyArray<CartesianTickItem> | undefined {
1958
- return combineAxisTicks(
1959
- selectChartLayout(state),
1960
- selectRenderableAxisSettings(state, axisType, axisId),
1961
- selectRealScaleType(state, axisType, axisId),
1962
- selectAxisScale(state, axisType, axisId, isPanorama),
1963
- selectNiceTicks(state, axisType, axisId, isPanorama),
1964
- selectAxisRange(state, axisType, axisId, isPanorama),
1965
- selectDuplicateDomain(state, axisType, axisId, isPanorama),
1966
- selectCategoricalDomain(state, axisType, axisId, isPanorama),
1967
- axisType,
1968
- )
1969
- })
1970
-
1971
- /**
1972
- * Of on four almost identical implementations of tick generation.
1973
- * The four horsemen of tick generation are:
1974
- * - {@link selectTooltipAxisTicks}
1975
- * - {@link combineAxisTicks}
1976
- * - {@link getTicksOfAxis}.
1977
- * - {@link combineGraphicalItemTicks}
1978
- */
1979
- export const combineGraphicalItemTicks = (
1980
- layout: LayoutType,
1981
- axis: RenderableAxisSettings,
1982
- scale: RechartsScale | undefined,
1983
- axisRange: AxisRange | undefined,
1984
- duplicateDomain: ReadonlyArray<unknown> | undefined,
1985
- categoricalDomain: ReadonlyArray<unknown> | undefined,
1986
- axisType: RenderableAxisType,
1987
- ): TickItem[] | undefined => {
1988
- if (axis == null || scale == null || axisRange == null || axisRange[0] === axisRange[1]) {
1989
- return undefined
1990
- }
1991
- const isCategorical = isCategoricalAxis(layout, axisType)
1992
-
1993
- const { tickCount } = axis
1994
-
1995
- let offset = 0
1996
-
1997
- offset =
1998
- axisType === "angleAxis" && axisRange?.length >= 2
1999
- ? mathSign(axisRange[0] - axisRange[1]) * 2 * offset
2000
- : offset
2001
-
2002
- if (isCategorical && categoricalDomain) {
2003
- return categoricalDomain
2004
- .map((entry: unknown, index: number): TickItem | null => {
2005
- const scaled = scale.map(entry)
2006
- if (!isWellBehavedNumber(scaled)) {
2007
- return null
2008
- }
2009
- return {
2010
- coordinate: scaled + offset,
2011
- index,
2012
- offset,
2013
- value: entry,
2014
- }
2015
- })
2016
- .filter(isNotNil)
2017
- }
2018
-
2019
- if (scale.ticks) {
2020
- return scale
2021
- .ticks(tickCount)
2022
- .map((entry: number, index: number): TickItem | null => {
2023
- const scaled = scale.map(entry)
2024
- if (!isWellBehavedNumber(scaled)) {
2025
- return null
2026
- }
2027
- return { coordinate: scaled + offset, index, offset, value: entry }
2028
- })
2029
- .filter(isNotNil)
2030
- }
2031
-
2032
- return scale
2033
- .domain()
2034
- .map((entry: CategoricalDomainItem, index: number): TickItem | null => {
2035
- const scaled = scale.map(entry)
2036
- if (!isWellBehavedNumber(scaled)) {
2037
- return null
2038
- }
2039
- return {
2040
- coordinate: scaled + offset,
2041
- index,
2042
- offset,
2043
- value: duplicateDomain ? duplicateDomain[entry as unknown as number] : entry,
2044
- }
2045
- })
2046
- .filter(isNotNil)
2047
- }
2048
-
2049
- export const selectTicksOfGraphicalItem = chartSelector(function selectTicksOfGraphicalItem(state: ChartState, axisType: RenderableAxisType, axisId: AxisId, isPanorama: boolean): TickItem[] | undefined {
2050
- return combineGraphicalItemTicks(
2051
- selectChartLayout(state),
2052
- selectRenderableAxisSettings(state, axisType, axisId),
2053
- selectAxisScale(state, axisType, axisId, isPanorama),
2054
- selectAxisRange(state, axisType, axisId, isPanorama),
2055
- selectDuplicateDomain(state, axisType, axisId, isPanorama),
2056
- selectCategoricalDomain(state, axisType, axisId, isPanorama),
2057
- axisType,
2058
- )
2059
- })
2060
-
2061
- /**
2062
- * This is the internal representation of an axis along with its scale function.
2063
- * Here we have already computed the scale function for the axis,
2064
- * and replaced the union type of scale (string | function) with just the function type.
2065
- */
2066
- export type BaseAxisWithScale = Omit<BaseCartesianAxis, "scale"> & { scale: RechartsScale }
2067
-
2068
- export const selectAxisWithScale = chartSelector(function selectAxisWithScale(state: ChartState, axisType: RenderableAxisType, axisId: AxisId, isPanorama: boolean, override?: XAxisSettings | YAxisSettings): BaseAxisWithScale | undefined {
2069
- const axis = override !== undefined ? override : selectBaseAxis(state, axisType, axisId)
2070
- const scale = selectAxisScale(state, axisType, axisId, isPanorama)
2071
- if (axis == null || scale == null) {
2072
- return undefined
2073
- }
2074
- return {
2075
- ...axis,
2076
- scale,
2077
- }
2078
- })
2079
-
2080
- const selectZAxisConfiguredScale = chartSelector(function selectZAxisConfiguredScale(state: ChartState, axisType: "zAxis", axisId: AxisId, isPanorama: false): CustomScaleDefinition | undefined {
2081
- return combineConfiguredScale(
2082
- selectBaseAxis(state, axisType, axisId),
2083
- selectRealScaleType(state, axisType, axisId),
2084
- selectAxisDomain(state, axisType, axisId, isPanorama),
2085
- selectAxisRangeWithReverse(state, axisType, axisId, isPanorama),
2086
- )
2087
- })
2088
-
2089
- const selectZAxisScale = chartSelector(function selectZAxisScale(state: ChartState, axisType: "zAxis", axisId: AxisId, isPanorama: false): RechartsScale | undefined {
2090
- return rechartsScaleFactory(selectZAxisConfiguredScale(state, axisType, axisId, isPanorama))
2091
- })
2092
-
2093
- export type ZAxisWithScale = Omit<ZAxisSettings, "scale"> & { scale: RechartsScale }
2094
-
2095
- export const selectZAxisWithScale = chartSelector(function selectZAxisWithScale(state: ChartState, _axisType: "zAxis", axisId: AxisId, isPanorama: false): ZAxisWithScale | undefined {
2096
- const axis = selectZAxisSettings(state, axisId)
2097
- const scale = selectZAxisScale(state, "zAxis", axisId, isPanorama)
2098
- if (axis == null || scale == null) {
2099
- return undefined
2100
- }
2101
- return {
2102
- ...axis,
2103
- scale,
2104
- }
2105
- })
2106
-
2107
- /**
2108
- * We are also going to need to implement polar chart directions if we want to support keyboard controls for those.
2109
- */
2110
- export type AxisDirection = "left-to-right" | "right-to-left" | "top-to-bottom" | "bottom-to-top"
2111
-
2112
- export const selectChartDirection = chartSelector(function selectChartDirection(state: ChartState): AxisDirection | undefined {
2113
- const layout = selectChartLayout(state)
2114
- const allXAxes = selectAllXAxes(state)
2115
- const allYAxes = selectAllYAxes(state)
2116
-
2117
- switch (layout) {
2118
- case "horizontal": {
2119
- return allXAxes.some((axis) => axis.reversed) ? "right-to-left" : "left-to-right"
2120
- }
2121
- case "vertical": {
2122
- return allYAxes.some((axis) => axis.reversed) ? "bottom-to-top" : "top-to-bottom"
2123
- }
2124
- case "centric":
2125
- case "radial": {
2126
- return "left-to-right"
2127
- }
2128
- default: {
2129
- return undefined
2130
- }
2131
- }
2132
- })
2133
-
2134
- export const selectAxisInverseTickSnapScale = chartSelector(function selectAxisInverseTickSnapScale(state: ChartState, axisType: RenderableAxisType, axisId: AxisId, isPanorama: boolean): InverseScaleFunction | undefined {
2135
- const ticks = selectTicksOfAxis(state, axisType, axisId, isPanorama)
2136
- if (!ticks || ticks.length === 0) {
2137
- return undefined
2138
- }
2139
-
2140
- return (pixelValue: number) => {
2141
- let minDistance = Infinity
2142
- let closestTick = ticks[0]
2143
-
2144
- for (const tick of ticks) {
2145
- const distance = Math.abs(tick.coordinate - pixelValue)
2146
- if (distance < minDistance) {
2147
- minDistance = distance
2148
- closestTick = tick
2149
- }
2150
- }
2151
- return closestTick?.value
2152
- }
2153
- })
2154
-
2155
- export const selectRenderedTicksOfAxis = chartSelector(function selectRenderedTicksOfAxis(state: ChartState, axisType: "xAxis" | "yAxis", axisId: AxisId): ReadonlyArray<TickItem> | undefined {
2156
- return readChartState(state).renderedTicks[axisType]?.[String(axisId)]
2157
- })