feat(views): draw reference lines independently of the crosshairs tool - #921
Merged
Conversation
✅ Deploy Preview for volview-dev ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
PaulHax
force-pushed
the
reference-lines
branch
2 times, most recently
from
August 16, 2026 15:34
da5e53c to
6b4cbee
Compare
Cross-reference lines were drawn inside the crosshairs tool, so they only existed while that tool was active. Pull them out into a standalone feature that a setting can turn on persistently, and that the crosshairs tool borrows as its on-screen appearance while it is active. Visibility is derived (enabled || crosshairs active) rather than snapshot and restored, which gives the auto-on/restore behavior with no extra state and covers press-and-hold temporary crosshairs for free. The geometry is a general plane-plane intersection clipped to the image box in index space, not an axis-aligned special case, so oblique planes only need wiring into the peer enumeration later. The intersection direction is transformed by the linear part of worldToIndex: a direction is a vector, so it never wanted the translation, and recovering it by subtracting two transformed points collapsed to zero in float32 for nearly parallel planes. Peers come from the layout slots, so lines survive maximizing a view and no stale viewByID entry can produce a ghost line. Each line breaks around every point where another drawn line crosses it, leaving 16px of clear space. Doing that as a screen-space pass over the projected segments keeps the gap decoupled from the crosshairs position, so it appears the same way in always-on mode. The crosshairs tool keeps its slicing inside the image its view shows. The slice write used to hang off a watcher on the crosshair position in the active image's index space, so merely focusing another image's view slammed every view of the newly active image to wherever the crosshair had been left in the other one. The move now propagates from the interaction itself: the view widget reports which view the point was picked in, and the store resolves the image from that view, clamps the point in its index space and slices only the layout views showing it. That leaves the widget state with nothing image-specific to track, so the shared matrices and handle bounds go away with it. The feature lives in src/referenceLines, following src/processing: a single public surface plus a pure layer of geometry, crossings and peer enumeration, with the boundary enforced by eslint import zones. Behavior changes that come with the pull-out: - lines sit at the peers' rounded slice positions and step during a crosshairs drag instead of tracking the pointer continuously - lines no longer hide when a view's slice differs from the crosshair slice - no lines when there is no peer 2D view
PaulHax
force-pushed
the
reference-lines
branch
from
August 16, 2026 15:41
6b4cbee to
cd56bef
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cross-reference lines were drawn inside the crosshairs tool, so they only existed while that tool was active. Pull them out into a standalone feature that a setting can turn on persistently, and that the crosshairs tool borrows as its on-screen appearance while it is active.
Visibility is derived (enabled || crosshairs active) rather than snapshot and restored, which gives the auto-on/restore behavior with no extra state and covers press-and-hold temporary crosshairs for free.
The geometry is a general plane-plane intersection clipped to the image box in index space, not an axis-aligned special case, so oblique planes only need wiring into the peer enumeration later. The intersection direction is transformed by the linear part of worldToIndex: a direction is a vector, so it never wanted the translation, and recovering it by subtracting two transformed points collapsed to zero in float32 for nearly parallel planes. Peers come from the layout slots, so lines survive maximizing a view and no stale viewByID entry can produce a ghost line.
Each line breaks around every point where another drawn line crosses it, leaving 16px of clear space. Doing that as a screen-space pass over the projected segments keeps the gap decoupled from the crosshairs position, so it appears the same way in always-on mode.
The crosshairs tool keeps its slicing inside the image its view shows. The slice write used to hang off a watcher on the crosshair position in the active image's index space, so merely focusing another image's view slammed every view of the newly active image to wherever the crosshair had been left in the other one. The move now propagates from the interaction itself: the view widget reports which view the point was picked in, and the store resolves the image from that view, clamps the point in its index space and slices only the layout views showing it. That leaves the widget state with nothing image-specific to track, so the shared matrices and handle bounds go away with it.
The feature lives in src/referenceLines, following src/processing: a single public surface plus a pure layer of geometry, crossings and peer enumeration, with the boundary enforced by eslint import zones.
Behavior changes that come with the pull-out:
https://youtu.be/0pFMbjRyXbA