Skip to content

Commit 28181f8

Browse files
authored
Merge pull request #1461 from visualize-admin/feat/improve-resizing-behavior
feat: Improve resizing behavior
2 parents 2368b72 + d93eb39 commit 28181f8

File tree

4 files changed

+51
-19
lines changed

4 files changed

+51
-19
lines changed

Diff for: CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ You can also check the [release page](https://github.com/visualize-admin/visuali
1616
- Sidebar content no longer gets unmounted when data is being re-fetched (e.g. when interacting with time slider in temporal X axes)
1717
- Reduced content layout shift when changing chart type
1818
- Filters are now correctly applied when adding a new chart
19+
- Charts now resize immediately to remove a "laggy" feeling caused by calling transitions multiple times
1920
- Style
2021
- Introduced smaller UI improvements in the options panel
2122
- Performance

Diff for: app/charts/shared/containers.tsx

+9-4
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,15 @@ export const ChartContainer = ({ children }: { children: ReactNode }) => {
2222
}
2323

2424
const sel = select(ref.current);
25-
(enableTransition
26-
? sel.transition().duration(transitionDuration)
27-
: sel
28-
).style("height", `${height}px`);
25+
26+
if (enableTransition) {
27+
sel
28+
.transition()
29+
.duration(transitionDuration)
30+
.style("height", `${height}px`);
31+
} else {
32+
sel.style("height", `${height}px`);
33+
}
2934
}
3035
}, [height, enableTransition, transitionDuration]);
3136

Diff for: app/charts/shared/use-width.tsx

+25-15
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,56 @@
1-
import { createContext, ReactNode, useContext } from "react";
1+
import React, { createContext, ReactNode, useContext } from "react";
22

3+
import { useTransitionStore } from "@/stores/transition";
34
import { useResizeObserver } from "@/utils/use-resize-observer";
5+
import { useTimedPrevious } from "@/utils/use-timed-previous";
46

5-
export interface Margins {
7+
export type Margins = {
68
top: number;
79
right: number;
810
bottom: number;
911
left: number;
10-
}
11-
export type Width = number;
12-
export interface Bounds {
12+
};
13+
14+
export type Bounds = {
1315
width: number;
1416
height: number;
1517
margins: Margins;
1618
chartWidth: number;
1719
chartHeight: number;
18-
}
20+
};
1921

20-
const INITIAL_WIDTH: Width = 1;
22+
const INITIAL_WIDTH = 1;
2123

2224
export const Observer = ({ children }: { children: ReactNode }) => {
23-
const [resizeRef, width] = useResizeObserver<HTMLDivElement>();
25+
const [ref, width] = useResizeObserver<HTMLDivElement>();
26+
const prev = useTimedPrevious(width, 500);
27+
const isResizing = prev !== width;
28+
const setEnableTransition = useTransitionStore((state) => state.setEnable);
29+
30+
React.useEffect(
31+
() => setEnableTransition(!isResizing),
32+
[isResizing, setEnableTransition]
33+
);
2434

2535
return (
26-
<div ref={resizeRef}>
27-
{width > 1 ? (
28-
<ChartObserverContext.Provider value={width}>
29-
{children}
30-
</ChartObserverContext.Provider>
31-
) : null}
36+
<div ref={ref} style={{ display: "flex", minHeight: "100%" }}>
37+
<ChartObserverContext.Provider value={width}>
38+
{children}
39+
</ChartObserverContext.Provider>
3240
</div>
3341
);
3442
};
3543

36-
const ChartObserverContext = createContext<Width>(INITIAL_WIDTH);
44+
const ChartObserverContext = createContext(INITIAL_WIDTH);
3745

3846
export const useWidth = () => {
3947
const ctx = useContext(ChartObserverContext);
48+
4049
if (ctx === undefined) {
4150
throw Error(
4251
"You need to wrap your component in <ChartObserverContextProvider /> to useWidth()"
4352
);
4453
}
54+
4555
return ctx;
4656
};

Diff for: app/utils/use-timed-previous.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React from "react";
2+
3+
export const useTimedPrevious = <T>(value: T, duration: number): T => {
4+
const [previousValue, setPreviousValue] = React.useState<T>(value);
5+
React.useEffect(() => {
6+
const timeoutId = setTimeout(() => {
7+
setPreviousValue(value);
8+
}, duration);
9+
10+
return () => {
11+
clearTimeout(timeoutId);
12+
};
13+
}, [value, duration]);
14+
15+
return previousValue;
16+
};

0 commit comments

Comments
 (0)