@solidports/recharts 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (304) hide show
  1. package/dist/index.d.ts +40 -2
  2. package/dist/index.js +14238 -7174
  3. package/dist/{dev.js → index.jsx} +18367 -15900
  4. package/dist/server.js +48178 -0
  5. package/package.json +36 -19
  6. package/src/animation/AnimatedItems.tsx +0 -183
  7. package/src/animation/AnimationController.ts +0 -33
  8. package/src/animation/AnimationControllerImpl.ts +0 -36
  9. package/src/animation/AnimationHandle.ts +0 -307
  10. package/src/animation/CSSTransitionAnimate.tsx +0 -170
  11. package/src/animation/JavascriptAnimate.tsx +0 -119
  12. package/src/animation/easing.ts +0 -221
  13. package/src/animation/matchBy.ts +0 -164
  14. package/src/animation/timeoutController.ts +0 -70
  15. package/src/animation/useAnimationController.tsx +0 -34
  16. package/src/animation/useAnimationStartSnapshot.ts +0 -118
  17. package/src/animation/util.ts +0 -41
  18. package/src/cartesian/Area.tsx +0 -915
  19. package/src/cartesian/AreaRevealShape.tsx +0 -190
  20. package/src/cartesian/Bar.tsx +0 -1369
  21. package/src/cartesian/BarStack.tsx +0 -152
  22. package/src/cartesian/Brush.tsx +0 -951
  23. package/src/cartesian/CartesianAxis.tsx +0 -722
  24. package/src/cartesian/CartesianGrid.tsx +0 -711
  25. package/src/cartesian/ErrorBar.tsx +0 -361
  26. package/src/cartesian/Funnel.tsx +0 -803
  27. package/src/cartesian/GraphicalItemClipPath.tsx +0 -67
  28. package/src/cartesian/Line.tsx +0 -863
  29. package/src/cartesian/LineDrawShape.tsx +0 -89
  30. package/src/cartesian/ReferenceArea.tsx +0 -331
  31. package/src/cartesian/ReferenceDot.tsx +0 -304
  32. package/src/cartesian/ReferenceLine.tsx +0 -474
  33. package/src/cartesian/Scatter.tsx +0 -888
  34. package/src/cartesian/XAxis.tsx +0 -433
  35. package/src/cartesian/YAxis.tsx +0 -443
  36. package/src/cartesian/ZAxis.tsx +0 -155
  37. package/src/cartesian/cartesianPositionToCSSTranslate.tsx +0 -29
  38. package/src/cartesian/cartesianViewBoxToTrapezoid.tsx +0 -21
  39. package/src/cartesian/getCartesianPosition.tsx +0 -267
  40. package/src/cartesian/getEquidistantTicks.ts +0 -144
  41. package/src/cartesian/getTicks.ts +0 -225
  42. package/src/cartesian/isOutsidePosition.ts +0 -15
  43. package/src/cartesian/useAnimatedLineLength.ts +0 -54
  44. package/src/chart/AreaChart.tsx +0 -29
  45. package/src/chart/BarChart.tsx +0 -29
  46. package/src/chart/CartesianChart.tsx +0 -131
  47. package/src/chart/CategoricalChart.tsx +0 -94
  48. package/src/chart/ComposedChart.tsx +0 -29
  49. package/src/chart/FunnelChart.tsx +0 -29
  50. package/src/chart/LineChart.tsx +0 -29
  51. package/src/chart/PieChart.tsx +0 -50
  52. package/src/chart/PolarChart.tsx +0 -164
  53. package/src/chart/RadarChart.tsx +0 -70
  54. package/src/chart/RadialBarChart.tsx +0 -46
  55. package/src/chart/RechartsWrapper.tsx +0 -551
  56. package/src/chart/Sankey.tsx +0 -1534
  57. package/src/chart/ScatterChart.tsx +0 -29
  58. package/src/chart/SunburstChart.tsx +0 -504
  59. package/src/chart/Treemap.tsx +0 -1223
  60. package/src/chart/createInitialRootProps.ts +0 -24
  61. package/src/chart/types.ts +0 -53
  62. package/src/component/ActivePoints.tsx +0 -144
  63. package/src/component/Cell.tsx +0 -37
  64. package/src/component/Cursor.tsx +0 -185
  65. package/src/component/Customized.tsx +0 -50
  66. package/src/component/DefaultLegendContent.tsx +0 -348
  67. package/src/component/DefaultTooltipContent.tsx +0 -224
  68. package/src/component/Dots.tsx +0 -157
  69. package/src/component/Label.tsx +0 -636
  70. package/src/component/LabelList.tsx +0 -375
  71. package/src/component/Legend.tsx +0 -512
  72. package/src/component/ResponsiveContainer.tsx +0 -348
  73. package/src/component/Text.tsx +0 -541
  74. package/src/component/Tooltip.tsx +0 -470
  75. package/src/component/TooltipBoundingBox.tsx +0 -146
  76. package/src/component/responsiveContainerUtils.ts +0 -134
  77. package/src/container/ClipPathProvider.tsx +0 -51
  78. package/src/container/Layer.tsx +0 -38
  79. package/src/container/RootSurface.tsx +0 -120
  80. package/src/container/Surface.tsx +0 -61
  81. package/src/context/CellsContext.tsx +0 -54
  82. package/src/context/ErrorBarContext.tsx +0 -146
  83. package/src/context/GraphicalItemChildrenScope.tsx +0 -18
  84. package/src/context/PanoramaContext.tsx +0 -9
  85. package/src/context/RegisterGraphicalItemId.tsx +0 -30
  86. package/src/context/accessibilityContext.tsx +0 -6
  87. package/src/context/brushUpdateContext.tsx +0 -9
  88. package/src/context/chartDataContext.tsx +0 -97
  89. package/src/context/chartLayoutContext.tsx +0 -201
  90. package/src/context/legendPayloadContext.tsx +0 -20
  91. package/src/context/legendPortalContext.tsx +0 -12
  92. package/src/context/tooltipContext.tsx +0 -89
  93. package/src/context/tooltipPortalContext.tsx +0 -12
  94. package/src/context/useTooltipAxis.ts +0 -22
  95. package/src/hooks.ts +0 -476
  96. package/src/index.ts +0 -280
  97. package/src/polar/Pie.tsx +0 -1360
  98. package/src/polar/PolarAngleAxis.tsx +0 -616
  99. package/src/polar/PolarGrid.tsx +0 -312
  100. package/src/polar/PolarRadiusAxis.tsx +0 -547
  101. package/src/polar/Radar.tsx +0 -734
  102. package/src/polar/RadialBar.tsx +0 -917
  103. package/src/polar/defaultPolarAngleAxisProps.tsx +0 -27
  104. package/src/polar/defaultPolarRadiusAxisProps.tsx +0 -25
  105. package/src/shape/Cross.tsx +0 -89
  106. package/src/shape/Curve.tsx +0 -343
  107. package/src/shape/Dot.tsx +0 -70
  108. package/src/shape/Polygon.tsx +0 -195
  109. package/src/shape/Rectangle.tsx +0 -470
  110. package/src/shape/Sector.tsx +0 -347
  111. package/src/shape/Symbols.tsx +0 -139
  112. package/src/shape/Trapezoid.tsx +0 -280
  113. package/src/state/RechartsStateContext.tsx +0 -12
  114. package/src/state/RechartsStateProvider.tsx +0 -87
  115. package/src/state/RechartsStoreContext.tsx +0 -25
  116. package/src/state/RechartsStoreProvider.tsx +0 -35
  117. package/src/state/ReportChartProps.tsx +0 -40
  118. package/src/state/ReportEventSettings.tsx +0 -30
  119. package/src/state/ReportMainChartProps.tsx +0 -61
  120. package/src/state/ReportPolarOptions.tsx +0 -35
  121. package/src/state/SetGraphicalItem.ts +0 -79
  122. package/src/state/SetLegendPayload.ts +0 -134
  123. package/src/state/SetTooltipEntrySettings.tsx +0 -72
  124. package/src/state/actions.ts +0 -464
  125. package/src/state/brushSlice.ts +0 -13
  126. package/src/state/cartesianAxisSlice.ts +0 -141
  127. package/src/state/chartDataSlice.ts +0 -50
  128. package/src/state/chartState.ts +0 -297
  129. package/src/state/errorBarSlice.ts +0 -29
  130. package/src/state/eventSettingsSlice.ts +0 -8
  131. package/src/state/events.ts +0 -76
  132. package/src/state/externalEventsMiddleware.ts +0 -255
  133. package/src/state/graphicalItemsSlice.ts +0 -74
  134. package/src/state/hooks/useChartSelectors.tsx +0 -45
  135. package/src/state/keyboardEventsMiddleware.ts +0 -228
  136. package/src/state/layoutSlice.ts +0 -21
  137. package/src/state/legendSlice.ts +0 -57
  138. package/src/state/mouseEventsMiddleware.ts +0 -185
  139. package/src/state/optionsSlice.ts +0 -47
  140. package/src/state/polarAxisSlice.ts +0 -10
  141. package/src/state/polarOptionsSlice.ts +0 -12
  142. package/src/state/rawData.ts +0 -26
  143. package/src/state/referenceElementsSlice.ts +0 -40
  144. package/src/state/renderedTicksSlice.ts +0 -15
  145. package/src/state/rootPropsSlice.ts +0 -47
  146. package/src/state/selectors/areaSelectors.ts +0 -240
  147. package/src/state/selectors/arrayEqualityCheck.ts +0 -29
  148. package/src/state/selectors/axisSelectors.ts +0 -2157
  149. package/src/state/selectors/barSelectors.ts +0 -310
  150. package/src/state/selectors/barStackSelectors.ts +0 -77
  151. package/src/state/selectors/brushSelectors.ts +0 -33
  152. package/src/state/selectors/chartSelector.ts +0 -185
  153. package/src/state/selectors/combiners/combineActiveLabel.ts +0 -16
  154. package/src/state/selectors/combiners/combineActiveTooltipIndex.ts +0 -95
  155. package/src/state/selectors/combiners/combineAllBarPositions.ts +0 -122
  156. package/src/state/selectors/combiners/combineAxisRangeWithReverse.ts +0 -16
  157. package/src/state/selectors/combiners/combineBarPosition.ts +0 -23
  158. package/src/state/selectors/combiners/combineBarSizeList.ts +0 -80
  159. package/src/state/selectors/combiners/combineCheckedDomain.ts +0 -48
  160. package/src/state/selectors/combiners/combineConfiguredScale.ts +0 -111
  161. package/src/state/selectors/combiners/combineCoordinateForDefaultIndex.ts +0 -45
  162. package/src/state/selectors/combiners/combineDisplayedStackedData.ts +0 -50
  163. package/src/state/selectors/combiners/combineInverseScaleFunction.ts +0 -16
  164. package/src/state/selectors/combiners/combineRealScaleType.ts +0 -44
  165. package/src/state/selectors/combiners/combineStackedData.ts +0 -27
  166. package/src/state/selectors/combiners/combineTooltipInteractionState.ts +0 -86
  167. package/src/state/selectors/combiners/combineTooltipPayload.ts +0 -205
  168. package/src/state/selectors/combiners/combineTooltipPayloadConfigurations.ts +0 -58
  169. package/src/state/selectors/containerSelectors.ts +0 -12
  170. package/src/state/selectors/dataSelectors.ts +0 -88
  171. package/src/state/selectors/funnelSelectors.ts +0 -75
  172. package/src/state/selectors/graphicalItemSelectors.ts +0 -30
  173. package/src/state/selectors/legendSelectors.ts +0 -29
  174. package/src/state/selectors/lineSelectors.ts +0 -134
  175. package/src/state/selectors/numberDomainEqualityCheck.ts +0 -14
  176. package/src/state/selectors/pickAxisId.ts +0 -5
  177. package/src/state/selectors/pickAxisType.ts +0 -3
  178. package/src/state/selectors/pieSelectors.ts +0 -97
  179. package/src/state/selectors/polarAxisSelectors.ts +0 -201
  180. package/src/state/selectors/polarGridSelectors.ts +0 -28
  181. package/src/state/selectors/polarScaleSelectors.ts +0 -133
  182. package/src/state/selectors/polarSelectors.ts +0 -219
  183. package/src/state/selectors/radarSelectors.ts +0 -191
  184. package/src/state/selectors/radialBarSelectors.ts +0 -435
  185. package/src/state/selectors/rootPropsSelectors.ts +0 -25
  186. package/src/state/selectors/scatterSelectors.ts +0 -96
  187. package/src/state/selectors/selectActivePropsFromChartPointer.ts +0 -26
  188. package/src/state/selectors/selectAllAxes.ts +0 -17
  189. package/src/state/selectors/selectChartOffset.ts +0 -16
  190. package/src/state/selectors/selectChartOffsetInternal.ts +0 -136
  191. package/src/state/selectors/selectLegendArea.ts +0 -20
  192. package/src/state/selectors/selectPlotArea.ts +0 -22
  193. package/src/state/selectors/selectTooltipAxisId.ts +0 -7
  194. package/src/state/selectors/selectTooltipAxisType.ts +0 -32
  195. package/src/state/selectors/selectTooltipEventType.ts +0 -48
  196. package/src/state/selectors/selectTooltipPayloadSearcher.ts +0 -6
  197. package/src/state/selectors/selectTooltipSettings.ts +0 -39
  198. package/src/state/selectors/selectTooltipState.ts +0 -8
  199. package/src/state/selectors/selectors.ts +0 -271
  200. package/src/state/selectors/tooltipSelectors.ts +0 -578
  201. package/src/state/selectors/touchSelectors.ts +0 -31
  202. package/src/state/store.ts +0 -29
  203. package/src/state/storeIdentity.ts +0 -9
  204. package/src/state/teardownWrite.ts +0 -10
  205. package/src/state/tooltipInteraction.ts +0 -23
  206. package/src/state/tooltipSlice.ts +0 -334
  207. package/src/state/touchEventsMiddleware.ts +0 -214
  208. package/src/state/types/AnimationSettings.ts +0 -20
  209. package/src/state/types/AreaSettings.ts +0 -14
  210. package/src/state/types/BarSettings.ts +0 -15
  211. package/src/state/types/LineSettings.ts +0 -9
  212. package/src/state/types/PieSettings.ts +0 -34
  213. package/src/state/types/RadarSettings.ts +0 -5
  214. package/src/state/types/RadialBarSettings.ts +0 -10
  215. package/src/state/types/ScatterSettings.ts +0 -12
  216. package/src/state/types/StackedGraphicalItem.ts +0 -34
  217. package/src/state/useChartState.ts +0 -17
  218. package/src/state/zIndexSlice.ts +0 -39
  219. package/src/synchronisation/syncSelectors.ts +0 -7
  220. package/src/synchronisation/types.ts +0 -44
  221. package/src/synchronisation/useChartSynchronisation.tsx +0 -404
  222. package/src/theme/RechartsTheme.ts +0 -16
  223. package/src/theme/RechartsThemeContext.ts +0 -19
  224. package/src/theme/darkTheme.ts +0 -13
  225. package/src/theme/graphicalItemIdentity.ts +0 -70
  226. package/src/theme/legacyTheme.ts +0 -17
  227. package/src/theme/lightTheme.ts +0 -13
  228. package/src/types.ts +0 -54
  229. package/src/util/ActiveShapeUtils.tsx +0 -162
  230. package/src/util/BarUtils.tsx +0 -62
  231. package/src/util/BarePortal.tsx +0 -50
  232. package/src/util/CamelCaseSVGAttrs.ts +0 -34
  233. package/src/util/CartesianUtils.ts +0 -48
  234. package/src/util/ChartUtils.ts +0 -802
  235. package/src/util/Constants.ts +0 -42
  236. package/src/util/CssPrefixUtils.ts +0 -20
  237. package/src/util/DOMUtils.ts +0 -129
  238. package/src/util/DataUtils.ts +0 -216
  239. package/src/util/Events.ts +0 -16
  240. package/src/util/FunnelUtils.tsx +0 -15
  241. package/src/util/Global.ts +0 -12
  242. package/src/util/IfOverflow.ts +0 -15
  243. package/src/util/LRUCache.ts +0 -41
  244. package/src/util/LogUtils.ts +0 -22
  245. package/src/util/PolarUtils.ts +0 -132
  246. package/src/util/RadialBarUtils.tsx +0 -24
  247. package/src/util/ReactUtils.ts +0 -95
  248. package/src/util/ReduceCSSCalc.ts +0 -187
  249. package/src/util/ScatterUtils.tsx +0 -52
  250. package/src/util/ShapeElementProps.tsx +0 -87
  251. package/src/util/TickUtils.ts +0 -60
  252. package/src/util/XAxisUtils.ts +0 -48
  253. package/src/util/YAxisUtils.ts +0 -48
  254. package/src/util/axisPropsAreEqual.ts +0 -48
  255. package/src/util/createCartesianCharts.tsx +0 -150
  256. package/src/util/createEventProxy.ts +0 -20
  257. package/src/util/createPolarCharts.tsx +0 -112
  258. package/src/util/cursor/getCursorPoints.ts +0 -46
  259. package/src/util/cursor/getCursorRectangle.ts +0 -28
  260. package/src/util/cursor/getRadialCursorPoints.ts +0 -32
  261. package/src/util/excludeEventProps.ts +0 -171
  262. package/src/util/getActiveCoordinate.ts +0 -213
  263. package/src/util/getAxisTypeBasedOnLayout.ts +0 -21
  264. package/src/util/getClassNameFromUnknown.ts +0 -6
  265. package/src/util/getEveryNth.ts +0 -27
  266. package/src/util/getRadiusAndStrokeWidthFromDot.ts +0 -35
  267. package/src/util/getRelativeCoordinate.ts +0 -80
  268. package/src/util/getSliced.ts +0 -13
  269. package/src/util/hoverDedupe.ts +0 -41
  270. package/src/util/isDomainSpecifiedByUser.ts +0 -219
  271. package/src/util/isWellBehavedNumber.ts +0 -7
  272. package/src/util/pathTotalLength.ts +0 -25
  273. package/src/util/payload/getUniqPayload.ts +0 -28
  274. package/src/util/propsAreEqual.ts +0 -121
  275. package/src/util/resolveDefaultProps.ts +0 -161
  276. package/src/util/round.ts +0 -32
  277. package/src/util/scale/CartesianScaleHelper.ts +0 -72
  278. package/src/util/scale/CustomScaleDefinition.ts +0 -81
  279. package/src/util/scale/RechartsScale.ts +0 -130
  280. package/src/util/scale/createCategoricalInverse.ts +0 -72
  281. package/src/util/scale/getNiceTickValues.ts +0 -311
  282. package/src/util/scale/index.ts +0 -2
  283. package/src/util/scale/util/arithmetic.ts +0 -54
  284. package/src/util/solid-1-compat.ts +0 -310
  285. package/src/util/solidJsxCamelAugment.d.ts +0 -84
  286. package/src/util/stacks/getStackSeriesIdentifier.ts +0 -21
  287. package/src/util/stacks/stackTypes.ts +0 -60
  288. package/src/util/structurallyEqual.ts +0 -31
  289. package/src/util/svgPropertiesAndEvents.ts +0 -53
  290. package/src/util/svgPropertiesNoEvents.ts +0 -571
  291. package/src/util/tooltip/translate.ts +0 -171
  292. package/src/util/typedDataKey.ts +0 -48
  293. package/src/util/types.ts +0 -1560
  294. package/src/util/useAnimationId.ts +0 -31
  295. package/src/util/useElementOffset.ts +0 -110
  296. package/src/util/useId.ts +0 -8
  297. package/src/util/usePrefersReducedMotion.ts +0 -48
  298. package/src/util/useReportScale.ts +0 -24
  299. package/src/util/useUniqueId.ts +0 -30
  300. package/src/zIndex/DefaultZIndexes.ts +0 -84
  301. package/src/zIndex/ZIndexLayer.tsx +0 -121
  302. package/src/zIndex/ZIndexPortal.tsx +0 -79
  303. package/src/zIndex/getZIndexFromUnknown.ts +0 -14
  304. package/src/zIndex/zIndexSelectors.ts +0 -48
@@ -1,951 +0,0 @@
1
- /* eslint-disable import/no-cycle, sort-keys */
2
- import { createMemo, createSignal, onCleanup, Show, createEffect, untrack } from 'solid-js';
3
- import type { WithoutRemoveFalse } from "../util/types"
4
- import type { JSX } from '@solidjs/web';
5
- import { clsx } from "clsx"
6
- import { scalePoint } from "victory-vendor/d3-scale"
7
- import range from "es-toolkit/compat/range"
8
- import { Layer } from "../container/Layer"
9
- import { Text } from "../component/Text"
10
- import { getValueByDataKey } from "../util/ChartUtils"
11
- import { isNumber, isNotNil } from "../util/DataUtils"
12
- import { generatePrefixStyle } from "../util/CssPrefixUtils"
13
- import type { DataConsumer, DataKey, Padding } from "../util/types"
14
- import { useChartData, useDataIndex } from "../context/chartDataContext"
15
- import type { BrushStartEndIndex, OnBrushUpdate } from "../context/brushUpdateContext"
16
- import { useChartStore } from "../state/RechartsStoreContext"
17
- import { useOptionalChartState } from "../state/useChartState"
18
- import type { ChartData } from "../state/chartDataSlice"
19
- import type { BrushSettings } from "../state/brushSlice"
20
- import { PanoramaContextProvider } from "../context/PanoramaContext"
21
- import { selectBrushDimensions } from "../state/selectors/brushSelectors"
22
- import { useBrushChartSynchronisation } from "../synchronisation/useChartSynchronisation"
23
- import type { RequiresDefaultProps } from "../util/resolveDefaultProps"
24
- import { resolveDefaultProps } from "../util/resolveDefaultProps"
25
- import { svgPropertiesNoEvents } from "../util/svgPropertiesNoEvents"
26
- import { cloneJsxNodeWithProps, isJsxNode } from "../util/ReactUtils"
27
- import { teardownWrite } from "../state/teardownWrite"
28
-
29
- type BrushTravellerType = JSX.Element | ((travellerProps: TravellerProps) => JSX.Element)
30
-
31
- type BrushTickFormatter = (value: unknown, index: number) => number | string
32
-
33
- interface BrushProps<DataPointType = unknown, DataValueType = unknown> extends DataConsumer<
34
- DataPointType,
35
- DataValueType
36
- > {
37
- x?: number
38
- y?: number
39
- dy?: number
40
- width?: number
41
- className?: string
42
- ariaLabel?: string
43
- /** @defaultValue 40 */
44
- height?: number
45
- /** @defaultValue 5 */
46
- travellerWidth?: number
47
- traveller?: BrushTravellerType
48
- /** @defaultValue 1 */
49
- gap?: number
50
- padding?: Padding
51
- startIndex?: number
52
- endIndex?: number
53
- tickFormatter?: BrushTickFormatter
54
- children?: JSX.Element
55
- onChange?: OnBrushUpdate
56
- onDragEnd?: OnBrushUpdate
57
- /** @defaultValue 1000 */
58
- leaveTimeOut?: number
59
- /** @defaultValue false */
60
- alwaysShowText?: boolean
61
- }
62
-
63
- export type Props = WithoutRemoveFalse<Omit<JSX.GSVGAttributes<SVGGElement>, "onChange" | "onDragEnd" | "ref">> &
64
- BrushProps
65
-
66
- type InternalProps = WithoutRemoveFalse<Omit<JSX.GSVGAttributes<SVGGElement>, "onChange" | "onDragEnd" | "ref">> &
67
- RequiresDefaultProps<BrushProps, typeof defaultBrushProps>
68
-
69
- type BrushTravellerId = "startX" | "endX"
70
-
71
- type TravellerProps = {
72
- x: number
73
- y: number
74
- width: number
75
- height: number
76
- stroke?: string
77
- }
78
-
79
- function DefaultTraveller(props: TravellerProps) {
80
- const lineY = () => Math.floor(props.y + props.height / 2) - 1
81
-
82
- return (
83
- <>
84
- <rect
85
- x={props.x}
86
- y={props.y}
87
- width={props.width}
88
- height={props.height}
89
- fill={props.stroke}
90
- stroke="none"
91
- />
92
- <line
93
- x1={props.x + 1}
94
- y1={lineY()}
95
- x2={props.x + props.width - 1}
96
- y2={lineY()}
97
- fill="none"
98
- stroke="#fff"
99
- />
100
- <line
101
- x1={props.x + 1}
102
- y1={lineY() + 2}
103
- x2={props.x + props.width - 1}
104
- y2={lineY() + 2}
105
- fill="none"
106
- stroke="#fff"
107
- />
108
- </>
109
- )
110
- }
111
-
112
- /* eslint-disable solid/reactivity -- travellerType/travellerProps reads are structural type checks at component setup; Traveller is called once per mount, not in a reactive context */
113
- function Traveller(props: {
114
- travellerType: BrushTravellerType | undefined
115
- travellerProps: TravellerProps
116
- }): JSX.Element {
117
- return <>{renderTraveller(props)}</>
118
- }
119
-
120
- /* Runs inside Traveller's JSX expression so every reactive read is tracked. */
121
- function renderTraveller(props: {
122
- travellerType: BrushTravellerType | undefined
123
- travellerProps: TravellerProps
124
- }) {
125
- if (typeof props.travellerType === "function") {
126
- return (props.travellerType as (p: TravellerProps) => JSX.Element)(props.travellerProps)
127
- }
128
- if (isJsxNode(props.travellerType)) {
129
- return <>{cloneJsxNodeWithProps(props.travellerType, props.travellerProps as unknown as Record<string, unknown>) as unknown as JSX.Element}</>
130
- }
131
- return <DefaultTraveller {...props.travellerProps} />
132
- }
133
- /* eslint-enable solid/reactivity */
134
-
135
- function getNameFromUnknown(value: unknown): string | undefined {
136
- if (
137
- isNotNil(value) &&
138
- typeof value === "object" &&
139
- "name" in (value as Record<string, unknown>) &&
140
- typeof (value as Record<string, unknown>).name === "string"
141
- ) {
142
- return (value as Record<string, unknown>).name as string
143
- }
144
- return undefined
145
- }
146
-
147
- function getAriaLabel(data: ReadonlyArray<unknown>, startIndex: number, endIndex: number) {
148
- const start = getNameFromUnknown(data[startIndex])
149
- const end = getNameFromUnknown(data[endIndex])
150
- return `Min value: ${start}, Max value: ${end}`
151
- }
152
-
153
- /* eslint-disable solid/reactivity -- plain utility fn; props parameter is not a Solid reactive proxy at this call site */
154
- function getTextOfTick(props: {
155
- index: number
156
- data: ChartData
157
- dataKey: DataKey<unknown, string | number> | undefined
158
- tickFormatter: BrushTickFormatter | undefined
159
- }): number | string {
160
- const text: string | number = getValueByDataKey(
161
- props.data[props.index],
162
- props.dataKey,
163
- props.index,
164
- )
165
- return typeof props.tickFormatter === "function" ? props.tickFormatter(text, props.index) : text
166
- }
167
- /* eslint-enable solid/reactivity */
168
-
169
- function getIndexInRange(valueRange: number[], x: number) {
170
- const len = valueRange.length
171
- let start = 0
172
- let end = len - 1
173
-
174
- while (end - start > 1) {
175
- const middle = Math.floor((start + end) / 2)
176
- const middleValue = valueRange[middle]
177
-
178
- if (middleValue != null && middleValue > x) {
179
- end = middle
180
- } else {
181
- start = middle
182
- }
183
- }
184
-
185
- const endValue = valueRange[end]
186
- return endValue != null && x >= endValue ? end : start
187
- }
188
-
189
- function getIndex({
190
- startX,
191
- endX,
192
- scaleValues,
193
- gap,
194
- data,
195
- }: {
196
- startX: number
197
- endX: number
198
- scaleValues: number[]
199
- gap: number
200
- data: ChartData
201
- }): BrushStartEndIndex {
202
- const lastIndex = data.length - 1
203
- const min = Math.min(startX, endX)
204
- const max = Math.max(startX, endX)
205
- const minIndex = getIndexInRange(scaleValues, min)
206
- const maxIndex = getIndexInRange(scaleValues, max)
207
- return {
208
- endIndex: maxIndex === lastIndex ? lastIndex : maxIndex - (maxIndex % gap),
209
- startIndex: minIndex - (minIndex % gap),
210
- }
211
- }
212
-
213
- function Background(props: {
214
- x: number
215
- y: number
216
- width: number
217
- height: number
218
- fill: string | undefined
219
- stroke: string | undefined
220
- }) {
221
- return (
222
- <rect
223
- stroke={props.stroke}
224
- fill={props.fill}
225
- x={props.x}
226
- y={props.y}
227
- width={props.width}
228
- height={props.height}
229
- />
230
- )
231
- }
232
-
233
- function BrushText(props: {
234
- startIndex: number
235
- endIndex: number
236
- y: number
237
- height: number
238
- travellerWidth: number
239
- stroke: string | undefined
240
- tickFormatter: BrushTickFormatter | undefined
241
- dataKey: DataKey<unknown> | undefined
242
- data: ChartData
243
- startX: number
244
- endX: number
245
- }) {
246
- const offset = 5
247
- const attrs = () => ({
248
- fill: props.stroke,
249
- pointerEvents: "none" as const,
250
- })
251
-
252
- return (
253
- <Layer class="recharts-brush-texts">
254
- <Text
255
- textAnchor="end"
256
- verticalAnchor="middle"
257
- x={Math.min(props.startX, props.endX) - offset}
258
- y={props.y + props.height / 2}
259
- {...attrs()}
260
- >
261
- {getTextOfTick({
262
- data: props.data,
263
- dataKey: props.dataKey,
264
- index: props.startIndex,
265
- tickFormatter: props.tickFormatter,
266
- })}
267
- </Text>
268
- <Text
269
- textAnchor="start"
270
- verticalAnchor="middle"
271
- x={Math.max(props.startX, props.endX) + props.travellerWidth + offset}
272
- y={props.y + props.height / 2}
273
- {...attrs()}
274
- >
275
- {getTextOfTick({
276
- data: props.data,
277
- dataKey: props.dataKey,
278
- index: props.endIndex,
279
- tickFormatter: props.tickFormatter,
280
- })}
281
- </Text>
282
- </Layer>
283
- )
284
- }
285
-
286
- function Slide(props: {
287
- y: number
288
- height: number
289
- stroke: string | undefined
290
- travellerWidth: number
291
- startX: number
292
- endX: number
293
- onMouseEnter: (e: MouseEvent | TouchEvent) => void
294
- onMouseLeave: (e: MouseEvent | TouchEvent) => void
295
- onMouseDown: (e: MouseEvent | TouchEvent) => void
296
- onTouchStart: (e: MouseEvent | TouchEvent) => void
297
- }) {
298
- const x = () => Math.min(props.startX, props.endX) + props.travellerWidth
299
- const width = () => Math.max(Math.abs(props.endX - props.startX) - props.travellerWidth, 0)
300
-
301
- return (
302
- <rect
303
- class="recharts-brush-slide"
304
- onMouseEnter={(e) => props.onMouseEnter(e)}
305
- onMouseOver={(e) => props.onMouseEnter(e)}
306
- onMouseLeave={(e) => props.onMouseLeave(e)}
307
- onMouseOut={(e) => props.onMouseLeave(e)}
308
- onMouseDown={(e) => props.onMouseDown(e)}
309
- onTouchStart={(e) => props.onTouchStart(e)}
310
- style={{ cursor: "move" }}
311
- stroke="none"
312
- fill={props.stroke}
313
- fill-opacity={0.2}
314
- x={x()}
315
- y={props.y}
316
- width={width()}
317
- height={props.height}
318
- />
319
- )
320
- }
321
-
322
- function Panorama(props: {
323
- x: number
324
- y: number
325
- width: number
326
- height: number
327
- data: ChartData
328
- children: JSX.Element | undefined
329
- padding: Padding
330
- }) {
331
- /* In Solid, we cannot use Children.count/Children.only. Instead we pass children directly. */
332
- return <Show when={props.children != null}>{props.children}</Show>
333
- }
334
-
335
- const createScale = ({
336
- data,
337
- startIndex,
338
- endIndex,
339
- x,
340
- width,
341
- travellerWidth,
342
- }: {
343
- data: ChartData | undefined
344
- startIndex: number
345
- endIndex: number
346
- x: number
347
- width: number
348
- travellerWidth: number
349
- }) => {
350
- if (!data || !data.length) {
351
- return {}
352
- }
353
-
354
- const len = data.length
355
- const scale = scalePoint<number>()
356
- .domain(range(0, len))
357
- .range([x, x + width - travellerWidth])
358
- const scaleValues = scale
359
- .domain()
360
- .map((entry) => scale(entry))
361
- .filter(isNotNil)
362
-
363
- return {
364
- endX: scale(endIndex),
365
- scale,
366
- scaleValues,
367
- startX: scale(startIndex),
368
- }
369
- }
370
-
371
- /**
372
- * Brush implemented with Solid signals instead of React class component state.
373
- */
374
- function BrushWithState(
375
- props: InternalProps & {
376
- data: ChartData
377
- x: number
378
- y: number
379
- width: number
380
- startIndex: number
381
- endIndex: number
382
- onChange: OnBrushUpdate
383
- startIndexControlledFromProps?: number
384
- endIndexControlledFromProps?: number
385
- },
386
- ) {
387
- const scaleData = () =>
388
- createScale({
389
- data: props.data,
390
- endIndex: props.endIndex,
391
- startIndex: props.startIndex,
392
- travellerWidth: props.travellerWidth,
393
- width: props.width,
394
- x: props.x,
395
- })
396
-
397
- /* Seed traveller positions before first render, like upstream's derived state. */
398
- const initialScale = untrack(scaleData)
399
- const [startX, setStartX] = createSignal(initialScale.startX ?? 0)
400
- const [endX, setEndX] = createSignal(initialScale.endX ?? 0)
401
- const [isTextActive, setIsTextActive] = createSignal(false)
402
- const [isSlideMoving, setIsSlideMoving] = createSignal(false)
403
- const [isTravellerMoving, setIsTravellerMoving] = createSignal(false)
404
- const [isTravellerFocused, setIsTravellerFocused] = createSignal(false)
405
-
406
- let slideMoveStartX = 0
407
- let brushMoveStartX = 0
408
- let movingTravellerId: BrushTravellerId | undefined
409
- let leaveTimer: number | null = null
410
- let prevData: ChartData | undefined
411
- let prevWidth: number | undefined
412
- let prevX: number | undefined
413
- let prevTravellerWidth: number | undefined
414
- let prevStartIndexControlledFromProps: number | undefined
415
- let prevEndIndexControlledFromProps: number | undefined
416
-
417
- createEffect(
418
- () => ({
419
- data: props.data,
420
- endControlled: props.endIndexControlledFromProps,
421
- endIndex: props.endIndex,
422
- interacting: isSlideMoving() || isTravellerMoving() || isTravellerFocused() || isTextActive(),
423
- startControlled: props.startIndexControlledFromProps,
424
- startIndex: props.startIndex,
425
- travellerWidth: props.travellerWidth,
426
- width: props.width,
427
- x: props.x,
428
- }),
429
- (input) => untrack(() => {
430
- const { data, endControlled, endIndex, interacting, startControlled, startIndex, travellerWidth, width, x } = input
431
- const sd = createScale({
432
- data,
433
- endIndex,
434
- startIndex,
435
- travellerWidth,
436
- width,
437
- x,
438
- })
439
-
440
- if (data !== prevData) {
441
- prevData = data
442
- prevWidth = width
443
- prevX = x
444
- prevTravellerWidth = travellerWidth
445
- prevStartIndexControlledFromProps = startControlled
446
- prevEndIndexControlledFromProps = endControlled
447
- if (sd.startX != null) setStartX(sd.startX)
448
- if (sd.endX != null) setEndX(sd.endX)
449
- return
450
- }
451
-
452
- if (width !== prevWidth || x !== prevX || travellerWidth !== prevTravellerWidth) {
453
- prevWidth = width
454
- prevX = x
455
- prevTravellerWidth = travellerWidth
456
- if (sd.startX != null) setStartX(sd.startX)
457
- if (sd.endX != null) setEndX(sd.endX)
458
- return
459
- }
460
-
461
- if (interacting) {
462
- return
463
- }
464
-
465
- if (startControlled != null && prevStartIndexControlledFromProps !== startControlled) {
466
- prevStartIndexControlledFromProps = startControlled
467
- const next = createScale({
468
- data,
469
- endIndex,
470
- startIndex: startControlled,
471
- travellerWidth,
472
- width,
473
- x,
474
- })
475
- if (next.startX != null) setStartX(next.startX)
476
- }
477
- if (endControlled != null && prevEndIndexControlledFromProps !== endControlled) {
478
- prevEndIndexControlledFromProps = endControlled
479
- const next = createScale({
480
- data,
481
- endIndex: endControlled,
482
- startIndex,
483
- travellerWidth,
484
- width,
485
- x,
486
- })
487
- if (next.endX != null) setEndX(next.endX)
488
- }
489
- }),
490
- )
491
-
492
- const detachDragEndListener = () => {
493
- window.removeEventListener("mouseup", handleDragEnd, true)
494
- window.removeEventListener("touchend", handleDragEnd, true)
495
- window.removeEventListener("mousemove", handleDrag, true)
496
- }
497
-
498
- const attachDragEndListener = () => {
499
- window.addEventListener("mouseup", handleDragEnd, true)
500
- window.addEventListener("touchend", handleDragEnd, true)
501
- window.addEventListener("mousemove", handleDrag, true)
502
- }
503
-
504
- onCleanup(() => {
505
- if (leaveTimer) {
506
- clearTimeout(leaveTimer)
507
- leaveTimer = null
508
- }
509
- detachDragEndListener()
510
- })
511
-
512
- const handleDragEnd = () => {
513
- setIsTravellerMoving(false)
514
- setIsSlideMoving(false)
515
- props.onDragEnd?.({ endIndex: props.endIndex, startIndex: props.startIndex })
516
- detachDragEndListener()
517
- }
518
-
519
- const handleDrag = (e: MouseEvent | TouchEvent) => {
520
- if (leaveTimer) {
521
- clearTimeout(leaveTimer)
522
- leaveTimer = null
523
- }
524
- const pageX = "changedTouches" in e ? (e.changedTouches[0]?.pageX ?? 0) : e.pageX
525
- if (isTravellerMoving()) {
526
- handleTravellerMove(pageX)
527
- } else if (isSlideMoving()) {
528
- handleSlideDrag(pageX)
529
- }
530
- }
531
-
532
- const handleSlideDrag = (pageX: number) => {
533
- const sv = scaleData().scaleValues
534
- if (sv == null) return
535
- let delta = pageX - slideMoveStartX
536
-
537
- if (delta > 0) {
538
- delta = Math.min(
539
- delta,
540
- props.x + props.width - props.travellerWidth - endX(),
541
- props.x + props.width - props.travellerWidth - startX(),
542
- )
543
- } else if (delta < 0) {
544
- delta = Math.max(delta, props.x - startX(), props.x - endX())
545
- }
546
- const newIndex = getIndex({
547
- data: props.data,
548
- endX: endX() + delta,
549
- gap: props.gap,
550
- scaleValues: sv,
551
- startX: startX() + delta,
552
- })
553
-
554
- if (newIndex.startIndex !== props.startIndex || newIndex.endIndex !== props.endIndex) {
555
- props.onChange(newIndex)
556
- }
557
-
558
- setStartX((prev) => prev + delta)
559
- setEndX((prev) => prev + delta)
560
- slideMoveStartX = pageX
561
- }
562
-
563
- const handleTravellerMove = (pageX: number) => {
564
- const sv = scaleData().scaleValues
565
- if (movingTravellerId == null || sv == null) return
566
- const prevValue = movingTravellerId === "startX" ? startX() : endX()
567
-
568
- let delta = pageX - brushMoveStartX
569
- if (delta > 0) {
570
- delta = Math.min(delta, props.x + props.width - props.travellerWidth - prevValue)
571
- } else if (delta < 0) {
572
- delta = Math.max(delta, props.x - prevValue)
573
- }
574
-
575
- const params = {
576
- data: props.data,
577
- endX: endX(),
578
- gap: props.gap,
579
- scaleValues: sv,
580
- startX: startX(),
581
- }
582
- if (movingTravellerId === "startX") {
583
- params.startX = prevValue + delta
584
- } else {
585
- params.endX = prevValue + delta
586
- }
587
-
588
- const newIndex = getIndex(params)
589
-
590
- if (movingTravellerId === "startX") {
591
- setStartX(prevValue + delta)
592
- } else {
593
- setEndX(prevValue + delta)
594
- }
595
- brushMoveStartX = pageX
596
-
597
- props.onChange(newIndex)
598
- }
599
-
600
- const handleSlideDragStart = (e: MouseEvent | TouchEvent) => {
601
- const pageX =
602
- "changedTouches" in e ? (e.changedTouches[0]?.pageX ?? 0) : (e as MouseEvent).pageX
603
- setIsTravellerMoving(false)
604
- setIsSlideMoving(true)
605
- slideMoveStartX = pageX
606
- attachDragEndListener()
607
- }
608
-
609
- const handleTravellerDragStart = (id: BrushTravellerId, e: MouseEvent | TouchEvent) => {
610
- const pageX =
611
- "changedTouches" in e ? (e.changedTouches[0]?.pageX ?? 0) : (e as MouseEvent).pageX
612
- setIsSlideMoving(false)
613
- setIsTravellerMoving(true)
614
- movingTravellerId = id
615
- brushMoveStartX = pageX
616
- attachDragEndListener()
617
- }
618
-
619
- const handleTravellerMoveKeyboard = (direction: 1 | -1, id: BrushTravellerId) => {
620
- const sv = scaleData().scaleValues
621
- if (sv == null) return
622
-
623
- let currentIndex = -1
624
- if (id === "startX") currentIndex = props.startIndex
625
- else if (id === "endX") currentIndex = props.endIndex
626
-
627
- if (currentIndex < 0 || currentIndex >= props.data.length) return
628
-
629
- const newIndex = currentIndex + direction
630
- if (newIndex === -1 || newIndex >= sv.length) return
631
-
632
- const newScaleValue = sv[newIndex]
633
- if (newScaleValue == null) return
634
-
635
- if (
636
- (id === "startX" && newScaleValue >= endX()) ||
637
- (id === "endX" && newScaleValue <= startX())
638
- )
639
- return
640
-
641
- if (id === "startX") setStartX(newScaleValue)
642
- else setEndX(newScaleValue)
643
-
644
- props.onChange(
645
- getIndex({
646
- data: props.data,
647
- endX: id === "endX" ? newScaleValue : endX(),
648
- gap: props.gap,
649
- scaleValues: sv,
650
- startX: id === "startX" ? newScaleValue : startX(),
651
- }),
652
- )
653
- }
654
-
655
- const handleLeaveWrapper = () => {
656
- if (isTravellerMoving() || isSlideMoving()) {
657
- leaveTimer = window.setTimeout(handleDragEnd, props.leaveTimeOut)
658
- }
659
- }
660
-
661
- const handleEnterSlideOrTraveller = () => setIsTextActive(true)
662
- const handleLeaveSlideOrTraveller = () => setIsTextActive(false)
663
- /* React's onMouseEnter/Leave derive from mouseover/mouseout; a mouseout into one of the
664
- traveller's own children is not a leave. */
665
- const handleOutSlideOrTraveller = (e: MouseEvent) => {
666
- const next = e.relatedTarget as Node | null
667
- if (next != null && (e.currentTarget as Element).contains(next)) {
668
- return
669
- }
670
- handleLeaveSlideOrTraveller()
671
- }
672
-
673
- const calculatedY = () => props.y + (props.dy ?? 0)
674
-
675
- const shouldRender = () =>
676
- props.data &&
677
- props.data.length &&
678
- isNumber(props.x) &&
679
- isNumber(props.y) &&
680
- isNumber(props.width) &&
681
- isNumber(props.height) &&
682
- props.width > 0 &&
683
- props.height > 0
684
-
685
- const layerClass = () => clsx("recharts-brush", props.className)
686
- const style = generatePrefixStyle("userSelect", "none")
687
- const ariaLabelBrush = () =>
688
- props.ariaLabel || getAriaLabel(props.data, props.startIndex, props.endIndex)
689
-
690
- const travellerProps = (travellerX: number): TravellerProps => {
691
- const filteredSvg = svgPropertiesNoEvents(props) as Record<string, unknown>
692
- const { x: _x, y: _y, width: _w, height: _h, ...rest } = filteredSvg
693
- return {
694
- x: Math.max(travellerX, props.x),
695
- y: calculatedY(),
696
- width: props.travellerWidth,
697
- height: props.height,
698
- ...(rest as Record<string, unknown>),
699
- } as TravellerProps
700
- }
701
-
702
- return (
703
- <Show when={shouldRender()}>
704
- <Layer
705
- class={layerClass()}
706
- onMouseLeave={handleLeaveWrapper}
707
- onTouchMove={(e: TouchEvent) => {
708
- const touch = e.changedTouches?.[0]
709
- if (touch != null) handleDrag(e)
710
- }}
711
- style={style}
712
- >
713
- <Background
714
- x={props.x}
715
- y={calculatedY()}
716
- width={props.width}
717
- height={props.height}
718
- fill={props.fill}
719
- stroke={props.stroke}
720
- />
721
- <PanoramaContextProvider>
722
- <Panorama
723
- x={props.x}
724
- y={calculatedY()}
725
- width={props.width}
726
- height={props.height}
727
- data={props.data}
728
- padding={props.padding}
729
- >
730
- {props.children}
731
- </Panorama>
732
- </PanoramaContextProvider>
733
- <Slide
734
- y={calculatedY()}
735
- height={props.height}
736
- stroke={props.stroke}
737
- travellerWidth={props.travellerWidth}
738
- startX={startX()}
739
- endX={endX()}
740
- onMouseEnter={handleEnterSlideOrTraveller}
741
- onMouseLeave={handleLeaveSlideOrTraveller}
742
- onMouseDown={handleSlideDragStart}
743
- onTouchStart={handleSlideDragStart}
744
- />
745
- {/* Start traveller */}
746
- <Layer
747
- tabindex={0}
748
- /* eslint-disable-next-line jsx-a11y/prefer-tag-over-role -- SVG has no <input>; upstream uses role="slider" on the traveller group */
749
- role="slider"
750
- aria-label={ariaLabelBrush()}
751
- aria-valuemin={0}
752
- aria-valuemax={props.data.length - 1}
753
- aria-valuenow={startX()}
754
- class="recharts-brush-traveller"
755
- onMouseEnter={handleEnterSlideOrTraveller}
756
- onMouseOver={handleEnterSlideOrTraveller}
757
- onMouseLeave={handleLeaveSlideOrTraveller}
758
- onMouseOut={handleOutSlideOrTraveller}
759
- onMouseDown={(e: MouseEvent) => handleTravellerDragStart("startX", e)}
760
- onTouchStart={(e: TouchEvent) => handleTravellerDragStart("startX", e)}
761
- onKeyDown={(e: KeyboardEvent) => {
762
- if (!["ArrowLeft", "ArrowRight"].includes(e.key)) return
763
- e.preventDefault()
764
- e.stopPropagation()
765
- handleTravellerMoveKeyboard(e.key === "ArrowRight" ? 1 : -1, "startX")
766
- }}
767
- onFocus={() => setIsTravellerFocused(true)}
768
- onBlur={() => setIsTravellerFocused(false)}
769
- style={{ cursor: "col-resize" }}
770
- >
771
- <Traveller travellerType={props.traveller} travellerProps={travellerProps(startX())} />
772
- </Layer>
773
- {/* End traveller */}
774
- <Layer
775
- tabindex={0}
776
- /* eslint-disable-next-line jsx-a11y/prefer-tag-over-role -- SVG has no <input>; upstream uses role="slider" on the traveller group */
777
- role="slider"
778
- aria-label={ariaLabelBrush()}
779
- aria-valuemin={0}
780
- aria-valuemax={props.data.length - 1}
781
- aria-valuenow={endX()}
782
- class="recharts-brush-traveller"
783
- onMouseEnter={handleEnterSlideOrTraveller}
784
- onMouseOver={handleEnterSlideOrTraveller}
785
- onMouseLeave={handleLeaveSlideOrTraveller}
786
- onMouseOut={handleOutSlideOrTraveller}
787
- onMouseDown={(e: MouseEvent) => handleTravellerDragStart("endX", e)}
788
- onTouchStart={(e: TouchEvent) => handleTravellerDragStart("endX", e)}
789
- onKeyDown={(e: KeyboardEvent) => {
790
- if (!["ArrowLeft", "ArrowRight"].includes(e.key)) return
791
- e.preventDefault()
792
- e.stopPropagation()
793
- handleTravellerMoveKeyboard(e.key === "ArrowRight" ? 1 : -1, "endX")
794
- }}
795
- onFocus={() => setIsTravellerFocused(true)}
796
- onBlur={() => setIsTravellerFocused(false)}
797
- style={{ cursor: "col-resize" }}
798
- >
799
- <Traveller travellerType={props.traveller} travellerProps={travellerProps(endX())} />
800
- </Layer>
801
- <Show
802
- when={
803
- isTextActive() ||
804
- isSlideMoving() ||
805
- isTravellerMoving() ||
806
- isTravellerFocused() ||
807
- props.alwaysShowText
808
- }
809
- >
810
- <BrushText
811
- startIndex={props.startIndex}
812
- endIndex={props.endIndex}
813
- y={calculatedY()}
814
- height={props.height}
815
- travellerWidth={props.travellerWidth}
816
- stroke={props.stroke}
817
- tickFormatter={props.tickFormatter}
818
- dataKey={props.dataKey}
819
- data={props.data}
820
- startX={startX()}
821
- endX={endX()}
822
- />
823
- </Show>
824
- </Layer>
825
- </Show>
826
- )
827
- }
828
-
829
- function BrushInternal(props: InternalProps) {
830
- const ctx = useChartStore()
831
- const newCtx = useOptionalChartState()
832
- /* Memos resolve context at setup, so event handlers can read them later. */
833
- const chartData = createMemo(() => useChartData())
834
- const dataIndexes = createMemo(() => useDataIndex())
835
- const onChangeFromProps = () => props.onChange
836
-
837
- createEffect(
838
- () => {
839
- chartData()
840
- return { endIndex: props.endIndex, startIndex: props.startIndex }
841
- },
842
- ({ endIndex, startIndex }) => {
843
- if (startIndex !== undefined) {
844
- newCtx?.setState("chartData", "dataStartIndex", startIndex)
845
- }
846
- if (endIndex !== undefined) {
847
- newCtx?.setState("chartData", "dataEndIndex", endIndex)
848
- }
849
- },
850
- )
851
-
852
- useBrushChartSynchronisation()
853
-
854
- const onChange = (nextState: BrushStartEndIndex) => {
855
- const idx = dataIndexes()
856
- if (idx == null) return
857
- if (nextState.startIndex !== idx.startIndex || nextState.endIndex !== idx.endIndex) {
858
- onChangeFromProps()?.(nextState)
859
- if (nextState.startIndex !== undefined) {
860
- newCtx?.setState("chartData", "dataStartIndex", nextState.startIndex)
861
- }
862
- if (nextState.endIndex !== undefined) {
863
- newCtx?.setState("chartData", "dataEndIndex", nextState.endIndex)
864
- }
865
- }
866
- }
867
-
868
- /* perf: cache selector result; without memo every consumer read triggers full chain. */
869
- const brushDimensions = createMemo(() => (ctx ? selectBrushDimensions(ctx.store) : undefined))
870
-
871
- return (
872
- <Show
873
- when={
874
- brushDimensions() != null &&
875
- dataIndexes() != null &&
876
- chartData() != null &&
877
- chartData()?.length
878
- }
879
- >
880
- <BrushWithState
881
- {...props}
882
- data={chartData() as ChartData}
883
- x={brushDimensions()?.x ?? 0}
884
- y={brushDimensions()?.y ?? 0}
885
- width={brushDimensions()?.width ?? 0}
886
- startIndex={dataIndexes()?.startIndex ?? 0}
887
- endIndex={dataIndexes()?.endIndex ?? 0}
888
- onChange={onChange}
889
- startIndexControlledFromProps={props.startIndex ?? undefined}
890
- endIndexControlledFromProps={props.endIndex ?? undefined}
891
- />
892
- </Show>
893
- )
894
- }
895
-
896
- function BrushSettingsDispatcher(props: BrushSettings): null {
897
- const newCtx = useOptionalChartState()
898
- createEffect(
899
- () => ({ height: props.height, padding: props.padding, width: props.width, x: props.x, y: props.y }),
900
- (settings) => {
901
- newCtx?.setState("brush", settings)
902
- return () => {
903
- teardownWrite(() => {
904
- newCtx?.setState("brush", { height: 0, padding: { bottom: 0, left: 0, right: 0, top: 0 }, width: 0, x: 0, y: 0 })
905
- })
906
- }
907
- },
908
- )
909
- return null
910
- }
911
-
912
- export const defaultBrushProps = {
913
- alwaysShowText: false,
914
- fill: "#fff",
915
- gap: 1,
916
- height: 40,
917
- leaveTimeOut: 1000,
918
- padding: { bottom: 1, left: 1, right: 1, top: 1 },
919
- stroke: "#666",
920
- travellerWidth: 5,
921
- } as const satisfies Partial<Props>
922
-
923
- /**
924
- * Renders a scrollbar that allows the user to zoom and pan in the chart along its XAxis.
925
- * It also allows you to render a small overview of the chart inside the brush that is always visible
926
- * and shows the full data set so that the user can see where they are zoomed in.
927
- *
928
- * If a chart is synchronized with other charts using the `syncId` prop on the chart,
929
- * the brush will also synchronize the zooming and panning between all synchronized charts.
930
- *
931
- * @see {@link https://recharts.github.io/en-US/examples/BrushBarChart/ BarChart with Brush}
932
- * @see {@link https://recharts.github.io/en-US/examples/SynchronizedLineChart/ Synchronized Brush}
933
- *
934
- * @consumes CartesianChartContext
935
- */
936
- export function Brush(outsideProps: Props) {
937
- const props = resolveDefaultProps(outsideProps, defaultBrushProps)
938
- return (
939
- <>
940
- <BrushSettingsDispatcher
941
- height={props.height}
942
- x={props.x}
943
- y={props.y}
944
- width={props.width}
945
- padding={props.padding}
946
- />
947
- <BrushInternal {...props} />
948
- </>
949
- )
950
- }
951
- Brush.displayName = "Brush"