Skip to content

CODAP-1469: make residual-plot points marquee-selectable - #2677

Open
kswenson wants to merge 9 commits into
mainfrom
CODAP-1469-residual-plot-marquee-selection
Open

CODAP-1469: make residual-plot points marquee-selectable#2677
kswenson wants to merge 9 commits into
mainfrom
CODAP-1469-residual-plot-marquee-selection

Conversation

@kswenson

Copy link
Copy Markdown
Member

Summary

Adds marquee (drag-rectangle) selection to the residual plot, alongside the
existing click selection. Fixes CODAP-1469.

  • Dragging on the residual strip selects the residual points inside the rectangle;
    selection updates dynamically while dragging, and Shift adds to the current
    selection.
  • Selection is confined to the residual strip (separate zone) — the upper-plot
    marquee and the map marquee are unchanged. A rectangle spanning both the main
    Y-axis space and the residual space has no coherent meaning, so the two zones
    stay independent.
  • A click (no drag) still deselects all cases, as before.

Implementation notes

  • Residual points are hand-drawn SVG circles that the point renderer doesn't
    track, so the shared Background marquee (which hit-tests the renderer's
    R-tree) can't see them. The new useResidualMarquee hook builds its own
    R-tree from the residual positions on pointerdown and selects via the same
    delta hit-testing — the R-tree is built up front to stay efficient with large
    datasets (one residual point per case).
  • Refactor: the residual rendering/sync code was extracted out of
    scatter-plot.tsx into a useResidualPlot hook, and Background's
    getCasesForDelta was moved into data-display-utils.ts so both marquees
    share it.

Reviewer notes

This PR is a mix of new logic and mechanical moves — the commit history is
structured so each is reviewable on its own.

New code (warrants closer review):

  • use-residual-marquee.ts — the new drag-select behavior: R-tree build,
    delta hit-testing, dynamic/Shift selection, the pointer→plot-area coordinate
    conversion, and the click-vs-drag threshold that preserves click-to-deselect.
  • residual-marquee-utils.ts — new pure helpers (buildResidualPositions,
    clampRectToLowerRegion) + their unit tests.
  • scatter-plot.tsx — the new bits only: the useResidualMarquee call and
    the residual hit-rect's onPointerDown/onClick wiring (the rest of the diff
    in this file is the extraction below).
  • use-marquee-state.ts + the MarqueeStateContext provider in graph.tsx
    new, but trivial context plumbing.
  • bivariate-adornments.spec.ts — new Cypress test.
  • the getCasesForDelta unit test in data-display-utils.test.ts.

Moved / mechanical (lighter review):

  • use-residual-plot.ts — a behavior-preserving extraction of the residual
    rendering/sync code out of scatter-plot.tsx (no logic changes; the guards
    and untracked wrapping were moved verbatim). Most of the scatter-plot.tsx
    deletions are the other side of this move.
  • getCasesForDelta moved from background.tsx into data-display-utils.ts;
    background.tsx just imports it now.
  • the graph.tsx reindent commit is whitespace only (JSX nested under the new
    provider).

Testing

  • Unit tests for the extracted getCasesForDelta and the pure residual-marquee
    geometry helpers.
  • Cypress e2e: drag-selecting residual points on the strip (plus the existing
    click select/deselect coverage).

kswenson and others added 7 commits July 27, 2026 13:14
Move the delta hit-test helper (and its RTree / CaseObject types) out of
background.tsx into data-display-utils.ts, next to the rectangleSubtract it
calls, so the residual-plot marquee can reuse it. No behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the Residual Plot's SVG rendering, split-layout sync autorun, and
selection-halo restyle out of scatter-plot.tsx into a useResidualPlot hook,
slimming the core component. Behavior-preserving; existing residual tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
buildResidualPositions maps residual points to screen coords (matching the drawn
circles); clampRectToLowerRegion confines a marquee rect to the residual strip.
Both pure and unit-tested.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add useResidualMarquee: a drag-rectangle selection confined to the residual
strip, independent of the upper-plot marquee. Builds its own R-tree from the
residual positions on pointerdown and selects via the shared delta hit-testing;
dynamic while dragging, Shift adds. A no-drag click still deselects. Shares the
display's MarqueeState with the plot via a new MarqueeStateContext.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drag a marquee across the residual strip and assert residual points become
selected, alongside the existing click-select/deselect coverage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The pointer-to-frame conversion used ownerSVGElement (origin outside the axes),
offsetting the marquee — and its hit-testing — right by the left-axis margin.
Anchor to the residual hit rect's own box instead: it is drawn at frame
(0, plotHeight) in the same group as the residual points, so its screen top-left
maps to that frame regardless of margins.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reindent the graph's returned JSX now that it is nested inside the
MarqueeStateContext provider added for the residual marquee.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kswenson kswenson added the v3 CODAP v3 label Jul 27, 2026
@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.69027% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.79%. Comparing base (6fc144a) to head (5a084d9).

Files with missing lines Patch % Lines
...ents/graph/plots/scatter-plot/use-residual-plot.ts 94.28% 6 Missing ⚠️
...s/graph/plots/scatter-plot/use-residual-marquee.ts 95.00% 4 Missing ⚠️
.../components/data-display/components/background.tsx 33.33% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             main    #2677       +/-   ##
===========================================
+ Coverage   72.82%   87.79%   +14.96%     
===========================================
  Files         810      814        +4     
  Lines       46933    47045      +112     
  Branches    11999    12012       +13     
===========================================
+ Hits        34179    41303     +7124     
+ Misses      12721     5726     -6995     
+ Partials       33       16       -17     
Flag Coverage Δ
cypress 69.69% <94.00%> (+31.53%) ⬆️
jest 62.64% <22.56%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cypress

cypress Bot commented Jul 27, 2026

Copy link
Copy Markdown

codap-v3    Run #12092

Run Properties:  status check passed Passed #12092  •  git commit 5a084d9f9f: null
Project codap-v3
Branch Review CODAP-1469-residual-plot-marquee-selection
Run status status check passed Passed #12092
Run duration 08m 37s
Commit git commit 5a084d9f9f: null
Committer null
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 1
Tests that did not run due to a developer annotating a test with .skip  Pending 82
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 383
View all changes introduced in this branch ↗︎

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds residual-strip marquee (drag-rectangle) selection to the scatter plot’s residual plot, sharing marquee state/logic with existing background selection and preserving click-to-deselect behavior (CODAP-1469).

Changes:

  • Introduces a residual-specific marquee implementation (useResidualMarquee) that builds an R-tree from residual point positions on pointerdown and updates selection dynamically while dragging.
  • Refactors residual plot rendering/sync/selection styling into useResidualPlot, and shares delta hit-testing via getCasesForDelta moved into data-display-utils.ts.
  • Adds MarqueeState context plumbing and new unit/Cypress coverage for residual marquee behavior and helper utilities.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
v3/src/components/graph/plots/scatter-plot/use-residual-plot.ts New hook encapsulating residual plot rendering, axis/split-layout sync, and selection restyling.
v3/src/components/graph/plots/scatter-plot/use-residual-marquee.ts New residual-strip-only marquee selection logic (R-tree build + delta hit-testing).
v3/src/components/graph/plots/scatter-plot/scatter-plot.tsx Wires in useResidualPlot + useResidualMarquee and updates residual background hit-rect handlers.
v3/src/components/graph/plots/scatter-plot/residual-marquee-utils.ts Pure helpers for residual point screen positions and lower-region rect clamping.
v3/src/components/graph/plots/scatter-plot/residual-marquee-utils.test.ts Unit tests for residual marquee helper utilities.
v3/src/components/graph/components/graph.tsx Provides MarqueeState via context in addition to existing prop threading.
v3/src/components/data-display/hooks/use-marquee-state.ts Adds MarqueeStateContext + hook for descendant access.
v3/src/components/data-display/data-display-utils.ts Moves/exports getCasesForDelta and related types for shared marquee delta selection.
v3/src/components/data-display/data-display-utils.test.ts Adds unit tests for getCasesForDelta.
v3/src/components/data-display/components/background.tsx Uses shared getCasesForDelta and shared CaseObject/RTree types.
v3/cypress/e2e/bivariate-adornments.spec.ts Adds e2e coverage for residual-strip marquee selection.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread v3/src/components/graph/plots/scatter-plot/use-residual-marquee.ts
Comment thread v3/src/components/data-display/data-display-utils.ts Outdated
- End the residual marquee drag on pointercancel too, so touch/gesture
  cancellation doesn't leave window listeners attached or the marquee stuck.
- Drop the runtime `rtree` import from the widely-imported data-display-utils:
  getCasesForDelta only needs the tree's type, so declare a minimal RTree
  interface instead of ReturnType<typeof RTreeLib>. Tree construction stays in
  the callers that already depend on rtree.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Comment thread v3/src/components/graph/plots/scatter-plot/use-residual-marquee.ts
Comment thread v3/src/components/graph/plots/scatter-plot/use-residual-marquee.ts
If a drag ended without a trailing click on the hit rect (e.g. pointerup off the
rect), suppressClickRef stayed true and swallowed the next genuine click. Reset
it at the start of each pointer interaction so suppression only applies to the
click immediately following a drag.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants