diff --git a/src/charts/forecast_chart.zig b/src/charts/forecast_chart.zig index b87cede..cb2264e 100644 --- a/src/charts/forecast_chart.zig +++ b/src/charts/forecast_chart.zig @@ -75,9 +75,12 @@ pub const RenderedForecast = struct { } }; -/// Thin RGB wrapper over `renderConvergenceToSurface` for the TUI's -/// kitty path: renders without axis labels, extracts RGB, frees the -/// surface. +/// RGB wrapper over `renderConvergenceToSurface` for the inline kitty +/// path (CLI + TUI). Renders WITH axis labels baked in: unlike the +/// projection chart - whose callers stamp their own labels into the +/// cell grid - nothing draws the forecast chart's labels separately, +/// so the years y-ticks + observation-date x-endpoints go into the +/// surface here (matching the PNG export). pub fn renderConvergenceChart( io: std.Io, alloc: std.mem.Allocator, @@ -86,7 +89,7 @@ pub fn renderConvergenceChart( height_px: u32, th: theme.Theme, ) !ChartResult { - var rendered = try renderConvergenceToSurface(io, alloc, points, width_px, height_px, th, false); + var rendered = try renderConvergenceToSurface(io, alloc, points, width_px, height_px, th, true); defer rendered.deinit(alloc); return .{ .rgb_data = try rendered.extractRgb(alloc), diff --git a/src/charts/text.zig b/src/charts/text.zig index dcdbd89..4dc2f5f 100644 --- a/src/charts/text.zig +++ b/src/charts/text.zig @@ -13,8 +13,9 @@ //! The glyph set is intentionally minimal - just what axis labels and //! chart legends need: digits, `$`, `.`, `,`, `-`, `%`, the `T`/`B`/`M` //! magnitude suffixes emitted by `format.fmtLargeNum`, and the -//! lowercase letters `t`/`h`/`e`/`n`/`o`/`w` for the comparison -//! chart's "then"/"now" legend. Space and unknown chars render blank. +//! lowercase letters `t`/`h`/`e`/`n`/`o`/`w` (comparison-chart +//! "then"/"now" legend) plus `y` (convergence "years" axis ticks). +//! Space and unknown chars render blank. //! //! Coordinates are in surface pixels; `scale` multiplies the 5x7 cell //! (so `scale = 3` renders 15x21 glyphs). Drawing is clipped to the @@ -62,15 +63,17 @@ const glyph_T: Glyph = .{ 0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 }; const glyph_B: Glyph = .{ 0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E }; const glyph_M: Glyph = .{ 0x11, 0x1B, 0x15, 0x15, 0x11, 0x11, 0x11 }; -// Lowercase letters - just what the comparison chart's "then"/"now" -// legend needs (t, h, e, n, o, w). 5x7, low 5 bits per row. Named -// `lc_*` to avoid colliding with the `glyph_w`/`glyph_h` cell dims. +// Lowercase letters: the comparison chart's "then"/"now" legend +// (t, h, e, n, o, w) plus `y` for the convergence "years" axis ticks. +// 5x7, low 5 bits per row. Named `lc_*` to avoid colliding with the +// `glyph_w`/`glyph_h` cell dims. const lc_t: Glyph = .{ 0x08, 0x08, 0x1C, 0x08, 0x08, 0x08, 0x0C }; const lc_h: Glyph = .{ 0x10, 0x10, 0x10, 0x1E, 0x12, 0x12, 0x12 }; const lc_e: Glyph = .{ 0x00, 0x00, 0x0E, 0x11, 0x1F, 0x10, 0x0E }; const lc_n: Glyph = .{ 0x00, 0x00, 0x1E, 0x12, 0x12, 0x12, 0x12 }; const lc_o: Glyph = .{ 0x00, 0x00, 0x0E, 0x11, 0x11, 0x11, 0x0E }; const lc_w: Glyph = .{ 0x00, 0x00, 0x11, 0x11, 0x15, 0x15, 0x0A }; +const lc_y: Glyph = .{ 0x00, 0x00, 0x11, 0x11, 0x0E, 0x04, 0x08 }; /// Look up the bitmap for a character. Unknown characters (including /// space) render blank. @@ -91,6 +94,7 @@ fn glyphFor(ch: u8) Glyph { 'n' => lc_n, 'o' => lc_o, 'w' => lc_w, + 'y' => lc_y, else => blank, }; } @@ -230,13 +234,13 @@ test "drawText renders the comma glyph (so thousands separators show)" { try testing.expectEqual(@as(usize, 5), draw.countColor(&sfc, white)); } -test "drawText renders the lowercase legend letters (then/now)" { +test "drawText renders the lowercase glyphs (then/now legend + years axis)" { const alloc = testing.allocator; var sfc = try Surface.init(.image_surface_rgb, alloc, 64, 16); defer sfc.deinit(alloc); const white = [3]u8{ 0xFF, 0xFF, 0xFF }; - // "thenow" exercises all six lowercase glyphs; none may be blank. - drawText(&sfc, 1, 1, 1, white, "thenow"); + // "thenowy" exercises all seven lowercase glyphs; none may be blank. + drawText(&sfc, 1, 1, 1, white, "thenowy"); try testing.expect(draw.countColor(&sfc, white) > 30); }