test(plot): pin the crosshair's lookup, readout, placement, sync and clip

This commit is contained in:
Martino Ferrari committed 2026-09-28 19:07:22 +02:00
1 parent fd0c471430
commit 8e27e22ebe
6 files changed
+798 -17

No files matched your search

+24 -12
View File
@@ -170,7 +170,7 @@ class Renderer {
///
/// **The clip** is the one piece of state the frame moves to keep data inside the plot
/// area (spec §13): the passes that draw *inside* `axes` -- grid, traces, regions,
/// cursors, the measurement band, annotations and the legend -- run with the scissor
/// cursors, the measurement band, annotations, the legend and the crosshair -- run with the scissor
/// narrowed to `layout().axes`, intersected with the frame's viewport, while the axis
/// lines (chrome drawn on the rect's own edge, which overhangs it by half a stroke) and
/// the tick labels and titles (outside the rect by design) run with the frame's viewport
@@ -487,18 +487,30 @@ class Renderer {
/// them again, so the panel a test asserts and the panel this draws are the same
/// numbers.
void draw_legend(const Plot& plot, const PlotLayout& layout);
/// The crosshair: the two lines, a marker per trace, and the readout panel with a swatch and
/// a value per listed row. Every rect -- the two stroke boxes, the panel, the markers'
/// positions and the rows' boxes -- comes from `PlotLayout::crosshair`, which placed it
/// inside `axes`; this stages exactly that geometry, so the crosshair a test measures and the
/// crosshair a frame paints are one set of numbers. Clipped to `axes` with the rest of the
/// interior passes, which is what keeps a marker for an off-scale sample inside the rect.
/// The crosshair's **lines and markers**: the vertical and horizontal strokes and a small
/// cross at each trace's intersection.
///
/// The panel is a backplate like the legend's, so it is drawn after the lines and the
/// markers and before any of the frame's text. The rows' values were formatted by the plot
/// (in the trace's own y axis' format) and are staged here as they stand -- this layer
/// formats nothing.
void draw_crosshair(const Plot& plot, const PlotLayout& layout);
/// Every rect -- the two stroke boxes and the markers' positions -- comes from
/// `PlotLayout::crosshair`, which placed them inside `axes`; this stages exactly that
/// geometry, so the crosshair a test measures and the crosshair a frame paints are one set of
/// numbers. Clipped to `axes` with the rest of the interior passes, which is what keeps a
/// marker for a sample far outside the visible y range inside the rect instead of over a
/// label strip.
///
/// Drawn over the data and *under* the handles -- regions, cursors -- because the crosshair
/// sits wherever the pointer is, including on top of the handle a gesture is manipulating, and
/// a hover or grab highlight must not be hidden by the instrument that happens to share its
/// column. Its readout panel is the other half (`draw_crosshair_readout()`), drawn last.
void draw_crosshair_lines(const Plot& plot, const PlotLayout& layout);
/// The crosshair's **readout panel**: the backplate, its border and one swatch, label and
/// value per listed row, all read from `PlotLayout::crosshair` -- the plot formatted the
/// values (in each trace's own y axis' format) and placed every box, so this layer formats
/// nothing and derives no rect. A row that is not listed is skipped; a row whose trace has no
/// sample at the crosshair's x stages no value at all rather than a fabricated one.
///
/// Drawn after every other interior pass -- the legend included -- because it is what the
/// pointer is on: a readout the legend covered would be the feature failing at its one job.
void draw_crosshair_readout(const Plot& plot, const PlotLayout& layout);
/// The built-in backend the renderer owns, and the face the frames draw with:
/// `set_text_backend()` writes `font_`, which starts here and comes back here