Skip to content

Commit 28c8e78

Browse files
committed
fix: do not render/compute interaction layers unless active
1 parent d1e38ef commit 28c8e78

File tree

6 files changed

+83
-25
lines changed

6 files changed

+83
-25
lines changed

examples/simple/src/components/StressTest.tsx

+30-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ export default function StressTest() {
1414
liveDataInterval,
1515
showPoints,
1616
memoizeSeries,
17+
height,
18+
showAxes,
1719
},
1820
setState,
1921
] = React.useState({
@@ -25,6 +27,8 @@ export default function StressTest() {
2527
liveDataInterval: 1000,
2628
showPoints: true,
2729
memoizeSeries: false,
30+
height: 100,
31+
showAxes: true,
2832
});
2933

3034
const { data, randomizeData } = useDemoConfig({
@@ -41,8 +45,9 @@ export default function StressTest() {
4145
>(
4246
() => ({
4347
getValue: (datum) => datum.primary as unknown as Date,
48+
show: showAxes,
4449
}),
45-
[]
50+
[showAxes]
4651
);
4752

4853
const secondaryAxes = React.useMemo<
@@ -52,9 +57,10 @@ export default function StressTest() {
5257
{
5358
getValue: (datum) => datum.secondary,
5459
showDatumElements: showPoints,
60+
show: showAxes,
5561
},
5662
],
57-
[showPoints]
63+
[showAxes, showPoints]
5864
);
5965

6066
React.useEffect(() => {
@@ -145,6 +151,17 @@ export default function StressTest() {
145151
}}
146152
/>
147153
</label>
154+
<label>
155+
Show Axes:{" "}
156+
<input
157+
type="checkbox"
158+
checked={showAxes}
159+
onChange={(e) => {
160+
e.persist();
161+
setState((old) => ({ ...old, showAxes: !!e.target.checked }));
162+
}}
163+
/>
164+
</label>
148165
<br />
149166
<label>
150167
Memoize Series:{" "}
@@ -192,11 +209,21 @@ export default function StressTest() {
192209
</select>
193210
</label>
194211
<br />
212+
<label>
213+
Chart Height
214+
<input
215+
type="number"
216+
value={height}
217+
onChange={(e) => {
218+
setState((old) => ({ ...old, height: parseInt(e.target.value) }));
219+
}}
220+
/>
221+
</label>
195222
<button onClick={randomizeData}>Randomize Data</button>
196223
<br />
197224
<br />
198225
{[...new Array(chartCount)].map((d, i) => (
199-
<ResizableBox key={i} height={100}>
226+
<ResizableBox key={i} height={height}>
200227
<Chart
201228
options={{
202229
data,

examples/simple/src/useLagRadar.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ function lagRadar(config = {}) {
3434

3535
const styles = document.createTextNode(`
3636
.lagRadar {
37-
pointer-events: none;
38-
}
39-
.lagRadar-sweep > * {
37+
pointer-events: none;
38+
}
39+
.lagRadar-sweep > * {
4040
shape-rendering: crispEdges;
4141
}
4242
.lagRadar-face {

src/components/Chart.tsx

+20-1
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,9 @@ function ChartInner<TDatum>({
307307

308308
const [axisDimensions] = axisDimensionsState
309309

310+
const isInteractingState = React.useState<boolean>(false)
311+
const [isInteracting] = isInteractingState
312+
310313
const focusedDatumState = React.useState<Datum<TDatum> | null>(null)
311314
const [focusedDatum] = focusedDatumState
312315

@@ -464,11 +467,19 @@ function ChartInner<TDatum>({
464467
}, [allDatums, gridDimensions, height, secondaryAxesOptions, series, width])
465468

466469
const [datumsByInteractionGroup, datumsByTooltipGroup] = React.useMemo(() => {
470+
if (!isInteracting) {
471+
return [new Map(), new Map()]
472+
}
473+
467474
const datumsByInteractionGroup = new Map<any, Datum<TDatum>[]>()
468475
const datumsByTooltipGroup = new Map<any, Datum<TDatum>[]>()
469476

477+
const allBarAndNotStacked = secondaryAxes.every(
478+
d => d.elementType === 'bar' && !d.stacked
479+
)
480+
470481
let getInteractionPrimary = (datum: Datum<TDatum>) => {
471-
if (secondaryAxes.every(d => d.elementType === 'bar' && !d.stacked)) {
482+
if (allBarAndNotStacked) {
472483
const secondaryAxis = secondaryAxes.find(
473484
d => d.id === datum.secondaryAxisId
474485
)!
@@ -537,6 +548,7 @@ function ChartInner<TDatum>({
537548

538549
return [datumsByInteractionGroup, datumsByTooltipGroup]
539550
}, [
551+
isInteracting,
540552
allDatums,
541553
options.interactionMode,
542554
primaryAxis,
@@ -615,6 +627,7 @@ function ChartInner<TDatum>({
615627
axisDimensionsState,
616628
focusedDatumState,
617629
svgRef,
630+
isInteractingState,
618631
}
619632

620633
const seriesByAxisId = React.useMemo(
@@ -696,6 +709,12 @@ function ChartInner<TDatum>({
696709
overflow: options.brush ? 'hidden' : 'visible',
697710
}}
698711
onClick={e => options.onClickDatum?.(focusedDatum, e)}
712+
onMouseEnter={() => {
713+
isInteractingState[1](true)
714+
}}
715+
onMouseLeave={() => {
716+
isInteractingState[1](false)
717+
}}
699718
>
700719
<g className="axes">
701720
{[primaryAxis, ...secondaryAxes].map(axis => (

src/components/Voronoi.tsx

+10-7
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ import { line } from 'd3-shape'
99
import { getPrimaryGroupLength, getPrimaryLength } from '../seriesTypes/Bar'
1010

1111
export default function Voronoi<TDatum>() {
12-
const { getOptions, focusedDatumState } = useChartContext<TDatum>()
12+
const { getOptions, focusedDatumState, isInteractingState } =
13+
useChartContext<TDatum>()
1314

1415
const [, setFocusedDatum] = focusedDatumState
16+
const [isInteracting] = isInteractingState
1517

1618
const {
1719
onFocusDatum,
@@ -32,12 +34,13 @@ export default function Voronoi<TDatum>() {
3234
)
3335

3436
const needsVoronoi =
35-
onFocusDatum ||
36-
onClickDatum ||
37-
tooltip ||
38-
primaryCursor ||
39-
secondaryCursor ||
40-
showVoronoi
37+
isInteracting &&
38+
(showVoronoi ||
39+
onFocusDatum ||
40+
onClickDatum ||
41+
tooltip ||
42+
primaryCursor ||
43+
secondaryCursor)
4144

4245
if (!needsVoronoi) {
4346
return null

src/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ export type ChartContextValue<TDatum> = {
109109
Datum<TDatum> | null,
110110
React.Dispatch<React.SetStateAction<Datum<TDatum> | null>>
111111
]
112+
isInteractingState: [boolean, React.Dispatch<React.SetStateAction<boolean>>]
112113
}
113114

114115
export type TooltipOptions<TDatum> = {

src/utils/buildAxis.linear.ts

+19-11
Original file line numberDiff line numberDiff line change
@@ -493,17 +493,21 @@ function stackSeries<TDatum>(
493493
})
494494
)
495495

496-
stacked.forEach((s, sIndex) => {
497-
s.forEach((datum, i) => {
496+
for (let sIndex = 0; sIndex < stacked.length; sIndex++) {
497+
const s = stacked[sIndex]
498+
499+
for (let i = 0; i < s.length; i++) {
500+
const datum = s[i]
501+
498502
if (axisSeries[sIndex].datums[i]) {
499503
// @ts-ignore
500504
datum.data = axisSeries[sIndex].datums[i]
501505

502506
axisSeries[sIndex].datums[i].stackData =
503507
datum as unknown as StackDatum<TDatum>
504508
}
505-
})
506-
})
509+
}
510+
}
507511
}
508512

509513
function buildPrimaryBandScale<TDatum>(
@@ -516,25 +520,29 @@ function buildPrimaryBandScale<TDatum>(
516520

517521
let impliedBandWidth: number = Math.max(...range)
518522

519-
series.forEach(serie => {
520-
serie.datums.forEach(d1 => {
523+
for (let i = 0; i < series.length; i++) {
524+
const serie = series[i]
525+
526+
for (let j = 0; j < serie.datums.length; j++) {
527+
const d1 = serie.datums[j]
521528
const one = scale(d1.primaryValue ?? NaN)
522529

523-
serie.datums.forEach(d2 => {
530+
for (let k = 0; k < serie.datums.length; k++) {
531+
const d2 = serie.datums[k]
524532
const two = scale(d2.primaryValue ?? NaN)
525533

526534
if (one === two) {
527-
return
535+
continue
528536
}
529537

530538
const diff = Math.abs(Math.max(one, two) - Math.min(one, two))
531539

532540
if (diff < impliedBandWidth) {
533541
impliedBandWidth = diff
534542
}
535-
})
536-
})
537-
})
543+
}
544+
}
545+
}
538546

539547
const bandRange = Math.max(...range)
540548

0 commit comments

Comments
 (0)