Observed on 9.7.0, in a multi-page takeoff document with saved measurements.
Repro:
- Open a takeoff document that has measurements on page N (N > 1).
- Navigate to page N (thumbnail click or page arrows). The PDF renders, but no measurements appear.
- In the sidebar, toggle the measurement group's visibility off and back on. The measurements appear.
Root cause: the page render's async continuation wipes the overlay after the overlay-draw effect has already painted. Two effects in frontend/src/modules/pdf-takeoff/TakeoffViewerModule.tsx both depend on currentPage:
- The page-render effect (
:957-996) is an async IIFE whose first statement is await pdfDoc.getPage(currentPage) (:963), so on a page change it suspends immediately.
- The overlay-draw effect (
:1055, deps at :1653) runs later in the same synchronous effect flush (of the two effects between them, one suspends at its own first await and the other is synchronous scroll handling that never touches the overlay) and draws the new page's measurements. At this moment the overlay is correct.
- The render continuation then resumes: it sets
overlayRef.current.width/height (:976-977) and calls clearRect (:980). Assigning a canvas's width/height resets its bitmap, so this erases the just-drawn measurements. The effect ends without redrawing the overlay.
The visibility toggle "fixes" it because hiddenGroups is in the draw effect's deps (:1653) but not the render effect's (:996): the toggle re-runs only the draw effect, and nothing wipes afterward.
The bug is not page-specific. Page 1 looks correct on initial load only because of timing: measurements load per document (frontend/src/modules/pdf-takeoff/useMeasurementPersistence.ts:662) and arrive after the first render completes, and their arrival re-runs the draw effect (via the measurements dep) after the wipe. Navigate away from page 1 and back, and page 1 loses its measurements like any other page. The repro says N > 1 only so that the first observation is a navigation rather than the initial load. The same wipe happens on zoom changes (zoom is in both dep arrays); a repaint then only occurs incidentally while a drawing tool is active, because mouse movement updates liveCursor (a draw-effect dep) only for the drawing tools (:2449-2462). In the select tool, zooming should reproduce the same disappearance.
Suggested fix: the invariant is that the overlay resize + clear must never run after the measurement draw without a follow-up draw. One small way to get there is a render-completion signal:
// at the end of the render IIFE (after await task.promise), non-cancelled path:
setRenderNonce((n) => n + 1);
// and add renderNonce to the overlay-draw effect's dep array (:1653)
Redrawing the overlay directly at the end of the render continuation would work equally well. (Resizing the overlay before the await is not an option as-is: the viewport dimensions come from the resolved page object.)
Observed on 9.7.0, in a multi-page takeoff document with saved measurements.
Repro:
Root cause: the page render's async continuation wipes the overlay after the overlay-draw effect has already painted. Two effects in
frontend/src/modules/pdf-takeoff/TakeoffViewerModule.tsxboth depend oncurrentPage::957-996) is an async IIFE whose first statement isawait pdfDoc.getPage(currentPage)(:963), so on a page change it suspends immediately.:1055, deps at:1653) runs later in the same synchronous effect flush (of the two effects between them, one suspends at its own firstawaitand the other is synchronous scroll handling that never touches the overlay) and draws the new page's measurements. At this moment the overlay is correct.overlayRef.current.width/height(:976-977) and callsclearRect(:980). Assigning a canvas'swidth/heightresets its bitmap, so this erases the just-drawn measurements. The effect ends without redrawing the overlay.The visibility toggle "fixes" it because
hiddenGroupsis in the draw effect's deps (:1653) but not the render effect's (:996): the toggle re-runs only the draw effect, and nothing wipes afterward.The bug is not page-specific. Page 1 looks correct on initial load only because of timing: measurements load per document (
frontend/src/modules/pdf-takeoff/useMeasurementPersistence.ts:662) and arrive after the first render completes, and their arrival re-runs the draw effect (via themeasurementsdep) after the wipe. Navigate away from page 1 and back, and page 1 loses its measurements like any other page. The repro says N > 1 only so that the first observation is a navigation rather than the initial load. The same wipe happens on zoom changes (zoomis in both dep arrays); a repaint then only occurs incidentally while a drawing tool is active, because mouse movement updatesliveCursor(a draw-effect dep) only for the drawing tools (:2449-2462). In the select tool, zooming should reproduce the same disappearance.Suggested fix: the invariant is that the overlay resize + clear must never run after the measurement draw without a follow-up draw. One small way to get there is a render-completion signal:
Redrawing the overlay directly at the end of the render continuation would work equally well. (Resizing the overlay before the
awaitis not an option as-is: the viewport dimensions come from the resolved page object.)