solid-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 (639) hide show
  1. package/NEXT_SESSION_PROMPT.md +114 -0
  2. package/package.json +28 -0
  3. package/src/animation/AnimatedItems.tsx +169 -0
  4. package/src/animation/AnimationController.ts +24 -0
  5. package/src/animation/AnimationControllerImpl.ts +37 -0
  6. package/src/animation/AnimationHandle.ts +273 -0
  7. package/src/animation/CSSTransitionAnimate.tsx +142 -0
  8. package/src/animation/JavascriptAnimate.tsx +107 -0
  9. package/src/animation/easing.ts +261 -0
  10. package/src/animation/matchBy.ts +211 -0
  11. package/src/animation/timeoutController.ts +51 -0
  12. package/src/animation/useAnimationController.tsx +31 -0
  13. package/src/animation/useAnimationStartSnapshot.ts +73 -0
  14. package/src/animation/util.ts +16 -0
  15. package/src/cartesian/Area.tsx +810 -0
  16. package/src/cartesian/AreaRevealShape.tsx +250 -0
  17. package/src/cartesian/Bar.tsx +1216 -0
  18. package/src/cartesian/BarStack.tsx +148 -0
  19. package/src/cartesian/Brush.tsx +653 -0
  20. package/src/cartesian/CartesianAxis.tsx +541 -0
  21. package/src/cartesian/CartesianGrid.tsx +605 -0
  22. package/src/cartesian/ErrorBar.tsx +319 -0
  23. package/src/cartesian/Funnel.tsx +594 -0
  24. package/src/cartesian/GraphicalItemClipPath.tsx +75 -0
  25. package/src/cartesian/Line.tsx +742 -0
  26. package/src/cartesian/LineDrawShape.tsx +190 -0
  27. package/src/cartesian/ReferenceArea.tsx +275 -0
  28. package/src/cartesian/ReferenceDot.tsx +286 -0
  29. package/src/cartesian/ReferenceLine.tsx +414 -0
  30. package/src/cartesian/RenderedTicksReporter.tsx +49 -0
  31. package/src/cartesian/Scatter.tsx +741 -0
  32. package/src/cartesian/XAxis.tsx +293 -0
  33. package/src/cartesian/YAxis.tsx +333 -0
  34. package/src/cartesian/ZAxis.tsx +80 -0
  35. package/src/cartesian/getCartesianPosition.ts +255 -0
  36. package/src/cartesian/getEquidistantTicks.ts +126 -0
  37. package/src/cartesian/getTicks.ts +225 -0
  38. package/src/cartesian/useAnimatedLineLength.ts +84 -0
  39. package/src/chart/AreaChart.tsx +30 -0
  40. package/src/chart/BarChart.tsx +27 -0
  41. package/src/chart/CartesianChart.tsx +91 -0
  42. package/src/chart/CategoricalChart.tsx +60 -0
  43. package/src/chart/ComposedChart.tsx +29 -0
  44. package/src/chart/FunnelChart.tsx +29 -0
  45. package/src/chart/LineChart.tsx +29 -0
  46. package/src/chart/PieChart.tsx +41 -0
  47. package/src/chart/PolarChart.tsx +97 -0
  48. package/src/chart/RadarChart.tsx +37 -0
  49. package/src/chart/RadialBarChart.tsx +39 -0
  50. package/src/chart/RechartsWrapper.tsx +486 -0
  51. package/src/chart/Sankey.tsx +992 -0
  52. package/src/chart/ScatterChart.tsx +29 -0
  53. package/src/chart/SunburstChart.tsx +394 -0
  54. package/src/chart/Treemap.tsx +874 -0
  55. package/src/chart/types.ts +37 -0
  56. package/src/component/ActivePoints.tsx +136 -0
  57. package/src/component/Cell.tsx +72 -0
  58. package/src/component/Cursor.tsx +249 -0
  59. package/src/component/Customized.tsx +8 -0
  60. package/src/component/DefaultLegendContent.tsx +205 -0
  61. package/src/component/DefaultTooltipContent.tsx +247 -0
  62. package/src/component/Dots.tsx +128 -0
  63. package/src/component/Label.tsx +507 -0
  64. package/src/component/LabelList.tsx +270 -0
  65. package/src/component/Legend.tsx +273 -0
  66. package/src/component/ResponsiveContainer.tsx +397 -0
  67. package/src/component/Text.tsx +436 -0
  68. package/src/component/Tooltip.tsx +309 -0
  69. package/src/component/TooltipBoundingBox.tsx +152 -0
  70. package/src/component/responsiveContainerUtils.ts +128 -0
  71. package/src/container/ClipPathProvider.tsx +40 -0
  72. package/src/container/Layer.tsx +38 -0
  73. package/src/container/RootSurface.tsx +124 -0
  74. package/src/container/Surface.tsx +70 -0
  75. package/src/context/ErrorBarContext.tsx +85 -0
  76. package/src/context/PanoramaContext.tsx +13 -0
  77. package/src/context/RegisterGraphicalItemId.tsx +41 -0
  78. package/src/context/accessibilityContext.tsx +10 -0
  79. package/src/context/brushUpdateContext.ts +14 -0
  80. package/src/context/chartDataContext.tsx +79 -0
  81. package/src/context/chartLayoutContext.tsx +158 -0
  82. package/src/context/legendPayloadContext.ts +11 -0
  83. package/src/context/legendPortalContext.ts +11 -0
  84. package/src/context/tooltipContext.ts +72 -0
  85. package/src/context/tooltipPortalContext.ts +14 -0
  86. package/src/context/useTooltipAxis.ts +24 -0
  87. package/src/hooks.ts +312 -0
  88. package/src/index.ts +288 -0
  89. package/src/polar/Pie.tsx +912 -0
  90. package/src/polar/PolarAngleAxis.tsx +494 -0
  91. package/src/polar/PolarGrid.tsx +269 -0
  92. package/src/polar/PolarRadiusAxis.tsx +422 -0
  93. package/src/polar/Radar.tsx +652 -0
  94. package/src/polar/RadialBar.tsx +767 -0
  95. package/src/polar/defaultPolarAngleAxisProps.tsx +33 -0
  96. package/src/polar/defaultPolarRadiusAxisProps.tsx +28 -0
  97. package/src/shape/Cross.tsx +83 -0
  98. package/src/shape/Curve.tsx +335 -0
  99. package/src/shape/Dot.tsx +49 -0
  100. package/src/shape/Polygon.tsx +168 -0
  101. package/src/shape/Rectangle.tsx +301 -0
  102. package/src/shape/Sector.tsx +304 -0
  103. package/src/shape/Symbols.tsx +144 -0
  104. package/src/shape/Trapezoid.tsx +228 -0
  105. package/src/state/RechartsReduxContext.tsx +8 -0
  106. package/src/state/RechartsStoreContext.ts +15 -0
  107. package/src/state/RechartsStoreProvider.tsx +27 -0
  108. package/src/state/ReportChartProps.tsx +19 -0
  109. package/src/state/ReportEventSettings.tsx +19 -0
  110. package/src/state/ReportMainChartProps.tsx +35 -0
  111. package/src/state/ReportPolarOptions.tsx +28 -0
  112. package/src/state/SetLegendPayload.ts +50 -0
  113. package/src/state/SetTooltipEntrySettings.tsx +46 -0
  114. package/src/state/brushSlice.ts +60 -0
  115. package/src/state/cartesianAxisSlice.ts +288 -0
  116. package/src/state/chartDataSlice.ts +115 -0
  117. package/src/state/errorBarSlice.ts +84 -0
  118. package/src/state/eventSettingsSlice.ts +41 -0
  119. package/src/state/externalEventsMiddleware.ts +136 -0
  120. package/src/state/graphicalItemsSlice.ts +162 -0
  121. package/src/state/hooks.ts +42 -0
  122. package/src/state/keyboardEventsMiddleware.ts +213 -0
  123. package/src/state/layoutSlice.ts +71 -0
  124. package/src/state/legendSlice.ts +107 -0
  125. package/src/state/mouseEventsMiddleware.ts +103 -0
  126. package/src/state/optionsSlice.ts +64 -0
  127. package/src/state/polarAxisSlice.ts +65 -0
  128. package/src/state/polarOptionsSlice.ts +54 -0
  129. package/src/state/reduxDevtoolsJsonStringifyReplacer.ts +15 -0
  130. package/src/state/referenceElementsSlice.ts +121 -0
  131. package/src/state/renderedTicksSlice.ts +61 -0
  132. package/src/state/rootPropsSlice.ts +70 -0
  133. package/src/state/selectors/areaSelectors.ts +169 -0
  134. package/src/state/selectors/arrayEqualityCheck.ts +8 -0
  135. package/src/state/selectors/axisSelectors.ts +2196 -0
  136. package/src/state/selectors/barSelectors.ts +319 -0
  137. package/src/state/selectors/barStackSelectors.ts +79 -0
  138. package/src/state/selectors/brushSelectors.ts +40 -0
  139. package/src/state/selectors/combiners/combineActiveLabel.ts +21 -0
  140. package/src/state/selectors/combiners/combineActiveTooltipIndex.ts +93 -0
  141. package/src/state/selectors/combiners/combineAllBarPositions.ts +131 -0
  142. package/src/state/selectors/combiners/combineAxisRangeWithReverse.ts +17 -0
  143. package/src/state/selectors/combiners/combineBarPosition.ts +24 -0
  144. package/src/state/selectors/combiners/combineBarSizeList.ts +75 -0
  145. package/src/state/selectors/combiners/combineCheckedDomain.ts +49 -0
  146. package/src/state/selectors/combiners/combineConfiguredScale.ts +121 -0
  147. package/src/state/selectors/combiners/combineCoordinateForDefaultIndex.ts +43 -0
  148. package/src/state/selectors/combiners/combineDisplayedStackedData.ts +50 -0
  149. package/src/state/selectors/combiners/combineInverseScaleFunction.ts +17 -0
  150. package/src/state/selectors/combiners/combineRealScaleType.ts +48 -0
  151. package/src/state/selectors/combiners/combineStackedData.ts +28 -0
  152. package/src/state/selectors/combiners/combineTooltipInteractionState.ts +86 -0
  153. package/src/state/selectors/combiners/combineTooltipPayload.ts +203 -0
  154. package/src/state/selectors/combiners/combineTooltipPayloadConfigurations.ts +45 -0
  155. package/src/state/selectors/containerSelectors.ts +12 -0
  156. package/src/state/selectors/dataSelectors.ts +90 -0
  157. package/src/state/selectors/funnelSelectors.ts +83 -0
  158. package/src/state/selectors/graphicalItemSelectors.ts +23 -0
  159. package/src/state/selectors/legendSelectors.ts +29 -0
  160. package/src/state/selectors/lineSelectors.ts +111 -0
  161. package/src/state/selectors/numberDomainEqualityCheck.ts +8 -0
  162. package/src/state/selectors/pickAxisId.ts +6 -0
  163. package/src/state/selectors/pickAxisType.ts +4 -0
  164. package/src/state/selectors/pieSelectors.ts +103 -0
  165. package/src/state/selectors/polarAxisSelectors.ts +202 -0
  166. package/src/state/selectors/polarGridSelectors.ts +24 -0
  167. package/src/state/selectors/polarScaleSelectors.ts +149 -0
  168. package/src/state/selectors/polarSelectors.ts +211 -0
  169. package/src/state/selectors/radarSelectors.ts +152 -0
  170. package/src/state/selectors/radialBarSelectors.ts +328 -0
  171. package/src/state/selectors/rootPropsSelectors.ts +36 -0
  172. package/src/state/selectors/scatterSelectors.ts +77 -0
  173. package/src/state/selectors/selectAllAxes.ts +10 -0
  174. package/src/state/selectors/selectChartOffset.ts +15 -0
  175. package/src/state/selectors/selectChartOffsetInternal.ts +111 -0
  176. package/src/state/selectors/selectPlotArea.ts +27 -0
  177. package/src/state/selectors/selectTooltipAxisId.ts +6 -0
  178. package/src/state/selectors/selectTooltipAxisType.ts +33 -0
  179. package/src/state/selectors/selectTooltipEventType.ts +45 -0
  180. package/src/state/selectors/selectTooltipPayloadSearcher.ts +7 -0
  181. package/src/state/selectors/selectTooltipSettings.ts +6 -0
  182. package/src/state/selectors/selectTooltipState.ts +5 -0
  183. package/src/state/selectors/tooltipSelectors.ts +690 -0
  184. package/src/state/selectors/touchSelectors.ts +29 -0
  185. package/src/state/store.ts +167 -0
  186. package/src/state/tooltipSlice.ts +289 -0
  187. package/src/state/types/AreaSettings.ts +17 -0
  188. package/src/state/types/BarSettings.ts +16 -0
  189. package/src/state/types/LineSettings.ts +12 -0
  190. package/src/state/types/PieSettings.ts +32 -0
  191. package/src/state/types/RadarSettings.ts +6 -0
  192. package/src/state/types/RadialBarSettings.ts +10 -0
  193. package/src/state/types/ScatterSettings.ts +13 -0
  194. package/src/state/types/StackedGraphicalItem.ts +33 -0
  195. package/src/state/unregisterOnCleanup.ts +26 -0
  196. package/src/state/zIndexSlice.ts +128 -0
  197. package/src/synchronisation/syncRegistry.ts +131 -0
  198. package/src/synchronisation/syncSelectors.ts +7 -0
  199. package/src/synchronisation/types.ts +42 -0
  200. package/src/synchronisation/useChartSynchronisation.tsx +372 -0
  201. package/src/types.ts +39 -0
  202. package/src/util/ActiveShapeUtils.tsx +80 -0
  203. package/src/util/BarUtils.tsx +74 -0
  204. package/src/util/CartesianUtils.ts +53 -0
  205. package/src/util/ChartUtils.ts +696 -0
  206. package/src/util/Constants.ts +42 -0
  207. package/src/util/CssPrefixUtils.ts +24 -0
  208. package/src/util/DOMUtils.ts +141 -0
  209. package/src/util/DataUtils.ts +205 -0
  210. package/src/util/FunnelUtils.tsx +37 -0
  211. package/src/util/Global.ts +15 -0
  212. package/src/util/IfOverflow.ts +17 -0
  213. package/src/util/LRUCache.ts +46 -0
  214. package/src/util/LogUtils.ts +26 -0
  215. package/src/util/PolarUtils.ts +134 -0
  216. package/src/util/RadialBarUtils.tsx +35 -0
  217. package/src/util/ReduceCSSCalc.ts +186 -0
  218. package/src/util/ShallowEqual.ts +43 -0
  219. package/src/util/TickUtils.ts +61 -0
  220. package/src/util/YAxisUtils.ts +49 -0
  221. package/src/util/adaptEventHandlers.ts +69 -0
  222. package/src/util/axisPropsAreEqual.ts +42 -0
  223. package/src/util/collectionUtils.ts +83 -0
  224. package/src/util/createCartesianCharts.tsx +101 -0
  225. package/src/util/createEventProxy.ts +24 -0
  226. package/src/util/createPolarCharts.tsx +86 -0
  227. package/src/util/cursor/getCursorPoints.ts +48 -0
  228. package/src/util/cursor/getCursorRectangle.ts +31 -0
  229. package/src/util/cursor/getRadialCursorPoints.ts +34 -0
  230. package/src/util/excludeEventProps.ts +172 -0
  231. package/src/util/getActiveCoordinate.ts +205 -0
  232. package/src/util/getAxisTypeBasedOnLayout.ts +21 -0
  233. package/src/util/getEveryNth.ts +30 -0
  234. package/src/util/getRadiusAndStrokeWidthFromDot.ts +35 -0
  235. package/src/util/getRelativeCoordinate.ts +84 -0
  236. package/src/util/getSliced.ts +21 -0
  237. package/src/util/isDomainSpecifiedByUser.ts +217 -0
  238. package/src/util/isWellBehavedNumber.ts +10 -0
  239. package/src/util/objectPath.ts +129 -0
  240. package/src/util/payload/getUniqPayload.ts +31 -0
  241. package/src/util/propsAreEqual.ts +137 -0
  242. package/src/util/resolveDefaultProps.tsx +8 -0
  243. package/src/util/round.ts +35 -0
  244. package/src/util/scale/CartesianScaleHelper.ts +72 -0
  245. package/src/util/scale/CustomScaleDefinition.ts +82 -0
  246. package/src/util/scale/RechartsScale.ts +131 -0
  247. package/src/util/scale/createCategoricalInverse.ts +83 -0
  248. package/src/util/scale/getNiceTickValues.ts +334 -0
  249. package/src/util/scale/index.ts +3 -0
  250. package/src/util/scale/util/DecimalLite.ts +194 -0
  251. package/src/util/scale/util/arithmetic.ts +56 -0
  252. package/src/util/stacks/getStackSeriesIdentifier.ts +20 -0
  253. package/src/util/stacks/stackTypes.ts +53 -0
  254. package/src/util/svgPropertiesAndEvents.ts +84 -0
  255. package/src/util/svgPropertiesNoEvents.ts +520 -0
  256. package/src/util/tooltip/translate.ts +179 -0
  257. package/src/util/typedDataKey.ts +8 -0
  258. package/src/util/types.ts +724 -0
  259. package/src/util/useAnimationId.tsx +31 -0
  260. package/src/util/useElementOffset.ts +164 -0
  261. package/src/util/useId.ts +20 -0
  262. package/src/util/usePrefersReducedMotion.ts +44 -0
  263. package/src/util/useUniqueId.ts +34 -0
  264. package/src/zIndex/DefaultZIndexes.tsx +87 -0
  265. package/src/zIndex/ZIndexLayer.tsx +126 -0
  266. package/src/zIndex/ZIndexPortal.tsx +69 -0
  267. package/src/zIndex/getZIndexFromUnknown.tsx +17 -0
  268. package/src/zIndex/zIndexSelectors.ts +46 -0
  269. package/test/_data.ts +408 -0
  270. package/test/animation/AnimationController.typed.spec.ts +53 -0
  271. package/test/animation/AnimationControllerImpl.spec.ts +271 -0
  272. package/test/animation/CSSTransitionAnimate.timing.spec.tsx +473 -0
  273. package/test/animation/JavascriptAnimate.spec.tsx +62 -0
  274. package/test/animation/RechartsAnimation.spec.ts +636 -0
  275. package/test/animation/easing.spec.ts +218 -0
  276. package/test/animation/legacyAnimationLengthChange.spec.tsx +803 -0
  277. package/test/animation/matchBy.spec.ts +467 -0
  278. package/test/animation/mockAnimationController.ts +40 -0
  279. package/test/animation/mockControllerAnimationManager.ts +143 -0
  280. package/test/animation/mockTimeoutController.ts +114 -0
  281. package/test/animation/timeoutController.spec.ts +138 -0
  282. package/test/animation/useAnimationStartSnapshot.spec.ts +147 -0
  283. package/test/animation/util.spec.ts +28 -0
  284. package/test/cartesian/Area.animation.spec.tsx +363 -0
  285. package/test/cartesian/Area.range.spec.tsx +54 -0
  286. package/test/cartesian/Area.spec.tsx +1202 -0
  287. package/test/cartesian/Area.stacked.render.spec.tsx +69 -0
  288. package/test/cartesian/Area.typed.spec.tsx +209 -0
  289. package/test/cartesian/Axis.integration.spec.tsx +158 -0
  290. package/test/cartesian/Bar/Bar.csstransition.spec.tsx +299 -0
  291. package/test/cartesian/Bar/Bar.spec.tsx +2314 -0
  292. package/test/cartesian/Bar/Bar.typed.spec.tsx +192 -0
  293. package/test/cartesian/Bar.animation.spec.tsx +426 -0
  294. package/test/cartesian/Bar.stackDomain.spec.tsx +66 -0
  295. package/test/cartesian/Bar.stacked.render.spec.tsx +53 -0
  296. package/test/cartesian/Bar.truncateByDomain.spec.tsx +237 -0
  297. package/test/cartesian/Bar.zeroDimensionFiltering.spec.tsx +336 -0
  298. package/test/cartesian/BarStack.spec.tsx +91 -0
  299. package/test/cartesian/Brush.keyboard.spec.tsx +88 -0
  300. package/test/cartesian/Brush.panorama.spec.tsx +41 -0
  301. package/test/cartesian/Brush.props.spec.tsx +63 -0
  302. package/test/cartesian/Brush.render.spec.tsx +117 -0
  303. package/test/cartesian/Brush.spec.tsx +522 -0
  304. package/test/cartesian/Brush.stacked.spec.tsx +221 -0
  305. package/test/cartesian/CartesianAxis.render.spec.tsx +50 -0
  306. package/test/cartesian/CartesianAxis.spec.tsx +396 -0
  307. package/test/cartesian/CartesianGrid.render.spec.tsx +39 -0
  308. package/test/cartesian/CartesianGrid.spec.tsx +2103 -0
  309. package/test/cartesian/ErrorBar.render.spec.tsx +69 -0
  310. package/test/cartesian/ErrorBar.spec.tsx +2414 -0
  311. package/test/cartesian/Funnel.animation.spec.tsx +241 -0
  312. package/test/cartesian/Funnel.spec.tsx +226 -0
  313. package/test/cartesian/Funnel.typed.spec.tsx +221 -0
  314. package/test/cartesian/GraphicalItemClipPath.scale-behavior.spec.tsx +627 -0
  315. package/test/cartesian/GraphicalItemClipPath.spec.tsx +427 -0
  316. package/test/cartesian/Line.animation.spec.tsx +643 -0
  317. package/test/cartesian/Line.sparseAnimationPath.spec.tsx +98 -0
  318. package/test/cartesian/Line.spec.tsx +471 -0
  319. package/test/cartesian/Line.typed.spec.tsx +152 -0
  320. package/test/cartesian/ReferenceArea.render.spec.tsx +63 -0
  321. package/test/cartesian/ReferenceArea.spec.tsx +663 -0
  322. package/test/cartesian/ReferenceArea.typed.spec.tsx +74 -0
  323. package/test/cartesian/ReferenceDot.render.spec.tsx +55 -0
  324. package/test/cartesian/ReferenceDot.spec.tsx +462 -0
  325. package/test/cartesian/ReferenceDot.typed.spec.tsx +76 -0
  326. package/test/cartesian/ReferenceLine/ReferenceLine.panorama.spec.tsx +184 -0
  327. package/test/cartesian/ReferenceLine/ReferenceLine.spec.tsx +744 -0
  328. package/test/cartesian/ReferenceLine/ReferenceLine.typed.spec.tsx +74 -0
  329. package/test/cartesian/ReferenceLine/getEndPoints.spec.ts +399 -0
  330. package/test/cartesian/ReferenceLine.render.spec.tsx +134 -0
  331. package/test/cartesian/Scatter.animation.spec.tsx +381 -0
  332. package/test/cartesian/Scatter.render.spec.tsx +61 -0
  333. package/test/cartesian/Scatter.spec.tsx +406 -0
  334. package/test/cartesian/Scatter.typed.spec.tsx +153 -0
  335. package/test/cartesian/XAxis/XAxis.barSize.spec.tsx +336 -0
  336. package/test/cartesian/XAxis/XAxis.brush.spec.tsx +266 -0
  337. package/test/cartesian/XAxis/XAxis.categorydomain.spec.tsx +872 -0
  338. package/test/cartesian/XAxis/XAxis.dataKey.spec.tsx +86 -0
  339. package/test/cartesian/XAxis/XAxis.datatypes.spec.tsx +127 -0
  340. package/test/cartesian/XAxis/XAxis.hide.spec.tsx +106 -0
  341. package/test/cartesian/XAxis/XAxis.multiaxis.spec.tsx +336 -0
  342. package/test/cartesian/XAxis/XAxis.numberdomain.spec.tsx +1466 -0
  343. package/test/cartesian/XAxis/XAxis.padding.spec.tsx +758 -0
  344. package/test/cartesian/XAxis/XAxis.padding_clip.spec.tsx +65 -0
  345. package/test/cartesian/XAxis/XAxis.state.spec.tsx +355 -0
  346. package/test/cartesian/XAxis/XAxis.tick.spec.tsx +493 -0
  347. package/test/cartesian/XAxis/XAxis.timescale.spec.tsx +233 -0
  348. package/test/cartesian/XAxis/XAxis.type.spec.tsx +107 -0
  349. package/test/cartesian/XAxis/XAxis.typed.spec.tsx +102 -0
  350. package/test/cartesian/XAxis/XAxis.vertical.spec.tsx +265 -0
  351. package/test/cartesian/XAxis.tickFormatter.spec.tsx +54 -0
  352. package/test/cartesian/YAxis/YAxis.7362.derivedDomain.spec.tsx +230 -0
  353. package/test/cartesian/YAxis/YAxis.7362.spec.tsx +104 -0
  354. package/test/cartesian/YAxis/YAxis.interval-zero.spec.tsx +88 -0
  355. package/test/cartesian/YAxis/YAxis.label.spec.tsx +219 -0
  356. package/test/cartesian/YAxis/YAxis.spec.tsx +1595 -0
  357. package/test/cartesian/YAxis/YAxis.tick.spec.tsx +428 -0
  358. package/test/cartesian/YAxis/YAxis.tickFormatter.spec.tsx +54 -0
  359. package/test/cartesian/YAxis/YAxis.ticks.spec.tsx +263 -0
  360. package/test/cartesian/YAxis/YAxis.type.spec.tsx +107 -0
  361. package/test/cartesian/YAxis/YAxis.typed.spec.tsx +102 -0
  362. package/test/cartesian/ZAxis.spec.tsx +300 -0
  363. package/test/cartesian/ZAxis.typed.spec.tsx +33 -0
  364. package/test/cartesian/__snapshots__/Brush.spec.tsx.snap +5 -0
  365. package/test/cartesian/axisLineAndStroke.spec.tsx +72 -0
  366. package/test/cartesian/getCartesianPosition.spec.ts +907 -0
  367. package/test/cartesian/getEquidistantTicks.spec.ts +88 -0
  368. package/test/cartesian/getTicks.spec.ts +378 -0
  369. package/test/cartesian/miscFeatureGaps.spec.tsx +89 -0
  370. package/test/cartesian/useAnimatedLineLength.spec.ts +168 -0
  371. package/test/chart/AccessibilityLayer.spec.tsx +569 -0
  372. package/test/chart/AccessibilityScans.spec.tsx +286 -0
  373. package/test/chart/AreaChart.spec.tsx +409 -0
  374. package/test/chart/AreaChart.stacked.spec.tsx +1407 -0
  375. package/test/chart/AreaChart.typed.spec.tsx +39 -0
  376. package/test/chart/BarChart.spec.tsx +3719 -0
  377. package/test/chart/BarChart.typed.spec.tsx +60 -0
  378. package/test/chart/CategoricalChart.spec.tsx +255 -0
  379. package/test/chart/ComposedChart.spec.tsx +199 -0
  380. package/test/chart/ComposedChart.typed.spec.tsx +39 -0
  381. package/test/chart/FunnelChart.spec.tsx +215 -0
  382. package/test/chart/FunnelChart.typed.spec.tsx +39 -0
  383. package/test/chart/LineChart.multiseries.spec.tsx +50 -0
  384. package/test/chart/LineChart.smoke.spec.tsx +50 -0
  385. package/test/chart/LineChart.spec.tsx +930 -0
  386. package/test/chart/LineChart.typed.spec.tsx +39 -0
  387. package/test/chart/NicheChartTooltip.spec.tsx +81 -0
  388. package/test/chart/PieChart.spec.tsx +793 -0
  389. package/test/chart/PieChart.typed.spec.tsx +39 -0
  390. package/test/chart/RadarChart.spec.tsx +530 -0
  391. package/test/chart/RadarChart.typed.spec.tsx +39 -0
  392. package/test/chart/RadialBarChart.5966.spec.tsx +48 -0
  393. package/test/chart/RadialBarChart.spec.tsx +679 -0
  394. package/test/chart/RadialBarChart.typed.spec.tsx +39 -0
  395. package/test/chart/RechartsWrapper.spec.tsx +83 -0
  396. package/test/chart/Sankey.content.spec.tsx +46 -0
  397. package/test/chart/Sankey.spec.tsx +952 -0
  398. package/test/chart/Sankey.typed.spec.tsx +29 -0
  399. package/test/chart/ScatterChart.spec.tsx +2613 -0
  400. package/test/chart/ScatterChart.typed.spec.tsx +39 -0
  401. package/test/chart/SunburstChart.spec.tsx +146 -0
  402. package/test/chart/Treemap.animation.spec.tsx +52 -0
  403. package/test/chart/Treemap.spec.tsx +1003 -0
  404. package/test/chart/Treemap.typed.spec.tsx +26 -0
  405. package/test/chart/chartEvents.spec.tsx +127 -0
  406. package/test/chart/responsive.spec.tsx +620 -0
  407. package/test/component/Cell.render.spec.tsx +155 -0
  408. package/test/component/Cell.spec.tsx +12 -0
  409. package/test/component/Cursor.spec.tsx +186 -0
  410. package/test/component/DefaultTooltipContent.spec.tsx +102 -0
  411. package/test/component/Label.render.spec.tsx +63 -0
  412. package/test/component/Label.spec.tsx +686 -0
  413. package/test/component/Label.typed.spec.tsx +46 -0
  414. package/test/component/LabelList.spec.tsx +188 -0
  415. package/test/component/Legend.itemSorter.spec.tsx +704 -0
  416. package/test/component/Legend.render.spec.tsx +92 -0
  417. package/test/component/Legend.spec.tsx +2213 -0
  418. package/test/component/Legend.typed.spec.tsx +22 -0
  419. package/test/component/ResponsiveContainer.spec.tsx +523 -0
  420. package/test/component/ResponsiveContainerDataTest.spec.tsx +51 -0
  421. package/test/component/Text.spec.tsx +415 -0
  422. package/test/component/Text.typed.spec.tsx +46 -0
  423. package/test/component/Tooltip/ActiveDot.spec.tsx +370 -0
  424. package/test/component/Tooltip/Tooltip.animation.spec.tsx +209 -0
  425. package/test/component/Tooltip/Tooltip.content.spec.tsx +128 -0
  426. package/test/component/Tooltip/Tooltip.formatter.spec.tsx +152 -0
  427. package/test/component/Tooltip/Tooltip.includeHidden.spec.tsx +79 -0
  428. package/test/component/Tooltip/Tooltip.multipleDataArrays.spec.tsx +165 -0
  429. package/test/component/Tooltip/Tooltip.offset.spec.tsx +113 -0
  430. package/test/component/Tooltip/Tooltip.state.spec.tsx +74 -0
  431. package/test/component/Tooltip/Tooltip.sync.spec.tsx +639 -0
  432. package/test/component/Tooltip/defaultIndex.spec.tsx +227 -0
  433. package/test/component/Tooltip/graphicalItem.formatter.spec.tsx +138 -0
  434. package/test/component/Tooltip/itemSorter.spec.tsx +2815 -0
  435. package/test/component/Tooltip/tooltipEventType.spec.tsx +344 -0
  436. package/test/component/Tooltip/tooltipMouseHoverSelectors.ts +41 -0
  437. package/test/component/Tooltip/tooltipTestHelpers.tsx +162 -0
  438. package/test/component/Tooltip.defaultIndex.spec.tsx +48 -0
  439. package/test/component/Tooltip.hover.spec.tsx +61 -0
  440. package/test/component/Tooltip.item.spec.tsx +54 -0
  441. package/test/component/Tooltip.keyboard.spec.tsx +51 -0
  442. package/test/component/Tooltip.payload.spec.tsx +1716 -0
  443. package/test/component/Tooltip.touch.spec.tsx +39 -0
  444. package/test/component/Tooltip.visibility.spec.tsx +1889 -0
  445. package/test/component/TooltipBoundingBox.spec.tsx +89 -0
  446. package/test/component/responsiveContainerUtils.spec.ts +205 -0
  447. package/test/container/ClipPath.spec.tsx +602 -0
  448. package/test/container/chartDimensions.spec.tsx +368 -0
  449. package/test/context/chartLayoutContext.spec.tsx +378 -0
  450. package/test/helper/ExpectAxisDomain.tsx +27 -0
  451. package/test/helper/assertNotNull.ts +6 -0
  452. package/test/helper/assertZIndexLayerOrder.ts +19 -0
  453. package/test/helper/createSelectorTestCase.tsx +176 -0
  454. package/test/helper/expectAnimatedPieAngles.ts +100 -0
  455. package/test/helper/expectAnimatedPiePaths.ts +78 -0
  456. package/test/helper/expectAreaCurve.ts +15 -0
  457. package/test/helper/expectAxisTicks.ts +48 -0
  458. package/test/helper/expectBars.ts +54 -0
  459. package/test/helper/expectFunctionReturning.ts +58 -0
  460. package/test/helper/expectLabel.ts +32 -0
  461. package/test/helper/expectLastCalledWith.ts +48 -0
  462. package/test/helper/expectLine.ts +20 -0
  463. package/test/helper/expectPieSectors.ts +80 -0
  464. package/test/helper/expectScale.ts +37 -0
  465. package/test/helper/expectScatterPoints.ts +52 -0
  466. package/test/helper/expectStackGroups.ts +144 -0
  467. package/test/helper/mockAxes.ts +22 -0
  468. package/test/helper/mockGetBoundingClientRect.ts +66 -0
  469. package/test/helper/mockHTMLElementProperty.ts +19 -0
  470. package/test/helper/mockTouchingElement.ts +27 -0
  471. package/test/helper/offsetHelpers.ts +19 -0
  472. package/test/helper/parameterizedTestCases.tsx +99 -0
  473. package/test/helper/produceState.ts +32 -0
  474. package/test/helper/render.ts +7 -0
  475. package/test/helper/selectorTestHelpers.tsx +63 -0
  476. package/test/helper/trim.spec.ts +35 -0
  477. package/test/helper/trim.ts +11 -0
  478. package/test/hooks/useActiveTooltipDataPoints.spec.tsx +358 -0
  479. package/test/hooks/useAxisDomain.spec.tsx +361 -0
  480. package/test/hooks/useAxisScale.spec.tsx +283 -0
  481. package/test/hooks/useAxisTicks.spec.tsx +130 -0
  482. package/test/hooks/useOffset.spec.tsx +248 -0
  483. package/test/hooks/useTooltipStateHooks.spec.tsx +109 -0
  484. package/test/polar/Pie/Pie-TwoLevelPieChart.spec.tsx +135 -0
  485. package/test/polar/Pie/Pie.spec.tsx +784 -0
  486. package/test/polar/Pie/Pie.typed.spec.tsx +78 -0
  487. package/test/polar/Pie.animation.spec.tsx +529 -0
  488. package/test/polar/PieWithLegend.animation.spec.tsx +142 -0
  489. package/test/polar/PolarAngleAxis/PolarAngleAxis.events.spec.tsx +76 -0
  490. package/test/polar/PolarAngleAxis/PolarAngleAxis.spec.tsx +2079 -0
  491. package/test/polar/PolarAngleAxis/PolarAngleAxis.typed.spec.tsx +102 -0
  492. package/test/polar/PolarAngleAxis.render.spec.tsx +79 -0
  493. package/test/polar/PolarGrid.render.spec.tsx +75 -0
  494. package/test/polar/PolarGrid.spec.tsx +918 -0
  495. package/test/polar/PolarLegendPerRow.render.spec.tsx +85 -0
  496. package/test/polar/PolarRadiusAxis.events.spec.tsx +65 -0
  497. package/test/polar/PolarRadiusAxis.render.spec.tsx +52 -0
  498. package/test/polar/PolarRadiusAxis.spec.tsx +991 -0
  499. package/test/polar/PolarRadiusAxis.typed.spec.tsx +84 -0
  500. package/test/polar/PolarTooltipLegend.render.spec.tsx +80 -0
  501. package/test/polar/Radar.animation.spec.tsx +570 -0
  502. package/test/polar/Radar.render.spec.tsx +71 -0
  503. package/test/polar/Radar.spec.tsx +265 -0
  504. package/test/polar/Radar.typed.spec.tsx +119 -0
  505. package/test/polar/RadialBar/RadialBar.spec.tsx +1521 -0
  506. package/test/polar/RadialBar/RadialBar.typed.spec.tsx +132 -0
  507. package/test/polar/RadialBar.animation.spec.tsx +375 -0
  508. package/test/polar/RadialBar.render.spec.tsx +66 -0
  509. package/test/polar/RadialBar.stacked.spec.tsx +57 -0
  510. package/test/setup.ts +84 -0
  511. package/test/shape/ActiveShape.spec.tsx +181 -0
  512. package/test/shape/Cross.spec.tsx +60 -0
  513. package/test/shape/Cross.typed.spec.tsx +26 -0
  514. package/test/shape/Curve.spec.tsx +368 -0
  515. package/test/shape/Curve.typed.spec.tsx +69 -0
  516. package/test/shape/Dot.spec.tsx +73 -0
  517. package/test/shape/Dot.typed.spec.tsx +30 -0
  518. package/test/shape/Polygon.spec.tsx +357 -0
  519. package/test/shape/Polygon.typed.spec.tsx +28 -0
  520. package/test/shape/Rectangle.animation.spec.tsx +451 -0
  521. package/test/shape/Rectangle.spec.tsx +68 -0
  522. package/test/shape/Rectangle.typed.spec.tsx +24 -0
  523. package/test/shape/Sector.spec.tsx +76 -0
  524. package/test/shape/Sector.typed.spec.tsx +24 -0
  525. package/test/shape/Symbols.spec.tsx +43 -0
  526. package/test/shape/Symbols.typed.spec.tsx +24 -0
  527. package/test/shape/Trapezoid.spec.tsx +50 -0
  528. package/test/shape/Trapezoid.typed.spec.tsx +24 -0
  529. package/test/shape/__snapshots__/Cross.spec.tsx.snap +62 -0
  530. package/test/shape/__snapshots__/Curve.spec.tsx.snap +460 -0
  531. package/test/shape/__snapshots__/Polygon.spec.tsx.snap +58 -0
  532. package/test/shape/__snapshots__/Rectangle.spec.tsx.snap +117 -0
  533. package/test/shape/__snapshots__/Sector.spec.tsx.snap +71 -0
  534. package/test/shape/__snapshots__/Trapezoid.spec.tsx.snap +64 -0
  535. package/test/state/chartDataSlice.spec.ts +53 -0
  536. package/test/state/externalEventsMiddleware.spec.ts +178 -0
  537. package/test/state/graphicalItemsSlice.spec.ts +92 -0
  538. package/test/state/hooks.spec.tsx +68 -0
  539. package/test/state/legendSlice.spec.ts +44 -0
  540. package/test/state/mouseEventsMiddleware.spec.ts +75 -0
  541. package/test/state/optionsSlice.spec.ts +19 -0
  542. package/test/state/reduxDevtoolsJsonStringifyReplacer.spec.ts +25 -0
  543. package/test/state/referenceElementsSlice.spec.ts +84 -0
  544. package/test/state/selectors/areaSelectors.spec.tsx +77 -0
  545. package/test/state/selectors/axisSelectors.spec.tsx +1418 -0
  546. package/test/state/selectors/barStackSelectors.spec.tsx +752 -0
  547. package/test/state/selectors/brushSelectors.spec.tsx +30 -0
  548. package/test/state/selectors/cartesianAxisSlice.spec.ts +96 -0
  549. package/test/state/selectors/combineNiceTicks.spec.ts +207 -0
  550. package/test/state/selectors/combiners/combineActiveTooltipIndex.spec.ts +61 -0
  551. package/test/state/selectors/combiners/combineAllBarPositions.spec.ts +39 -0
  552. package/test/state/selectors/combiners/combineConfiguredScale.spec.ts +56 -0
  553. package/test/state/selectors/combiners/combineDisplayedStackedData.spec.ts +123 -0
  554. package/test/state/selectors/combiners/combineRealScaleType.spec.ts +80 -0
  555. package/test/state/selectors/containerSelectors.spec.tsx +168 -0
  556. package/test/state/selectors/dataSelectors.spec.tsx +136 -0
  557. package/test/state/selectors/legendSelectors.spec.tsx +113 -0
  558. package/test/state/selectors/lineSelectors.spec.tsx +60 -0
  559. package/test/state/selectors/pieSelectors.spec.tsx +72 -0
  560. package/test/state/selectors/radarSelectors.spec.tsx +496 -0
  561. package/test/state/selectors/rootPropsSelectors.spec.tsx +169 -0
  562. package/test/state/selectors/scatterSelectors.spec.tsx +47 -0
  563. package/test/state/selectors/selectActiveTooltipIndex.spec.tsx +234 -0
  564. package/test/state/selectors/selectAllAxes.spec.tsx +18 -0
  565. package/test/state/selectors/selectAxisDomain.spec.tsx +21 -0
  566. package/test/state/selectors/selectAxisDomainIncludingNiceTicks.spec.tsx +19 -0
  567. package/test/state/selectors/selectAxisRangeWithReverse.spec.tsx +22 -0
  568. package/test/state/selectors/selectAxisScale.spec.tsx +91 -0
  569. package/test/state/selectors/selectBarRectangles.stackOffset.spec.tsx +503 -0
  570. package/test/state/selectors/selectBaseAxis.spec.tsx +56 -0
  571. package/test/state/selectors/selectCartesianItemsSettings.spec.tsx +57 -0
  572. package/test/state/selectors/selectChartOffset.spec.tsx +26 -0
  573. package/test/state/selectors/selectDisplayedData.spec.tsx +282 -0
  574. package/test/state/selectors/selectIsTooltipActive.spec.tsx +231 -0
  575. package/test/state/selectors/selectNumericalDomain.spec.tsx +21 -0
  576. package/test/state/selectors/selectRealScaleType.spec.tsx +19 -0
  577. package/test/state/selectors/selectStackGroups.spec.tsx +322 -0
  578. package/test/state/selectors/selectXAxisPosition.spec.tsx +22 -0
  579. package/test/state/selectors/selectYAxisPosition.spec.tsx +22 -0
  580. package/test/state/selectors/selectors.spec.tsx +1613 -0
  581. package/test/state/throttling.spec.ts +200 -0
  582. package/test/state/zIndexSlice.spec.ts +85 -0
  583. package/test/synchronisation/useChartSynchronisation.spec.tsx +225 -0
  584. package/test/util/BarUtils.spec.ts +39 -0
  585. package/test/util/CartesianUtils/CartesianUtils.spec.ts +261 -0
  586. package/test/util/CartesianUtils/rectWithPoints.spec.ts +48 -0
  587. package/test/util/ChartUtils/ChartUtils.spec.ts +491 -0
  588. package/test/util/ChartUtils/appendOffsetOfLegend.spec.ts +136 -0
  589. package/test/util/ChartUtils/appendOffsetOfLegend.spec.tsx +133 -0
  590. package/test/util/ChartUtils/getCateCoordinateOfLine.spec.ts +83 -0
  591. package/test/util/ChartUtils/getStackedData.spec.ts +416 -0
  592. package/test/util/ChartUtils/truncateByDomain.spec.ts +70 -0
  593. package/test/util/DataUtils.spec.ts +385 -0
  594. package/test/util/DomUtils.spec.tsx +117 -0
  595. package/test/util/FunnelUtils.spec.tsx +70 -0
  596. package/test/util/Global.spec.ts +11 -0
  597. package/test/util/LRUCache.spec.ts +81 -0
  598. package/test/util/LogUtils.spec.ts +45 -0
  599. package/test/util/PolarUtils.spec.ts +66 -0
  600. package/test/util/ReduceCssCalcPrototype.spec.ts +141 -0
  601. package/test/util/ShallowEqual.spec.ts +102 -0
  602. package/test/util/TickUtils.spec.ts +29 -0
  603. package/test/util/axisPropsAreEqual.spec.ts +93 -0
  604. package/test/util/createChartHelpers.spec.tsx +210 -0
  605. package/test/util/cursor/getCursorPoints.spec.ts +136 -0
  606. package/test/util/cursor/getCursorRectangle.spec.ts +50 -0
  607. package/test/util/cursor/getRadialCursorPoints.spec.ts +36 -0
  608. package/test/util/errorValue.spec.ts +69 -0
  609. package/test/util/getEveryNth.spec.ts +39 -0
  610. package/test/util/getRadiusAndStrokeWidthFromDot.spec.ts +51 -0
  611. package/test/util/getRelativeCoordinate.spec.ts +250 -0
  612. package/test/util/getSliced.spec.ts +45 -0
  613. package/test/util/isDomainSpecifiedByUser.spec.ts +207 -0
  614. package/test/util/isWellBehavedNumber.spec.ts +54 -0
  615. package/test/util/payload/getUniqPayload.spec.ts +56 -0
  616. package/test/util/propsAreEqual.spec.ts +75 -0
  617. package/test/util/round.spec.ts +112 -0
  618. package/test/util/scale/arithmetic.spec.ts +61 -0
  619. package/test/util/scale/createCategoricalInverse.spec.ts +84 -0
  620. package/test/util/scale/getNiceTickValues.spec.ts +421 -0
  621. package/test/util/scale/getTickValuesFixedDomain.spec.ts +155 -0
  622. package/test/util/svgPropertiesAndEvents.spec.tsx +206 -0
  623. package/test/util/svgPropertiesNoEvents.spec.tsx +228 -0
  624. package/test/util/tooltip/translate.spec.ts +396 -0
  625. package/test/util/useAnimationId.spec.tsx +59 -0
  626. package/test/util/useElementOffset.spec.tsx +173 -0
  627. package/test/util/usePrefersReducedMotion.spec.ts +54 -0
  628. package/test/util/useUniqueId.spec.ts +99 -0
  629. package/test/utils/diagnostics-allowlist.ts +18 -0
  630. package/test/utils/diagnostics.ts +58 -0
  631. package/test/zIndex/AllZIndexPortals.spec.tsx +83 -0
  632. package/test/zIndex/DefaultZIndexes.spec.ts +80 -0
  633. package/test/zIndex/DynamicZIndex.spec.tsx +102 -0
  634. package/test/zIndex/ZIndexLayer.portalOwner.spec.tsx +125 -0
  635. package/test/zIndex/componentZIndex.spec.tsx +255 -0
  636. package/test/zIndex/getZIndexFromUnknown.spec.ts +51 -0
  637. package/test/zIndex/multiChartZIndexIsolation.spec.tsx +90 -0
  638. package/test/zIndex/zIndexSelectors.spec.ts +172 -0
  639. package/tsconfig.json +11 -0
@@ -0,0 +1,627 @@
1
+ // Ported from recharts 3.8.1 test/cartesian/GraphicalItemClipPath.scale-behavior.spec.tsx.
2
+ //
3
+ // These tests investigate why categorical (scalePoint) and numerical (scaleLinear)
4
+ // axes compute different pixel positions for the same data points when data slides.
5
+ //
6
+ // Tier-A (pure d3-scale) cases are byte-identical — they only exercise victory-vendor
7
+ // d3-scale and so are golden-anchored to d3.
8
+ //
9
+ // Tier-B (real LineChart) cases port the selector-spy harness: React useState + an
10
+ // `act(button.click())` data slide becomes a Solid `data` signal flipped on click,
11
+ // and the selectLinePoints accessor is spied through createSelectorTestCase. The
12
+ // last spy call holds the current points. `p.payload` is `unknown` in our port
13
+ // (recharts erases it via `any`), so a runtime guard reads `name`/`x` — no `as`.
14
+ import { describe, it, expect, beforeEach } from "vitest";
15
+ import { scaleLinear, scalePoint } from "victory-vendor/d3-scale";
16
+ import { createSignal, flush } from "solid-js";
17
+ import type { JSX } from "@solidjs/web";
18
+ import { fireEvent } from "../helper/render";
19
+ import { Line, LineChart, XAxis, YAxis } from "../../src";
20
+ import { createSelectorTestCase } from "../helper/createSelectorTestCase";
21
+ import { mockGetBoundingClientRect } from "../helper/mockGetBoundingClientRect";
22
+ import { selectLinePoints } from "../../src/state/selectors/lineSelectors";
23
+ import type { LinePointItem } from "../../src/cartesian/Line";
24
+ import { assertNotNull } from "../helper/assertNotNull";
25
+
26
+ // Runtime guards (not casts) that read the named fields off the erased payload.
27
+ function payloadName(p: LinePointItem): string | undefined {
28
+ const payload = p.payload;
29
+ if (payload != null && typeof payload === "object" && "name" in payload) {
30
+ const name = (payload as { name: unknown }).name;
31
+ return typeof name === "string" ? name : undefined;
32
+ }
33
+ return undefined;
34
+ }
35
+
36
+ function payloadX(p: LinePointItem): number | undefined {
37
+ const payload = p.payload;
38
+ if (payload != null && typeof payload === "object" && "x" in payload) {
39
+ const x = (payload as { x: unknown }).x;
40
+ return typeof x === "number" ? x : undefined;
41
+ }
42
+ return undefined;
43
+ }
44
+
45
+ describe("Scale behavior: categorical vs numerical point positions during data sliding", () => {
46
+ describe("d3 scalePoint (categorical) behavior", () => {
47
+ const RANGE: [number, number] = [0, 500];
48
+
49
+ it("distributes categories evenly across the range", () => {
50
+ const scale = scalePoint<string>().domain(["A", "B", "C", "D", "E", "F"]).range(RANGE);
51
+
52
+ expect(scale("A")).toBe(0);
53
+ expect(scale("B")).toBe(100);
54
+ expect(scale("C")).toBe(200);
55
+ expect(scale("D")).toBe(300);
56
+ expect(scale("E")).toBe(400);
57
+ expect(scale("F")).toBe(500);
58
+ });
59
+
60
+ it("redistributes ALL points when domain changes from [A..F] to [B..G]", () => {
61
+ const before = scalePoint<string>().domain(["A", "B", "C", "D", "E", "F"]).range(RANGE);
62
+ const after = scalePoint<string>().domain(["B", "C", "D", "E", "F", "G"]).range(RANGE);
63
+
64
+ // Every surviving point gets a completely new position
65
+ // B: was at 100, now at 0 — shifted by -100
66
+ expect(before("B")).toBe(100);
67
+ expect(after("B")).toBe(0);
68
+
69
+ // C: was at 200, now at 100 — shifted by -100
70
+ expect(before("C")).toBe(200);
71
+ expect(after("C")).toBe(100);
72
+
73
+ // F: was at 500, now at 400 — shifted by -100
74
+ expect(before("F")).toBe(500);
75
+ expect(after("F")).toBe(400);
76
+
77
+ // The removed point A is no longer in the domain
78
+ expect(after("A")).toBeUndefined();
79
+
80
+ // The new point G gets the last position
81
+ expect(after("G")).toBe(500);
82
+ });
83
+
84
+ it("the shift is consistent because the same number of categories fill the same range", () => {
85
+ const before = scalePoint<string>().domain(["A", "B", "C", "D", "E", "F"]).range(RANGE);
86
+ const after = scalePoint<string>().domain(["B", "C", "D", "E", "F", "G"]).range(RANGE);
87
+
88
+ // When removing one item from start and adding one to end (same count),
89
+ // the spacing stays constant: 500 / 5 = 100
90
+ const spacingBefore = before("B")! - before("A")!;
91
+ const spacingAfter = after("C")! - after("B")!;
92
+ expect(spacingBefore).toBe(100);
93
+ expect(spacingAfter).toBe(100);
94
+
95
+ // Every surviving point shifts by exactly one spacing unit
96
+ for (const label of ["B", "C", "D", "E", "F"]) {
97
+ const shift = before(label)! - after(label)!;
98
+ expect(shift).toBe(100);
99
+ }
100
+ });
101
+
102
+ it("returns undefined for values not in the domain — animation must extrapolate", () => {
103
+ const after = scalePoint<string>().domain(["B", "C", "D", "E", "F", "G"]).range(RANGE);
104
+ // The removed point A cannot be positioned by the new scale
105
+ // The animation system must guess where to animate it to
106
+ expect(after("A")).toBeUndefined();
107
+ });
108
+
109
+ it("has different spacing when the count changes", () => {
110
+ // If we go from 6 items to 5 items, the spacing changes
111
+ const before = scalePoint<string>().domain(["A", "B", "C", "D", "E", "F"]).range(RANGE);
112
+ const after = scalePoint<string>().domain(["B", "C", "D", "E", "F"]).range(RANGE);
113
+
114
+ const spacingBefore = before("B")! - before("A")!;
115
+ const spacingAfter = after("C")! - after("B")!;
116
+
117
+ expect(spacingBefore).toBe(100); // 500 / 5
118
+ expect(spacingAfter).toBe(125); // 500 / 4
119
+
120
+ // Surviving points shift by different amounts!
121
+ const shiftB = before("B")! - after("B")!;
122
+ const shiftF = before("F")! - after("F")!;
123
+ expect(shiftB).toBe(100); // 100 → 0
124
+ expect(shiftF).toBe(0); // 500 → 500
125
+
126
+ // B and F have different shifts — this makes animation non-uniform
127
+ expect(shiftB).not.toBe(shiftF);
128
+ });
129
+ });
130
+
131
+ describe("d3 scaleLinear (numerical) behavior", () => {
132
+ const RANGE: [number, number] = [0, 500];
133
+
134
+ it("maps values proportionally across the range", () => {
135
+ const scale = scaleLinear().domain([1, 6]).range(RANGE);
136
+
137
+ expect(scale(1)).toBe(0);
138
+ expect(scale(2)).toBe(100);
139
+ expect(scale(3)).toBe(200);
140
+ expect(scale(4)).toBe(300);
141
+ expect(scale(5)).toBe(400);
142
+ expect(scale(6)).toBe(500);
143
+ });
144
+
145
+ it("repositions points proportionally when domain slides from [1,6] to [2,7]", () => {
146
+ const before = scaleLinear().domain([1, 6]).range(RANGE);
147
+ const after = scaleLinear().domain([2, 7]).range(RANGE);
148
+
149
+ // Point 2: was at (2-1)/(6-1) * 500 = 100, now at (2-2)/(7-2) * 500 = 0
150
+ expect(before(2)).toBe(100);
151
+ expect(after(2)).toBe(0);
152
+
153
+ // Point 6: was at (6-1)/(6-1) * 500 = 500, now at (6-2)/(7-2) * 500 = 400
154
+ expect(before(6)).toBe(500);
155
+ expect(after(6)).toBe(400);
156
+
157
+ // Every surviving point shifts by exactly 100 (same as categorical with equal count)
158
+ for (const val of [2, 3, 4, 5, 6]) {
159
+ const shift = before(val) - after(val);
160
+ expect(shift).toBe(100);
161
+ }
162
+ });
163
+
164
+ it("can compute positions for values OUTSIDE the domain (extrapolation)", () => {
165
+ const after = scaleLinear().domain([2, 7]).range(RANGE);
166
+
167
+ // The removed point 1 is below the domain minimum
168
+ // scaleLinear extrapolates: (1-2)/(7-2) * 500 = -100
169
+ expect(after(1)).toBe(-100);
170
+
171
+ // The new point 7 is at the domain maximum
172
+ expect(after(7)).toBe(500);
173
+ });
174
+
175
+ it("extrapolation means removed points animate to just outside the left edge", () => {
176
+ const before = scaleLinear().domain([1, 6]).range(RANGE);
177
+ const after = scaleLinear().domain([2, 7]).range(RANGE);
178
+
179
+ // Point 1's position in the old scale was at 0 (left edge)
180
+ expect(before(1)).toBe(0);
181
+
182
+ // In the new scale, point 1 would be at -100 (just past the left edge)
183
+ expect(after(1)).toBe(-100);
184
+
185
+ // This is exactly one spacing unit past the left edge,
186
+ // which creates a smooth sliding-off animation
187
+ const spacing = after(3) - after(2);
188
+ expect(spacing).toBe(100);
189
+ expect(after(1)).toBe(after(2) - spacing);
190
+ });
191
+
192
+ it("new points entering from the right also land at a natural position", () => {
193
+ const before = scaleLinear().domain([1, 6]).range(RANGE);
194
+ const after = scaleLinear().domain([2, 7]).range(RANGE);
195
+
196
+ // Point 7 in the OLD scale would be at (7-1)/(6-1) * 500 = 600
197
+ expect(before(7)).toBe(600);
198
+
199
+ // In the new scale, point 7 is at 500 (right edge)
200
+ expect(after(7)).toBe(500);
201
+
202
+ // So animating from before(7)=600 to after(7)=500 means
203
+ // the point enters from just past the right edge — smooth!
204
+ });
205
+
206
+ it("has the SAME spacing when count changes (unlike scalePoint)", () => {
207
+ // Even if we go from 6 values to 5, the spacing per unit stays constant
208
+ // because it's determined by domain range / pixel range, not by item count
209
+ const before = scaleLinear().domain([1, 6]).range(RANGE);
210
+ const after = scaleLinear().domain([2, 6]).range(RANGE);
211
+
212
+ const spacingBefore = before(2) - before(1);
213
+ const spacingAfter = after(3) - after(2);
214
+
215
+ expect(spacingBefore).toBe(100); // 500 / 5
216
+ expect(spacingAfter).toBe(125); // 500 / 4
217
+
218
+ // Spacing changes because the domain range changed (was 5, now 4)
219
+ // but the key difference is: scaleLinear CAN position the removed value
220
+ expect(after(1)).toBe(-125);
221
+ });
222
+ });
223
+
224
+ describe("key difference for animation: extrapolation capability", () => {
225
+ const RANGE: [number, number] = [0, 500];
226
+
227
+ it("scalePoint returns undefined for removed items — animation system must invent a position", () => {
228
+ const oldScale = scalePoint<string>().domain(["A", "B", "C", "D", "E", "F"]).range(RANGE);
229
+ const newScale = scalePoint<string>().domain(["B", "C", "D", "E", "F", "G"]).range(RANGE);
230
+
231
+ // A was at position 0 in the old scale
232
+ expect(oldScale("A")).toBe(0);
233
+ // A cannot be positioned in the new scale
234
+ expect(newScale("A")).toBeUndefined();
235
+ });
236
+
237
+ it("scaleLinear can position any value including removed ones — natural animation", () => {
238
+ const oldScale = scaleLinear().domain([1, 6]).range(RANGE);
239
+ const newScale = scaleLinear().domain([2, 7]).range(RANGE);
240
+
241
+ // Point 1 was at position 0
242
+ expect(oldScale(1)).toBe(0);
243
+ // Point 1 can STILL be positioned in the new scale: it's at -100
244
+ expect(newScale(1)).toBe(-100);
245
+
246
+ // Similarly, point 7 in the old scale is at 600 (past the right edge)
247
+ expect(oldScale(7)).toBe(600);
248
+ // And in the new scale it's at 500 (right edge)
249
+ expect(newScale(7)).toBe(500);
250
+ });
251
+ });
252
+
253
+ describe("in a real LineChart: selectLinePoints with categorical XAxis", () => {
254
+ beforeEach(() => {
255
+ mockGetBoundingClientRect({ width: 500, height: 300 });
256
+ });
257
+
258
+ const dataWindow1 = [
259
+ { name: "A", value: 10 },
260
+ { name: "B", value: 20 },
261
+ { name: "C", value: 30 },
262
+ { name: "D", value: 40 },
263
+ { name: "E", value: 50 },
264
+ { name: "F", value: 60 },
265
+ ];
266
+
267
+ const dataWindow2 = [
268
+ { name: "B", value: 20 },
269
+ { name: "C", value: 30 },
270
+ { name: "D", value: 40 },
271
+ { name: "E", value: 50 },
272
+ { name: "F", value: 60 },
273
+ { name: "G", value: 70 },
274
+ ];
275
+
276
+ it("should redistribute all x positions when data slides with categorical axis", () => {
277
+ const [data, setData] = createSignal(dataWindow1);
278
+ const DataSlidingChart = (props: { children: JSX.Element }): JSX.Element => (
279
+ <>
280
+ <button type="button" onClick={() => setData(dataWindow2)}>
281
+ Slide
282
+ </button>
283
+ <LineChart width={500} height={300} data={data()}>
284
+ <XAxis dataKey="name" />
285
+ <YAxis />
286
+ <Line isAnimationActive={false} dataKey="value" id="line" />
287
+ {props.children}
288
+ </LineChart>
289
+ </>
290
+ );
291
+
292
+ const renderTestCase = createSelectorTestCase(DataSlidingChart);
293
+ const { container, spy } = renderTestCase((state) =>
294
+ selectLinePoints(state, 0, 0, false, "line"),
295
+ );
296
+
297
+ // Get positions before slide
298
+ const beforePoints: ReadonlyArray<LinePointItem> | undefined =
299
+ spy.mock.calls[spy.mock.calls.length - 1]?.[0];
300
+ assertNotNull(beforePoints);
301
+ expect(beforePoints).toHaveLength(6);
302
+
303
+ const beforeXPositions = beforePoints.map((p) => ({ name: payloadName(p), x: p.x }));
304
+
305
+ // Slide the data
306
+ const button = container.querySelector("button")!;
307
+ fireEvent.click(button);
308
+ flush();
309
+
310
+ const afterPoints: ReadonlyArray<LinePointItem> | undefined =
311
+ spy.mock.calls[spy.mock.calls.length - 1]?.[0];
312
+ assertNotNull(afterPoints);
313
+ expect(afterPoints).toHaveLength(6);
314
+
315
+ const afterXPositions = afterPoints.map((p) => ({ name: payloadName(p), x: p.x }));
316
+
317
+ // Key observation: B's x position changes from its "before" position
318
+ const beforeB = beforeXPositions.find((p) => p.name === "B")!;
319
+ const afterB = afterXPositions.find((p) => p.name === "B")!;
320
+ expect(beforeB.x).not.toBe(afterB.x);
321
+
322
+ // B was at position index 1 (of 6), now at position index 0 (of 6)
323
+ // With scalePoint, all positions redistribute
324
+ // B moves from where "B" was to where "A" used to be (approximately)
325
+ expect(afterB.x).toBeLessThan(beforeB.x!);
326
+
327
+ // Similarly for F: was at position 5 (of 6), now at position 4 (of 6)
328
+ const beforeF = beforeXPositions.find((p) => p.name === "F")!;
329
+ const afterF = afterXPositions.find((p) => p.name === "F")!;
330
+ expect(afterF.x).toBeLessThan(beforeF.x!);
331
+
332
+ // The shift for each surviving point should be equal (same spacing, same count)
333
+ const shiftB = beforeB.x! - afterB.x!;
334
+ const shiftF = beforeF.x! - afterF.x!;
335
+ expect(shiftB).toBeCloseTo(shiftF, 1);
336
+
337
+ // Point A is no longer in the data at all — animation must extrapolate its exit position
338
+ expect(afterXPositions.find((p) => p.name === "A")).toBeUndefined();
339
+ });
340
+ });
341
+
342
+ describe("in a real LineChart: selectLinePoints with numerical XAxis", () => {
343
+ beforeEach(() => {
344
+ mockGetBoundingClientRect({ width: 500, height: 300 });
345
+ });
346
+
347
+ const dataWindow1 = [
348
+ { x: 1, value: 10 },
349
+ { x: 2, value: 20 },
350
+ { x: 3, value: 30 },
351
+ { x: 4, value: 40 },
352
+ { x: 5, value: 50 },
353
+ { x: 6, value: 60 },
354
+ ];
355
+
356
+ const dataWindow2 = [
357
+ { x: 2, value: 20 },
358
+ { x: 3, value: 30 },
359
+ { x: 4, value: 40 },
360
+ { x: 5, value: 50 },
361
+ { x: 6, value: 60 },
362
+ { x: 7, value: 70 },
363
+ ];
364
+
365
+ it("should compute positions based on numeric values with linear scale", () => {
366
+ const [data, setData] = createSignal(dataWindow1);
367
+ const DataSlidingChart = (props: { children: JSX.Element }): JSX.Element => (
368
+ <>
369
+ <button type="button" onClick={() => setData(dataWindow2)}>
370
+ Slide
371
+ </button>
372
+ <LineChart width={500} height={300} data={data()}>
373
+ <XAxis dataKey="x" type="number" domain={["dataMin", "dataMax"]} />
374
+ <YAxis />
375
+ <Line isAnimationActive={false} dataKey="value" id="line" />
376
+ {props.children}
377
+ </LineChart>
378
+ </>
379
+ );
380
+
381
+ const renderTestCase = createSelectorTestCase(DataSlidingChart);
382
+ const { container, spy } = renderTestCase((state) =>
383
+ selectLinePoints(state, 0, 0, false, "line"),
384
+ );
385
+
386
+ const beforePoints: ReadonlyArray<LinePointItem> | undefined =
387
+ spy.mock.calls[spy.mock.calls.length - 1]?.[0];
388
+ assertNotNull(beforePoints);
389
+ expect(beforePoints).toHaveLength(6);
390
+
391
+ const beforeXPositions = beforePoints.map((p) => ({ x: payloadX(p), px: p.x }));
392
+
393
+ // Slide the data
394
+ const button = container.querySelector("button")!;
395
+ fireEvent.click(button);
396
+ flush();
397
+
398
+ const afterPoints: ReadonlyArray<LinePointItem> | undefined =
399
+ spy.mock.calls[spy.mock.calls.length - 1]?.[0];
400
+ assertNotNull(afterPoints);
401
+ expect(afterPoints).toHaveLength(6);
402
+
403
+ const afterXPositions = afterPoints.map((p) => ({ x: payloadX(p), px: p.x }));
404
+
405
+ // Key observation: positions shift proportionally
406
+ const beforeP2 = beforeXPositions.find((p) => p.x === 2)!;
407
+ const afterP2 = afterXPositions.find((p) => p.x === 2)!;
408
+
409
+ // Point 2 moves left because the domain shifted from [1,6] to [2,7]
410
+ expect(afterP2.px).toBeLessThan(beforeP2.px!);
411
+
412
+ // All surviving points should shift by the same amount
413
+ const shifts = [2, 3, 4, 5, 6].map((val) => {
414
+ const before = beforeXPositions.find((p) => p.x === val)!;
415
+ const after = afterXPositions.find((p) => p.x === val)!;
416
+ return before.px! - after.px!;
417
+ });
418
+
419
+ // All shifts should be equal (linear scale preserves uniform shift)
420
+ for (const shift of shifts) {
421
+ expect(shift).toBeCloseTo(shifts[0]!, 1);
422
+ }
423
+
424
+ // The new point (x=7) is at the right edge of the plot
425
+ const p7 = afterXPositions.find((p) => p.x === 7)!;
426
+ const p6 = afterXPositions.find((p) => p.x === 6)!;
427
+ const spacing = p7.px! - p6.px!;
428
+ expect(spacing).toBeGreaterThan(0);
429
+ });
430
+
431
+ it("should position the leftmost point at the left edge of plot area after slide", () => {
432
+ const [data, setData] = createSignal(dataWindow1);
433
+ const DataSlidingChart = (props: { children: JSX.Element }): JSX.Element => (
434
+ <>
435
+ <button type="button" onClick={() => setData(dataWindow2)}>
436
+ Slide
437
+ </button>
438
+ <LineChart width={500} height={300} data={data()}>
439
+ <XAxis dataKey="x" type="number" domain={["dataMin", "dataMax"]} />
440
+ <YAxis />
441
+ <Line isAnimationActive={false} dataKey="value" id="line" />
442
+ {props.children}
443
+ </LineChart>
444
+ </>
445
+ );
446
+
447
+ const renderTestCase = createSelectorTestCase(DataSlidingChart);
448
+ const { container, spy } = renderTestCase((state) =>
449
+ selectLinePoints(state, 0, 0, false, "line"),
450
+ );
451
+
452
+ const beforePoints: ReadonlyArray<LinePointItem> | undefined =
453
+ spy.mock.calls[spy.mock.calls.length - 1]?.[0];
454
+ assertNotNull(beforePoints);
455
+ // Point 1 (leftmost) should be at the left edge
456
+ const p1Before = beforePoints.find((p) => payloadX(p) === 1)!;
457
+ // Point 6 (rightmost) should be at the right edge
458
+ const p6Before = beforePoints.find((p) => payloadX(p) === 6)!;
459
+
460
+ const button = container.querySelector("button")!;
461
+ fireEvent.click(button);
462
+ flush();
463
+
464
+ const afterPoints: ReadonlyArray<LinePointItem> | undefined =
465
+ spy.mock.calls[spy.mock.calls.length - 1]?.[0];
466
+ assertNotNull(afterPoints);
467
+ // Point 2 (now leftmost) should be at the left edge
468
+ const p2After = afterPoints.find((p) => payloadX(p) === 2)!;
469
+ // Point 7 (now rightmost) should be at the right edge
470
+ const p7After = afterPoints.find((p) => payloadX(p) === 7)!;
471
+
472
+ // With domain=['dataMin','dataMax'], the leftmost is always at the same x
473
+ // and the rightmost is always at the same x
474
+ expect(p2After.x).toBe(p1Before.x);
475
+ expect(p7After.x).toBe(p6Before.x);
476
+ });
477
+ });
478
+
479
+ describe("comparing shifts: categorical vs numerical during identical data slide", () => {
480
+ beforeEach(() => {
481
+ mockGetBoundingClientRect({ width: 500, height: 300 });
482
+ });
483
+
484
+ it("both axis types produce the same shift magnitude when item count stays constant", () => {
485
+ // Categorical
486
+ const catChart = (props: { children: JSX.Element }): JSX.Element => (
487
+ <LineChart
488
+ width={500}
489
+ height={300}
490
+ data={[
491
+ { name: "A", value: 10 },
492
+ { name: "B", value: 20 },
493
+ { name: "C", value: 30 },
494
+ ]}
495
+ >
496
+ <XAxis dataKey="name" />
497
+ <Line isAnimationActive={false} dataKey="value" id="line" />
498
+ {props.children}
499
+ </LineChart>
500
+ );
501
+ const catRender = createSelectorTestCase(catChart);
502
+ const { spy: catSpy } = catRender((state) => selectLinePoints(state, 0, 0, false, "line"));
503
+ const catPoints: ReadonlyArray<LinePointItem> | undefined =
504
+ catSpy.mock.calls[catSpy.mock.calls.length - 1]?.[0];
505
+ assertNotNull(catPoints);
506
+
507
+ // Numerical
508
+ const numChart = (props: { children: JSX.Element }): JSX.Element => (
509
+ <LineChart
510
+ width={500}
511
+ height={300}
512
+ data={[
513
+ { x: 1, value: 10 },
514
+ { x: 2, value: 20 },
515
+ { x: 3, value: 30 },
516
+ ]}
517
+ >
518
+ <XAxis dataKey="x" type="number" domain={["dataMin", "dataMax"]} />
519
+ <Line isAnimationActive={false} dataKey="value" id="line" />
520
+ {props.children}
521
+ </LineChart>
522
+ );
523
+ const numRender = createSelectorTestCase(numChart);
524
+ const { spy: numSpy } = numRender((state) => selectLinePoints(state, 0, 0, false, "line"));
525
+ const numPoints: ReadonlyArray<LinePointItem> | undefined =
526
+ numSpy.mock.calls[numSpy.mock.calls.length - 1]?.[0];
527
+ assertNotNull(numPoints);
528
+
529
+ // Both should have same number of points
530
+ expect(catPoints).toHaveLength(3);
531
+ expect(numPoints).toHaveLength(3);
532
+
533
+ // Both should use the same range, so the first and last point positions
534
+ // should be similar (they both map to the edges of the plot area)
535
+ const catSpacing = catPoints[1]!.x! - catPoints[0]!.x!;
536
+ const numSpacing = numPoints[1]!.x! - numPoints[0]!.x!;
537
+
538
+ // Both spacings should be equal because both have the same number of points
539
+ // across the same plot width
540
+ expect(catSpacing).toBeCloseTo(numSpacing, 0);
541
+ });
542
+ });
543
+
544
+ describe("animation implications: what defaultLineAnimateItems must handle", () => {
545
+ it("with scalePoint: removed item has no position in new frame, must be computed from shift", () => {
546
+ const RANGE: [number, number] = [0, 500];
547
+ const before = scalePoint<string>().domain(["A", "B", "C", "D", "E", "F"]).range(RANGE);
548
+ const after = scalePoint<string>().domain(["B", "C", "D", "E", "F", "G"]).range(RANGE);
549
+
550
+ // Simulate what defaultLineAnimateItems does:
551
+ // 1. Match surviving points: B→B, C→C, D→D, E→E, F→F
552
+ const matchedPairs = ["B", "C", "D", "E", "F"].map((label) => ({
553
+ label,
554
+ prevX: before(label)!,
555
+ nextX: after(label)!,
556
+ }));
557
+
558
+ // 2. Compute average shift
559
+ const shifts = matchedPairs.map((p) => p.nextX - p.prevX);
560
+ const avgShift = shifts.reduce((a, b) => a + b, 0) / shifts.length;
561
+ expect(avgShift).toBe(-100); // all points shifted left by 100
562
+
563
+ // 3. For removed item A: animate from prev position to prev position + shift
564
+ const removedPrevX = before("A")!;
565
+ expect(removedPrevX).toBe(0);
566
+ const removedExitX = removedPrevX + avgShift;
567
+ expect(removedExitX).toBe(-100); // slides off the left edge — correct!
568
+
569
+ // 4. For new item G: animate from next position - shift to next position
570
+ const newNextX = after("G")!;
571
+ expect(newNextX).toBe(500);
572
+ const newEntryX = newNextX - avgShift;
573
+ expect(newEntryX).toBe(600); // enters from past the right edge — correct!
574
+ });
575
+
576
+ it("with scaleLinear: the scale itself handles extrapolation", () => {
577
+ const RANGE: [number, number] = [0, 500];
578
+ const before = scaleLinear().domain([1, 6]).range(RANGE);
579
+ const after = scaleLinear().domain([2, 7]).range(RANGE);
580
+
581
+ // The matched pairs work the same way
582
+ const matchedPairs = [2, 3, 4, 5, 6].map((val) => ({
583
+ val,
584
+ prevX: before(val),
585
+ nextX: after(val),
586
+ }));
587
+
588
+ const shifts = matchedPairs.map((p) => p.nextX - p.prevX);
589
+ const avgShift = shifts.reduce((a, b) => a + b, 0) / shifts.length;
590
+ expect(avgShift).toBe(-100);
591
+
592
+ // For removed item 1: our animation computes prev + shift = 0 + (-100) = -100
593
+ const removedExitX = before(1) + avgShift;
594
+ expect(removedExitX).toBe(-100);
595
+
596
+ // But scaleLinear can also extrapolate directly: after(1) = -100
597
+ expect(after(1)).toBe(-100);
598
+ });
599
+
600
+ it("both approaches produce the same exit/entry positions when count stays constant", () => {
601
+ const RANGE: [number, number] = [0, 500];
602
+
603
+ // scalePoint approach
604
+ const catBefore = scalePoint<string>().domain(["A", "B", "C", "D", "E", "F"]).range(RANGE);
605
+ const catAfter = scalePoint<string>().domain(["B", "C", "D", "E", "F", "G"]).range(RANGE);
606
+ const catShift = catAfter("B")! - catBefore("B")!;
607
+ const catRemovedExit = catBefore("A")! + catShift;
608
+ const catNewEntry = catAfter("G")! - catShift;
609
+
610
+ // scaleLinear approach
611
+ const numBefore = scaleLinear().domain([1, 6]).range(RANGE);
612
+ const numAfter = scaleLinear().domain([2, 7]).range(RANGE);
613
+ const numShift = numAfter(2) - numBefore(2);
614
+ const numRemovedExit = numBefore(1) + numShift;
615
+ const numNewEntry = numAfter(7) - numShift;
616
+
617
+ // All the same!
618
+ expect(catShift).toBe(numShift);
619
+ expect(catRemovedExit).toBe(numRemovedExit);
620
+ expect(catNewEntry).toBe(numNewEntry);
621
+
622
+ // Both produce: exit at -100, entry from 600
623
+ expect(catRemovedExit).toBe(-100);
624
+ expect(catNewEntry).toBe(600);
625
+ });
626
+ });
627
+ });