Update Card Placement Keep In View Logic#388
Conversation
There was a problem hiding this comment.
Code Review
This pull request updates the camera behavior when revealing a freshly placed card in the atlas scope. It introduces a canFitWithinZoomCap helper to determine if the entire page bounds can fit within the viewport without hitting the minimum zoom cap. If so, the camera zooms to fit; otherwise, it centers on the new card. The reviewer identified potential robustness issues in canFitWithinZoomCap related to NaN propagation from undefined padding and division by zero when bounds dimensions are non-positive, providing a code suggestion to address these edge cases.
| const canFitWithinZoomCap = (editor: Editor, bounds: Box): boolean => { | ||
| const screen = editor.getViewportScreenBounds(); | ||
| const inset = Math.min(editor.options.zoomToFitPadding, screen.width * 0.28); | ||
| const fitZoom = Math.min( | ||
| (screen.width - inset) / bounds.w, | ||
| (screen.height - inset) / bounds.h, | ||
| ); | ||
|
|
||
| const minZoomStep = editor.getCameraOptions().zoomSteps[0] ?? MIN_ZOOM; | ||
| const minZoom = minZoomStep * editor.getBaseZoom(); | ||
|
|
||
| return fitZoom >= minZoom; | ||
| }; |
There was a problem hiding this comment.
In canFitWithinZoomCap, there are two potential issues that could lead to unexpected behavior or NaN values:
- Potential
NaNfromeditor.options.zoomToFitPadding: IfzoomToFitPaddingis undefined or not set,Math.min(editor.options.zoomToFitPadding, ...)will returnNaN. This propagates through the calculations, causingfitZoomto beNaNand the function to always returnfalse(preventing step 2 from ever running). - Division by Zero: If
bounds.worbounds.his0(e.g., if there are no shapes or the bounding box is empty), dividing by them will result inInfinityorNaN. We should guard against non-positive dimensions early.
Adding a fallback for zoomToFitPadding (defaulting to 128 as per tldraw's defaults) and a guard clause for non-positive bounds dimensions will make this logic much more robust.
const canFitWithinZoomCap = (editor: Editor, bounds: Box): boolean => {
if (bounds.w <= 0 || bounds.h <= 0) return false;
const screen = editor.getViewportScreenBounds();
const zoomToFitPadding = editor.options.zoomToFitPadding ?? 128;
const inset = Math.min(zoomToFitPadding, screen.width * 0.28);
const fitZoom = Math.min(
(screen.width - inset) / bounds.w,
(screen.height - inset) / bounds.h,
);
const minZoomStep = editor.getCameraOptions().zoomSteps[0] ?? MIN_ZOOM;
const minZoom = minZoomStep * editor.getBaseZoom();
return fitZoom >= minZoom;
};
Overview
Update placement logic to follow 3 steps: