feat(render): independent major and minor grid classes tied to the tick set
This commit is contained in:
1 parent
69495a3799
commit
eaae07d8e0
7 files changed
+635
-16
No files matched your search
+6
-2
@@ -26,16 +26,20 @@ void Grid::build(const std::vector<Tick>& x_ticks, Range x_range,
|
||||
|
||||
// Segments stay in data space: the renderer applies the transform, so a pan or
|
||||
// zoom needs no grid rebuild other than for a changed tick set.
|
||||
//
|
||||
// Both classes are built: the tick set is the only source of positions, and
|
||||
// `Style::grid_*_visible` decides what the renderer stages from here, so a class
|
||||
// is never filtered out of the tick set (that would be a second, geometry-side
|
||||
// switch for the same behaviour, and the grid would then disagree with the tick
|
||||
// list a caller can read).
|
||||
if (vertical) {
|
||||
for (const Tick& tick : x_ticks) {
|
||||
if (!tick.major && !show_minor) continue;
|
||||
if (!std::isfinite(tick.value) || !inside(tick.value, x_range)) continue;
|
||||
lines_.push_back(GridLine{tick.value, y_range.min, tick.value, y_range.max, tick.major});
|
||||
}
|
||||
}
|
||||
if (horizontal) {
|
||||
for (const Tick& tick : y_ticks) {
|
||||
if (!tick.major && !show_minor) continue;
|
||||
if (!std::isfinite(tick.value) || !inside(tick.value, y_range)) continue;
|
||||
lines_.push_back(GridLine{x_range.min, tick.value, x_range.max, tick.value, tick.major});
|
||||
}
|
||||
|
||||
+20
-11
@@ -543,21 +543,30 @@ void Renderer::draw_grid(const Plot& plot) {
|
||||
// transforms even when a trace uses another pair.
|
||||
const bool log_x = plot.x_axis(0).log;
|
||||
const bool log_y = plot.y_axis(0).log;
|
||||
// A grid line is a size a user perceives, so it is one logical pixel wide at
|
||||
// every DPI rather than a hairline on a 1x panel and a slab on a 2x one. (Spec §11
|
||||
// gives the two classes a width each; until then both are this one logical pixel.)
|
||||
const f32 grid_width = style_.device(1.0f);
|
||||
|
||||
// Two colour groups, one pass over the segments each: `LineBatch::clear()`
|
||||
// keeps its capacity, so the second group re-uses the first one's storage.
|
||||
for (u32 pass = 0; pass < 2u; ++pass) {
|
||||
const bool majors = pass == 0u;
|
||||
// Two classes, one pass over the segment list each: the tick set decides *where*
|
||||
// the lines are and this decides only how one is drawn -- its class' colour and
|
||||
// its class' logical width, converted to device pixels here, the one conversion
|
||||
// point (spec §11: a grid line is a size a user perceives, the same hairline on a
|
||||
// 1x panel and a 2x one). A class the style switched off stages nothing at all:
|
||||
// the pass is skipped before the first segment, so a disabled class costs nothing
|
||||
// to draw rather than being drawn transparent. Majors first, minors over them, as
|
||||
// the single group order always did. `LineBatch::clear()` keeps its capacity, so
|
||||
// the second pass re-uses the first one's storage.
|
||||
const auto draw_class = [&](bool major, bool visible, Color color, f32 width) {
|
||||
if (!visible) {
|
||||
return;
|
||||
}
|
||||
for (const GridLine& line : grid.lines()) {
|
||||
if (line.major != majors) continue; // grid.build() already dropped non-finite ones
|
||||
if (line.major != major) continue; // grid.build() already dropped non-finite ones
|
||||
stage_segment(line.x0, line.y0, line.x1, line.y1, log_x, log_y);
|
||||
}
|
||||
flush_lines(map, majors ? style_.grid_major : style_.grid_minor, grid_width);
|
||||
}
|
||||
flush_lines(map, color, width);
|
||||
};
|
||||
draw_class(true, style_.grid_major_visible, style_.grid_major,
|
||||
style_.device(style_.grid_major_width));
|
||||
draw_class(false, style_.grid_minor_visible, style_.grid_minor,
|
||||
style_.device(style_.grid_minor_width));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------- axis chrome
|
||||
|
||||
Reference in new issue
Block a user