@solidports/recharts 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (306) hide show
  1. package/LICENSE +22 -0
  2. package/NOTICE +19 -0
  3. package/README.md +102 -0
  4. package/dist/dev.js +28564 -0
  5. package/dist/index.d.ts +7859 -0
  6. package/dist/index.js +28546 -0
  7. package/package.json +98 -0
  8. package/src/animation/AnimatedItems.tsx +183 -0
  9. package/src/animation/AnimationController.ts +33 -0
  10. package/src/animation/AnimationControllerImpl.ts +36 -0
  11. package/src/animation/AnimationHandle.ts +307 -0
  12. package/src/animation/CSSTransitionAnimate.tsx +170 -0
  13. package/src/animation/JavascriptAnimate.tsx +119 -0
  14. package/src/animation/easing.ts +221 -0
  15. package/src/animation/matchBy.ts +164 -0
  16. package/src/animation/timeoutController.ts +70 -0
  17. package/src/animation/useAnimationController.tsx +34 -0
  18. package/src/animation/useAnimationStartSnapshot.ts +118 -0
  19. package/src/animation/util.ts +41 -0
  20. package/src/cartesian/Area.tsx +915 -0
  21. package/src/cartesian/AreaRevealShape.tsx +190 -0
  22. package/src/cartesian/Bar.tsx +1369 -0
  23. package/src/cartesian/BarStack.tsx +152 -0
  24. package/src/cartesian/Brush.tsx +951 -0
  25. package/src/cartesian/CartesianAxis.tsx +722 -0
  26. package/src/cartesian/CartesianGrid.tsx +711 -0
  27. package/src/cartesian/ErrorBar.tsx +361 -0
  28. package/src/cartesian/Funnel.tsx +803 -0
  29. package/src/cartesian/GraphicalItemClipPath.tsx +67 -0
  30. package/src/cartesian/Line.tsx +863 -0
  31. package/src/cartesian/LineDrawShape.tsx +89 -0
  32. package/src/cartesian/ReferenceArea.tsx +331 -0
  33. package/src/cartesian/ReferenceDot.tsx +304 -0
  34. package/src/cartesian/ReferenceLine.tsx +474 -0
  35. package/src/cartesian/Scatter.tsx +888 -0
  36. package/src/cartesian/XAxis.tsx +433 -0
  37. package/src/cartesian/YAxis.tsx +443 -0
  38. package/src/cartesian/ZAxis.tsx +155 -0
  39. package/src/cartesian/cartesianPositionToCSSTranslate.tsx +29 -0
  40. package/src/cartesian/cartesianViewBoxToTrapezoid.tsx +21 -0
  41. package/src/cartesian/getCartesianPosition.tsx +267 -0
  42. package/src/cartesian/getEquidistantTicks.ts +144 -0
  43. package/src/cartesian/getTicks.ts +225 -0
  44. package/src/cartesian/isOutsidePosition.ts +15 -0
  45. package/src/cartesian/useAnimatedLineLength.ts +54 -0
  46. package/src/chart/AreaChart.tsx +29 -0
  47. package/src/chart/BarChart.tsx +29 -0
  48. package/src/chart/CartesianChart.tsx +131 -0
  49. package/src/chart/CategoricalChart.tsx +94 -0
  50. package/src/chart/ComposedChart.tsx +29 -0
  51. package/src/chart/FunnelChart.tsx +29 -0
  52. package/src/chart/LineChart.tsx +29 -0
  53. package/src/chart/PieChart.tsx +50 -0
  54. package/src/chart/PolarChart.tsx +164 -0
  55. package/src/chart/RadarChart.tsx +70 -0
  56. package/src/chart/RadialBarChart.tsx +46 -0
  57. package/src/chart/RechartsWrapper.tsx +551 -0
  58. package/src/chart/Sankey.tsx +1534 -0
  59. package/src/chart/ScatterChart.tsx +29 -0
  60. package/src/chart/SunburstChart.tsx +504 -0
  61. package/src/chart/Treemap.tsx +1223 -0
  62. package/src/chart/createInitialRootProps.ts +24 -0
  63. package/src/chart/types.ts +53 -0
  64. package/src/component/ActivePoints.tsx +144 -0
  65. package/src/component/Cell.tsx +37 -0
  66. package/src/component/Cursor.tsx +185 -0
  67. package/src/component/Customized.tsx +50 -0
  68. package/src/component/DefaultLegendContent.tsx +348 -0
  69. package/src/component/DefaultTooltipContent.tsx +224 -0
  70. package/src/component/Dots.tsx +157 -0
  71. package/src/component/Label.tsx +636 -0
  72. package/src/component/LabelList.tsx +375 -0
  73. package/src/component/Legend.tsx +512 -0
  74. package/src/component/ResponsiveContainer.tsx +348 -0
  75. package/src/component/Text.tsx +541 -0
  76. package/src/component/Tooltip.tsx +470 -0
  77. package/src/component/TooltipBoundingBox.tsx +146 -0
  78. package/src/component/responsiveContainerUtils.ts +134 -0
  79. package/src/container/ClipPathProvider.tsx +51 -0
  80. package/src/container/Layer.tsx +38 -0
  81. package/src/container/RootSurface.tsx +120 -0
  82. package/src/container/Surface.tsx +61 -0
  83. package/src/context/CellsContext.tsx +54 -0
  84. package/src/context/ErrorBarContext.tsx +146 -0
  85. package/src/context/GraphicalItemChildrenScope.tsx +18 -0
  86. package/src/context/PanoramaContext.tsx +9 -0
  87. package/src/context/RegisterGraphicalItemId.tsx +30 -0
  88. package/src/context/accessibilityContext.tsx +6 -0
  89. package/src/context/brushUpdateContext.tsx +9 -0
  90. package/src/context/chartDataContext.tsx +97 -0
  91. package/src/context/chartLayoutContext.tsx +201 -0
  92. package/src/context/legendPayloadContext.tsx +20 -0
  93. package/src/context/legendPortalContext.tsx +12 -0
  94. package/src/context/tooltipContext.tsx +89 -0
  95. package/src/context/tooltipPortalContext.tsx +12 -0
  96. package/src/context/useTooltipAxis.ts +22 -0
  97. package/src/hooks.ts +476 -0
  98. package/src/index.ts +280 -0
  99. package/src/polar/Pie.tsx +1360 -0
  100. package/src/polar/PolarAngleAxis.tsx +616 -0
  101. package/src/polar/PolarGrid.tsx +312 -0
  102. package/src/polar/PolarRadiusAxis.tsx +547 -0
  103. package/src/polar/Radar.tsx +734 -0
  104. package/src/polar/RadialBar.tsx +917 -0
  105. package/src/polar/defaultPolarAngleAxisProps.tsx +27 -0
  106. package/src/polar/defaultPolarRadiusAxisProps.tsx +25 -0
  107. package/src/shape/Cross.tsx +89 -0
  108. package/src/shape/Curve.tsx +343 -0
  109. package/src/shape/Dot.tsx +70 -0
  110. package/src/shape/Polygon.tsx +195 -0
  111. package/src/shape/Rectangle.tsx +470 -0
  112. package/src/shape/Sector.tsx +347 -0
  113. package/src/shape/Symbols.tsx +139 -0
  114. package/src/shape/Trapezoid.tsx +280 -0
  115. package/src/state/RechartsStateContext.tsx +12 -0
  116. package/src/state/RechartsStateProvider.tsx +87 -0
  117. package/src/state/RechartsStoreContext.tsx +25 -0
  118. package/src/state/RechartsStoreProvider.tsx +35 -0
  119. package/src/state/ReportChartProps.tsx +40 -0
  120. package/src/state/ReportEventSettings.tsx +30 -0
  121. package/src/state/ReportMainChartProps.tsx +61 -0
  122. package/src/state/ReportPolarOptions.tsx +35 -0
  123. package/src/state/SetGraphicalItem.ts +79 -0
  124. package/src/state/SetLegendPayload.ts +134 -0
  125. package/src/state/SetTooltipEntrySettings.tsx +72 -0
  126. package/src/state/actions.ts +464 -0
  127. package/src/state/brushSlice.ts +13 -0
  128. package/src/state/cartesianAxisSlice.ts +141 -0
  129. package/src/state/chartDataSlice.ts +50 -0
  130. package/src/state/chartState.ts +297 -0
  131. package/src/state/errorBarSlice.ts +29 -0
  132. package/src/state/eventSettingsSlice.ts +8 -0
  133. package/src/state/events.ts +76 -0
  134. package/src/state/externalEventsMiddleware.ts +255 -0
  135. package/src/state/graphicalItemsSlice.ts +74 -0
  136. package/src/state/hooks/useChartSelectors.tsx +45 -0
  137. package/src/state/keyboardEventsMiddleware.ts +228 -0
  138. package/src/state/layoutSlice.ts +21 -0
  139. package/src/state/legendSlice.ts +57 -0
  140. package/src/state/mouseEventsMiddleware.ts +185 -0
  141. package/src/state/optionsSlice.ts +47 -0
  142. package/src/state/polarAxisSlice.ts +10 -0
  143. package/src/state/polarOptionsSlice.ts +12 -0
  144. package/src/state/rawData.ts +26 -0
  145. package/src/state/referenceElementsSlice.ts +40 -0
  146. package/src/state/renderedTicksSlice.ts +15 -0
  147. package/src/state/rootPropsSlice.ts +47 -0
  148. package/src/state/selectors/areaSelectors.ts +240 -0
  149. package/src/state/selectors/arrayEqualityCheck.ts +29 -0
  150. package/src/state/selectors/axisSelectors.ts +2157 -0
  151. package/src/state/selectors/barSelectors.ts +310 -0
  152. package/src/state/selectors/barStackSelectors.ts +77 -0
  153. package/src/state/selectors/brushSelectors.ts +33 -0
  154. package/src/state/selectors/chartSelector.ts +185 -0
  155. package/src/state/selectors/combiners/combineActiveLabel.ts +16 -0
  156. package/src/state/selectors/combiners/combineActiveTooltipIndex.ts +95 -0
  157. package/src/state/selectors/combiners/combineAllBarPositions.ts +122 -0
  158. package/src/state/selectors/combiners/combineAxisRangeWithReverse.ts +16 -0
  159. package/src/state/selectors/combiners/combineBarPosition.ts +23 -0
  160. package/src/state/selectors/combiners/combineBarSizeList.ts +80 -0
  161. package/src/state/selectors/combiners/combineCheckedDomain.ts +48 -0
  162. package/src/state/selectors/combiners/combineConfiguredScale.ts +111 -0
  163. package/src/state/selectors/combiners/combineCoordinateForDefaultIndex.ts +45 -0
  164. package/src/state/selectors/combiners/combineDisplayedStackedData.ts +50 -0
  165. package/src/state/selectors/combiners/combineInverseScaleFunction.ts +16 -0
  166. package/src/state/selectors/combiners/combineRealScaleType.ts +44 -0
  167. package/src/state/selectors/combiners/combineStackedData.ts +27 -0
  168. package/src/state/selectors/combiners/combineTooltipInteractionState.ts +86 -0
  169. package/src/state/selectors/combiners/combineTooltipPayload.ts +205 -0
  170. package/src/state/selectors/combiners/combineTooltipPayloadConfigurations.ts +58 -0
  171. package/src/state/selectors/containerSelectors.ts +12 -0
  172. package/src/state/selectors/dataSelectors.ts +88 -0
  173. package/src/state/selectors/funnelSelectors.ts +75 -0
  174. package/src/state/selectors/graphicalItemSelectors.ts +30 -0
  175. package/src/state/selectors/legendSelectors.ts +29 -0
  176. package/src/state/selectors/lineSelectors.ts +134 -0
  177. package/src/state/selectors/numberDomainEqualityCheck.ts +14 -0
  178. package/src/state/selectors/pickAxisId.ts +5 -0
  179. package/src/state/selectors/pickAxisType.ts +3 -0
  180. package/src/state/selectors/pieSelectors.ts +97 -0
  181. package/src/state/selectors/polarAxisSelectors.ts +201 -0
  182. package/src/state/selectors/polarGridSelectors.ts +28 -0
  183. package/src/state/selectors/polarScaleSelectors.ts +133 -0
  184. package/src/state/selectors/polarSelectors.ts +219 -0
  185. package/src/state/selectors/radarSelectors.ts +191 -0
  186. package/src/state/selectors/radialBarSelectors.ts +435 -0
  187. package/src/state/selectors/rootPropsSelectors.ts +25 -0
  188. package/src/state/selectors/scatterSelectors.ts +96 -0
  189. package/src/state/selectors/selectActivePropsFromChartPointer.ts +26 -0
  190. package/src/state/selectors/selectAllAxes.ts +17 -0
  191. package/src/state/selectors/selectChartOffset.ts +16 -0
  192. package/src/state/selectors/selectChartOffsetInternal.ts +136 -0
  193. package/src/state/selectors/selectLegendArea.ts +20 -0
  194. package/src/state/selectors/selectPlotArea.ts +22 -0
  195. package/src/state/selectors/selectTooltipAxisId.ts +7 -0
  196. package/src/state/selectors/selectTooltipAxisType.ts +32 -0
  197. package/src/state/selectors/selectTooltipEventType.ts +48 -0
  198. package/src/state/selectors/selectTooltipPayloadSearcher.ts +6 -0
  199. package/src/state/selectors/selectTooltipSettings.ts +39 -0
  200. package/src/state/selectors/selectTooltipState.ts +8 -0
  201. package/src/state/selectors/selectors.ts +271 -0
  202. package/src/state/selectors/tooltipSelectors.ts +578 -0
  203. package/src/state/selectors/touchSelectors.ts +31 -0
  204. package/src/state/store.ts +29 -0
  205. package/src/state/storeIdentity.ts +9 -0
  206. package/src/state/teardownWrite.ts +10 -0
  207. package/src/state/tooltipInteraction.ts +23 -0
  208. package/src/state/tooltipSlice.ts +334 -0
  209. package/src/state/touchEventsMiddleware.ts +214 -0
  210. package/src/state/types/AnimationSettings.ts +20 -0
  211. package/src/state/types/AreaSettings.ts +14 -0
  212. package/src/state/types/BarSettings.ts +15 -0
  213. package/src/state/types/LineSettings.ts +9 -0
  214. package/src/state/types/PieSettings.ts +34 -0
  215. package/src/state/types/RadarSettings.ts +5 -0
  216. package/src/state/types/RadialBarSettings.ts +10 -0
  217. package/src/state/types/ScatterSettings.ts +12 -0
  218. package/src/state/types/StackedGraphicalItem.ts +34 -0
  219. package/src/state/useChartState.ts +17 -0
  220. package/src/state/zIndexSlice.ts +39 -0
  221. package/src/synchronisation/syncSelectors.ts +7 -0
  222. package/src/synchronisation/types.ts +44 -0
  223. package/src/synchronisation/useChartSynchronisation.tsx +404 -0
  224. package/src/theme/RechartsTheme.ts +16 -0
  225. package/src/theme/RechartsThemeContext.ts +19 -0
  226. package/src/theme/darkTheme.ts +13 -0
  227. package/src/theme/graphicalItemIdentity.ts +70 -0
  228. package/src/theme/legacyTheme.ts +17 -0
  229. package/src/theme/lightTheme.ts +13 -0
  230. package/src/types.ts +54 -0
  231. package/src/util/ActiveShapeUtils.tsx +162 -0
  232. package/src/util/BarUtils.tsx +62 -0
  233. package/src/util/BarePortal.tsx +50 -0
  234. package/src/util/CamelCaseSVGAttrs.ts +34 -0
  235. package/src/util/CartesianUtils.ts +48 -0
  236. package/src/util/ChartUtils.ts +802 -0
  237. package/src/util/Constants.ts +42 -0
  238. package/src/util/CssPrefixUtils.ts +20 -0
  239. package/src/util/DOMUtils.ts +129 -0
  240. package/src/util/DataUtils.ts +216 -0
  241. package/src/util/Events.ts +16 -0
  242. package/src/util/FunnelUtils.tsx +15 -0
  243. package/src/util/Global.ts +12 -0
  244. package/src/util/IfOverflow.ts +15 -0
  245. package/src/util/LRUCache.ts +41 -0
  246. package/src/util/LogUtils.ts +22 -0
  247. package/src/util/PolarUtils.ts +132 -0
  248. package/src/util/RadialBarUtils.tsx +24 -0
  249. package/src/util/ReactUtils.ts +95 -0
  250. package/src/util/ReduceCSSCalc.ts +187 -0
  251. package/src/util/ScatterUtils.tsx +52 -0
  252. package/src/util/ShapeElementProps.tsx +87 -0
  253. package/src/util/TickUtils.ts +60 -0
  254. package/src/util/XAxisUtils.ts +48 -0
  255. package/src/util/YAxisUtils.ts +48 -0
  256. package/src/util/axisPropsAreEqual.ts +48 -0
  257. package/src/util/createCartesianCharts.tsx +150 -0
  258. package/src/util/createEventProxy.ts +20 -0
  259. package/src/util/createPolarCharts.tsx +112 -0
  260. package/src/util/cursor/getCursorPoints.ts +46 -0
  261. package/src/util/cursor/getCursorRectangle.ts +28 -0
  262. package/src/util/cursor/getRadialCursorPoints.ts +32 -0
  263. package/src/util/excludeEventProps.ts +171 -0
  264. package/src/util/getActiveCoordinate.ts +213 -0
  265. package/src/util/getAxisTypeBasedOnLayout.ts +21 -0
  266. package/src/util/getClassNameFromUnknown.ts +6 -0
  267. package/src/util/getEveryNth.ts +27 -0
  268. package/src/util/getRadiusAndStrokeWidthFromDot.ts +35 -0
  269. package/src/util/getRelativeCoordinate.ts +80 -0
  270. package/src/util/getSliced.ts +13 -0
  271. package/src/util/hoverDedupe.ts +41 -0
  272. package/src/util/isDomainSpecifiedByUser.ts +219 -0
  273. package/src/util/isWellBehavedNumber.ts +7 -0
  274. package/src/util/pathTotalLength.ts +25 -0
  275. package/src/util/payload/getUniqPayload.ts +28 -0
  276. package/src/util/propsAreEqual.ts +121 -0
  277. package/src/util/resolveDefaultProps.ts +161 -0
  278. package/src/util/round.ts +32 -0
  279. package/src/util/scale/CartesianScaleHelper.ts +72 -0
  280. package/src/util/scale/CustomScaleDefinition.ts +81 -0
  281. package/src/util/scale/RechartsScale.ts +130 -0
  282. package/src/util/scale/createCategoricalInverse.ts +72 -0
  283. package/src/util/scale/getNiceTickValues.ts +311 -0
  284. package/src/util/scale/index.ts +2 -0
  285. package/src/util/scale/util/arithmetic.ts +54 -0
  286. package/src/util/solid-1-compat.ts +310 -0
  287. package/src/util/solidJsxCamelAugment.d.ts +84 -0
  288. package/src/util/stacks/getStackSeriesIdentifier.ts +21 -0
  289. package/src/util/stacks/stackTypes.ts +60 -0
  290. package/src/util/structurallyEqual.ts +31 -0
  291. package/src/util/svgPropertiesAndEvents.ts +53 -0
  292. package/src/util/svgPropertiesNoEvents.ts +571 -0
  293. package/src/util/tooltip/translate.ts +171 -0
  294. package/src/util/typedDataKey.ts +48 -0
  295. package/src/util/types.ts +1560 -0
  296. package/src/util/useAnimationId.ts +31 -0
  297. package/src/util/useElementOffset.ts +110 -0
  298. package/src/util/useId.ts +8 -0
  299. package/src/util/usePrefersReducedMotion.ts +48 -0
  300. package/src/util/useReportScale.ts +24 -0
  301. package/src/util/useUniqueId.ts +30 -0
  302. package/src/zIndex/DefaultZIndexes.ts +84 -0
  303. package/src/zIndex/ZIndexLayer.tsx +121 -0
  304. package/src/zIndex/ZIndexPortal.tsx +79 -0
  305. package/src/zIndex/getZIndexFromUnknown.ts +14 -0
  306. package/src/zIndex/zIndexSelectors.ts +48 -0
@@ -0,0 +1,213 @@
1
+ /* eslint-disable import/no-cycle */
2
+ import {
3
+ AxisType,
4
+ CartesianLayout,
5
+ ChartOffsetInternal,
6
+ RelativePointer,
7
+ Coordinate,
8
+ PolarCoordinate,
9
+ PolarLayout,
10
+ RangeObj,
11
+ TickItem,
12
+ } from "./types"
13
+ import { polarToCartesian } from "./PolarUtils"
14
+ import { AxisRange } from "../state/selectors/axisSelectors"
15
+ import { mathSign } from "./DataUtils"
16
+
17
+ export const getActiveCartesianCoordinate = (
18
+ layout: CartesianLayout,
19
+ tooltipTicks: readonly TickItem[],
20
+ activeIndex: number | undefined,
21
+ pointer: RelativePointer,
22
+ ): Coordinate => {
23
+ const entry = tooltipTicks.find((tick) => tick && tick.index === activeIndex)
24
+
25
+ if (entry) {
26
+ if (layout === "horizontal") {
27
+ return { x: entry.coordinate, y: pointer.relativeY }
28
+ }
29
+ if (layout === "vertical") {
30
+ return { x: pointer.relativeX, y: entry.coordinate }
31
+ }
32
+ }
33
+
34
+ return { x: 0, y: 0 }
35
+ }
36
+
37
+ /**
38
+ * Get the active coordinate in polar coordinate system.
39
+ * Internally we only really use x and y, but this returned object is part of public API
40
+ * (because it goes straight to the tooltip content) so we keep all the other properties
41
+ * for backwards compatibility.
42
+ *
43
+ * @param layout - The polar layout type ('centric' or 'radial').
44
+ * @param tooltipTicks - Array of tick items used for tooltips.
45
+ * @param activeIndex - The index of the active tick.
46
+ * @param rangeObj - The range object containing polar chart properties.
47
+ * @returns The active coordinate object with polar properties.
48
+ */
49
+ export const getActivePolarCoordinate = (
50
+ layout: PolarLayout,
51
+ tooltipTicks: readonly TickItem[],
52
+ activeIndex: number | undefined,
53
+ rangeObj: RangeObj,
54
+ ): PolarCoordinate => {
55
+ const entry = tooltipTicks.find((tick) => tick && tick.index === activeIndex)
56
+
57
+ if (entry) {
58
+ if (layout === "centric") {
59
+ const angle = entry.coordinate
60
+ const { radius } = rangeObj
61
+
62
+ return {
63
+ ...rangeObj,
64
+ ...polarToCartesian(rangeObj.cx, rangeObj.cy, radius, angle),
65
+ angle,
66
+ radius,
67
+ }
68
+ }
69
+
70
+ const radius = entry.coordinate
71
+ const { angle } = rangeObj
72
+
73
+ return {
74
+ ...rangeObj,
75
+ ...polarToCartesian(rangeObj.cx, rangeObj.cy, radius, angle),
76
+ angle,
77
+ radius,
78
+ }
79
+ }
80
+
81
+ return {
82
+ angle: 0,
83
+ clockWise: false,
84
+ cx: 0,
85
+ cy: 0,
86
+ endAngle: 0,
87
+ innerRadius: 0,
88
+ outerRadius: 0,
89
+ radius: 0,
90
+ startAngle: 0,
91
+ x: 0,
92
+ y: 0,
93
+ }
94
+ }
95
+
96
+ export function isInCartesianRange(pointer: RelativePointer, offset: ChartOffsetInternal): boolean {
97
+ const { relativeX: x, relativeY: y } = pointer
98
+ return (
99
+ x >= offset.left &&
100
+ x <= offset.left + offset.width &&
101
+ y >= offset.top &&
102
+ y <= offset.top + offset.height
103
+ )
104
+ }
105
+
106
+ export const calculateActiveTickIndex = (
107
+ /**
108
+ * For different layouts, `coordinate` is different:
109
+ * In horizontal layout, this is expected to be the `x` coordinate
110
+ * vertical -> y
111
+ * centric -> angle
112
+ * radial -> radius
113
+ */
114
+ coordinate: number | undefined,
115
+ ticks: ReadonlyArray<TickItem> | undefined,
116
+ unsortedTicks: ReadonlyArray<TickItem>,
117
+ axisType: AxisType | undefined,
118
+ range: AxisRange | undefined,
119
+ ): number | undefined => {
120
+ const len = ticks?.length ?? 0
121
+
122
+ if (len <= 1 || coordinate == null) {
123
+ return 0
124
+ }
125
+
126
+ if (
127
+ axisType === "angleAxis" &&
128
+ range != null &&
129
+ Math.abs(Math.abs(range[1] - range[0]) - 360) <= 1e-6
130
+ ) {
131
+ const span = range[1] - range[0]
132
+ /* The pointer may sit in the wrap-around gap of a full circle; test it shifted by ±360 too. */
133
+ const isInside = (lowerLimit: number, upperLimit: number, inclusiveLower: boolean): boolean =>
134
+ [coordinate, coordinate + span, coordinate - span].some(
135
+ (c) => (inclusiveLower ? c >= lowerLimit : c > lowerLimit) && c <= upperLimit,
136
+ )
137
+ for (let i = 0; i < len; i++) {
138
+ const before = i > 0 ? unsortedTicks[i - 1]?.coordinate : unsortedTicks[len - 1]?.coordinate
139
+ const cur = unsortedTicks[i]?.coordinate
140
+ const after = i >= len - 1 ? unsortedTicks[0]?.coordinate : unsortedTicks[i + 1]?.coordinate
141
+ let sameDirectionCoord
142
+
143
+ if (before == null || cur == null || after == null) {
144
+ continue
145
+ }
146
+
147
+ if (mathSign(cur - before) !== mathSign(after - cur)) {
148
+ const diffInterval: number[] = []
149
+ if (mathSign(after - cur) === mathSign(range[1] - range[0])) {
150
+ sameDirectionCoord = after
151
+
152
+ const curInRange = cur + range[1] - range[0]
153
+ diffInterval[0] = Math.min(curInRange, (curInRange + before) / 2)
154
+ diffInterval[1] = Math.max(curInRange, (curInRange + before) / 2)
155
+ } else {
156
+ sameDirectionCoord = before
157
+
158
+ const afterInRange = after + range[1] - range[0]
159
+ diffInterval[0] = Math.min(cur, (afterInRange + cur) / 2)
160
+ diffInterval[1] = Math.max(cur, (afterInRange + cur) / 2)
161
+ }
162
+ const sameInterval: [number, number] = [
163
+ Math.min(cur, (sameDirectionCoord + cur) / 2),
164
+ Math.max(cur, (sameDirectionCoord + cur) / 2),
165
+ ]
166
+
167
+ if (
168
+ isInside(sameInterval[0], sameInterval[1], false) ||
169
+ isInside(diffInterval[0] ?? 0, diffInterval[1] ?? 0, true)
170
+ ) {
171
+ return unsortedTicks[i]?.index
172
+ }
173
+ } else {
174
+ const minValue = Math.min(before, after)
175
+ const maxValue = Math.max(before, after)
176
+
177
+ if (isInside((minValue + cur) / 2, (maxValue + cur) / 2, false)) {
178
+ return unsortedTicks[i]?.index
179
+ }
180
+ }
181
+ }
182
+ } else if (ticks) {
183
+ for (let i = 0; i < len; i++) {
184
+ const curr = ticks[i]
185
+ if (curr == null) {
186
+ continue
187
+ }
188
+ const next = ticks[i + 1]
189
+ const prev = ticks[i - 1]
190
+
191
+ if (i === 0 && next != null && coordinate <= (curr.coordinate + next.coordinate) / 2) {
192
+ return curr.index
193
+ }
194
+
195
+ if (i === len - 1 && prev != null && coordinate > (curr.coordinate + prev.coordinate) / 2) {
196
+ return curr.index
197
+ }
198
+
199
+ if (
200
+ i > 0 &&
201
+ i < len - 1 &&
202
+ prev != null &&
203
+ next != null &&
204
+ coordinate > (curr.coordinate + prev.coordinate) / 2 &&
205
+ coordinate <= (curr.coordinate + next.coordinate) / 2
206
+ ) {
207
+ return curr.index
208
+ }
209
+ }
210
+ }
211
+
212
+ return -1
213
+ }
@@ -0,0 +1,21 @@
1
+ /* eslint-disable import/no-cycle */
2
+ import { AxisDomainTypeInput, AxisType, EvaluatedAxisDomainType, LayoutType } from "./types"
3
+ import { isCategoricalAxis } from "./ChartUtils"
4
+
5
+ /**
6
+ * This function evaluates the "auto" axis domain type based on the chart layout and axis type.
7
+ * It outputs a definitive axis domain type that can be used for further processing.
8
+ */
9
+ export function getAxisTypeBasedOnLayout(
10
+ layout: LayoutType | undefined,
11
+ axisType: AxisType,
12
+ axisDomainType: AxisDomainTypeInput,
13
+ ): EvaluatedAxisDomainType | undefined {
14
+ if (axisDomainType !== "auto") {
15
+ return axisDomainType
16
+ }
17
+ if (layout == null) {
18
+ return undefined
19
+ }
20
+ return isCategoricalAxis(layout, axisType) ? "category" : "number"
21
+ }
@@ -0,0 +1,6 @@
1
+ export function getClassNameFromUnknown(u: unknown): string {
2
+ if (u && typeof u === "object" && "className" in u && typeof u.className === "string") {
3
+ return u.className
4
+ }
5
+ return ""
6
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Given an array and a number N, return a new array which contains every nTh
3
+ * element of the input array. For n below 1, an empty array is returned.
4
+ * For n equal to 1, the input array is returned as is.
5
+ * For n greater than the length of the array, an array containing the first element
6
+ * and every nTh element after that (if any) is returned.
7
+ *
8
+ * @param array An input array.
9
+ * @param n A number specifying which elements to take.
10
+ * @returns The result array of the same type as the input array.
11
+ */
12
+ export function getEveryNth<Type>(array: ReadonlyArray<Type>, n: number): ReadonlyArray<Type> {
13
+ if (n < 1) {
14
+ return []
15
+ }
16
+ if (n === 1) {
17
+ return array
18
+ }
19
+ const result: Type[] = []
20
+ for (let i = 0; i < array.length; i += n) {
21
+ const item = array[i]
22
+ if (item !== undefined) {
23
+ result.push(item)
24
+ }
25
+ }
26
+ return result
27
+ }
@@ -0,0 +1,35 @@
1
+ /* eslint-disable import/no-cycle */
2
+ import { ActiveDotType, DotType } from "./types"
3
+ import { svgPropertiesNoEventsFromUnknown } from "./svgPropertiesNoEvents"
4
+
5
+ export function getRadiusAndStrokeWidthFromDot(dot: ActiveDotType | DotType): {
6
+ r: number
7
+ strokeWidth: number
8
+ } {
9
+ const props = svgPropertiesNoEventsFromUnknown(dot) as
10
+ | Record<string, unknown>
11
+ | null
12
+ const defaultR = 3
13
+ const defaultStrokeWidth = 2
14
+ if (props != null) {
15
+ const r = props.r
16
+ /* svgPropertiesNoEvents canonicalizes camelCase → kebab; check both forms. */
17
+ const strokeWidth = props["stroke-width"] ?? props.strokeWidth
18
+ let realR = Number(r)
19
+ let realStrokeWidth = Number(strokeWidth)
20
+ if (Number.isNaN(realR) || realR < 0) {
21
+ realR = defaultR
22
+ }
23
+ if (Number.isNaN(realStrokeWidth) || realStrokeWidth < 0) {
24
+ realStrokeWidth = defaultStrokeWidth
25
+ }
26
+ return {
27
+ r: realR,
28
+ strokeWidth: realStrokeWidth,
29
+ }
30
+ }
31
+ return {
32
+ r: defaultR,
33
+ strokeWidth: defaultStrokeWidth,
34
+ }
35
+ }
@@ -0,0 +1,80 @@
1
+ /* eslint-disable import/no-cycle */
2
+ import {
3
+ RelativePointer,
4
+ MousePointer,
5
+ SVGMousePointer,
6
+ TouchPointer,
7
+ SVGTouchPointer,
8
+ } from "./types"
9
+
10
+ /**
11
+ * Type guard to check if the pointer event is from an SVG element.
12
+ */
13
+ function isSvgPointer(
14
+ pointer: MousePointer | TouchPointer,
15
+ ): pointer is SVGMousePointer | SVGTouchPointer {
16
+ return "getBBox" in pointer.currentTarget && typeof pointer.currentTarget.getBBox === "function"
17
+ }
18
+
19
+ /**
20
+ * Computes relative element coordinates from mouse or touch event.
21
+ *
22
+ * The output coordinates are relative to the top-left corner of the active element (= currentTarget),
23
+ * where the top-left corner is (0, 0).
24
+ * Moving right, the x-coordinate increases, and moving down, the y-coordinate increases.
25
+ *
26
+ * The coordinates are rounded to the nearest integer and account for CSS transform scale.
27
+ * So element that's scaled will return the same coordinates as element that's not scaled.
28
+ *
29
+ * In other words: you zoom in or out, numbers stay the same.
30
+ *
31
+ * This function works with both HTML elements and SVG elements.
32
+ *
33
+ * It works with both Mouse and Touch events.
34
+ * For Touch events, it returns an array of coordinates, one for each touch point.
35
+ * For Mouse events, it returns a single coordinate object.
36
+ *
37
+ * @since 3.8
38
+ * @param event The mouse or touch event (works with both HTML and SVG elements)
39
+ * @returns Coordinates relative to the top-left corner of the element. Single object for Mouse events, array of objects for Touch events.
40
+ */
41
+ export function getRelativeCoordinate(event: MousePointer): RelativePointer
42
+ export function getRelativeCoordinate(event: TouchPointer): Array<RelativePointer>
43
+ export function getRelativeCoordinate(
44
+ event: MousePointer | TouchPointer,
45
+ ): RelativePointer | Array<RelativePointer> {
46
+ const rect = event.currentTarget.getBoundingClientRect()
47
+
48
+ let scaleX: number, scaleY: number
49
+
50
+ if (isSvgPointer(event)) {
51
+ const bbox = event.currentTarget.getBBox()
52
+ scaleX = bbox.width > 0 ? rect.width / bbox.width : 1
53
+ scaleY = bbox.height > 0 ? rect.height / bbox.height : 1
54
+ } else {
55
+ const element = event.currentTarget
56
+ scaleX = element.offsetWidth > 0 ? rect.width / element.offsetWidth : 1
57
+ scaleY = element.offsetHeight > 0 ? rect.height / element.offsetHeight : 1
58
+ }
59
+
60
+ const getCoordinates = (clientX: number, clientY: number): RelativePointer => ({
61
+ /*
62
+ * Here it's important to use:
63
+ * - event.clientX and event.clientY to get the mouse position relative to the viewport, including scroll.
64
+ * - pageX and pageY are not used because they are relative to the whole document, and ignore scroll.
65
+ * - rect.left and rect.top are used to get the position of the chart relative to the viewport.
66
+ * - offsetX and offsetY are not used because they are relative to the offset parent
67
+ * which may or may not be the same as the clientX and clientY, depending on the position of the chart in the DOM
68
+ * and surrounding element styles. CSS position: relative, absolute, fixed, will change the offset parent.
69
+ * - scaleX and scaleY are necessary for when the chart element is scaled using CSS `transform: scale(N)`.
70
+ */
71
+ relativeX: Math.round((clientX - rect.left) / scaleX),
72
+ relativeY: Math.round((clientY - rect.top) / scaleY),
73
+ })
74
+
75
+ if ("touches" in event) {
76
+ return Array.from(event.touches).map((touch) => getCoordinates(touch.clientX, touch.clientY))
77
+ }
78
+
79
+ return getCoordinates(event.clientX, event.clientY)
80
+ }
@@ -0,0 +1,13 @@
1
+ export function getSliced<T>(
2
+ arr: ReadonlyArray<T>,
3
+ startIndex: number,
4
+ endIndex: number,
5
+ ): ReadonlyArray<T> {
6
+ if (!Array.isArray(arr)) {
7
+ return arr
8
+ }
9
+ if (arr && startIndex + endIndex !== 0) {
10
+ return arr.slice(startIndex, endIndex + 1)
11
+ }
12
+ return arr
13
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * React derives onMouseEnter/onMouseLeave from the bubbling mouseover/mouseout events. Solid binds
3
+ * native events 1:1, so items bind both pairs; one pointer move then fires both mouseover and
4
+ * mouseenter (and mouseout + mouseleave), which must dispatch once.
5
+ *
6
+ * Shared by one list of items: entering another item ends the previous entry, the way moving the
7
+ * pointer from one item to the next does, so re-entering an item always dispatches again. A
8
+ * mouseout into the item's own descendant is not a leave.
9
+ */
10
+ export type HoverDedupe = {
11
+ /** True when this enter event should dispatch. */
12
+ enter(event: Event): boolean
13
+ /** True when this leave event should dispatch. */
14
+ leave(event: Event): boolean
15
+ }
16
+
17
+ export function createHoverDedupe(): HoverDedupe {
18
+ let current: EventTarget | null = null
19
+ return {
20
+ enter(event) {
21
+ const target = event.currentTarget
22
+ if (target == null || current === target) {
23
+ return false
24
+ }
25
+ current = target
26
+ return true
27
+ },
28
+ leave(event) {
29
+ const target = event.currentTarget
30
+ if (target == null || current !== target) {
31
+ return false
32
+ }
33
+ const next = (event as MouseEvent).relatedTarget
34
+ if (event.type === "mouseout" && next instanceof Node && target instanceof Node && target.contains(next)) {
35
+ return false
36
+ }
37
+ current = null
38
+ return true
39
+ },
40
+ }
41
+ }
@@ -0,0 +1,219 @@
1
+ /* eslint-disable import/no-cycle */
2
+ import { MAX_VALUE_REG, MIN_VALUE_REG } from "./ChartUtils"
3
+ import { isNumber } from "./DataUtils"
4
+ import { AxisDomain, NumberDomain } from "./types"
5
+ import { isWellBehavedNumber } from "./isWellBehavedNumber"
6
+
7
+ export function isWellFormedNumberDomain(v: unknown): v is NumberDomain {
8
+ if (Array.isArray(v) && v.length === 2) {
9
+ const [min, max] = v
10
+ if (isWellBehavedNumber(min) && isWellBehavedNumber(max)) {
11
+ return true
12
+ }
13
+ }
14
+ return false
15
+ }
16
+
17
+ export function extendDomain(
18
+ providedDomain: NumberDomain,
19
+ boundaryDomain: NumberDomain,
20
+ allowDataOverflow: boolean,
21
+ ): NumberDomain {
22
+ if (allowDataOverflow) {
23
+ return providedDomain
24
+ }
25
+ /*
26
+ * If the data are not allowed to overflow - we need to extend the domain.
27
+ * Means that effectively the user is allowed to make the domain larger
28
+ * but not smaller.
29
+ */
30
+ return [
31
+ Math.min(providedDomain[0], boundaryDomain[0]),
32
+ Math.max(providedDomain[1], boundaryDomain[1]),
33
+ ]
34
+ }
35
+
36
+ /**
37
+ * So Recharts allows users to provide their own domains,
38
+ * but it also places some expectations on what the domain is.
39
+ * We can improve on the typescript typing, but we also need a runtime test
40
+ * to observe that the user-provided domain is well-formed,
41
+ * that is: an array with exactly two numbers.
42
+ *
43
+ * This function does not accept data as an argument.
44
+ * This is to enable a performance optimization - if the domain is there,
45
+ * and we know what it is without traversing all the data,
46
+ * then we don't have to traverse all the data!
47
+ *
48
+ * If the user-provided domain is not well-formed,
49
+ * this function will return undefined - in which case we should traverse the data to calculate the real domain.
50
+ *
51
+ * This function is for parsing the numerical domain only.
52
+ *
53
+ * @param userDomain external prop, user provided, before validation. Can have various shapes: array, function, special magical strings inside too.
54
+ * @param allowDataOverflow boolean, provided by users. If true then the data domain wins
55
+ *
56
+ * @return [min, max] domain if it's well-formed; undefined if the domain is invalid
57
+ */
58
+ export function numericalDomainSpecifiedWithoutRequiringData(
59
+ userDomain: AxisDomain | undefined,
60
+ allowDataOverflow: boolean,
61
+ ) {
62
+ if (!allowDataOverflow) {
63
+ return undefined
64
+ }
65
+ if (typeof userDomain === "function") {
66
+ return undefined
67
+ }
68
+ if (Array.isArray(userDomain) && userDomain.length === 2) {
69
+ const [providedMin, providedMax] = userDomain
70
+ let finalMin, finalMax: string | number | undefined
71
+
72
+ if (isWellBehavedNumber(providedMin)) {
73
+ finalMin = providedMin
74
+ } else if (typeof providedMin === "function") {
75
+ return undefined
76
+ }
77
+
78
+ if (isWellBehavedNumber(providedMax)) {
79
+ finalMax = providedMax
80
+ } else if (typeof providedMax === "function") {
81
+ return undefined
82
+ }
83
+
84
+ const candidate = [finalMin, finalMax]
85
+ if (isWellFormedNumberDomain(candidate)) {
86
+ return candidate
87
+ }
88
+ }
89
+ return undefined
90
+ }
91
+
92
+ /**
93
+ * So Recharts allows users to provide their own domains,
94
+ * but it also places some expectations on what the domain is.
95
+ * We can improve on the typescript typing, but we also need a runtime test
96
+ * to observe that the user-provided domain is well-formed,
97
+ * that is: an array with exactly two numbers.
98
+ * If the user-provided domain is not well-formed,
99
+ * this function will return undefined - in which case we should traverse the data to calculate the real domain.
100
+ *
101
+ * This function is for parsing the numerical domain only.
102
+ *
103
+ * You are probably thinking, why does domain need tick count?
104
+ * Well it adjusts the domain based on where the "nice ticks" land, and nice ticks depend on the tick count.
105
+ *
106
+ * @param userDomain external prop, user provided, before validation. Can have various shapes: array, function, special magical strings inside too.
107
+ * @param dataDomain calculated from data. Can be undefined, as an option for performance optimization
108
+ * @param allowDataOverflow provided by users. If true then the data domain wins
109
+ *
110
+ * @return [min, max] domain if it's well-formed; undefined if the domain is invalid
111
+ */
112
+ /*
113
+ * Upstream evaluates the user's domain functions inside memoized (reselect) selectors, so a
114
+ * function runs once per distinct input. Our selectors are plain functions evaluated by several
115
+ * memos; remember the last call per function to keep the same call pattern.
116
+ */
117
+ const lastDomainCalls = new WeakMap<Function, { args: ReadonlyArray<unknown>; result: unknown }>()
118
+
119
+ function sameArg(a: unknown, b: unknown): boolean {
120
+ if (Array.isArray(a) && Array.isArray(b)) {
121
+ return a.length === b.length && a.every((value, i) => Object.is(value, b[i]))
122
+ }
123
+ return Object.is(a, b)
124
+ }
125
+
126
+ function callDomainFunction<R>(fn: (...args: never[]) => R, ...args: ReadonlyArray<unknown>): R {
127
+ const last = lastDomainCalls.get(fn)
128
+ if (last != null && last.args.length === args.length && last.args.every((arg, i) => sameArg(arg, args[i]))) {
129
+ return last.result as R
130
+ }
131
+ const result = (fn as (...a: ReadonlyArray<unknown>) => R)(...args)
132
+ lastDomainCalls.set(fn, { args, result })
133
+ return result
134
+ }
135
+
136
+ export function parseNumericalUserDomain(
137
+ userDomain: AxisDomain | undefined,
138
+ dataDomain: NumberDomain | undefined,
139
+ allowDataOverflow: boolean,
140
+ ): NumberDomain | undefined {
141
+ if (!allowDataOverflow && dataDomain == null) {
142
+ return undefined
143
+ }
144
+ if (typeof userDomain === "function" && dataDomain != null) {
145
+ try {
146
+ const result = callDomainFunction(userDomain, dataDomain, allowDataOverflow)
147
+ if (isWellFormedNumberDomain(result)) {
148
+ return extendDomain(result, dataDomain, allowDataOverflow)
149
+ }
150
+ } catch {
151
+ /* ignore the exception and compute domain from data later */
152
+ }
153
+ }
154
+ if (Array.isArray(userDomain) && userDomain.length === 2) {
155
+ const [providedMin, providedMax] = userDomain
156
+ let finalMin, finalMax: string | number | undefined
157
+
158
+ if (providedMin === "auto") {
159
+ if (dataDomain != null) {
160
+ finalMin = Math.min(...dataDomain)
161
+ }
162
+ } else if (isNumber(providedMin)) {
163
+ finalMin = providedMin
164
+ } else if (typeof providedMin === "function") {
165
+ try {
166
+ if (dataDomain != null) {
167
+ finalMin = callDomainFunction(providedMin, dataDomain?.[0])
168
+ }
169
+ } catch {
170
+ /* ignore the exception and compute domain from data later */
171
+ }
172
+ } else if (typeof providedMin === "string" && MIN_VALUE_REG.test(providedMin)) {
173
+ const match = MIN_VALUE_REG.exec(providedMin)
174
+ if (match == null || match[1] == null || dataDomain == null) {
175
+ finalMin = undefined
176
+ } else {
177
+ const value = +match[1]
178
+ finalMin = dataDomain[0] - value
179
+ }
180
+ } else {
181
+ finalMin = dataDomain?.[0]
182
+ }
183
+
184
+ if (providedMax === "auto") {
185
+ if (dataDomain != null) {
186
+ finalMax = Math.max(...dataDomain)
187
+ }
188
+ } else if (isNumber(providedMax)) {
189
+ finalMax = providedMax
190
+ } else if (typeof providedMax === "function") {
191
+ try {
192
+ if (dataDomain != null) {
193
+ finalMax = callDomainFunction(providedMax, dataDomain?.[1])
194
+ }
195
+ } catch {
196
+ /* ignore the exception and compute domain from data later */
197
+ }
198
+ } else if (typeof providedMax === "string" && MAX_VALUE_REG.test(providedMax)) {
199
+ const match = MAX_VALUE_REG.exec(providedMax)
200
+ if (match == null || match[1] == null || dataDomain == null) {
201
+ finalMax = undefined
202
+ } else {
203
+ const value = +match[1]
204
+ finalMax = dataDomain[1] + value
205
+ }
206
+ } else {
207
+ finalMax = dataDomain?.[1]
208
+ }
209
+
210
+ const candidate = [finalMin, finalMax]
211
+ if (isWellFormedNumberDomain(candidate)) {
212
+ if (dataDomain == null) {
213
+ return candidate
214
+ }
215
+ return extendDomain(candidate, dataDomain, allowDataOverflow)
216
+ }
217
+ }
218
+ return undefined
219
+ }
@@ -0,0 +1,7 @@
1
+ export function isWellBehavedNumber(n: unknown): n is number {
2
+ return Number.isFinite(n)
3
+ }
4
+
5
+ export function isPositiveNumber(n: unknown): n is number {
6
+ return typeof n === "number" && n > 0 && Number.isFinite(n)
7
+ }
@@ -0,0 +1,25 @@
1
+ /*
2
+ * getTotalLength forces path geometry (layout) on every call. The line draw animation asks for it
3
+ * on every frame while the path `d` stays fixed, so the length is cached per element and `d`.
4
+ * Keyed by the element itself: the entry dies with the DOM node.
5
+ */
6
+ const measured = new WeakMap<SVGPathElement, { d: string | null; length: number }>()
7
+
8
+ export function pathTotalLength(path: SVGPathElement | null | undefined): number {
9
+ if (path == null || typeof path.getTotalLength !== "function") {
10
+ return 0
11
+ }
12
+ const d = path.getAttribute("d")
13
+ const cached = measured.get(path)
14
+ if (cached != null && cached.d === d) {
15
+ return cached.length
16
+ }
17
+ let length = 0
18
+ try {
19
+ length = path.getTotalLength() || 0
20
+ } catch {
21
+ length = 0
22
+ }
23
+ measured.set(path, { d, length })
24
+ return length
25
+ }