From 889cfc215a714df3b147e0e92edd888fb71f875a Mon Sep 17 00:00:00 2001 From: Emil Lerch Date: Thu, 25 Jun 2026 15:29:19 -0700 Subject: [PATCH] move y-axis labels to the right --- src/charts/axis.zig | 19 +++++++++++-------- src/charts/chart.zig | 6 +++--- src/charts/line_chart.zig | 6 +++--- src/charts/projection_chart.zig | 6 +++--- 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/charts/axis.zig b/src/charts/axis.zig index e9bc288..19723d5 100644 --- a/src/charts/axis.zig +++ b/src/charts/axis.zig @@ -63,15 +63,17 @@ pub fn fmtDollar(buf: []u8, value: f64) []const u8 { return std.fmt.bufPrint(buf, "{s}${s}", .{ sign, commas }) catch "$?"; } -/// Draw `n + 1` right-aligned dollar labels evenly spaced from -/// `value_max` (at `top`) down to `value_min` (at `bottom`), with each -/// label's right edge a small pad left of `right_x` (typically the -/// plot's left edge) and vertically centered on its level. +/// Draw `n + 1` left-aligned dollar labels evenly spaced from +/// `value_max` (at `top`) down to `value_min` (at `bottom`), placed in +/// the right margin a small pad to the right of `plot_right` (the plot's +/// right edge) and vertically centered on each level. Right-side y-axis +/// is the financial convention: the latest (rightmost) values sit next +/// to the scale as the series grows. pub fn drawYDollarTicks( sfc: *Surface, scale: i32, color: [3]u8, - right_x: f64, + plot_right: f64, top: f64, bottom: f64, value_min: f64, @@ -82,6 +84,7 @@ pub fn drawYDollarTicks( const span = bottom - top; const half_h = @divFloor(text.glyph_h * scale, 2); const pad: f64 = labelGap(scale); + const lx: i32 = @intFromFloat(plot_right + pad); var i: usize = 0; while (i <= n) : (i += 1) { const frac = @as(f64, @floatFromInt(i)) / @as(f64, @floatFromInt(n)); @@ -89,8 +92,6 @@ pub fn drawYDollarTicks( const y = top + frac * span; var buf: [24]u8 = undefined; const label = fmtDollar(&buf, val); - const lw = text.measureWidth(label, scale); - const lx = @as(i32, @intFromFloat(right_x - pad)) - lw; const ly = @as(i32, @intFromFloat(y)) - half_h; text.drawText(sfc, lx, ly, scale, color, label); } @@ -142,7 +143,9 @@ test "drawYDollarTicks stamps labels in the requested color" { const color = [3]u8{ 0xCC, 0xCC, 0xCC }; try testing.expectEqual(@as(usize, 0), draw.countColor(&sfc, color)); - drawYDollarTicks(&sfc, 2, color, 280, 10, 190, 1_000_000, 5_000_000, 5); + // plot_right=180 leaves room for the labels in the right margin of a + // 300px-wide surface. + drawYDollarTicks(&sfc, 2, color, 180, 10, 190, 1_000_000, 5_000_000, 5); try testing.expect(draw.countColor(&sfc, color) > 0); } diff --git a/src/charts/chart.zig b/src/charts/chart.zig index 15e3e6c..2abf02f 100644 --- a/src/charts/chart.zig +++ b/src/charts/chart.zig @@ -287,8 +287,8 @@ pub fn renderToSurface( // scaled to the surface so labels stay legible on large exports. const label_scale: i32 = axis.labelScale(h); const label_char_h: f64 = axis.charHeight(label_scale); - const m_left: f64 = if (axis_labels) axis.yAxisMargin(label_scale) else margin_left; - const m_right: f64 = if (axis_labels) label_char_h else margin_right; + const m_left: f64 = if (axis_labels) label_char_h else margin_left; + const m_right: f64 = if (axis_labels) axis.yAxisMargin(label_scale) else margin_right; const m_top: f64 = if (axis_labels) (label_char_h / 2 + 4) else margin_top; const m_bottom: f64 = if (axis_labels) axis.bottomMargin(label_scale) else margin_bottom; @@ -502,7 +502,7 @@ pub fn renderToSurface( // ── Axis labels (export only) ──────────────────────────────── if (axis_labels) { // Dollar ticks against the price panel; start/end dates below. - axis.drawYDollarTicks(&sfc, label_scale, th.text_muted, chart_left, price_top, price_bottom, price_min, price_max, 4); + axis.drawYDollarTicks(&sfc, label_scale, th.text_muted, chart_right, price_top, price_bottom, price_min, price_max, 4); var fbuf: [12]u8 = undefined; var lbuf: [12]u8 = undefined; const first_s = std.fmt.bufPrint(&fbuf, "{f}", .{data[0].date}) catch ""; diff --git a/src/charts/line_chart.zig b/src/charts/line_chart.zig index 8c97548..a4ba09f 100644 --- a/src/charts/line_chart.zig +++ b/src/charts/line_chart.zig @@ -149,8 +149,8 @@ pub fn renderToSurface( // with the surface so labels stay legible on large exports. const label_scale: i32 = axis.labelScale(h); const label_char_h: f64 = axis.charHeight(label_scale); - const m_left: f64 = if (opts.axis_labels) axis.yAxisMargin(label_scale) else margin_left; - const m_right: f64 = if (opts.axis_labels) label_char_h else margin_right; + const m_left: f64 = if (opts.axis_labels) label_char_h else margin_left; + const m_right: f64 = if (opts.axis_labels) axis.yAxisMargin(label_scale) else margin_right; const m_top: f64 = if (opts.axis_labels) (label_char_h / 2 + 4) else margin_top; const m_bottom: f64 = if (opts.axis_labels) axis.bottomMargin(label_scale) else margin_bottom; @@ -246,7 +246,7 @@ pub fn renderToSurface( // ── Axis labels (export only; drawn directly into the buffer) ── if (opts.axis_labels) { - axis.drawYDollarTicks(&sfc, label_scale, th.text_muted, chart_left, chart_top, chart_bottom, value_min, value_max, 5); + axis.drawYDollarTicks(&sfc, label_scale, th.text_muted, chart_right, chart_top, chart_bottom, value_min, value_max, 5); var fbuf: [12]u8 = undefined; var lbuf: [12]u8 = undefined; const first_s = std.fmt.bufPrint(&fbuf, "{f}", .{points[0].date}) catch ""; diff --git a/src/charts/projection_chart.zig b/src/charts/projection_chart.zig index 7d66507..2bf145b 100644 --- a/src/charts/projection_chart.zig +++ b/src/charts/projection_chart.zig @@ -124,8 +124,8 @@ pub fn renderToSurface( // ticks) and a bottom margin (year endpoints), scaled to the surface. const label_scale: i32 = axis.labelScale(h); const label_char_h: f64 = axis.charHeight(label_scale); - const m_left: f64 = if (axis_labels) axis.yAxisMargin(label_scale) else margin_left; - const m_right: f64 = if (axis_labels) label_char_h else margin_right; + const m_left: f64 = if (axis_labels) label_char_h else margin_left; + const m_right: f64 = if (axis_labels) axis.yAxisMargin(label_scale) else margin_right; const m_top: f64 = if (axis_labels) (label_char_h / 2 + 4) else margin_top; const m_bottom: f64 = if (axis_labels) axis.bottomMargin(label_scale) else margin_bottom; const chart_left = m_left; @@ -311,7 +311,7 @@ pub fn renderToSurface( // ── Axis labels (export only) ──────────────────────────────── if (axis_labels) { - axis.drawYDollarTicks(&sfc, label_scale, th.text_muted, chart_left, chart_top, chart_bottom, value_min, value_max, 5); + axis.drawYDollarTicks(&sfc, label_scale, th.text_muted, chart_right, chart_top, chart_bottom, value_min, value_max, 5); var fbuf: [8]u8 = undefined; var lbuf: [8]u8 = undefined; const first_s = std.fmt.bufPrint(&fbuf, "{d}", .{bands[0].year}) catch "";