(
nextScale: number,
clientX: number,
clientY: number,
)
| 2374 | } |
| 2375 | |
| 2376 | function applyZoomAtClientPoint( |
| 2377 | nextScale: number, |
| 2378 | clientX: number, |
| 2379 | clientY: number, |
| 2380 | ) { |
| 2381 | const canvasRect = outerCanvasRef.current?.getBoundingClientRect(); |
| 2382 | if (!canvasRect) { |
| 2383 | applyZoom( |
| 2384 | nextScale, |
| 2385 | { |
| 2386 | x: panRef.current.x, |
| 2387 | y: panRef.current.y + autoViewportOffsetY, |
| 2388 | }, |
| 2389 | false, |
| 2390 | ); |
| 2391 | return; |
| 2392 | } |
| 2393 | |
| 2394 | const currentZoom = effectiveZoomRef.current; |
| 2395 | const currentPan = panRef.current; |
| 2396 | const clampedScale = clampZoom(nextScale, fitScale); |
| 2397 | const ratio = clampedScale / Math.max(currentZoom, 0.001); |
| 2398 | const cursor = { |
| 2399 | x: clientX - (canvasRect.left + canvasRect.width / 2), |
| 2400 | y: clientY - (canvasRect.top + canvasRect.height / 2), |
| 2401 | }; |
| 2402 | const currentVisualPan = { |
| 2403 | x: currentPan.x, |
| 2404 | y: currentPan.y + autoViewportOffsetY, |
| 2405 | }; |
| 2406 | const nextVisualPan = { |
| 2407 | x: cursor.x - (cursor.x - currentVisualPan.x) * ratio, |
| 2408 | y: cursor.y - (cursor.y - currentVisualPan.y) * ratio, |
| 2409 | }; |
| 2410 | applyZoom( |
| 2411 | clampedScale, |
| 2412 | { |
| 2413 | x: nextVisualPan.x, |
| 2414 | y: nextVisualPan.y, |
| 2415 | }, |
| 2416 | false, |
| 2417 | ); |
| 2418 | } |
| 2419 | |
| 2420 | useEffect(() => { |
| 2421 | applyZoomAtClientPointRef.current = applyZoomAtClientPoint; |
no test coverage detected