@@ -35,6 +35,9 @@ export interface TrackDrawing {
3535// currently its a bit messy with the turns, so we disable them for now
3636const ENABLE_TURNS = false ;
3737
38+ // Throttle position updates to 2fps (500ms interval)
39+ const POSITION_UPDATE_INTERVAL = 500 ;
40+
3841export const TrackCanvas = ( { trackId, drivers } : TrackProps ) => {
3942 const [ positions , setPositions ] = useState <
4043 Record < number , TrackDriver & { position : { x : number ; y : number } } >
@@ -46,6 +49,8 @@ export const TrackCanvas = ({ trackId, drivers }: TrackProps) => {
4649 const lastPositionsRef = useRef <
4750 Record < number , TrackDriver & { position : { x : number ; y : number } } >
4851 > ( { } ) ;
52+ const lastUpdateTimeRef = useRef < number > ( 0 ) ;
53+ const pendingDriversRef = useRef < TrackDriver [ ] > ( [ ] ) ;
4954
5055 // Memoize the SVG path element
5156 const line = useMemo ( ( ) => {
@@ -137,25 +142,62 @@ export const TrackCanvas = ({ trackId, drivers }: TrackProps) => {
137142 } ) ;
138143 } , [ drivers ] ) ;
139144
145+ // Throttled position update effect
140146 useEffect ( ( ) => {
141- if ( ! trackConstants || ! drivers ?. length || ! driversChanged ) return ;
142-
143- const updatedPositions = drivers . reduce (
144- ( acc , { driver, progress, isPlayer } ) => {
145- const position = updateCarPosition ( progress ) ;
146- return {
147- ...acc ,
148- [ driver . CarIdx ] : { position, driver, isPlayer, progress } ,
149- } ;
150- } ,
151- { } as Record < number , TrackDriver & { position : { x : number ; y : number } } >
152- ) ;
147+ if ( ! trackConstants || ! drivers ?. length ) return ;
148+
149+ // Store the latest drivers data
150+ pendingDriversRef . current = drivers ;
151+
152+ const now = Date . now ( ) ;
153+ const timeSinceLastUpdate = now - lastUpdateTimeRef . current ;
154+
155+ // Only update positions if enough time has passed or if drivers have changed significantly
156+ if ( timeSinceLastUpdate >= POSITION_UPDATE_INTERVAL || driversChanged ) {
157+ const updatedPositions = drivers . reduce (
158+ ( acc , { driver, progress, isPlayer } ) => {
159+ const position = updateCarPosition ( progress ) ;
160+ return {
161+ ...acc ,
162+ [ driver . CarIdx ] : { position, driver, isPlayer, progress } ,
163+ } ;
164+ } ,
165+ { } as Record < number , TrackDriver & { position : { x : number ; y : number } } >
166+ ) ;
153167
154- setPositions ( updatedPositions ) ;
155- lastDriversRef . current = drivers ;
156- lastPositionsRef . current = updatedPositions ;
168+ setPositions ( updatedPositions ) ;
169+ lastDriversRef . current = drivers ;
170+ lastPositionsRef . current = updatedPositions ;
171+ lastUpdateTimeRef . current = now ;
172+ }
157173 } , [ drivers , trackConstants , updateCarPosition , driversChanged ] ) ;
158174
175+ // Set up a timer for periodic position updates
176+ useEffect ( ( ) => {
177+ if ( ! trackConstants ) return ;
178+
179+ const intervalId = setInterval ( ( ) => {
180+ const pendingDrivers = pendingDriversRef . current ;
181+ if ( ! pendingDrivers ?. length ) return ;
182+
183+ const updatedPositions = pendingDrivers . reduce (
184+ ( acc , { driver, progress, isPlayer } ) => {
185+ const position = updateCarPosition ( progress ) ;
186+ return {
187+ ...acc ,
188+ [ driver . CarIdx ] : { position, driver, isPlayer, progress } ,
189+ } ;
190+ } ,
191+ { } as Record < number , TrackDriver & { position : { x : number ; y : number } } >
192+ ) ;
193+
194+ setPositions ( updatedPositions ) ;
195+ lastPositionsRef . current = updatedPositions ;
196+ } , POSITION_UPDATE_INTERVAL ) ;
197+
198+ return ( ) => clearInterval ( intervalId ) ;
199+ } , [ trackConstants , updateCarPosition ] ) ;
200+
159201 useEffect ( ( ) => {
160202 const ctx = canvasRef . current ?. getContext ( '2d' ) ;
161203 if ( ! ctx ) return ;
@@ -269,10 +311,35 @@ export const TrackCanvas = ({ trackId, drivers }: TrackProps) => {
269311 ctx . restore ( ) ;
270312 } ;
271313
314+ // Check if positions have actually changed
315+ const positionsChanged = ( ) => {
316+ const currentPositions = Object . keys ( positions ) ;
317+ const lastPositions = Object . keys ( lastPositionsRef . current ) ;
318+
319+ if ( currentPositions . length !== lastPositions . length ) return true ;
320+
321+ return currentPositions . some ( key => {
322+ const carIdx = parseInt ( key ) ;
323+ const current = positions [ carIdx ] ;
324+ const last = lastPositionsRef . current [ carIdx ] ;
325+
326+ if ( ! current || ! last ) return true ;
327+
328+ return (
329+ Math . abs ( current . position . x - last . position . x ) > 0.1 ||
330+ Math . abs ( current . position . y - last . position . y ) > 0.1 ||
331+ current . isPlayer !== last . isPlayer ||
332+ current . driver . CarNumber !== last . driver . CarNumber
333+ ) ;
334+ } ) ;
335+ } ;
336+
272337 // Only animate if positions have changed
273338 const animate = ( ) => {
274- draw ( ) ;
275- lastPositionsRef . current = { ...positions } ;
339+ if ( positionsChanged ( ) ) {
340+ draw ( ) ;
341+ lastPositionsRef . current = { ...positions } ;
342+ }
276343 animationFrameIdRef . current = requestAnimationFrame ( animate ) ;
277344 } ;
278345
0 commit comments