Skip to content

[BUG] PDF takeoff: per-measurement stroke width (#312) renders in screen space, not document space #321

Description

@arvildev

This is a follow-up to #312 ("[FEATURE] PDF takeoff: optional visible stroke width for distance/polyline measurements"), which shipped in v10.0.0 and is now closed. Everything the request asked for landed and works on v10.0.1 (4959faf): the field, a properties-panel control, a reset, and both renderers.

One design point did not carry through. #312 asked for the width to live in "document space, scaling with zoom like the geometry does, not in screen pixels like today's hairline." The shipped implementation renders it in screen space instead: a constant CSS-pixel width at every zoom, so the band does not scale with the drawing.

Where it renders today:

  • frontend/src/modules/pdf-takeoff/TakeoffViewerModule.tsx:1340: ctx.lineWidth = (m.strokeWidth ?? 2) * dpr;
  • frontend/src/features/takeoff/lib/takeoff-export.ts:258: ctx.lineWidth = (m.strokeWidth ?? 2) * dpr;
  • the field comment records the same intent (TakeoffViewerModule.tsx:258): Per-measurement stroke width in CSS px.

In both draw loops the distance and polyline point coordinates are transformed by * dpr * zoom (for example p0.x * dpr * zoom at TakeoffViewerModule.tsx:1350), but lineWidth is multiplied by dpr only. So the shape scales with zoom while the stroke stays a fixed screen width: zooming into a footing polyline makes it longer on screen but no wider, so it never reads as a band that covers the footing's plan width. The highlighter effect the request describes needs the width to ride the same zoom factor as the geometry.

Suggested change at both stroke sites, keeping the unset default as today's screen-space hairline so nothing changes for measurements that never set a width:

ctx.lineWidth = m.strokeWidth != null ? m.strokeWidth * dpr * zoom : 2 * dpr;

With that, an explicit strokeWidth is interpreted in the page's own coordinate space (the same base-render pixels the point coordinates already use), so it scales with zoom; an unset width stays the 2px screen hairline. The export renderer takes the same expression, where zoom is the page render scale rather than the interactive viewport zoom, so the exported stroke scales with the rendered page raster the same way its coordinates do. If a real-world basis is preferred over base-render pixels, the width could instead be divided through the page scale so it maps to a plan dimension, but the minimal change that meets the stated design point is the * zoom above.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions