@solidports/recharts 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/NOTICE +19 -0
- package/README.md +102 -0
- package/dist/dev.js +28564 -0
- package/dist/index.d.ts +7859 -0
- package/dist/index.js +28546 -0
- package/package.json +98 -0
- package/src/animation/AnimatedItems.tsx +183 -0
- package/src/animation/AnimationController.ts +33 -0
- package/src/animation/AnimationControllerImpl.ts +36 -0
- package/src/animation/AnimationHandle.ts +307 -0
- package/src/animation/CSSTransitionAnimate.tsx +170 -0
- package/src/animation/JavascriptAnimate.tsx +119 -0
- package/src/animation/easing.ts +221 -0
- package/src/animation/matchBy.ts +164 -0
- package/src/animation/timeoutController.ts +70 -0
- package/src/animation/useAnimationController.tsx +34 -0
- package/src/animation/useAnimationStartSnapshot.ts +118 -0
- package/src/animation/util.ts +41 -0
- package/src/cartesian/Area.tsx +915 -0
- package/src/cartesian/AreaRevealShape.tsx +190 -0
- package/src/cartesian/Bar.tsx +1369 -0
- package/src/cartesian/BarStack.tsx +152 -0
- package/src/cartesian/Brush.tsx +951 -0
- package/src/cartesian/CartesianAxis.tsx +722 -0
- package/src/cartesian/CartesianGrid.tsx +711 -0
- package/src/cartesian/ErrorBar.tsx +361 -0
- package/src/cartesian/Funnel.tsx +803 -0
- package/src/cartesian/GraphicalItemClipPath.tsx +67 -0
- package/src/cartesian/Line.tsx +863 -0
- package/src/cartesian/LineDrawShape.tsx +89 -0
- package/src/cartesian/ReferenceArea.tsx +331 -0
- package/src/cartesian/ReferenceDot.tsx +304 -0
- package/src/cartesian/ReferenceLine.tsx +474 -0
- package/src/cartesian/Scatter.tsx +888 -0
- package/src/cartesian/XAxis.tsx +433 -0
- package/src/cartesian/YAxis.tsx +443 -0
- package/src/cartesian/ZAxis.tsx +155 -0
- package/src/cartesian/cartesianPositionToCSSTranslate.tsx +29 -0
- package/src/cartesian/cartesianViewBoxToTrapezoid.tsx +21 -0
- package/src/cartesian/getCartesianPosition.tsx +267 -0
- package/src/cartesian/getEquidistantTicks.ts +144 -0
- package/src/cartesian/getTicks.ts +225 -0
- package/src/cartesian/isOutsidePosition.ts +15 -0
- package/src/cartesian/useAnimatedLineLength.ts +54 -0
- package/src/chart/AreaChart.tsx +29 -0
- package/src/chart/BarChart.tsx +29 -0
- package/src/chart/CartesianChart.tsx +131 -0
- package/src/chart/CategoricalChart.tsx +94 -0
- package/src/chart/ComposedChart.tsx +29 -0
- package/src/chart/FunnelChart.tsx +29 -0
- package/src/chart/LineChart.tsx +29 -0
- package/src/chart/PieChart.tsx +50 -0
- package/src/chart/PolarChart.tsx +164 -0
- package/src/chart/RadarChart.tsx +70 -0
- package/src/chart/RadialBarChart.tsx +46 -0
- package/src/chart/RechartsWrapper.tsx +551 -0
- package/src/chart/Sankey.tsx +1534 -0
- package/src/chart/ScatterChart.tsx +29 -0
- package/src/chart/SunburstChart.tsx +504 -0
- package/src/chart/Treemap.tsx +1223 -0
- package/src/chart/createInitialRootProps.ts +24 -0
- package/src/chart/types.ts +53 -0
- package/src/component/ActivePoints.tsx +144 -0
- package/src/component/Cell.tsx +37 -0
- package/src/component/Cursor.tsx +185 -0
- package/src/component/Customized.tsx +50 -0
- package/src/component/DefaultLegendContent.tsx +348 -0
- package/src/component/DefaultTooltipContent.tsx +224 -0
- package/src/component/Dots.tsx +157 -0
- package/src/component/Label.tsx +636 -0
- package/src/component/LabelList.tsx +375 -0
- package/src/component/Legend.tsx +512 -0
- package/src/component/ResponsiveContainer.tsx +348 -0
- package/src/component/Text.tsx +541 -0
- package/src/component/Tooltip.tsx +470 -0
- package/src/component/TooltipBoundingBox.tsx +146 -0
- package/src/component/responsiveContainerUtils.ts +134 -0
- package/src/container/ClipPathProvider.tsx +51 -0
- package/src/container/Layer.tsx +38 -0
- package/src/container/RootSurface.tsx +120 -0
- package/src/container/Surface.tsx +61 -0
- package/src/context/CellsContext.tsx +54 -0
- package/src/context/ErrorBarContext.tsx +146 -0
- package/src/context/GraphicalItemChildrenScope.tsx +18 -0
- package/src/context/PanoramaContext.tsx +9 -0
- package/src/context/RegisterGraphicalItemId.tsx +30 -0
- package/src/context/accessibilityContext.tsx +6 -0
- package/src/context/brushUpdateContext.tsx +9 -0
- package/src/context/chartDataContext.tsx +97 -0
- package/src/context/chartLayoutContext.tsx +201 -0
- package/src/context/legendPayloadContext.tsx +20 -0
- package/src/context/legendPortalContext.tsx +12 -0
- package/src/context/tooltipContext.tsx +89 -0
- package/src/context/tooltipPortalContext.tsx +12 -0
- package/src/context/useTooltipAxis.ts +22 -0
- package/src/hooks.ts +476 -0
- package/src/index.ts +280 -0
- package/src/polar/Pie.tsx +1360 -0
- package/src/polar/PolarAngleAxis.tsx +616 -0
- package/src/polar/PolarGrid.tsx +312 -0
- package/src/polar/PolarRadiusAxis.tsx +547 -0
- package/src/polar/Radar.tsx +734 -0
- package/src/polar/RadialBar.tsx +917 -0
- package/src/polar/defaultPolarAngleAxisProps.tsx +27 -0
- package/src/polar/defaultPolarRadiusAxisProps.tsx +25 -0
- package/src/shape/Cross.tsx +89 -0
- package/src/shape/Curve.tsx +343 -0
- package/src/shape/Dot.tsx +70 -0
- package/src/shape/Polygon.tsx +195 -0
- package/src/shape/Rectangle.tsx +470 -0
- package/src/shape/Sector.tsx +347 -0
- package/src/shape/Symbols.tsx +139 -0
- package/src/shape/Trapezoid.tsx +280 -0
- package/src/state/RechartsStateContext.tsx +12 -0
- package/src/state/RechartsStateProvider.tsx +87 -0
- package/src/state/RechartsStoreContext.tsx +25 -0
- package/src/state/RechartsStoreProvider.tsx +35 -0
- package/src/state/ReportChartProps.tsx +40 -0
- package/src/state/ReportEventSettings.tsx +30 -0
- package/src/state/ReportMainChartProps.tsx +61 -0
- package/src/state/ReportPolarOptions.tsx +35 -0
- package/src/state/SetGraphicalItem.ts +79 -0
- package/src/state/SetLegendPayload.ts +134 -0
- package/src/state/SetTooltipEntrySettings.tsx +72 -0
- package/src/state/actions.ts +464 -0
- package/src/state/brushSlice.ts +13 -0
- package/src/state/cartesianAxisSlice.ts +141 -0
- package/src/state/chartDataSlice.ts +50 -0
- package/src/state/chartState.ts +297 -0
- package/src/state/errorBarSlice.ts +29 -0
- package/src/state/eventSettingsSlice.ts +8 -0
- package/src/state/events.ts +76 -0
- package/src/state/externalEventsMiddleware.ts +255 -0
- package/src/state/graphicalItemsSlice.ts +74 -0
- package/src/state/hooks/useChartSelectors.tsx +45 -0
- package/src/state/keyboardEventsMiddleware.ts +228 -0
- package/src/state/layoutSlice.ts +21 -0
- package/src/state/legendSlice.ts +57 -0
- package/src/state/mouseEventsMiddleware.ts +185 -0
- package/src/state/optionsSlice.ts +47 -0
- package/src/state/polarAxisSlice.ts +10 -0
- package/src/state/polarOptionsSlice.ts +12 -0
- package/src/state/rawData.ts +26 -0
- package/src/state/referenceElementsSlice.ts +40 -0
- package/src/state/renderedTicksSlice.ts +15 -0
- package/src/state/rootPropsSlice.ts +47 -0
- package/src/state/selectors/areaSelectors.ts +240 -0
- package/src/state/selectors/arrayEqualityCheck.ts +29 -0
- package/src/state/selectors/axisSelectors.ts +2157 -0
- package/src/state/selectors/barSelectors.ts +310 -0
- package/src/state/selectors/barStackSelectors.ts +77 -0
- package/src/state/selectors/brushSelectors.ts +33 -0
- package/src/state/selectors/chartSelector.ts +185 -0
- package/src/state/selectors/combiners/combineActiveLabel.ts +16 -0
- package/src/state/selectors/combiners/combineActiveTooltipIndex.ts +95 -0
- package/src/state/selectors/combiners/combineAllBarPositions.ts +122 -0
- package/src/state/selectors/combiners/combineAxisRangeWithReverse.ts +16 -0
- package/src/state/selectors/combiners/combineBarPosition.ts +23 -0
- package/src/state/selectors/combiners/combineBarSizeList.ts +80 -0
- package/src/state/selectors/combiners/combineCheckedDomain.ts +48 -0
- package/src/state/selectors/combiners/combineConfiguredScale.ts +111 -0
- package/src/state/selectors/combiners/combineCoordinateForDefaultIndex.ts +45 -0
- package/src/state/selectors/combiners/combineDisplayedStackedData.ts +50 -0
- package/src/state/selectors/combiners/combineInverseScaleFunction.ts +16 -0
- package/src/state/selectors/combiners/combineRealScaleType.ts +44 -0
- package/src/state/selectors/combiners/combineStackedData.ts +27 -0
- package/src/state/selectors/combiners/combineTooltipInteractionState.ts +86 -0
- package/src/state/selectors/combiners/combineTooltipPayload.ts +205 -0
- package/src/state/selectors/combiners/combineTooltipPayloadConfigurations.ts +58 -0
- package/src/state/selectors/containerSelectors.ts +12 -0
- package/src/state/selectors/dataSelectors.ts +88 -0
- package/src/state/selectors/funnelSelectors.ts +75 -0
- package/src/state/selectors/graphicalItemSelectors.ts +30 -0
- package/src/state/selectors/legendSelectors.ts +29 -0
- package/src/state/selectors/lineSelectors.ts +134 -0
- package/src/state/selectors/numberDomainEqualityCheck.ts +14 -0
- package/src/state/selectors/pickAxisId.ts +5 -0
- package/src/state/selectors/pickAxisType.ts +3 -0
- package/src/state/selectors/pieSelectors.ts +97 -0
- package/src/state/selectors/polarAxisSelectors.ts +201 -0
- package/src/state/selectors/polarGridSelectors.ts +28 -0
- package/src/state/selectors/polarScaleSelectors.ts +133 -0
- package/src/state/selectors/polarSelectors.ts +219 -0
- package/src/state/selectors/radarSelectors.ts +191 -0
- package/src/state/selectors/radialBarSelectors.ts +435 -0
- package/src/state/selectors/rootPropsSelectors.ts +25 -0
- package/src/state/selectors/scatterSelectors.ts +96 -0
- package/src/state/selectors/selectActivePropsFromChartPointer.ts +26 -0
- package/src/state/selectors/selectAllAxes.ts +17 -0
- package/src/state/selectors/selectChartOffset.ts +16 -0
- package/src/state/selectors/selectChartOffsetInternal.ts +136 -0
- package/src/state/selectors/selectLegendArea.ts +20 -0
- package/src/state/selectors/selectPlotArea.ts +22 -0
- package/src/state/selectors/selectTooltipAxisId.ts +7 -0
- package/src/state/selectors/selectTooltipAxisType.ts +32 -0
- package/src/state/selectors/selectTooltipEventType.ts +48 -0
- package/src/state/selectors/selectTooltipPayloadSearcher.ts +6 -0
- package/src/state/selectors/selectTooltipSettings.ts +39 -0
- package/src/state/selectors/selectTooltipState.ts +8 -0
- package/src/state/selectors/selectors.ts +271 -0
- package/src/state/selectors/tooltipSelectors.ts +578 -0
- package/src/state/selectors/touchSelectors.ts +31 -0
- package/src/state/store.ts +29 -0
- package/src/state/storeIdentity.ts +9 -0
- package/src/state/teardownWrite.ts +10 -0
- package/src/state/tooltipInteraction.ts +23 -0
- package/src/state/tooltipSlice.ts +334 -0
- package/src/state/touchEventsMiddleware.ts +214 -0
- package/src/state/types/AnimationSettings.ts +20 -0
- package/src/state/types/AreaSettings.ts +14 -0
- package/src/state/types/BarSettings.ts +15 -0
- package/src/state/types/LineSettings.ts +9 -0
- package/src/state/types/PieSettings.ts +34 -0
- package/src/state/types/RadarSettings.ts +5 -0
- package/src/state/types/RadialBarSettings.ts +10 -0
- package/src/state/types/ScatterSettings.ts +12 -0
- package/src/state/types/StackedGraphicalItem.ts +34 -0
- package/src/state/useChartState.ts +17 -0
- package/src/state/zIndexSlice.ts +39 -0
- package/src/synchronisation/syncSelectors.ts +7 -0
- package/src/synchronisation/types.ts +44 -0
- package/src/synchronisation/useChartSynchronisation.tsx +404 -0
- package/src/theme/RechartsTheme.ts +16 -0
- package/src/theme/RechartsThemeContext.ts +19 -0
- package/src/theme/darkTheme.ts +13 -0
- package/src/theme/graphicalItemIdentity.ts +70 -0
- package/src/theme/legacyTheme.ts +17 -0
- package/src/theme/lightTheme.ts +13 -0
- package/src/types.ts +54 -0
- package/src/util/ActiveShapeUtils.tsx +162 -0
- package/src/util/BarUtils.tsx +62 -0
- package/src/util/BarePortal.tsx +50 -0
- package/src/util/CamelCaseSVGAttrs.ts +34 -0
- package/src/util/CartesianUtils.ts +48 -0
- package/src/util/ChartUtils.ts +802 -0
- package/src/util/Constants.ts +42 -0
- package/src/util/CssPrefixUtils.ts +20 -0
- package/src/util/DOMUtils.ts +129 -0
- package/src/util/DataUtils.ts +216 -0
- package/src/util/Events.ts +16 -0
- package/src/util/FunnelUtils.tsx +15 -0
- package/src/util/Global.ts +12 -0
- package/src/util/IfOverflow.ts +15 -0
- package/src/util/LRUCache.ts +41 -0
- package/src/util/LogUtils.ts +22 -0
- package/src/util/PolarUtils.ts +132 -0
- package/src/util/RadialBarUtils.tsx +24 -0
- package/src/util/ReactUtils.ts +95 -0
- package/src/util/ReduceCSSCalc.ts +187 -0
- package/src/util/ScatterUtils.tsx +52 -0
- package/src/util/ShapeElementProps.tsx +87 -0
- package/src/util/TickUtils.ts +60 -0
- package/src/util/XAxisUtils.ts +48 -0
- package/src/util/YAxisUtils.ts +48 -0
- package/src/util/axisPropsAreEqual.ts +48 -0
- package/src/util/createCartesianCharts.tsx +150 -0
- package/src/util/createEventProxy.ts +20 -0
- package/src/util/createPolarCharts.tsx +112 -0
- package/src/util/cursor/getCursorPoints.ts +46 -0
- package/src/util/cursor/getCursorRectangle.ts +28 -0
- package/src/util/cursor/getRadialCursorPoints.ts +32 -0
- package/src/util/excludeEventProps.ts +171 -0
- package/src/util/getActiveCoordinate.ts +213 -0
- package/src/util/getAxisTypeBasedOnLayout.ts +21 -0
- package/src/util/getClassNameFromUnknown.ts +6 -0
- package/src/util/getEveryNth.ts +27 -0
- package/src/util/getRadiusAndStrokeWidthFromDot.ts +35 -0
- package/src/util/getRelativeCoordinate.ts +80 -0
- package/src/util/getSliced.ts +13 -0
- package/src/util/hoverDedupe.ts +41 -0
- package/src/util/isDomainSpecifiedByUser.ts +219 -0
- package/src/util/isWellBehavedNumber.ts +7 -0
- package/src/util/pathTotalLength.ts +25 -0
- package/src/util/payload/getUniqPayload.ts +28 -0
- package/src/util/propsAreEqual.ts +121 -0
- package/src/util/resolveDefaultProps.ts +161 -0
- package/src/util/round.ts +32 -0
- package/src/util/scale/CartesianScaleHelper.ts +72 -0
- package/src/util/scale/CustomScaleDefinition.ts +81 -0
- package/src/util/scale/RechartsScale.ts +130 -0
- package/src/util/scale/createCategoricalInverse.ts +72 -0
- package/src/util/scale/getNiceTickValues.ts +311 -0
- package/src/util/scale/index.ts +2 -0
- package/src/util/scale/util/arithmetic.ts +54 -0
- package/src/util/solid-1-compat.ts +310 -0
- package/src/util/solidJsxCamelAugment.d.ts +84 -0
- package/src/util/stacks/getStackSeriesIdentifier.ts +21 -0
- package/src/util/stacks/stackTypes.ts +60 -0
- package/src/util/structurallyEqual.ts +31 -0
- package/src/util/svgPropertiesAndEvents.ts +53 -0
- package/src/util/svgPropertiesNoEvents.ts +571 -0
- package/src/util/tooltip/translate.ts +171 -0
- package/src/util/typedDataKey.ts +48 -0
- package/src/util/types.ts +1560 -0
- package/src/util/useAnimationId.ts +31 -0
- package/src/util/useElementOffset.ts +110 -0
- package/src/util/useId.ts +8 -0
- package/src/util/usePrefersReducedMotion.ts +48 -0
- package/src/util/useReportScale.ts +24 -0
- package/src/util/useUniqueId.ts +30 -0
- package/src/zIndex/DefaultZIndexes.ts +84 -0
- package/src/zIndex/ZIndexLayer.tsx +121 -0
- package/src/zIndex/ZIndexPortal.tsx +79 -0
- package/src/zIndex/getZIndexFromUnknown.ts +14 -0
- package/src/zIndex/zIndexSelectors.ts +48 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/* eslint-disable import/no-cycle */
|
|
2
|
+
import type { JSX } from '@solidjs/web';
|
|
3
|
+
import type { ChartState } from "../store"
|
|
4
|
+
import {
|
|
5
|
+
type BaseAxisWithScale,
|
|
6
|
+
selectAxisWithScale,
|
|
7
|
+
selectCartesianAxisSize,
|
|
8
|
+
selectStackGroups,
|
|
9
|
+
selectTicksOfGraphicalItem,
|
|
10
|
+
selectUnfilteredCartesianItems,
|
|
11
|
+
} from "./axisSelectors"
|
|
12
|
+
import type { XAxisSettings, YAxisSettings } from "../cartesianAxisSlice"
|
|
13
|
+
import { isNullish } from "../../util/DataUtils"
|
|
14
|
+
import { type BarPositionPosition, getBandSizeOfAxis, type StackId } from "../../util/ChartUtils"
|
|
15
|
+
import type {
|
|
16
|
+
CartesianViewBoxRequired,
|
|
17
|
+
ChartOffsetInternal,
|
|
18
|
+
DataKey,
|
|
19
|
+
TickItem,
|
|
20
|
+
} from "../../util/types"
|
|
21
|
+
import { type BarRectangleItem, computeBarRectangles } from "../../cartesian/Bar"
|
|
22
|
+
import { selectChartLayout } from "../../context/chartLayoutContext"
|
|
23
|
+
import type { ChartData } from "../chartDataSlice"
|
|
24
|
+
import { selectChartDataWithIndexesIfNotInPanoramaPosition3 } from "./dataSelectors"
|
|
25
|
+
import { selectAxisViewBox, selectChartOffsetInternal } from "./selectChartOffsetInternal"
|
|
26
|
+
import {
|
|
27
|
+
selectBarCategoryGap,
|
|
28
|
+
selectBarGap,
|
|
29
|
+
selectRootBarSize,
|
|
30
|
+
selectRootMaxBarSize,
|
|
31
|
+
} from "./rootPropsSelectors"
|
|
32
|
+
import type { AllStackGroups, StackSeries } from "../../util/stacks/stackTypes"
|
|
33
|
+
import type { BarSettings } from "../types/BarSettings"
|
|
34
|
+
|
|
35
|
+
/** Optional overrides — bypass the axis-settings lookup on hot animation frames. */
|
|
36
|
+
export type BarAxisOverrides = {
|
|
37
|
+
xAxis?: XAxisSettings
|
|
38
|
+
yAxis?: YAxisSettings
|
|
39
|
+
barSettings?: BarSettings
|
|
40
|
+
}
|
|
41
|
+
import type { GraphicalItemId } from "../graphicalItemsSlice"
|
|
42
|
+
import { type BarCategory, combineBarSizeList } from "./combiners/combineBarSizeList"
|
|
43
|
+
import { combineAllBarPositions } from "./combiners/combineAllBarPositions"
|
|
44
|
+
import { combineStackedData } from "./combiners/combineStackedData"
|
|
45
|
+
import { chartSelector } from "./chartSelector"
|
|
46
|
+
import {
|
|
47
|
+
selectXAxisIdFromGraphicalItemId,
|
|
48
|
+
selectYAxisIdFromGraphicalItemId,
|
|
49
|
+
} from "./graphicalItemSelectors"
|
|
50
|
+
import { combineBarPosition } from "./combiners/combineBarPosition"
|
|
51
|
+
|
|
52
|
+
const selectSynchronisedBarSettings = chartSelector(function selectSynchronisedBarSettings(state: ChartState, id: GraphicalItemId): BarSettings | undefined {
|
|
53
|
+
const graphicalItems = selectUnfilteredCartesianItems(state)
|
|
54
|
+
return graphicalItems.filter((item) => item.type === "bar").find((item) => item.id === id) as
|
|
55
|
+
| BarSettings
|
|
56
|
+
| undefined
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
export const selectMaxBarSize = chartSelector(function selectMaxBarSize(_state: ChartState, id: GraphicalItemId): number | undefined {
|
|
60
|
+
const barSettings = selectSynchronisedBarSettings(_state, id)
|
|
61
|
+
return barSettings?.maxBarSize
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
export const selectAllVisibleBars = chartSelector(function selectAllVisibleBars(state: ChartState, id: GraphicalItemId, isPanorama: boolean): ReadonlyArray<BarSettings> {
|
|
65
|
+
const layout = selectChartLayout(state)
|
|
66
|
+
const allItems = selectUnfilteredCartesianItems(state)
|
|
67
|
+
const xAxisId = selectXAxisIdFromGraphicalItemId(state, id)
|
|
68
|
+
const yAxisId = selectYAxisIdFromGraphicalItemId(state, id)
|
|
69
|
+
return allItems
|
|
70
|
+
.filter((i) => {
|
|
71
|
+
if (layout === "horizontal") {
|
|
72
|
+
return i.xAxisId === xAxisId
|
|
73
|
+
}
|
|
74
|
+
return i.yAxisId === yAxisId
|
|
75
|
+
})
|
|
76
|
+
.filter((i) => i.isPanorama === isPanorama)
|
|
77
|
+
.filter((i) => i.hide === false)
|
|
78
|
+
.filter((i) => i.type === "bar") as ReadonlyArray<BarSettings>
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
export type SizeList = ReadonlyArray<BarCategory>
|
|
82
|
+
|
|
83
|
+
const selectBarStackGroups = chartSelector((
|
|
84
|
+
state: ChartState,
|
|
85
|
+
id: GraphicalItemId,
|
|
86
|
+
isPanorama: boolean,
|
|
87
|
+
): AllStackGroups | undefined => {
|
|
88
|
+
const layout = selectChartLayout(state)
|
|
89
|
+
const xAxisId = selectXAxisIdFromGraphicalItemId(state, id)
|
|
90
|
+
const yAxisId = selectYAxisIdFromGraphicalItemId(state, id)
|
|
91
|
+
if (xAxisId == null || yAxisId == null) {
|
|
92
|
+
return undefined
|
|
93
|
+
}
|
|
94
|
+
if (layout === "horizontal") {
|
|
95
|
+
return selectStackGroups(state, "yAxis", yAxisId, isPanorama)
|
|
96
|
+
}
|
|
97
|
+
return selectStackGroups(state, "xAxis", xAxisId, isPanorama)
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
export const selectBarCartesianAxisSize = chartSelector((state: ChartState, id: GraphicalItemId) => {
|
|
101
|
+
const layout = selectChartLayout(state)
|
|
102
|
+
const xAxisId = selectXAxisIdFromGraphicalItemId(state, id)
|
|
103
|
+
const yAxisId = selectYAxisIdFromGraphicalItemId(state, id)
|
|
104
|
+
if (xAxisId == null || yAxisId == null) {
|
|
105
|
+
return undefined
|
|
106
|
+
}
|
|
107
|
+
if (layout === "horizontal") {
|
|
108
|
+
return selectCartesianAxisSize(state, "xAxis", xAxisId)
|
|
109
|
+
}
|
|
110
|
+
return selectCartesianAxisSize(state, "yAxis", yAxisId)
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
export const selectBarSizeList = chartSelector(function selectBarSizeList(state: ChartState, id: GraphicalItemId, isPanorama: boolean): SizeList {
|
|
114
|
+
return combineBarSizeList(
|
|
115
|
+
selectAllVisibleBars(state, id, isPanorama),
|
|
116
|
+
selectRootBarSize(state),
|
|
117
|
+
selectBarCartesianAxisSize(state, id),
|
|
118
|
+
)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
export const selectBarBandSize = chartSelector(function selectBarBandSize(state: ChartState, id: GraphicalItemId, isPanorama: boolean): number {
|
|
122
|
+
const barSettings = selectSynchronisedBarSettings(state, id)
|
|
123
|
+
if (barSettings == null) {
|
|
124
|
+
return 0
|
|
125
|
+
}
|
|
126
|
+
const xAxisId = selectXAxisIdFromGraphicalItemId(state, id)
|
|
127
|
+
const yAxisId = selectYAxisIdFromGraphicalItemId(state, id)
|
|
128
|
+
if (xAxisId == null || yAxisId == null) {
|
|
129
|
+
return 0
|
|
130
|
+
}
|
|
131
|
+
const layout = selectChartLayout(state)
|
|
132
|
+
const globalMaxBarSize: number | undefined = selectRootMaxBarSize(state)
|
|
133
|
+
const { maxBarSize: childMaxBarSize } = barSettings
|
|
134
|
+
const maxBarSize: number | undefined = isNullish(childMaxBarSize)
|
|
135
|
+
? globalMaxBarSize
|
|
136
|
+
: childMaxBarSize
|
|
137
|
+
let axis: BaseAxisWithScale | undefined
|
|
138
|
+
let ticks: ReadonlyArray<TickItem> | undefined
|
|
139
|
+
if (layout === "horizontal") {
|
|
140
|
+
axis = selectAxisWithScale(state, "xAxis", xAxisId, isPanorama)
|
|
141
|
+
ticks = selectTicksOfGraphicalItem(state, "xAxis", xAxisId, isPanorama)
|
|
142
|
+
} else {
|
|
143
|
+
axis = selectAxisWithScale(state, "yAxis", yAxisId, isPanorama)
|
|
144
|
+
ticks = selectTicksOfGraphicalItem(state, "yAxis", yAxisId, isPanorama)
|
|
145
|
+
}
|
|
146
|
+
return getBandSizeOfAxis(axis, ticks, true) ?? maxBarSize ?? 0
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
export const selectAxisBandSize = chartSelector(function selectAxisBandSize(state: ChartState, id: GraphicalItemId, isPanorama: boolean): number | undefined {
|
|
150
|
+
const layout = selectChartLayout(state)
|
|
151
|
+
const xAxisId = selectXAxisIdFromGraphicalItemId(state, id)
|
|
152
|
+
const yAxisId = selectYAxisIdFromGraphicalItemId(state, id)
|
|
153
|
+
if (xAxisId == null || yAxisId == null) {
|
|
154
|
+
return undefined
|
|
155
|
+
}
|
|
156
|
+
let axis: BaseAxisWithScale | undefined
|
|
157
|
+
let ticks: ReadonlyArray<TickItem> | undefined
|
|
158
|
+
if (layout === "horizontal") {
|
|
159
|
+
axis = selectAxisWithScale(state, "xAxis", xAxisId, isPanorama)
|
|
160
|
+
ticks = selectTicksOfGraphicalItem(state, "xAxis", xAxisId, isPanorama)
|
|
161
|
+
} else {
|
|
162
|
+
axis = selectAxisWithScale(state, "yAxis", yAxisId, isPanorama)
|
|
163
|
+
ticks = selectTicksOfGraphicalItem(state, "yAxis", yAxisId, isPanorama)
|
|
164
|
+
}
|
|
165
|
+
return getBandSizeOfAxis(axis, ticks)
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
export type BarWithPosition = {
|
|
169
|
+
stackId: StackId | undefined
|
|
170
|
+
/**
|
|
171
|
+
* List of dataKeys of items stacked at this position.
|
|
172
|
+
* All of these Bars are either sharing the same stackId,
|
|
173
|
+
* or this is an array with one Bar because it has no stackId defined.
|
|
174
|
+
*
|
|
175
|
+
* This structure limits us to having one dataKey only once per stack which I think is reasonable.
|
|
176
|
+
* People who want to have the same data twice can duplicate their data to have two distinct dataKeys.
|
|
177
|
+
*/
|
|
178
|
+
dataKeys: ReadonlyArray<DataKey<unknown>>
|
|
179
|
+
/**
|
|
180
|
+
* Position of this stack in absolute pixels measured from the start of the chart
|
|
181
|
+
*/
|
|
182
|
+
position: BarPositionPosition
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export const selectAllBarPositions = chartSelector(function selectAllBarPositions(state: ChartState, id: GraphicalItemId, isPanorama: boolean): ReadonlyArray<BarWithPosition> | undefined {
|
|
186
|
+
return combineAllBarPositions(
|
|
187
|
+
selectBarSizeList(state, id, isPanorama),
|
|
188
|
+
selectRootMaxBarSize(state),
|
|
189
|
+
selectBarGap(state),
|
|
190
|
+
selectBarCategoryGap(state),
|
|
191
|
+
selectBarBandSize(state, id, isPanorama),
|
|
192
|
+
selectAxisBandSize(state, id, isPanorama),
|
|
193
|
+
selectMaxBarSize(state, id),
|
|
194
|
+
)
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
const selectXAxisWithScale = chartSelector((
|
|
198
|
+
state: ChartState,
|
|
199
|
+
id: GraphicalItemId,
|
|
200
|
+
isPanorama: boolean,
|
|
201
|
+
override?: XAxisSettings,
|
|
202
|
+
) => {
|
|
203
|
+
const xAxisId = selectXAxisIdFromGraphicalItemId(state, id)
|
|
204
|
+
if (xAxisId == null) {
|
|
205
|
+
return undefined
|
|
206
|
+
}
|
|
207
|
+
return selectAxisWithScale(state, "xAxis", xAxisId, isPanorama, override)
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
const selectYAxisWithScale = chartSelector((
|
|
211
|
+
state: ChartState,
|
|
212
|
+
id: GraphicalItemId,
|
|
213
|
+
isPanorama: boolean,
|
|
214
|
+
override?: YAxisSettings,
|
|
215
|
+
) => {
|
|
216
|
+
const yAxisId = selectYAxisIdFromGraphicalItemId(state, id)
|
|
217
|
+
if (yAxisId == null) {
|
|
218
|
+
return undefined
|
|
219
|
+
}
|
|
220
|
+
return selectAxisWithScale(state, "yAxis", yAxisId, isPanorama, override)
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
const selectXAxisTicks = chartSelector((state: ChartState, id: GraphicalItemId, isPanorama: boolean) => {
|
|
224
|
+
const xAxisId = selectXAxisIdFromGraphicalItemId(state, id)
|
|
225
|
+
if (xAxisId == null) {
|
|
226
|
+
return undefined
|
|
227
|
+
}
|
|
228
|
+
return selectTicksOfGraphicalItem(state, "xAxis", xAxisId, isPanorama)
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
const selectYAxisTicks = chartSelector((state: ChartState, id: GraphicalItemId, isPanorama: boolean) => {
|
|
232
|
+
const yAxisId = selectYAxisIdFromGraphicalItemId(state, id)
|
|
233
|
+
if (yAxisId == null) {
|
|
234
|
+
return undefined
|
|
235
|
+
}
|
|
236
|
+
return selectTicksOfGraphicalItem(state, "yAxis", yAxisId, isPanorama)
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
export const selectBarPosition = chartSelector(function selectBarPosition(state: ChartState, id: GraphicalItemId, isPanorama: boolean): BarPositionPosition | undefined {
|
|
240
|
+
return combineBarPosition(
|
|
241
|
+
selectAllBarPositions(state, id, isPanorama),
|
|
242
|
+
selectSynchronisedBarSettings(state, id),
|
|
243
|
+
)
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
export const selectStackedDataOfItem = chartSelector(function selectStackedDataOfItem(state: ChartState, id: GraphicalItemId, isPanorama: boolean): StackSeries | undefined {
|
|
247
|
+
return combineStackedData(
|
|
248
|
+
selectBarStackGroups(state, id, isPanorama),
|
|
249
|
+
selectSynchronisedBarSettings(state, id),
|
|
250
|
+
)
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
export const selectBarRectangles = chartSelector(function selectBarRectangles(state: ChartState, id: GraphicalItemId, isPanorama: boolean, cells: ReadonlyArray<JSX.Element> | undefined, xAxisOverride?: XAxisSettings, yAxisOverride?: YAxisSettings, barSettingsOverride?: BarSettings): ReadonlyArray<BarRectangleItem> | undefined {
|
|
254
|
+
const offset: ChartOffsetInternal = selectChartOffsetInternal(state)
|
|
255
|
+
const axisViewBox: CartesianViewBoxRequired = selectAxisViewBox(state)
|
|
256
|
+
const xAxis = selectXAxisWithScale(state, id, isPanorama, xAxisOverride)
|
|
257
|
+
const yAxis = selectYAxisWithScale(state, id, isPanorama, yAxisOverride)
|
|
258
|
+
const xAxisTicks = selectXAxisTicks(state, id, isPanorama)
|
|
259
|
+
const yAxisTicks = selectYAxisTicks(state, id, isPanorama)
|
|
260
|
+
const pos = selectBarPosition(state, id, isPanorama)
|
|
261
|
+
const layout = selectChartLayout(state)
|
|
262
|
+
const { chartData, dataStartIndex, dataEndIndex } =
|
|
263
|
+
selectChartDataWithIndexesIfNotInPanoramaPosition3(state, undefined, isPanorama)
|
|
264
|
+
const bandSize = selectAxisBandSize(state, id, isPanorama)
|
|
265
|
+
const stackedData = selectStackedDataOfItem(state, id, isPanorama)
|
|
266
|
+
const barSettings = barSettingsOverride ?? selectSynchronisedBarSettings(state, id)
|
|
267
|
+
|
|
268
|
+
if (
|
|
269
|
+
barSettings == null ||
|
|
270
|
+
pos == null ||
|
|
271
|
+
axisViewBox == null ||
|
|
272
|
+
(layout !== "horizontal" && layout !== "vertical") ||
|
|
273
|
+
xAxis == null ||
|
|
274
|
+
yAxis == null ||
|
|
275
|
+
xAxisTicks == null ||
|
|
276
|
+
yAxisTicks == null ||
|
|
277
|
+
bandSize == null
|
|
278
|
+
) {
|
|
279
|
+
return undefined
|
|
280
|
+
}
|
|
281
|
+
const { data } = barSettings
|
|
282
|
+
|
|
283
|
+
let displayedData: ChartData | undefined
|
|
284
|
+
if (data != null && data.length > 0) {
|
|
285
|
+
displayedData = data
|
|
286
|
+
} else {
|
|
287
|
+
displayedData = chartData?.slice(dataStartIndex, dataEndIndex + 1)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (displayedData == null) {
|
|
291
|
+
return undefined
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return computeBarRectangles({
|
|
295
|
+
bandSize,
|
|
296
|
+
barSettings,
|
|
297
|
+
cells,
|
|
298
|
+
dataStartIndex,
|
|
299
|
+
displayedData,
|
|
300
|
+
layout,
|
|
301
|
+
offset,
|
|
302
|
+
parentViewBox: axisViewBox,
|
|
303
|
+
pos,
|
|
304
|
+
stackedData,
|
|
305
|
+
xAxis,
|
|
306
|
+
xAxisTicks,
|
|
307
|
+
yAxis,
|
|
308
|
+
yAxisTicks,
|
|
309
|
+
})
|
|
310
|
+
})
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/* eslint-disable import/no-cycle */
|
|
2
|
+
import type { ChartState } from "../store"
|
|
3
|
+
import type { NormalizedStackId } from "../../util/ChartUtils"
|
|
4
|
+
import type { BarSettings } from "../types/BarSettings"
|
|
5
|
+
import { selectUnfilteredCartesianItems } from "./axisSelectors"
|
|
6
|
+
import type { CartesianGraphicalItemSettings } from "../graphicalItemsSlice"
|
|
7
|
+
import { chartSelector } from "./chartSelector"
|
|
8
|
+
import { selectBarRectangles } from "./barSelectors"
|
|
9
|
+
|
|
10
|
+
export const selectAllBarsInStack = chartSelector(function selectAllBarsInStack(state: ChartState, stackId: NormalizedStackId, isPanorama: boolean): ReadonlyArray<BarSettings> {
|
|
11
|
+
const allItems: ReadonlyArray<CartesianGraphicalItemSettings> =
|
|
12
|
+
selectUnfilteredCartesianItems(state)
|
|
13
|
+
return allItems
|
|
14
|
+
.filter((i) => i.type === "bar")
|
|
15
|
+
.filter((i) => i.stackId === stackId)
|
|
16
|
+
.filter((i) => i.isPanorama === isPanorama)
|
|
17
|
+
.filter((i) => !i.hide) as ReadonlyArray<BarSettings>
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const selectAllBarIdsInStack = chartSelector(function selectAllBarIdsInStack(state: ChartState, stackId: NormalizedStackId, isPanorama: boolean) {
|
|
21
|
+
return selectAllBarsInStack(state, stackId, isPanorama).map((bar) => bar.id)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
export type BarStackItem = {
|
|
25
|
+
x: number
|
|
26
|
+
y: number
|
|
27
|
+
width: number
|
|
28
|
+
height: number
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Takes two rectangles and returns a new rectangle that encompasses both.
|
|
33
|
+
* It takes the minimum x and y, and the maximum width and height.
|
|
34
|
+
* It handles overlapping rectangles, and rectangles with a gap between them.
|
|
35
|
+
* @param rect1
|
|
36
|
+
* @param rect2
|
|
37
|
+
*/
|
|
38
|
+
export const expandRectangle = (
|
|
39
|
+
rect1: BarStackItem | undefined,
|
|
40
|
+
rect2: BarStackItem | undefined,
|
|
41
|
+
): BarStackItem | undefined => {
|
|
42
|
+
if (!rect1) {
|
|
43
|
+
return rect2
|
|
44
|
+
}
|
|
45
|
+
if (!rect2) {
|
|
46
|
+
return rect1
|
|
47
|
+
}
|
|
48
|
+
const x = Math.min(rect1.x, rect1.x + rect1.width, rect2.x, rect2.x + rect2.width)
|
|
49
|
+
const y = Math.min(rect1.y, rect1.y + rect1.height, rect2.y, rect2.y + rect2.height)
|
|
50
|
+
const maxX = Math.max(rect1.x, rect1.x + rect1.width, rect2.x, rect2.x + rect2.width)
|
|
51
|
+
const maxY = Math.max(rect1.y, rect1.y + rect1.height, rect2.y, rect2.y + rect2.height)
|
|
52
|
+
const width = maxX - x
|
|
53
|
+
const height = maxY - y
|
|
54
|
+
return { height, width, x, y }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function combineStackRects(
|
|
58
|
+
state: ChartState,
|
|
59
|
+
stackId: NormalizedStackId,
|
|
60
|
+
isPanorama: boolean,
|
|
61
|
+
): ReadonlyArray<BarStackItem | undefined> {
|
|
62
|
+
const allBarIds = selectAllBarIdsInStack(state, stackId, isPanorama)
|
|
63
|
+
const stackRects: Array<BarStackItem | undefined> = []
|
|
64
|
+
allBarIds.forEach((barId) => {
|
|
65
|
+
const rectangles = selectBarRectangles(state, barId, isPanorama, undefined)
|
|
66
|
+
rectangles?.forEach((rect) => {
|
|
67
|
+
/* Rectangles are filtered (zero dimension), so index by the original data position. */
|
|
68
|
+
const rectIndex = rect.originalDataIndex
|
|
69
|
+
stackRects[rectIndex] = expandRectangle(stackRects[rectIndex], rect)
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
return stackRects
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const selectStackRects = chartSelector(function selectStackRects(state: ChartState, stackId: NormalizedStackId, isPanorama: boolean): ReadonlyArray<BarStackItem | undefined> {
|
|
76
|
+
return combineStackRects(state, stackId, isPanorama)
|
|
77
|
+
})
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/* eslint-disable import/no-cycle */
|
|
2
|
+
import type { ChartState } from "../store"
|
|
3
|
+
import { readChartState } from "../chartState"
|
|
4
|
+
import { selectChartOffsetInternal } from "./selectChartOffsetInternal"
|
|
5
|
+
import { selectMargin } from "./containerSelectors"
|
|
6
|
+
import { isNumber } from "../../util/DataUtils"
|
|
7
|
+
import { chartSelector } from "./chartSelector"
|
|
8
|
+
import type { BrushSettings } from "../brushSlice"
|
|
9
|
+
|
|
10
|
+
export const selectBrushSettings = (state: ChartState): BrushSettings => {
|
|
11
|
+
return readChartState(state).brush
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type BrushDimensions = {
|
|
15
|
+
x: number
|
|
16
|
+
y: number
|
|
17
|
+
width: number
|
|
18
|
+
height: number
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const selectBrushDimensions = chartSelector(function selectBrushDimensions(state: ChartState): BrushDimensions {
|
|
22
|
+
const brushSettings = selectBrushSettings(state)
|
|
23
|
+
const offset = selectChartOffsetInternal(state)
|
|
24
|
+
const margin = selectMargin(state)
|
|
25
|
+
return {
|
|
26
|
+
height: brushSettings.height,
|
|
27
|
+
width: isNumber(brushSettings.width) ? brushSettings.width : offset.width,
|
|
28
|
+
x: isNumber(brushSettings.x) ? brushSettings.x : offset.left,
|
|
29
|
+
y: isNumber(brushSettings.y)
|
|
30
|
+
? brushSettings.y
|
|
31
|
+
: offset.top + offset.height + offset.brushBottom - (margin?.bottom || 0),
|
|
32
|
+
}
|
|
33
|
+
})
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { $PROXY, createMemo, onCleanup, runWithOwner } from "solid-js"
|
|
2
|
+
import type { Accessor, Owner } from "solid-js"
|
|
3
|
+
import type { ChartState } from "../chartState"
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* Per-chart memoized selector graph — the Solid stand-in for upstream's reselect `createSelector`.
|
|
7
|
+
*
|
|
8
|
+
* A wrapped selector called with a chart store resolves to one memo per (selector, argument tuple),
|
|
9
|
+
* owned by the chart provider and shared by every consumer. Each memo tracks only the store reads
|
|
10
|
+
* and selector reads of its own body, so an upstream memo that did not change (by `equals`) stops
|
|
11
|
+
* propagation exactly like a reselect cache hit.
|
|
12
|
+
*
|
|
13
|
+
* Stores without a registered owner (unit tests building a bare store, code outside a provider)
|
|
14
|
+
* call the raw function, so behavior is identical either way.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
type Selector<A extends unknown[], R> = (state: ChartState, ...args: A) => R
|
|
18
|
+
|
|
19
|
+
type ArgNode = {
|
|
20
|
+
memo: Accessor<unknown> | undefined
|
|
21
|
+
children: Map<unknown, ArgNode> | undefined
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type ChartCache = { owner: Owner; roots: WeakMap<object, ArgNode> }
|
|
25
|
+
|
|
26
|
+
const chartCaches = new WeakMap<ChartState, ChartCache>()
|
|
27
|
+
|
|
28
|
+
const newNode = (): ArgNode => ({ children: undefined, memo: undefined })
|
|
29
|
+
|
|
30
|
+
const isObjectArg = (value: unknown): boolean =>
|
|
31
|
+
(typeof value === "object" && value !== null) || typeof value === "function"
|
|
32
|
+
|
|
33
|
+
/* Map keys use SameValueZero, so undefined and NaN are valid keys without a sentinel. */
|
|
34
|
+
function childNode(node: ArgNode, key: unknown): ArgNode {
|
|
35
|
+
node.children ??= new Map()
|
|
36
|
+
let next = node.children.get(key)
|
|
37
|
+
if (next === undefined) {
|
|
38
|
+
next = newNode()
|
|
39
|
+
node.children.set(key, next)
|
|
40
|
+
}
|
|
41
|
+
return next
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const isStoreNode = (value: object): boolean => (value as { [$PROXY]?: unknown })[$PROXY] !== undefined
|
|
45
|
+
|
|
46
|
+
const isPlainObject = (value: unknown): value is Record<string, unknown> => {
|
|
47
|
+
if (typeof value !== "object" || value === null) {
|
|
48
|
+
return false
|
|
49
|
+
}
|
|
50
|
+
const proto = Object.getPrototypeOf(value)
|
|
51
|
+
return proto === Object.prototype || proto === null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Default output equality: `===`, then element-wise `===` for arrays, then own-key shallow `===`
|
|
56
|
+
* for plain non-store objects. Never deep — data arrays are compared by element identity only.
|
|
57
|
+
*/
|
|
58
|
+
export function defaultSelectorEquals(a: unknown, b: unknown): boolean {
|
|
59
|
+
if (a === b) {
|
|
60
|
+
return true
|
|
61
|
+
}
|
|
62
|
+
if (Array.isArray(a)) {
|
|
63
|
+
if (!Array.isArray(b) || a.length !== b.length) {
|
|
64
|
+
return false
|
|
65
|
+
}
|
|
66
|
+
for (let i = 0; i < a.length; i++) {
|
|
67
|
+
if (a[i] !== b[i]) {
|
|
68
|
+
return false
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return true
|
|
72
|
+
}
|
|
73
|
+
/* Distinct store nodes are never equal: keeping the old node would leave readers tracking
|
|
74
|
+
a different live object than the one the selector now resolves to. */
|
|
75
|
+
if (!isPlainObject(a) || !isPlainObject(b) || isStoreNode(a) || isStoreNode(b)) {
|
|
76
|
+
return false
|
|
77
|
+
}
|
|
78
|
+
const aKeys = Object.keys(a)
|
|
79
|
+
if (aKeys.length !== Object.keys(b).length) {
|
|
80
|
+
return false
|
|
81
|
+
}
|
|
82
|
+
for (const key of aKeys) {
|
|
83
|
+
if (a[key] !== b[key] || !(key in b)) {
|
|
84
|
+
return false
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return true
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Binds a chart store to the owner its selector memos live under. Called once per chart provider;
|
|
92
|
+
* the cache is dropped when that owner is disposed.
|
|
93
|
+
*/
|
|
94
|
+
export function registerChartOwner(state: ChartState, owner: Owner | null): void {
|
|
95
|
+
if (owner == null) {
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
chartCaches.set(state, { owner, roots: new WeakMap() })
|
|
99
|
+
onCleanup(() => {
|
|
100
|
+
chartCaches.delete(state)
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** The owner registered for a chart store, if any. */
|
|
105
|
+
export function ownerFor(state: ChartState): Owner | undefined {
|
|
106
|
+
return chartCaches.get(state)?.owner
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/*
|
|
110
|
+
* A memo keyed by stale arguments (an old settings node) can recompute in the same flush that its
|
|
111
|
+
* consumer will use to switch to new arguments. Errors are therefore captured and rethrown only to
|
|
112
|
+
* a reader, so a discarded stale computation never halts the reactive system.
|
|
113
|
+
*/
|
|
114
|
+
class SelectorError {
|
|
115
|
+
constructor(readonly error: unknown) {}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const withErrorBox = (equals: (prev: unknown, next: unknown) => boolean) => (prev: unknown, next: unknown) =>
|
|
119
|
+
!(prev instanceof SelectorError) && !(next instanceof SelectorError) && equals(prev, next)
|
|
120
|
+
|
|
121
|
+
export type ChartSelectorOptions<R> = {
|
|
122
|
+
equals?: (prev: R, next: R) => boolean
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Wraps a selector so calls on a provider-owned chart store share one memo per argument tuple.
|
|
127
|
+
* Same signature as `fn`.
|
|
128
|
+
*
|
|
129
|
+
* Only all-primitive tuples are memoized. A call carrying an object argument (settings node,
|
|
130
|
+
* cells, overrides) runs the raw function: a memo closed over a settings node that was later
|
|
131
|
+
* replaced would keep recomputing against new data until its consumer let go, running stale
|
|
132
|
+
* user callbacks such as a previous `dataKey` (recharts#4935).
|
|
133
|
+
*
|
|
134
|
+
* Do not wrap selectors whose arguments span an unbounded primitive space (pointer coordinates):
|
|
135
|
+
* every distinct tuple keeps a trie entry for the chart's lifetime.
|
|
136
|
+
*
|
|
137
|
+
* Memos are lazy: an unobserved memo goes dormant (detached from its sources and the owner)
|
|
138
|
+
* instead of recomputing on every write, and a later read reawakens it, so untracked readers such
|
|
139
|
+
* as event middleware cost no more than the raw function.
|
|
140
|
+
*/
|
|
141
|
+
export function chartSelector<A extends unknown[], R>(
|
|
142
|
+
fn: Selector<A, R>,
|
|
143
|
+
options?: ChartSelectorOptions<R>,
|
|
144
|
+
): Selector<A, R> {
|
|
145
|
+
const equals = withErrorBox((options?.equals ?? defaultSelectorEquals) as (prev: unknown, next: unknown) => boolean)
|
|
146
|
+
const selector = (state: ChartState, ...args: A): R => {
|
|
147
|
+
const cache = chartCaches.get(state)
|
|
148
|
+
if (cache === undefined) {
|
|
149
|
+
return fn(state, ...args)
|
|
150
|
+
}
|
|
151
|
+
let node = cache.roots.get(fn)
|
|
152
|
+
if (node === undefined) {
|
|
153
|
+
node = newNode()
|
|
154
|
+
cache.roots.set(fn, node)
|
|
155
|
+
}
|
|
156
|
+
for (const arg of args) {
|
|
157
|
+
if (isObjectArg(arg)) {
|
|
158
|
+
return fn(state, ...args)
|
|
159
|
+
}
|
|
160
|
+
node = childNode(node, arg)
|
|
161
|
+
}
|
|
162
|
+
let memo = node.memo
|
|
163
|
+
if (memo === undefined) {
|
|
164
|
+
const compute = (): unknown => {
|
|
165
|
+
try {
|
|
166
|
+
return fn(state, ...args)
|
|
167
|
+
} catch (error) {
|
|
168
|
+
return new SelectorError(error)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
memo = runWithOwner(cache.owner, () =>
|
|
172
|
+
createMemo<unknown>(compute, { equals, lazy: true, sync: true, transparent: true }),
|
|
173
|
+
)
|
|
174
|
+
node.memo = memo
|
|
175
|
+
}
|
|
176
|
+
const value = memo()
|
|
177
|
+
if (value instanceof SelectorError) {
|
|
178
|
+
throw value.error
|
|
179
|
+
}
|
|
180
|
+
return value as R
|
|
181
|
+
}
|
|
182
|
+
/* Keep the arity of the wrapped function; hook-compat checks read `selector.length`. */
|
|
183
|
+
Object.defineProperty(selector, "length", { value: fn.length })
|
|
184
|
+
return selector
|
|
185
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/* eslint-disable import/no-cycle */
|
|
2
|
+
import { TickItem } from "../../../util/types"
|
|
3
|
+
import { TooltipIndex } from "../../tooltipSlice"
|
|
4
|
+
import { isNan } from "../../../util/DataUtils"
|
|
5
|
+
import { ActiveLabel } from "../../../synchronisation/types"
|
|
6
|
+
|
|
7
|
+
export const combineActiveLabel = (
|
|
8
|
+
tooltipTicks: ReadonlyArray<TickItem> | undefined,
|
|
9
|
+
activeIndex: TooltipIndex,
|
|
10
|
+
): ActiveLabel => {
|
|
11
|
+
const n = Number(activeIndex)
|
|
12
|
+
if (isNan(n) || activeIndex == null) {
|
|
13
|
+
return undefined
|
|
14
|
+
}
|
|
15
|
+
return n >= 0 ? tooltipTicks?.[n]?.value : undefined
|
|
16
|
+
}
|