@@ -15,6 +15,12 @@ interface UsePlotWindowProps {
1515 defaultDownsamplingThreshold ?: number ;
1616}
1717
18+ interface PlaybackState {
19+ start : number ;
20+ windowSize : number ;
21+ isPlaying : boolean ;
22+ }
23+
1824export function usePlotWindow ( {
1925 data,
2026 defaultWindowSize = DEFAULT_WINDOW_SIZE ,
@@ -23,47 +29,53 @@ export function usePlotWindow({
2329 defaultDownsamplingThreshold = DEFAULT_DOWNSAMPLING_THRESHOLD ,
2430} : UsePlotWindowProps ) {
2531 const dataLength = data . length ;
26- const [ start , setStart ] = useState ( 0 ) ;
27- const [ windowSize , setWindowSize ] = useState ( defaultWindowSize ) ;
28- const [ interval , setInterval ] = useState ( defaultInterval ) ;
29- const [ increment , setIncrement ] = useState ( defaultIncrement ) ;
30- const [ downsamplingThreshold , setDownsamplingThreshold ] = useState (
32+ const [ playbackState , setPlaybackState ] = useState < PlaybackState > ( {
33+ start : 0 ,
34+ windowSize : defaultWindowSize ,
35+ isPlaying : false ,
36+ } ) ;
37+ const [ interval , setIntervalState ] = useState ( defaultInterval ) ;
38+ const [ increment , setIncrementState ] = useState ( defaultIncrement ) ;
39+ const [ downsamplingThreshold , setDownsamplingThresholdState ] = useState (
3140 defaultDownsamplingThreshold ,
3241 ) ;
33- const [ isPlaying , setIsPlaying ] = useState ( false ) ;
3442
3543 const animationRef = useRef < number | null > ( null ) ;
3644 const lastUpdateTimeRef = useRef < number > ( 0 ) ;
37- const maxStart = Math . max ( dataLength - windowSize , 0 ) ;
45+ const maxStart = Math . max ( dataLength - playbackState . windowSize , 0 ) ;
3846
3947 const togglePlay = useCallback ( ( ) => {
40- setIsPlaying ( ( prev ) => ! prev ) ;
48+ setPlaybackState ( ( prev ) => ( {
49+ ...prev ,
50+ isPlaying : ! prev . isPlaying ,
51+ } ) ) ;
4152 } , [ ] ) ;
4253
4354 const animateFrame = useCallback (
4455 ( timestamp : number ) => {
4556 if ( timestamp - lastUpdateTimeRef . current >= interval ) {
46- setStart ( ( prev ) => {
47- const newStart = prev + increment ;
48- if ( newStart >= maxStart ) {
49- setIsPlaying ( false ) ;
50- return maxStart ;
51- }
52- return newStart ;
57+ setPlaybackState ( ( prev ) => {
58+ const nextStart = Math . min ( prev . start + increment , maxStart ) ;
59+
60+ return {
61+ ...prev ,
62+ start : nextStart ,
63+ isPlaying : nextStart < maxStart ,
64+ } ;
5365 } ) ;
5466
5567 lastUpdateTimeRef . current = timestamp ;
5668 }
5769
58- if ( isPlaying ) {
70+ if ( playbackState . isPlaying ) {
5971 animationRef . current = requestAnimationFrame ( animateFrame ) ;
6072 }
6173 } ,
62- [ interval , increment , isPlaying , maxStart ] ,
74+ [ increment , interval , maxStart , playbackState . isPlaying ] ,
6375 ) ;
6476
6577 useEffect ( ( ) => {
66- if ( isPlaying ) {
78+ if ( playbackState . isPlaying ) {
6779 lastUpdateTimeRef . current = performance . now ( ) ;
6880 animationRef . current = requestAnimationFrame ( animateFrame ) ;
6981 } else if ( animationRef . current ) {
@@ -77,60 +89,75 @@ export function usePlotWindow({
7789 animationRef . current = null ;
7890 }
7991 } ;
80- } , [ isPlaying , animateFrame ] ) ;
92+ } , [ playbackState . isPlaying , animateFrame ] ) ;
8193
8294 useEffect ( ( ) => {
83- setIsPlaying ( false ) ;
84- setStart ( 0 ) ;
85-
86- if ( dataLength > 0 ) {
87- setWindowSize ( Math . min ( defaultWindowSize , dataLength ) ) ;
88- } else {
89- setWindowSize ( defaultWindowSize ) ;
90- }
95+ setPlaybackState ( ( prev ) => ( {
96+ ...prev ,
97+ isPlaying : false ,
98+ start : 0 ,
99+ windowSize :
100+ dataLength > 0
101+ ? Math . min ( defaultWindowSize , dataLength )
102+ : defaultWindowSize ,
103+ } ) ) ;
91104 } , [ dataLength , defaultWindowSize ] ) ;
92105
93106 const handleStartChange = useCallback (
94107 ( value : number ) => {
95- if ( dataLength === 0 ) {
96- setStart ( 0 ) ;
97- return ;
98- }
99-
100- setStart ( Math . max ( 0 , Math . min ( value , maxStart ) ) ) ;
108+ setPlaybackState ( ( prev ) => ( {
109+ ...prev ,
110+ start : dataLength === 0 ? 0 : Math . max ( 0 , Math . min ( value , maxStart ) ) ,
111+ } ) ) ;
101112 } ,
102113 [ dataLength , maxStart ] ,
103114 ) ;
104115
105116 const handleWindowSizeChange = useCallback (
106117 ( value : number ) => {
107118 if ( dataLength === 0 ) {
108- setWindowSize ( defaultWindowSize ) ;
109- setStart ( 0 ) ;
119+ setPlaybackState ( ( prev ) => ( {
120+ ...prev ,
121+ start : 0 ,
122+ windowSize : defaultWindowSize ,
123+ } ) ) ;
110124 return ;
111125 }
112126
113127 const nextWindowSize = Math . max ( 1 , Math . min ( value , dataLength ) ) ;
114- setWindowSize ( nextWindowSize ) ;
115- setStart ( ( currentStart ) =>
116- Math . min ( currentStart , Math . max ( dataLength - nextWindowSize , 0 ) ) ,
117- ) ;
128+ setPlaybackState ( ( prev ) => ( {
129+ ...prev ,
130+ windowSize : nextWindowSize ,
131+ start : Math . min ( prev . start , Math . max ( dataLength - nextWindowSize , 0 ) ) ,
132+ } ) ) ;
118133 } ,
119134 [ dataLength , defaultWindowSize ] ,
120135 ) ;
121136
137+ const handleIntervalChange = useCallback ( ( value : number ) => {
138+ setIntervalState ( value ) ;
139+ } , [ ] ) ;
140+
141+ const handleIncrementChange = useCallback ( ( value : number ) => {
142+ setIncrementState ( value ) ;
143+ } , [ ] ) ;
144+
145+ const handleDownsamplingThresholdChange = useCallback ( ( value : number ) => {
146+ setDownsamplingThresholdState ( value ) ;
147+ } , [ ] ) ;
148+
122149 return {
123- start,
150+ start : playbackState . start ,
124151 setStart : handleStartChange ,
125- windowSize,
152+ windowSize : playbackState . windowSize ,
126153 setWindowSize : handleWindowSizeChange ,
127154 interval,
128- setInterval,
155+ setInterval : handleIntervalChange ,
129156 increment,
130- setIncrement,
157+ setIncrement : handleIncrementChange ,
131158 downsamplingThreshold,
132- setDownsamplingThreshold,
133- isPlaying,
159+ setDownsamplingThreshold : handleDownsamplingThresholdChange ,
160+ isPlaying : playbackState . isPlaying ,
134161 togglePlay,
135162 } ;
136163}
0 commit comments