Skip to content

Commit c26aaac

Browse files
committed
fix: immediate cursor animation
1 parent 627a9de commit c26aaac

File tree

5 files changed

+1893
-1876
lines changed

5 files changed

+1893
-1876
lines changed

examples/simple/src/ResizableBox.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,18 @@ export default function ResizableBox({
99
height = 300,
1010
resizable = true,
1111
style = {},
12-
className = ''
12+
className = "",
1313
}) {
1414
return (
1515
<div>
1616
{resizable ? (
1717
<ReactResizableBox width={width} height={height}>
1818
<div
1919
style={{
20+
boxShadow: "0 20px 40px rgba(0,0,0,.1)",
2021
...style,
2122
width: "100%",
22-
height: "100%"
23+
height: "100%",
2324
}}
2425
className={className}
2526
>
@@ -31,7 +32,8 @@ export default function ResizableBox({
3132
style={{
3233
width: `${width}px`,
3334
height: `${height}px`,
34-
...style
35+
boxShadow: "0 20px 40px rgba(0,0,0,.1)",
36+
...style,
3537
}}
3638
className={className}
3739
>

src/components/Cursors.tsx

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,18 @@ function Cursor<TDatum>(props: {
114114

115115
const value = props.options.value ?? datumValue
116116

117-
const latestValue = useLatestWhen(
118-
props.options.value ?? resolveValue(latestFocusedDatum),
119-
typeof props.options.value !== 'undefined'
117+
const latestPropsValue = useLatestWhen(
118+
props.options.value,
119+
props.options.value != null
120120
)
121121

122+
const latestDatumValue = useLatestWhen(
123+
resolveValue(latestFocusedDatum),
124+
resolveValue(latestFocusedDatum) != null
125+
)
126+
127+
const latestValue = latestPropsValue ?? latestDatumValue
128+
122129
// Get the sibling range
123130
const siblingRange = siblingAxis.scale.range()
124131

@@ -133,10 +140,10 @@ function Cursor<TDatum>(props: {
133140

134141
const bandWidth = axis.axisFamily === 'band' ? axis.scale.bandwidth() : 1
135142

136-
const px = axis.scale(latestValue)
137-
138143
const show = typeof value !== 'undefined' && !Number.isNaN(value)
139144

145+
let px = axis.scale(value)
146+
140147
// Vertical alignment
141148
if (axis.isVertical) {
142149
y = px
@@ -162,12 +169,12 @@ function Cursor<TDatum>(props: {
162169
}
163170
}
164171

165-
const lineStartX = Math.min(x1, x2)
166-
const lineStartY = Math.min(y1, y2)
167-
const lineEndX = Math.max(x1, x2)
168-
const lineEndY = Math.max(y1, y2)
169-
const lineHeight = Math.max(lineEndY - lineStartY, 0)
170-
const lineWidth = Math.max(lineEndX - lineStartX, 0)
172+
let lineStartX = Math.min(x1, x2)
173+
let lineStartY = Math.min(y1, y2)
174+
let lineEndX = Math.max(x1, x2)
175+
let lineEndY = Math.max(y1, y2)
176+
let lineHeight = Math.max(lineEndY - lineStartY, 0)
177+
let lineWidth = Math.max(lineEndX - lineStartX, 0)
171178

172179
let bubbleX
173180
let bubbleY
@@ -212,12 +219,22 @@ function Cursor<TDatum>(props: {
212219

213220
const svgRect = useRect(svgRef.current, show)
214221

215-
const immediatePos = !axis.isVertical ? lineStartX : lineStartY
216-
const immediate = usePrevious(immediatePos) === -1 && immediatePos > -1
217-
218222
const lineRef = React.useRef<HTMLDivElement | null>(null)
219223
const bubbleRef = React.useRef<HTMLDivElement | null>(null)
220224

225+
const latestLineStartX = useLatestWhen(lineStartX, px != null)
226+
const latestLineStartY = useLatestWhen(lineStartY, px != null)
227+
const latestBubbleX = useLatestWhen(bubbleX, px != null)
228+
const latestBubbleY = useLatestWhen(bubbleY, px != null)
229+
230+
const previousTruePx = usePrevious(px)
231+
const immediate = previousTruePx == null && px !== null
232+
233+
lineStartX = (px != null ? lineStartX : latestLineStartX) ?? NaN
234+
lineStartY = (px != null ? lineStartY : latestLineStartY) ?? NaN
235+
bubbleX = (px != null ? bubbleX : latestBubbleX) ?? NaN
236+
bubbleY = (px != null ? bubbleY : latestBubbleY) ?? NaN
237+
221238
const lineXSpring = useSpring(
222239
lineStartX,
223240
[1, 210, 20],

src/hooks/useSpring.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,27 @@ export function useSpring(
66
value: number,
77
config: [number, number, number],
88
cb: (x: number) => void,
9-
immediate?: boolean
9+
immediate?: boolean,
10+
debug?: boolean
1011
) {
1112
const springRef = React.useRef(new Spring(value, ...config))
12-
const getImmediate = useGetLatest(immediate)
13+
const getValue = useGetLatest(value)
1314

1415
const [startRaf, stopRaf] = useRaf(() => {
1516
cb(springRef.current.x())
1617
return springRef.current.done()
1718
})
1819

20+
// Immediate
1921
React.useEffect(() => {
20-
if (springRef.current.endPosition !== value) {
21-
springRef.current.setEnd(value, getImmediate())
22+
if (immediate) {
23+
springRef.current.snap(getValue())
2224
startRaf()
25+
return
2326
}
24-
}, [getImmediate, startRaf, value])
27+
springRef.current.setEnd(value)
28+
startRaf()
29+
}, [debug, getValue, immediate, startRaf, stopRaf, value])
2530

2631
React.useEffect(() => {
2732
return () => {

src/utils/spring.ts

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,7 @@ export class Spring {
5858
return this._solution ? this._solution.dx(dt) : 0
5959
}
6060

61-
setEnd(x: number, immediate?: boolean) {
62-
if (immediate) {
63-
this._solution = null
64-
this.endPosition = x
65-
this._startTime = 0
66-
return
67-
}
68-
61+
setEnd(x: number) {
6962
const t = new Date().getTime()
7063

7164
let velocity = 0
@@ -87,18 +80,18 @@ export class Spring {
8780
this._startTime = t
8881
}
8982

90-
// snap(x: number) {
91-
// this._startTime = new Date().getTime()
92-
// this.endPosition = x
93-
// this._solution = {
94-
// x() {
95-
// return 0
96-
// },
97-
// dx() {
98-
// return 0
99-
// },
100-
// }
101-
// }
83+
snap(x: number) {
84+
this._startTime = new Date().getTime()
85+
this.endPosition = x
86+
this._solution = {
87+
x() {
88+
return 0
89+
},
90+
dx() {
91+
return 0
92+
},
93+
}
94+
}
10295

10396
done() {
10497
return almostEqual(this.x(), this.endPosition) && almostZero(this.dx())

0 commit comments

Comments
 (0)