feat(plot): vertical y-axis label via a rotated text run
This commit is contained in:
1 parent
1cb5970757
commit
daeb31b1ea
6 files changed
+453
-80
No files matched your search
+71
-10
@@ -82,10 +82,12 @@ PLOT_TEST(layout_derives_label_areas_from_font_metrics) {
|
||||
const f32 pad = p.style().grid_label_pad;
|
||||
PLOT_CHECK_NEAR(l.y_axis_width, widest_major_label(p.y_axis(ay), font) + 2.0f * pad, 1e-4);
|
||||
PLOT_CHECK_NEAR(l.x_axis_height, font.height() + 2.0f * pad, 1e-4);
|
||||
// The y axis carries the title "volts": it is drawn horizontally, so the strip
|
||||
// left of the label strip is as wide as the measured title. There is no x axis,
|
||||
// so the x direction reserves nothing beyond its label strip.
|
||||
PLOT_CHECK_NEAR(l.y_title_width, font.measure("volts") + 2.0f * pad, 1e-4);
|
||||
// The y axis carries the title "volts", drawn rotated to read bottom-to-top, so
|
||||
// the strip left of the label strip is one text line *wide* -- the column the
|
||||
// run advances up -- and not as wide as the title is when horizontal. There is
|
||||
// no x axis, so the x direction reserves nothing beyond its label strip.
|
||||
PLOT_CHECK_NEAR(l.y_title_width, font.height() + 2.0f * pad, 1e-4);
|
||||
PLOT_CHECK(l.y_title_width < font.measure("volts") + 2.0f * pad);
|
||||
PLOT_CHECK_NEAR(l.x_title_height, 0.0f, 1e-6);
|
||||
PLOT_CHECK_NEAR(l.axes.x, l.y_title_width + l.y_axis_width, 1e-4);
|
||||
PLOT_CHECK_NEAR(l.axes.w, 800.0f - (l.y_title_width + l.y_axis_width), 1e-4);
|
||||
@@ -100,8 +102,9 @@ PLOT_TEST(layout_derives_label_areas_from_font_metrics) {
|
||||
PLOT_CHECK_NEAR(l.x_label_area.y, l.axes.bottom(), 1e-4);
|
||||
}
|
||||
|
||||
/// Every titled axis of a direction gets its own text line inside its strip;
|
||||
/// without that, the second titled axis of an edge is drawn on top of the first.
|
||||
/// Every titled axis of a direction gets its own text line inside its strip; without
|
||||
/// that, the second titled axis of an edge is drawn on top of the first. An x line is
|
||||
/// a row of the strip, a y one a column of it, because the y title is drawn rotated.
|
||||
PLOT_TEST(layout_stacks_one_title_line_per_titled_axis) {
|
||||
plot::render::EmbeddedMonoFont font;
|
||||
plot::Plot p;
|
||||
@@ -117,10 +120,13 @@ PLOT_TEST(layout_stacks_one_title_line_per_titled_axis) {
|
||||
PLOT_CHECK(p.titled_y_axis_count() == 2u);
|
||||
// The x titles stack in rows, so the strip grows by a line per titled axis...
|
||||
PLOT_CHECK_NEAR(l.x_title_height, 2.0f * font.height() + 2.0f * pad, 1e-4);
|
||||
// ... while the y titles stack down the axes-tall strip, so the second one costs
|
||||
// height the axes already has rather than a second column of width.
|
||||
PLOT_CHECK_NEAR(l.y_title_width,
|
||||
std::max(font.measure("volts"), font.measure("amps")) + 2.0f * pad, 1e-4);
|
||||
// ... and the y titles, rotated, take a *column* each: the second titled y axis
|
||||
// costs another text line of width rather than a row of the strip's height, and
|
||||
// the pair still cannot be drawn over each other. The widest title's own width
|
||||
// plays no part in it.
|
||||
PLOT_CHECK_NEAR(l.y_title_width, 2.0f * font.height() + 2.0f * pad, 1e-4);
|
||||
PLOT_CHECK(l.y_title_width <
|
||||
std::max(font.measure("volts"), font.measure("amps")) + 2.0f * pad);
|
||||
PLOT_CHECK_NEAR(l.axes.h, 400.0f - (l.x_axis_height + l.x_title_height), 1e-4);
|
||||
}
|
||||
|
||||
@@ -143,6 +149,61 @@ PLOT_TEST(layout_reserves_no_title_strip_without_a_title) {
|
||||
PLOT_CHECK_NEAR(l.axes.h, 400.0f - l.x_axis_height, 1e-4);
|
||||
}
|
||||
|
||||
/// The y title is rotated, so its strip is a column: one text line wide where a
|
||||
/// horizontal run needed the title's own width, and as tall as the axes, which is
|
||||
/// where the run spends its length. The title here is wide enough to make the two
|
||||
/// models plainly different -- it measures more than ten of the lines it now costs.
|
||||
PLOT_TEST(y_title_strip_is_narrow_when_a_y_title_is_set) {
|
||||
plot::render::EmbeddedMonoFont font;
|
||||
plot::Plot p;
|
||||
p.set_text_backend(&font);
|
||||
p.set_viewport({0.0f, 0.0f, 800.0f, 400.0f});
|
||||
p.add_x_axis({"seconds", {0.0, 1.0}, false, plot::AxisPlace::Bottom, false});
|
||||
p.add_y_axis({"millivolts per division", {-1.0, 1.0}, false, plot::AxisPlace::Left, false});
|
||||
const plot::PlotLayout& l = p.layout();
|
||||
const plot::f32 pad = p.style().grid_label_pad;
|
||||
|
||||
// One text line wide -- a column, not the run's own width...
|
||||
PLOT_CHECK_NEAR(l.y_title_area.w, l.y_title_width, 1e-6);
|
||||
PLOT_CHECK_NEAR(l.y_title_width, font.height() + 2.0f * pad, 1e-4);
|
||||
PLOT_CHECK(l.y_title_width < font.measure("millivolts per division") + 2.0f * pad);
|
||||
// ... spanning the axes' whole vertical extent, so the run has the room to
|
||||
// advance in and a title longer than the axes is cut where the axes ends.
|
||||
PLOT_CHECK_NEAR(l.y_title_area.x, 0.0f, 1e-6);
|
||||
PLOT_CHECK_NEAR(l.y_title_area.y, l.axes.y, 1e-6);
|
||||
PLOT_CHECK_NEAR(l.y_title_area.h, l.axes.h, 1e-4);
|
||||
PLOT_CHECK(l.y_title_area.h > l.y_title_area.w);
|
||||
// The strips tile the viewport outside `axes`: title, then labels, then data.
|
||||
PLOT_CHECK_NEAR(l.y_title_area.right(), l.y_label_area.x, 1e-4);
|
||||
PLOT_CHECK_NEAR(l.y_label_area.right(), l.axes.x, 1e-4);
|
||||
PLOT_CHECK_NEAR(l.axes.x, l.y_title_width + l.y_axis_width, 1e-4);
|
||||
PLOT_CHECK_NEAR(l.axes.w, 800.0f - (l.y_title_width + l.y_axis_width), 1e-4);
|
||||
}
|
||||
|
||||
/// A Left and a Right titled y axis both draw in the one strip the layout reserves,
|
||||
/// so the strip has to hold two runs. They no longer stack down its height -- the
|
||||
/// runs are vertical, they would overlap from top to bottom -- so each gets a
|
||||
/// column, and the strip is two text lines wide. What the model must not do is go
|
||||
/// back to being as wide as the widest title: the columns are lines, not titles.
|
||||
PLOT_TEST(two_titled_y_axes_reserve_a_column_each) {
|
||||
plot::render::EmbeddedMonoFont font;
|
||||
plot::Plot p;
|
||||
p.set_text_backend(&font);
|
||||
p.set_viewport({0.0f, 0.0f, 800.0f, 400.0f});
|
||||
p.add_y_axis({"volts", {-1.0, 1.0}, false, plot::AxisPlace::Left, false});
|
||||
p.add_y_axis({"amps", {-1.0, 1.0}, false, plot::AxisPlace::Right, false});
|
||||
const plot::PlotLayout& l = p.layout();
|
||||
const plot::f32 pad = p.style().grid_label_pad;
|
||||
|
||||
PLOT_CHECK(p.titled_y_axis_count() == 2u);
|
||||
PLOT_CHECK_NEAR(l.y_title_width, 2.0f * font.height() + 2.0f * pad, 1e-4);
|
||||
// Two columns fit side by side inside the strip, and the axes is inset by it once.
|
||||
PLOT_CHECK(l.y_title_width >= 2.0f * font.height());
|
||||
PLOT_CHECK_NEAR(l.y_title_area.w, l.y_title_width, 1e-6);
|
||||
PLOT_CHECK_NEAR(l.y_title_area.right(), l.y_label_area.x, 1e-4);
|
||||
PLOT_CHECK_NEAR(l.axes.x, l.y_title_width + l.y_axis_width, 1e-4);
|
||||
}
|
||||
|
||||
PLOT_TEST(time_axis_tick_labels_use_format_time) {
|
||||
plot::Plot p;
|
||||
p.set_viewport({0.0f, 0.0f, 800.0f, 400.0f});
|
||||
|
||||
Reference in new issue
Block a user