Skip to content

Update Card Placement Keep In View Logic#388

Draft
PauloMFJ wants to merge 2 commits into
datacommonsorg:mainfrom
madebypxlp:paulo/card-placement
Draft

Update Card Placement Keep In View Logic#388
PauloMFJ wants to merge 2 commits into
datacommonsorg:mainfrom
madebypxlp:paulo/card-placement

Conversation

@PauloMFJ

@PauloMFJ PauloMFJ commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Overview

Update placement logic to follow 3 steps:

  1. If it already fits fully in the viewport, leave the camera be.
  2. If we can zoom out to frame every card at once, do that so the new card shows up in the context of the whole set.
  3. We couldn't fit everything without hitting the min-zoom cap, so just pan to the new card so it lands on-screen

@PauloMFJ PauloMFJ self-assigned this Jul 1, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +196 to +208
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;
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In canFitWithinZoomCap, there are two potential issues that could lead to unexpected behavior or NaN values:

  1. Potential NaN from editor.options.zoomToFitPadding: If zoomToFitPadding is undefined or not set, Math.min(editor.options.zoomToFitPadding, ...) will return NaN. This propagates through the calculations, causing fitZoom to be NaN and the function to always return false (preventing step 2 from ever running).
  2. Division by Zero: If bounds.w or bounds.h is 0 (e.g., if there are no shapes or the bounding box is empty), dividing by them will result in Infinity or NaN. 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;
};

@PauloMFJ PauloMFJ marked this pull request as draft July 1, 2026 16:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant