Skip to content

Commit 8b7aaac

Browse files
committed
Use composition for annotations with chart context
1 parent 9953b53 commit 8b7aaac

File tree

5 files changed

+177
-185
lines changed

5 files changed

+177
-185
lines changed

projects/js-packages/charts/src/components/line-chart/line-chart-annotations-overlay.tsx

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,32 @@
11
import { DataContext } from '@visx/xychart';
22
import { useEffect, useState, useCallback } from 'react';
3-
import LineChartAnnotation from './line-chart-annotation';
3+
import { useChartContext } from '../../providers/chart-context';
44
import styles from './line-chart.module.scss';
5-
import type { LineChartRef } from './line-chart';
6-
import type { LineChartAnnotationProps } from './line-chart-annotation';
75
import type { AxisScale } from '@visx/axis';
8-
import type { FC, RefObject } from 'react';
6+
import type { FC, ReactNode } from 'react';
97

108
interface LineChartAnnotationsProps {
11-
chartRef: RefObject< LineChartRef >;
12-
annotations: LineChartAnnotationProps[];
13-
chartWidth: number;
14-
chartHeight: number;
9+
chartId: string;
10+
children?: ReactNode;
1511
}
1612

1713
interface ScaleData {
1814
xScale: AxisScale< Date >;
1915
yScale: AxisScale< number >;
2016
}
2117

22-
const LineChartAnnotationsOverlay: FC< LineChartAnnotationsProps > = ( {
23-
chartRef,
24-
annotations,
25-
chartWidth,
26-
chartHeight,
27-
} ) => {
18+
const LineChartAnnotationsOverlay: FC< LineChartAnnotationsProps > = ( { chartId, children } ) => {
19+
const { getChartData } = useChartContext();
20+
21+
let chartData = null;
22+
if ( chartId ) {
23+
chartData = getChartData( chartId );
24+
}
25+
26+
const chartRef = chartData?.chartRef;
27+
const chartWidth = chartData?.chartWidth || 0;
28+
const chartHeight = chartData?.chartHeight || 0;
29+
2830
const [ scales, setScales ] = useState< ScaleData | null >( null );
2931
const [ scalesStable, setScalesStable ] = useState< boolean >( false );
3032

@@ -42,7 +44,7 @@ const LineChartAnnotationsOverlay: FC< LineChartAnnotationsProps > = ( {
4244

4345
// Get scales from chart ref and return them with signature for comparison
4446
const getScalesData = useCallback( () => {
45-
if ( chartRef.current ) {
47+
if ( chartRef?.current ) {
4648
const scaleData = chartRef.current.getScales();
4749

4850
if ( scaleData ) {
@@ -107,6 +109,11 @@ const LineChartAnnotationsOverlay: FC< LineChartAnnotationsProps > = ( {
107109
};
108110
}, [ getScalesData, chartWidth, chartHeight ] );
109111

112+
// Early return if no chart data available
113+
if ( ! chartRef || ! children ) {
114+
return null;
115+
}
116+
110117
if ( ! scales || ! scalesStable ) {
111118
return null;
112119
}
@@ -116,16 +123,9 @@ const LineChartAnnotationsOverlay: FC< LineChartAnnotationsProps > = ( {
116123
const dataContextValue = {
117124
xScale: scales.xScale,
118125
yScale: scales.yScale,
119-
// Add minimal required properties for DataContext
120-
theme: {},
121126
margin: { top: 0, right: 0, bottom: 0, left: 0 },
122127
width: chartWidth,
123128
height: chartHeight,
124-
// Additional visx DataContext properties that may be needed
125-
colorScale: undefined,
126-
dataRegistry: new Map(),
127-
registerData: () => {},
128-
unregisterData: () => {},
129129
} as unknown as Parameters< typeof DataContext.Provider >[ 0 ][ 'value' ];
130130

131131
return (
@@ -136,13 +136,7 @@ const LineChartAnnotationsOverlay: FC< LineChartAnnotationsProps > = ( {
136136
className={ styles[ 'line-chart__annotations-overlay' ] }
137137
data-testid="line-chart-annotations-overlay"
138138
>
139-
{ annotations.map( ( annotation, index ) => (
140-
<LineChartAnnotation
141-
key={ `overlay-annotation-${ index }` }
142-
testId={ `overlay-annotation-${ index }` }
143-
{ ...annotation }
144-
/>
145-
) ) }
139+
{ children }
146140
</svg>
147141
</DataContext.Provider>
148142
);

projects/js-packages/charts/src/components/line-chart/line-chart.tsx

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ import {
1111
useImperativeHandle,
1212
useState,
1313
useRef,
14+
Children,
15+
cloneElement,
16+
isValidElement,
1417
} from 'react';
1518
import { ChartProvider, useChartId, useChartRegistration } from '../../providers/chart-context';
1619
import { useXYChartTheme, useChartTheme } from '../../providers/theme/theme-provider';
@@ -21,9 +24,7 @@ import { useChartMargin } from '../shared/use-chart-margin';
2124
import { useElementHeight } from '../shared/use-element-height';
2225
import { withResponsive } from '../shared/with-responsive';
2326
import { AccessibleTooltip, useKeyboardNavigation } from '../tooltip/accessible-tooltip';
24-
import LineChartAnnotationsOverlay from './line-chart-annotations-overlay';
2527
import styles from './line-chart.module.scss';
26-
import type { LineChartAnnotationProps } from './line-chart-annotation';
2728
import type { BaseChartProps, DataPoint, DataPointDate, SeriesData } from '../../types';
2829
import type { TickFormatter } from '@visx/axis';
2930
import type { GlyphProps } from '@visx/xychart';
@@ -134,7 +135,7 @@ interface LineChartProps extends BaseChartProps< SeriesData[] > {
134135
showVertical?: boolean;
135136
showHorizontal?: boolean;
136137
};
137-
annotations?: LineChartAnnotationProps[];
138+
children?: ReactNode;
138139
}
139140

140141
type TooltipDatum = {
@@ -252,11 +253,11 @@ const LineChartInternal = forwardRef< LineChartRef, LineChartProps >(
252253
renderTooltip = renderDefaultTooltip,
253254
withStartGlyphs = false,
254255
options = {},
255-
annotations,
256256
onPointerDown = undefined,
257257
onPointerUp = undefined,
258258
onPointerMove = undefined,
259259
onPointerOut = undefined,
260+
children,
260261
},
261262
ref
262263
) => {
@@ -362,13 +363,25 @@ const LineChartInternal = forwardRef< LineChartRef, LineChartProps >(
362363
);
363364

364365
// Register chart with context only if data is valid
365-
useChartRegistration( chartId, legendItems, providerTheme, 'line', isDataValid, {
366-
withGradientFill,
367-
smoothing,
368-
curveType,
369-
withStartGlyphs,
370-
withLegendGlyph,
371-
} );
366+
useChartRegistration(
367+
chartId,
368+
legendItems,
369+
providerTheme,
370+
'line',
371+
isDataValid,
372+
{
373+
withGradientFill,
374+
smoothing,
375+
curveType,
376+
withStartGlyphs,
377+
withLegendGlyph,
378+
},
379+
{
380+
chartRef: internalChartRef,
381+
chartWidth: width,
382+
chartHeight: height - ( showLegend ? legendHeight : 0 ),
383+
}
384+
);
372385

373386
const accessors = {
374387
xAccessor: ( d: DataPointDate ) => d?.date,
@@ -505,16 +518,6 @@ const LineChartInternal = forwardRef< LineChartRef, LineChartProps >(
505518
</XYChart>
506519
</div>
507520

508-
{ /* Render annotations as external overlay to avoid interaction blocking */ }
509-
{ annotations?.length && (
510-
<LineChartAnnotationsOverlay
511-
chartRef={ internalChartRef }
512-
annotations={ annotations }
513-
chartWidth={ width }
514-
chartHeight={ height - ( showLegend ? legendHeight : 0 ) }
515-
/>
516-
) }
517-
518521
{ showLegend && (
519522
<Legend
520523
items={ legendItems }
@@ -526,6 +529,15 @@ const LineChartInternal = forwardRef< LineChartRef, LineChartProps >(
526529
ref={ legendRef }
527530
/>
528531
) }
532+
533+
{ /* Render children here so they have access to the chart ID */ }
534+
{ Children.map( children, child => {
535+
if ( isValidElement( child ) ) {
536+
return cloneElement( child, { chartId } as { chartId: string } );
537+
}
538+
539+
return child;
540+
} ) }
529541
</div>
530542
);
531543
}

0 commit comments

Comments
 (0)