Skip to content

Commit 2d4aa2d

Browse files
committed
simplify(pdf-server): pinch snap was transform-origin mismatch, not bitmap
The snap on pinch release was the page jumping vertically: transform-origin: center center scales around the wrapper's middle, but the flex container is align-items: flex-start so on commit the canvas grows from the TOP. Preview top edge moved up; committed top edge stays put → jump down. transform-origin: 50% 0 matches the layout anchor, no jump. Drop the canvas-snapshot placeholder (over-engineered, wrong fix), the dead transition='' lines (.page-wrapper has no CSS transition), and the containerDimensions→refit hook (ResizeObserver covers actual size changes; the host message isn't load-bearing).
1 parent a19cda2 commit 2d4aa2d

1 file changed

Lines changed: 8 additions & 30 deletions

File tree

examples/pdf-server/src/mcp-app.ts

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3041,37 +3041,20 @@ async function renderPage() {
30413041
const dpr = window.devicePixelRatio || 1;
30423042
const ctx = canvasEl.getContext("2d")!;
30433043

3044-
// If we're committing a pinch (transform still on .page-wrapper),
3045-
// snapshot the current bitmap so we can paint a scaled placeholder
3046-
// while page.render() runs. Without this, setting canvasEl.width
3047-
// below clears the backing store → blank flash → user sees a "snap".
3048-
let snap: HTMLCanvasElement | null = null;
3049-
if (pageWrapperEl.style.transform && canvasEl.width > 0) {
3050-
snap = document.createElement("canvas");
3051-
snap.width = canvasEl.width;
3052-
snap.height = canvasEl.height;
3053-
snap.getContext("2d")!.drawImage(canvasEl, 0, 0);
3054-
}
3055-
3056-
// Set canvas size in pixels (scaled for retina) — clears the bitmap
3044+
// Set canvas size in pixels (scaled for retina)
30573045
canvasEl.width = viewport.width * dpr;
30583046
canvasEl.height = viewport.height * dpr;
30593047

30603048
// Set display size in CSS pixels
30613049
canvasEl.style.width = `${viewport.width}px`;
30623050
canvasEl.style.height = `${viewport.height}px`;
3063-
// Drop the pinch preview transform in the same frame as the canvas
3051+
// Drop any pinch preview transform in the same frame as the canvas
30643052
// resize so the size handoff is atomic.
30653053
pageWrapperEl.style.transform = "";
30663054

30673055
// Scale context for retina
30683056
ctx.scale(dpr, dpr);
30693057

3070-
if (snap) {
3071-
// Stretched-but-correct-size placeholder until page.render replaces it.
3072-
ctx.drawImage(snap, 0, 0, viewport.width, viewport.height);
3073-
}
3074-
30753058
// Clear and setup text layer
30763059
textLayerEl.innerHTML = "";
30773060
textLayerEl.style.width = `${viewport.width}px`;
@@ -3782,11 +3765,10 @@ let pinchSettleTimer: ReturnType<typeof setTimeout> | null = null;
37823765
function beginPinch() {
37833766
pinchStartScale = scale;
37843767
previewScale = scale;
3785-
// Kill any transition so the transform snaps; transform-origin centers
3786-
// the zoom on the page (good enough — focal-point zoom is a lot more
3787-
// bookkeeping for an example viewer).
3788-
pageWrapperEl.style.transition = "none";
3789-
pageWrapperEl.style.transformOrigin = "center center";
3768+
// transform-origin matches the flex layout's anchor (justify-content:
3769+
// center, align-items: flex-start) so the preview and the committed
3770+
// canvas grow from the same point — otherwise the page jumps on release.
3771+
pageWrapperEl.style.transformOrigin = "50% 0";
37903772
}
37913773

37923774
function updatePinch(nextScale: number) {
@@ -3798,7 +3780,6 @@ function updatePinch(nextScale: number) {
37983780
}
37993781

38003782
function commitPinch() {
3801-
pageWrapperEl.style.transition = "";
38023783
if (Math.abs(previewScale - scale) < 0.01) {
38033784
// Dead-zone — no re-render. Clear here since renderPage won't run.
38043785
pageWrapperEl.style.transform = "";
@@ -3911,7 +3892,6 @@ canvasContainerEl.addEventListener("touchcancel", () => {
39113892
touchStartDist = 0;
39123893
// Cancelled (call, app-switch) → revert, don't commit a half-gesture.
39133894
pageWrapperEl.style.transform = "";
3914-
pageWrapperEl.style.transition = "";
39153895
zoomLevelEl.textContent = `${Math.round(scale * 100)}%`;
39163896
});
39173897

@@ -4741,12 +4721,10 @@ function handleHostContextChanged(ctx: McpUiHostContext) {
47414721
updateFullscreenButton();
47424722
}
47434723

4744-
// Recompute fit-to-width when container dimensions change (rotation,
4745-
// window resize, panel toggle). The displayMode block above already
4746-
// refits on inline→fullscreen so this is for everything else.
4724+
// ResizeObserver on canvasContainerEl drives refit on actual size change;
4725+
// ctx.containerDimensions is logged for debugging but isn't load-bearing.
47474726
if (ctx.containerDimensions) {
47484727
log.info("Container dimensions changed:", ctx.containerDimensions);
4749-
refitScale();
47504728
}
47514729
}
47524730

0 commit comments

Comments
 (0)