fix(plot): a figure row's strip shows labels and title independently, and the shared axis is the bottom row's strip
This commit is contained in:
1 parent
8f1e60a105
commit
770da4c2b2
9 files changed
+415
-175
No files matched your search
+37
-20
@@ -22,8 +22,9 @@ constexpr plot::f32 kH = 480.0f;
|
||||
plot::Rect whole_figure() { return plot::Rect{0.0f, 0.0f, kW, kH}; }
|
||||
|
||||
/// A figure whose every row has a y axis and an x axis, so a row is a plot in the
|
||||
/// shape the layout tests care about: it loses width to a y strip and height to
|
||||
/// nothing else (the x strip belongs to the figure under `labels_bottom_only`).
|
||||
/// shape the layout tests care about: it loses width to a y strip and, on the bottom
|
||||
/// row alone, height to the shared x strip -- which lives inside that row rather than
|
||||
/// in a band of its own.
|
||||
plot::Figure figure_with_axes(plot::u32 rows) {
|
||||
plot::Figure figure(rows);
|
||||
figure.set_viewport(whole_figure());
|
||||
@@ -65,21 +66,32 @@ PLOT_TEST(row_rects_tile_the_figure_without_overlap) {
|
||||
PLOT_CHECK(row.h > 0.0f);
|
||||
}
|
||||
// Top to bottom, in row order, touching: each row starts where the one above it
|
||||
// ended, and the last one ends on the rows' region's bottom edge (the figure's
|
||||
// height less the shared strip beneath it).
|
||||
// ended, and the last one ends on the figure's bottom edge -- the rows tile the
|
||||
// whole figure, because the shared x axis is the bottom row's own rather than a band
|
||||
// taken off the rows.
|
||||
const plot::FigureLayout layout = figure.layout();
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(rows[0].y), 0.0, 1e-6);
|
||||
for (std::size_t i = 1; i < rows.size(); ++i) {
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(rows[i].y), static_cast<plot::f64>(rows[i - 1].bottom()),
|
||||
1e-6);
|
||||
}
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(rows.back().bottom()),
|
||||
static_cast<plot::f64>(layout.x_axis_strip.y), 1e-6);
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(layout.x_axis_strip.bottom()), static_cast<plot::f64>(kH),
|
||||
1e-6);
|
||||
// ... and the strip shares the figure's width with the rows above it.
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(layout.x_axis_strip.w), static_cast<plot::f64>(kW), 1e-6);
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(rows.back().bottom()), static_cast<plot::f64>(kH), 1e-6);
|
||||
// The shared strip *is* the bottom row's own x label area: inside that row, below the
|
||||
// row's axes and above the row's title strip, and as wide as its axes -- which is what
|
||||
// puts it where the controller can hit-test it and where the renderer stages the one
|
||||
// set of labels.
|
||||
const plot::PlotLayout& bottom = figure.plot(2u).layout();
|
||||
PLOT_CHECK(layout.x_axis_strip.h > 0.0f);
|
||||
PLOT_CHECK(layout.x_axis_strip.y >= layout.rows.back().y);
|
||||
PLOT_CHECK(layout.x_axis_strip.bottom() <= layout.rows.back().bottom() + 1e-6f);
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(layout.x_axis_strip.h),
|
||||
static_cast<plot::f64>(bottom.x_label_area.h), 1e-6);
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(layout.x_axis_strip.x),
|
||||
static_cast<plot::f64>(bottom.x_label_area.x), 1e-6);
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(layout.x_axis_strip.y),
|
||||
static_cast<plot::f64>(bottom.x_label_area.y), 1e-6);
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(layout.x_axis_strip.w),
|
||||
static_cast<plot::f64>(bottom.x_label_area.w), 1e-6);
|
||||
|
||||
for (std::size_t i = 0; i < rows.size(); ++i) {
|
||||
for (std::size_t j = i + 1; j < rows.size(); ++j) {
|
||||
@@ -95,8 +107,11 @@ PLOT_TEST(row_rects_tile_the_figure_without_overlap) {
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(spaced[1].y - spaced[0].bottom()), 10.0, 1e-6);
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(spaced[2].y - spaced[1].bottom()), 10.0, 1e-6);
|
||||
PLOT_CHECK(spaced[0].h < rows[0].h); // the gaps came out of the rows
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(spaced.back().bottom()),
|
||||
static_cast<plot::f64>(figure.layout().x_axis_strip.y), 1e-6);
|
||||
// The last spaced row still ends on the figure's bottom edge -- the gaps came out of
|
||||
// the rows' share of the figure, not out of the figure -- and so does the strip.
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(spaced.back().bottom()), static_cast<plot::f64>(kH), 1e-6);
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(figure.layout().x_axis_strip.bottom()),
|
||||
static_cast<plot::f64>(kH), 1e-6);
|
||||
|
||||
// A figure with no rows has no geometry -- and no row to reach for while computing
|
||||
// it, which is the case that would read past the end of its own plot list.
|
||||
@@ -110,8 +125,9 @@ PLOT_TEST(row_rects_tile_the_figure_without_overlap) {
|
||||
|
||||
/// Weights change how the figure's height is divided -- a taller main plot, shorter
|
||||
/// rows under it -- and the rows still account for all of it: the sum of the heights
|
||||
/// plus the gaps is the figure less the shared strip, so no weight can leave a band
|
||||
/// unclaimed or push a row past the bottom.
|
||||
/// plus the gaps is the whole figure (the shared strip lives inside the bottom row, so
|
||||
/// it costs the division nothing), so no weight can leave a band unclaimed or push a
|
||||
/// row past the bottom.
|
||||
PLOT_TEST(row_weights_change_relative_heights_and_sum_to_the_viewport) {
|
||||
plot::Figure figure = figure_with_axes(3u);
|
||||
const std::vector<plot::Rect> equal = rows_of(figure);
|
||||
@@ -145,7 +161,7 @@ PLOT_TEST(row_weights_change_relative_heights_and_sum_to_the_viewport) {
|
||||
|
||||
plot::f32 total = 0.0f;
|
||||
for (const plot::Rect& row : rows) total += row.h;
|
||||
total += layout.row_gap * 2.0f + layout.x_axis_strip.h;
|
||||
total += layout.row_gap * 2.0f;
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(total), static_cast<plot::f64>(kH), 1e-3);
|
||||
|
||||
// Any positive scale is the same division: normalised, not absolute.
|
||||
@@ -206,8 +222,8 @@ PLOT_TEST(degenerate_row_weights_are_rejected) {
|
||||
|
||||
/// Every row keeps a positive height, whatever the figure's size and whatever the
|
||||
/// weights say -- a row that is not there is a plot that is not there, silently. The
|
||||
/// shared strip yields to the rows for the same reason: chrome may shrink a figure,
|
||||
/// never erase one.
|
||||
/// shared strip cannot take a row's height for the same reason: it is the bottom row's
|
||||
/// own, so chrome may shrink one row's *axes*, never erase a row.
|
||||
PLOT_TEST(every_row_keeps_a_positive_height) {
|
||||
// Five rows in a figure shorter than the strip one row would ask for.
|
||||
plot::Figure tiny(5u);
|
||||
@@ -220,9 +236,10 @@ PLOT_TEST(every_row_keeps_a_positive_height) {
|
||||
PLOT_CHECK(row.h > 0.0f);
|
||||
total += row.h;
|
||||
}
|
||||
// The rows took what they needed from the gap: a gap that does not fit is dropped,
|
||||
// so what is left of the figure is the rows' and the strip's, not the gap's.
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(total + layout.x_axis_strip.h), 12.0, 1e-3);
|
||||
// The rows took the whole figure: a gap that does not fit is dropped, and the shared
|
||||
// strip is inside the bottom row rather than a band beside it, so it costs the
|
||||
// division nothing.
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(total), 12.0, 1e-3);
|
||||
|
||||
// A wildly unbalanced weight set still cannot squeeze a row out. The tiny weights
|
||||
// here are small enough that a row's *share* of the leftover underflows to zero
|
||||
|
||||
Reference in new issue
Block a user