feat(render): independent major and minor grid classes tied to the tick set

This commit is contained in:
Martino Ferrari committed 2026-09-28 12:42:22 +02:00
1 parent 69495a3799
commit eaae07d8e0
7 files changed
+635 -16

No files matched your search

+11 -1
View File
@@ -12,16 +12,26 @@ namespace plot {
/// baking screen coordinates in here would break that uniform-only contract.
struct GridLine {
f64 x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0;
/// The class of the tick this segment came from: a major (labelled) tick, or one
/// of the minor subdivisions between them. The renderer picks the class' colour
/// and width from it, so the tick set is the one source for grid positions and
/// `Style` the one place that decides how a class looks and whether it is drawn.
bool major = true;
};
/// Tick-aligned grid geometry: one segment per tick, spanning the perpendicular
/// axis' full range.
class Grid {
///
/// Every tick within the perpendicular range contributes a segment, whatever its
/// class, tagged by it. Whether a class is *drawn* is style rather than geometry:
/// the renderer checks `Style::grid_major_visible` / `grid_minor_visible` per class
/// before it stages a segment, which is the only switch for that behaviour (spec
/// §11). A `Grid` therefore carries both classes' geometry whatever the style says,
/// and a caller that draws it itself applies the same two switches.
public:
bool vertical = true; ///< emit lines at x ticks
bool horizontal = true; ///< emit lines at y ticks
bool show_minor = true; ///< keep minor-tick lines
/// Rebuilds the segments from each axis' ticks and range. Ticks outside the
/// perpendicular range (or non-finite) are skipped, so a stale tick list can
+3 -2
View File
@@ -148,8 +148,9 @@ class Renderer {
/// Every metric here is a logical unit (`Style`'s unit rule): the host writes
/// `ui_scale` from the display it is on and this converts each metric with
/// `device()`. `line_width_px` is the width of the strokes framing the data (axis
/// lines, cursor markers) -- grid lines stay hairlines and every trace carries its
/// own width.
/// lines, cursor markers); the grid carries a width *per class*
/// (`grid_major_width` / `grid_minor_width`) and every trace its own, and a grid
/// class the style switches off stages no geometry at all.
render::Style& style() noexcept { return style_; }
const render::Style& style() const noexcept { return style_; }
+11
View File
@@ -55,6 +55,17 @@ struct Style {
f32 axis_font_px = 12.0f; ///< logical em the axis text is drawn at.
f32 grid_label_pad = 4.0f; ///< logical gap between a tick label and the axes,
///< and the inset inside a title strip.
/// The two grid classes, each with its own width and its own switch. The grid's
/// *positions* come from the tick set alone -- `Grid::build()` tags every segment
/// with the class of the tick it came from -- so these four decide only how a
/// class is drawn. A class switched off stages no geometry at all: the renderer
/// skips it before the first segment is staged, so a dense plot's minor grid
/// costs nothing rather than being drawn transparent (spec §11). The colours
/// above are already per class.
f32 grid_major_width = 1.0f; ///< logical width of a major (labelled-tick) line.
f32 grid_minor_width = 1.0f; ///< logical width of a minor (subdivision) line.
bool grid_major_visible = true; ///< stage the major grid at all.
bool grid_minor_visible = true; ///< stage the minor grid at all.
f32 line_width_px = 1.5f; ///< logical width of the strokes framing the data
///< (axis lines, cursor markers).
f32 tick_min_px = 60.0f; ///< logical minimum spacing between major ticks, so