@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,267 @@
1
+ /* eslint-disable import/no-cycle */
2
+ import { getPercentValue, isNumber, isPercent } from "../util/DataUtils"
3
+ import { CartesianViewBoxRequired, TrapezoidViewBox } from "../util/types"
4
+ import { TextAnchor, TextVerticalAnchor } from "../component/Text"
5
+ import { cartesianViewBoxToTrapezoid } from "./cartesianViewBoxToTrapezoid"
6
+
7
+ export type CartesianLabelPosition =
8
+ | "top"
9
+ | "left"
10
+ | "right"
11
+ | "bottom"
12
+ | "inside"
13
+ | "outside"
14
+ | "insideLeft"
15
+ | "insideRight"
16
+ | "insideTop"
17
+ | "insideBottom"
18
+ | "insideTopLeft"
19
+ | "insideBottomLeft"
20
+ | "insideTopRight"
21
+ | "insideBottomRight"
22
+ | "insideStart"
23
+ | "insideEnd"
24
+ | "end"
25
+ | "center"
26
+ | "centerTop"
27
+ | "centerBottom"
28
+ | "middle"
29
+ | {
30
+ x?: number | string
31
+ y?: number | string
32
+ }
33
+
34
+ export type GetCartesianPositionOptions = {
35
+ viewBox: TrapezoidViewBox | CartesianViewBoxRequired
36
+ parentViewBox?: CartesianViewBoxRequired
37
+ /**
38
+ * The offset to the specified "position". Direction of the offset depends on the position.
39
+ */
40
+ offset?: number
41
+ /**
42
+ * The position of the element relative to the view box.
43
+ */
44
+ position?: CartesianLabelPosition
45
+ /**
46
+ * If true, the returned width and height will be clamped to keep the element within the parentViewBox.
47
+ * This is useful for preventing labels from overflowing the chart area.
48
+ */
49
+ clamp?: boolean
50
+ }
51
+
52
+ export type CartesianPosition = {
53
+ x: number
54
+ y: number
55
+ horizontalAnchor: TextAnchor
56
+ verticalAnchor: TextVerticalAnchor
57
+ width?: number
58
+ height?: number
59
+ }
60
+
61
+ export { isOutsidePosition } from "./isOutsidePosition"
62
+
63
+ /**
64
+ * Calculates the position and alignment for a generic element in a Cartesian coordinate system.
65
+ *
66
+ * @param options - The options including viewBox, position, and offset.
67
+ * @returns The calculated x, y, alignment and size.
68
+ */
69
+ export const getCartesianPosition = (options: GetCartesianPositionOptions): CartesianPosition => {
70
+ const { viewBox, position, offset = 0, parentViewBox: parentViewBoxFromOptions, clamp } = options
71
+
72
+ const { x, y, height, upperWidth, lowerWidth } = cartesianViewBoxToTrapezoid(viewBox)
73
+
74
+ /* Funnel.tsx provides a viewBox where `x` is the top-left of the trapezoid shape. */
75
+ const upperX = x
76
+ /* The trapezoid is centered, so we can calculate the other corners from the top-left. */
77
+ const lowerX = x + (upperWidth - lowerWidth) / 2
78
+ /* middleX is the x-coordinate of the left edge at the vertical midpoint of the trapezoid. */
79
+ const middleX = (upperX + lowerX) / 2
80
+ /* The width of the trapezoid at its vertical midpoint. */
81
+ const midHeightWidth = (upperWidth + lowerWidth) / 2
82
+ /* The center x-coordinate is constant for the entire height of the trapezoid. */
83
+ const centerX = upperX + upperWidth / 2
84
+
85
+ /* Define vertical offsets and position inverts based on the value being positive or negative.
86
+ * This allows labels to be positioned correctly for bars with negative height. */
87
+ const verticalSign = height >= 0 ? 1 : -1
88
+ const verticalOffset = verticalSign * offset
89
+ const verticalEnd = verticalSign > 0 ? "end" : "start"
90
+ const verticalStart = verticalSign > 0 ? "start" : "end"
91
+
92
+ /* Define horizontal offsets and position inverts based on the value being positive or negative.
93
+ * This allows labels to be positioned correctly for bars with negative width. */
94
+ const horizontalSign = upperWidth >= 0 ? 1 : -1
95
+ const horizontalOffset = horizontalSign * offset
96
+ const horizontalEnd = horizontalSign > 0 ? "end" : "start"
97
+ const horizontalStart = horizontalSign > 0 ? "start" : "end"
98
+
99
+ /* We assume parentViewBox is generic if provided.
100
+ * The user has asserted that parentViewBox will be CartesianViewBoxRequired if present. */
101
+ const parentViewBox = parentViewBoxFromOptions
102
+
103
+ if (position === "top") {
104
+ const result: CartesianPosition = {
105
+ horizontalAnchor: "middle",
106
+ verticalAnchor: verticalEnd,
107
+ x: upperX + upperWidth / 2,
108
+ y: y - verticalOffset,
109
+ }
110
+
111
+ if (clamp && parentViewBox) {
112
+ result.height = Math.max(y - parentViewBox.y, 0)
113
+ result.width = upperWidth
114
+ }
115
+ return result
116
+ }
117
+
118
+ if (position === "bottom") {
119
+ const result: CartesianPosition = {
120
+ horizontalAnchor: "middle",
121
+ verticalAnchor: verticalStart,
122
+ x: lowerX + lowerWidth / 2,
123
+ y: y + height + verticalOffset,
124
+ }
125
+ if (clamp && parentViewBox) {
126
+ result.height = Math.max(parentViewBox.y + parentViewBox.height - (y + height), 0)
127
+ result.width = lowerWidth
128
+ }
129
+ return result
130
+ }
131
+
132
+ if (position === "left") {
133
+ const result: CartesianPosition = {
134
+ horizontalAnchor: horizontalEnd,
135
+ verticalAnchor: "middle",
136
+ x: middleX - horizontalOffset,
137
+ y: y + height / 2,
138
+ }
139
+ if (clamp && parentViewBox) {
140
+ result.width = Math.max(result.x - parentViewBox.x, 0)
141
+ result.height = height
142
+ }
143
+ return result
144
+ }
145
+
146
+ if (position === "right") {
147
+ const result: CartesianPosition = {
148
+ horizontalAnchor: horizontalStart,
149
+ verticalAnchor: "middle",
150
+ x: middleX + midHeightWidth + horizontalOffset,
151
+ y: y + height / 2,
152
+ }
153
+ if (clamp && parentViewBox) {
154
+ result.width = Math.max(parentViewBox.x + parentViewBox.width - result.x, 0)
155
+ result.height = height
156
+ }
157
+ return result
158
+ }
159
+
160
+ const sizeAttrs = clamp && parentViewBox ? { height, width: midHeightWidth } : {}
161
+
162
+ if (position === "insideLeft") {
163
+ return {
164
+ horizontalAnchor: horizontalStart,
165
+ verticalAnchor: "middle",
166
+ x: middleX + horizontalOffset,
167
+ y: y + height / 2,
168
+ ...sizeAttrs,
169
+ }
170
+ }
171
+
172
+ if (position === "insideRight") {
173
+ return {
174
+ horizontalAnchor: horizontalEnd,
175
+ verticalAnchor: "middle",
176
+ x: middleX + midHeightWidth - horizontalOffset,
177
+ y: y + height / 2,
178
+ ...sizeAttrs,
179
+ }
180
+ }
181
+
182
+ if (position === "insideTop") {
183
+ return {
184
+ horizontalAnchor: "middle",
185
+ verticalAnchor: verticalStart,
186
+ x: upperX + upperWidth / 2,
187
+ y: y + verticalOffset,
188
+ ...sizeAttrs,
189
+ }
190
+ }
191
+
192
+ if (position === "insideBottom") {
193
+ return {
194
+ horizontalAnchor: "middle",
195
+ verticalAnchor: verticalEnd,
196
+ x: lowerX + lowerWidth / 2,
197
+ y: y + height - verticalOffset,
198
+ ...sizeAttrs,
199
+ }
200
+ }
201
+
202
+ if (position === "insideTopLeft") {
203
+ return {
204
+ horizontalAnchor: horizontalStart,
205
+ verticalAnchor: verticalStart,
206
+ x: upperX + horizontalOffset,
207
+ y: y + verticalOffset,
208
+ ...sizeAttrs,
209
+ }
210
+ }
211
+
212
+ if (position === "insideTopRight") {
213
+ return {
214
+ horizontalAnchor: horizontalEnd,
215
+ verticalAnchor: verticalStart,
216
+ x: upperX + upperWidth - horizontalOffset,
217
+ y: y + verticalOffset,
218
+ ...sizeAttrs,
219
+ }
220
+ }
221
+
222
+ if (position === "insideBottomLeft") {
223
+ return {
224
+ horizontalAnchor: horizontalStart,
225
+ verticalAnchor: verticalEnd,
226
+ x: lowerX + horizontalOffset,
227
+ y: y + height - verticalOffset,
228
+ ...sizeAttrs,
229
+ }
230
+ }
231
+
232
+ if (position === "insideBottomRight") {
233
+ return {
234
+ horizontalAnchor: horizontalEnd,
235
+ verticalAnchor: verticalEnd,
236
+ x: lowerX + lowerWidth - horizontalOffset,
237
+ y: y + height - verticalOffset,
238
+ ...sizeAttrs,
239
+ }
240
+ }
241
+
242
+ if (
243
+ position != null &&
244
+ typeof position === "object" &&
245
+ (isNumber(position.x) || isPercent(position.x)) &&
246
+ (isNumber(position.y) || isPercent(position.y))
247
+ ) {
248
+ /* TODO: This is not quite right. The width of the trapezoid changes with y.
249
+ * A percentage-based x should be relative to the width at that y.
250
+ * For now, we use the mid-height width as a reasonable approximation. */
251
+ return {
252
+ horizontalAnchor: "end",
253
+ verticalAnchor: "end",
254
+ x: x + getPercentValue(position.x, midHeightWidth),
255
+ y: y + getPercentValue(position.y, height),
256
+ ...sizeAttrs,
257
+ }
258
+ }
259
+
260
+ return {
261
+ horizontalAnchor: "middle",
262
+ verticalAnchor: "middle",
263
+ x: centerX,
264
+ y: y + height / 2,
265
+ ...sizeAttrs,
266
+ }
267
+ }
@@ -0,0 +1,144 @@
1
+ /* eslint-disable import/no-cycle */
2
+ import { isVisible } from "../util/TickUtils"
3
+ import { CartesianTickItem } from "../util/types"
4
+ import { getEveryNth } from "../util/getEveryNth"
5
+ import { Sign } from "./getTicks"
6
+
7
+ export function getEquidistantTicks(
8
+ sign: Sign,
9
+ boundaries: { start: number; end: number },
10
+ getTickSize: (tick: CartesianTickItem, index: number) => number,
11
+ ticks: ReadonlyArray<CartesianTickItem>,
12
+ minTickGap: number,
13
+ ): ReadonlyArray<CartesianTickItem> {
14
+ /* If the ticks are readonly, then the slice might not be necessary */
15
+ const result = (ticks || []).slice()
16
+
17
+ const { start: initialStart, end } = boundaries
18
+ let index = 0
19
+ /* Premature optimisation idea 1: Estimate a lower bound, and start from there.
20
+ * For now, start from every tick */
21
+ let stepsize = 1
22
+ let start = initialStart
23
+
24
+ while (stepsize <= result.length) {
25
+ /* Given stepsize, evaluate whether every stepsize-th tick can be shown.
26
+ * If it can not, then increase the stepsize by 1, and try again. */
27
+
28
+ const entry = ticks?.[index]
29
+
30
+ /* Break condition - If we have evaluated all the ticks, then we are done. */
31
+ if (entry === undefined) {
32
+ return getEveryNth(ticks, stepsize)
33
+ }
34
+
35
+ /* Check if the element collides with the next element */
36
+ const i = index
37
+ let size: number | undefined
38
+ const getSize = () => {
39
+ if (size === undefined) {
40
+ size = getTickSize(entry, i)
41
+ }
42
+
43
+ return size
44
+ }
45
+
46
+ const tickCoord = entry.coordinate
47
+ /* We will always show the first tick. */
48
+ const isShow = index === 0 || isVisible(sign, tickCoord, getSize, start, end)
49
+
50
+ if (!isShow) {
51
+ /* Start all over with a larger stepsize */
52
+ index = 0
53
+ start = initialStart
54
+ stepsize += 1
55
+ }
56
+
57
+ if (isShow) {
58
+ /* If it can be shown, update the start */
59
+ start = tickCoord + sign * (getSize() / 2 + minTickGap)
60
+ index += stepsize
61
+ }
62
+ }
63
+
64
+ return []
65
+ }
66
+
67
+ export function getEquidistantPreserveEndTicks(
68
+ sign: Sign,
69
+ boundaries: { start: number; end: number },
70
+ getTickSize: (tick: CartesianTickItem, index: number) => number,
71
+ ticks: ReadonlyArray<CartesianTickItem>,
72
+ minTickGap: number,
73
+ ): ReadonlyArray<CartesianTickItem> {
74
+ /* If the ticks are readonly, then the slice might not be necessary */
75
+ /* Reworked logic for getEquidistantPreserveEndTicks */
76
+ const result = (ticks || []).slice()
77
+ const len = result.length
78
+
79
+ if (len === 0) {
80
+ return []
81
+ }
82
+
83
+ const { start: initialStart, end } = boundaries
84
+
85
+ /* Start with stepsize = 1 (every tick) up to the maximum possible stepsize (len) */
86
+ for (let stepsize = 1; stepsize <= len; stepsize++) {
87
+ /* 1. Calculate the offset so the last tick (index len - 1) is always included in the sequence. */
88
+ const offset = (len - 1) % stepsize
89
+ let start = initialStart
90
+ let ok = true
91
+
92
+ /* 2. Iterate through the end-anchored sequence: offset, offset + stepsize, ..., len - 1 */
93
+ for (let index = offset; index < len; index += stepsize) {
94
+ const entry = ticks[index]
95
+ if (entry == null) {
96
+ continue
97
+ }
98
+ const i = index
99
+ let size: number | undefined
100
+
101
+ /* Use a function to get size, as in the original code */
102
+ const getSize = () => {
103
+ if (size === undefined) {
104
+ size = getTickSize(entry, i)
105
+ }
106
+ return size
107
+ }
108
+
109
+ const tickCoord = entry.coordinate
110
+
111
+ /* 3. Apply visibility logic (including the first tick special case)
112
+ * The reviewer says *not* to unconditionally bypass checks for the last tick. */
113
+ const isShow = index === offset || isVisible(sign, tickCoord, getSize, start, end)
114
+
115
+ if (!isShow) {
116
+ /* If any tick in this end-anchored sequence fails visibility/collision,
117
+ * reject this stepsize and move to the next iteration (larger stepsize). */
118
+ ok = false
119
+ break
120
+ }
121
+
122
+ /* 4. If showable, update the 'start' coordinate for the next collision check */
123
+ if (isShow) {
124
+ start = tickCoord + sign * (getSize() / 2 + minTickGap)
125
+ }
126
+ }
127
+
128
+ /* 5. If the entire sequence for this stepsize passed the visibility check, return the result */
129
+ if (ok) {
130
+ /* Build the final result array explicitly using the validated stepsize and offset. */
131
+ const finalTicks: CartesianTickItem[] = []
132
+ for (let index = offset; index < len; index += stepsize) {
133
+ const tick = ticks[index]
134
+ if (tick != null) {
135
+ finalTicks.push(tick)
136
+ }
137
+ }
138
+ return finalTicks
139
+ }
140
+ }
141
+
142
+ /* If no stepsize works (this shouldn't happen unless minTickGap is huge), return an empty array. */
143
+ return []
144
+ }
@@ -0,0 +1,225 @@
1
+ /* eslint-disable import/no-cycle */
2
+ import { CartesianTickItem, CartesianViewBoxRequired, Size } from "../util/types"
3
+ import { mathSign, isNumber } from "../util/DataUtils"
4
+ import { getStringSize } from "../util/DOMUtils"
5
+ import { Global } from "../util/Global"
6
+ import {
7
+ isVisible,
8
+ getTickBoundaries,
9
+ getNumberIntervalTicks,
10
+ getAngledTickWidth,
11
+ } from "../util/TickUtils"
12
+ import { getEquidistantTicks, getEquidistantPreserveEndTicks } from "./getEquidistantTicks"
13
+ import {
14
+ CartesianAxisSettings,
15
+ XAxisOrientation,
16
+ YAxisOrientation,
17
+ } from "../state/cartesianAxisSlice"
18
+
19
+ export type Sign = 0 | 1 | -1
20
+
21
+ function getTicksEnd(
22
+ sign: Sign,
23
+ boundaries: { start: number; end: number },
24
+ getTickSize: (tick: CartesianTickItem, index: number) => number,
25
+ ticks: ReadonlyArray<CartesianTickItem>,
26
+ minTickGap: number,
27
+ ): ReadonlyArray<CartesianTickItem> {
28
+ const result = (ticks || []).slice()
29
+ const len = result.length
30
+
31
+ const { start } = boundaries
32
+ let { end } = boundaries
33
+
34
+ for (let i = len - 1; i >= 0; i--) {
35
+ const initialEntry = result[i]
36
+ if (initialEntry == null) {
37
+ continue
38
+ }
39
+ let entry = initialEntry
40
+ let size: number | undefined
41
+ const getSize = () => {
42
+ if (size === undefined) {
43
+ size = getTickSize(initialEntry, i)
44
+ }
45
+
46
+ return size
47
+ }
48
+
49
+ if (i === len - 1) {
50
+ const gap = sign * (entry.coordinate + (sign * getSize()) / 2 - end)
51
+ result[i] = entry = {
52
+ ...entry,
53
+ tickCoord: gap > 0 ? entry.coordinate - gap * sign : entry.coordinate,
54
+ }
55
+ } else {
56
+ result[i] = entry = { ...entry, tickCoord: entry.coordinate }
57
+ }
58
+
59
+ if (entry.tickCoord != null) {
60
+ const isShow = isVisible(sign, entry.tickCoord, getSize, start, end)
61
+
62
+ if (isShow) {
63
+ end = entry.tickCoord - sign * (getSize() / 2 + minTickGap)
64
+ result[i] = { ...entry, isShow: true }
65
+ }
66
+ }
67
+ }
68
+
69
+ return result
70
+ }
71
+
72
+ function getTicksStart(
73
+ sign: Sign,
74
+ boundaries: { start: number; end: number },
75
+ getTickSize: (tick: CartesianTickItem, index: number) => number,
76
+ ticks: ReadonlyArray<CartesianTickItem>,
77
+ minTickGap: number,
78
+ preserveEnd?: boolean,
79
+ ): ReadonlyArray<CartesianTickItem> {
80
+ /* This method is mutating the array so clone is indeed necessary here */
81
+ const result: Array<CartesianTickItem> = (ticks || []).slice()
82
+ const len = result.length
83
+
84
+ let { start, end } = boundaries
85
+
86
+ if (preserveEnd) {
87
+ /* Try to guarantee the tail to be displayed */
88
+ let tail = ticks[len - 1]
89
+ if (tail != null) {
90
+ const tailSize = getTickSize(tail, len - 1)
91
+ const tailGap = sign * (tail.coordinate + (sign * tailSize) / 2 - end)
92
+ result[len - 1] = tail = {
93
+ ...tail,
94
+ tickCoord: tailGap > 0 ? tail.coordinate - tailGap * sign : tail.coordinate,
95
+ }
96
+
97
+ if (tail.tickCoord != null) {
98
+ const isTailShow = isVisible(sign, tail.tickCoord, () => tailSize, start, end)
99
+
100
+ if (isTailShow) {
101
+ end = tail.tickCoord - sign * (tailSize / 2 + minTickGap)
102
+ result[len - 1] = { ...tail, isShow: true }
103
+ }
104
+ }
105
+ }
106
+ }
107
+
108
+ const count = preserveEnd ? len - 1 : len
109
+ for (let i = 0; i < count; i++) {
110
+ const initialEntry = result[i]
111
+ if (initialEntry == null) {
112
+ continue
113
+ }
114
+ let entry = initialEntry
115
+ let size: number | undefined
116
+ const getSize = () => {
117
+ if (size === undefined) {
118
+ size = getTickSize(initialEntry, i)
119
+ }
120
+
121
+ return size
122
+ }
123
+
124
+ if (i === 0) {
125
+ const gap = sign * (entry.coordinate - (sign * getSize()) / 2 - start)
126
+ result[i] = entry = {
127
+ ...entry,
128
+ tickCoord: gap < 0 ? entry.coordinate - gap * sign : entry.coordinate,
129
+ }
130
+ } else {
131
+ result[i] = entry = { ...entry, tickCoord: entry.coordinate }
132
+ }
133
+
134
+ if (entry.tickCoord != null) {
135
+ const isShow = isVisible(sign, entry.tickCoord, getSize, start, end)
136
+
137
+ if (isShow) {
138
+ start = entry.tickCoord + sign * (getSize() / 2 + minTickGap)
139
+ result[i] = { ...entry, isShow: true }
140
+ }
141
+ }
142
+ }
143
+
144
+ return result
145
+ }
146
+
147
+ export type GetTicksInput = {
148
+ angle?: number
149
+ interval: CartesianAxisSettings["interval"] | undefined
150
+ minTickGap: number
151
+ orientation: XAxisOrientation | YAxisOrientation
152
+ tick: CartesianAxisSettings["tick"]
153
+ tickFormatter?: CartesianAxisSettings["tickFormatter"]
154
+ ticks: ReadonlyArray<CartesianTickItem> | null
155
+ unit?: CartesianAxisSettings["unit"]
156
+ viewBox: CartesianViewBoxRequired
157
+ }
158
+
159
+ export function getTicks(
160
+ props: GetTicksInput,
161
+ fontSize?: string,
162
+ letterSpacing?: string,
163
+ ): ReadonlyArray<CartesianTickItem> {
164
+ const { tick, ticks, viewBox, minTickGap, orientation, interval, tickFormatter, unit, angle } =
165
+ props
166
+
167
+ if (!ticks || !ticks.length || !tick) {
168
+ return []
169
+ }
170
+
171
+ if (isNumber(interval) || Global.isSsr) {
172
+ return getNumberIntervalTicks(ticks, isNumber(interval) ? interval : 0) ?? []
173
+ }
174
+
175
+ let candidates: ReadonlyArray<CartesianTickItem> = []
176
+
177
+ const sizeKey = orientation === "top" || orientation === "bottom" ? "width" : "height"
178
+ const unitSize: Size =
179
+ unit && sizeKey === "width"
180
+ ? getStringSize(unit, { "font-size": fontSize, "letter-spacing": letterSpacing })
181
+ : { height: 0, width: 0 }
182
+
183
+ const getTickSize = (content: CartesianTickItem, index: number) => {
184
+ const value =
185
+ typeof tickFormatter === "function" ? tickFormatter(content.value, index) : content.value
186
+ /* Recharts only supports angles when sizeKey === 'width' */
187
+ return sizeKey === "width"
188
+ ? getAngledTickWidth(
189
+ getStringSize(value, { "font-size": fontSize, "letter-spacing": letterSpacing }),
190
+ unitSize,
191
+ angle,
192
+ )
193
+ : getStringSize(value, { "font-size": fontSize, "letter-spacing": letterSpacing })[sizeKey]
194
+ }
195
+
196
+ const tick0 = ticks[0]
197
+ const tick1 = ticks[1]
198
+ const sign =
199
+ ticks.length >= 2 && tick0 != null && tick1 != null
200
+ ? mathSign(tick1.coordinate - tick0.coordinate)
201
+ : 1
202
+ const boundaries = getTickBoundaries(viewBox, sign, sizeKey)
203
+
204
+ if (interval === "equidistantPreserveStart") {
205
+ return getEquidistantTicks(sign, boundaries, getTickSize, ticks, minTickGap)
206
+ }
207
+ if (interval === "equidistantPreserveEnd") {
208
+ return getEquidistantPreserveEndTicks(sign, boundaries, getTickSize, ticks, minTickGap)
209
+ }
210
+
211
+ if (interval === "preserveStart" || interval === "preserveStartEnd") {
212
+ candidates = getTicksStart(
213
+ sign,
214
+ boundaries,
215
+ getTickSize,
216
+ ticks,
217
+ minTickGap,
218
+ interval === "preserveStartEnd",
219
+ )
220
+ } else {
221
+ candidates = getTicksEnd(sign, boundaries, getTickSize, ticks, minTickGap)
222
+ }
223
+
224
+ return candidates.filter((entry) => entry.isShow)
225
+ }
@@ -0,0 +1,15 @@
1
+ const absolutePositions: ReadonlyArray<string> = ["top", "left", "right", "bottom"]
2
+
3
+ /**
4
+ * True when the legend (or label) sits outside the plot: `top`/`left`/`right`/`bottom`,
5
+ * or a coordinate object. Inside keywords (`insideTop`, …) return false.
6
+ */
7
+ export function isOutsidePosition(position: unknown): boolean {
8
+ if (position == null) {
9
+ return false
10
+ }
11
+ if (typeof position === "object") {
12
+ return true
13
+ }
14
+ return typeof position === "string" && absolutePositions.includes(position)
15
+ }
@@ -0,0 +1,54 @@
1
+ import { untrack } from "solid-js"
2
+ import type { Accessor } from "solid-js"
3
+ import { round } from "../util/round"
4
+
5
+ /**
6
+ * Tracks the animated visible length of a Line's SVG path across data changes.
7
+ *
8
+ * Invariants:
9
+ * 1. The visible length only grows (monotonically non-decreasing with animationElapsedTime).
10
+ * 2. The visible length changes continuously — no jumps when data changes mid-animation.
11
+ * This is achieved by tracking the maximum animated length in pixels and using it
12
+ * as the starting point for the next animation.
13
+ * 3. Once the line reaches 100% visibility, it never becomes partially visible again.
14
+ * In that case the callback returns `null`, meaning no animation stroke-dasharray is needed.
15
+ *
16
+ * @param animationInput Identity of the current data. When it changes, the next call
17
+ * starts a new animation from the current visible length.
18
+ * @returns A callback `(animationElapsedTime, totalLength) => number | null` where:
19
+ * - `animationElapsedTime` is the animation progress (0 to 1)
20
+ * - `totalLength` is the current total length of the SVG path in pixels
21
+ * - returns the visible length in pixels, or `null` if the line is fully visible
22
+ */
23
+ export function useAnimatedLineLength(
24
+ animationInput: Accessor<unknown>,
25
+ ): (animationElapsedTime: number, totalLength: number) => number | null {
26
+ let startingLength = 0
27
+ let maxAnimatedLength = 0
28
+ let reachedFull = false
29
+ let prevInput = untrack(animationInput)
30
+
31
+ return (animationElapsedTime: number, totalLength: number): number | null => {
32
+ const input = animationInput()
33
+ if (input !== prevInput) {
34
+ startingLength = maxAnimatedLength
35
+ prevInput = input
36
+ }
37
+
38
+ if (reachedFull) {
39
+ return null
40
+ }
41
+
42
+ const visibleLength = Math.min(round(startingLength + animationElapsedTime * totalLength), totalLength)
43
+
44
+ if (animationElapsedTime > 0 && totalLength > 0) {
45
+ maxAnimatedLength = Math.max(maxAnimatedLength, visibleLength)
46
+ if (visibleLength >= totalLength) {
47
+ reachedFull = true
48
+ return null
49
+ }
50
+ }
51
+
52
+ return visibleLength
53
+ }
54
+ }