Zoom the tile tab in the same steps as the scene view
game-maker / gate (push) Successful in 2m58s
game-maker / suite (push) Failing after 8m34s

The tile tab zoomed freely, so the pixels of a tile could end up
unevenly wide at odd factors. Scene view, container tab and animation
preview already snap to FREE_ZOOM_STEPS. The tile tab now does the
same, so every pixel editor zooms alike.

- The wheel steps through FREE_ZOOM_STEPS, counted in device pixels.
  The board position is rounded to whole device pixels.
- New wheelSteps() in src/viewport/view.ts turns wheel events into
  steps: one notch is one step, a trackpad gathers 50 px per step.
  FreeViewport uses it too, so the rule exists only once.
- Fit takes the largest step at which the whole board fits. Refitting
  on a new tab or board size stays as before.
- panAndZoom takes an optional zoom rule instead of limits. Graph and
  node board keep zooming freely.
- A saved view from before the steps snaps to the nearest step.
- The cap parameter of frameBoxes from 4027afc has no user anymore.
  It is removed together with its unit test.

Fit rounds down, and below 100 percent the steps are far apart. In the
small e2e window the 48 px board lands at 25 instead of 41 percent,
the 16 px board at 100 instead of 124 percent.

Tests:
- check.sh: 161 files, 2370 tests, exit 0 (-1 cap test,
  +1 wheelSteps test)
- e2e 1-5 and 39: all passed, 169 checks. Three checks in 39 now
  expect steps: Fit on a step with the next one too large, one notch
  goes 0.25 to 0.5, 16 px tiles refit to at least 100 percent.
- Counter check: a free Fit factor fails exactly those three checks
  (zoom 0.413 and 1.2396).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5.5 committed 2026-09-25 10:30:41 +02:00
1 parent 4027afc228
commit 021a6dcb56
8 files changed
+110 -47

No files matched your search

+14 -2
View File
@@ -41,6 +41,13 @@ export function zoomedAbout(
return { pan: { x: at.x - graphX * zoom, y: at.y - graphY * zoom }, zoom };
}
/**
* How the wheel zooms: smoothly within limits, or by a rule of the surface's own – the Tile tab
* takes the scene view's steps. A rule returns null while the wheel has not made a step yet.
*/
export type WheelZoom =
{ min: number; max: number } | ((view: GraphView, at: Point, deltaY: number) => GraphView | null);
/**
* Drag with any button to pan, wheel to zoom about the pointer – all a board does with the pointer
* when its content takes none. `set` receives each new view and which gesture made it.
@@ -49,7 +56,7 @@ export function panAndZoom(
surface: Container,
get: () => GraphView,
set: (view: GraphView, gesture: 'pan' | 'zoom') => void,
limits: { min: number; max: number } = ZOOM_LIMITS,
zoom: WheelZoom = ZOOM_LIMITS,
): void {
let panning: { start: Point; pan: Point } | null = null;
surface.on('pointerdown', (e: FederatedPointerEvent) => {
@@ -63,8 +70,13 @@ export function panAndZoom(
surface.on('pointerup', () => (panning = null));
surface.on('pointerupoutside', () => (panning = null));
surface.on('wheel', (e: FederatedWheelEvent) => {
set(zoomedAbout(get(), surface.toLocal(e.global), zoomFactor(e.deltaY), limits), 'zoom');
e.preventDefault();
const at = surface.toLocal(e.global);
const view =
typeof zoom === 'function'
? zoom(get(), at, e.deltaY)
: zoomedAbout(get(), at, zoomFactor(e.deltaY), zoom);
if (view) set(view, 'zoom');
});
}