mirror of
https://github.com/we-promise/sure.git
synced 2026-05-29 23:39:03 +00:00
fix(goals/funding-widget): switch sparkline to bars + shared scale
The shared-scale fix alone wasn't enough — a single outlier bucket on one account compressed every other row to invisibility, and the interpolated line between sparse non-zero buckets painted fake "event triangles" between actual data points. Switch from a stroked path to per-bucket bars: - 12 rects per row, x = `i * 8 + 1`, width 6, 2px gap between. - Bar height = `(value / shared_max) * 24`, floored at 1 unit so a non-zero bucket is always visible even when an outlier elsewhere dominates the scale. - Empty buckets render nothing — no fake baseline, no interpolated trough. - Bars grounded at `y = 28` (bottom of viewBox), so "zero" is implicit and the eye reads upward from a stable floor. - Shared `spark_max` across every account's bars (the component method introduced for the line version stays — that part of the diagnosis was right, it just needed a chart type that handled the scale honestly). Net read: the column-chart-on-each-row layout matches "12 weeks of deposits into this account" much more directly than a sparkline ever did, and outlier-vs-modest-but-steady contributions are both legible at a glance.
This commit is contained in:
@@ -39,7 +39,7 @@
|
||||
<% account = row[:account] %>
|
||||
<% color = Goals::AvatarComponent.color_for(account.name) %>
|
||||
<% spark = row[:sparkline_points] %>
|
||||
<% spark_max = [ spark.max, 1.0 ].max %>
|
||||
<% spark_max = shared_spark_max %>
|
||||
<div class="px-4 py-3 grid grid-cols-[24px_minmax(0,1.5fr)_72px_minmax(60px,1fr)_96px] items-center gap-3">
|
||||
<%= render Goals::AvatarComponent.new(name: account.name, color: color, size: "sm") %>
|
||||
|
||||
@@ -57,10 +57,12 @@
|
||||
<% end %>
|
||||
|
||||
<svg viewBox="0 0 <%= spark.size * 8 %> 28" preserveAspectRatio="none" class="w-full h-7" aria-hidden="true">
|
||||
<% xs = spark.each_with_index.map { |_, i| 2 + (i / (spark.size - 1).to_f) * (spark.size * 8 - 4) } %>
|
||||
<% ys = spark.map { |v| 24 - (v / spark_max) * 20 } %>
|
||||
<% path = xs.zip(ys).each_with_index.map { |(x, y), i| "#{i.zero? ? "M" : "L"} #{x.round(2)} #{y.round(2)}" }.join(" ") %>
|
||||
<path d="<%= path %>" fill="none" stroke="<%= color %>" stroke-width="1.5" stroke-linejoin="round" />
|
||||
<% spark.each_with_index do |v, i| %>
|
||||
<% next if v.to_f.zero? %>
|
||||
<% raw_h = (v.to_f / spark_max) * 24 %>
|
||||
<% bar_h = [ raw_h, 1.0 ].max %>
|
||||
<rect x="<%= i * 8 + 1 %>" y="<%= (28 - bar_h).round(2) %>" width="6" height="<%= bar_h.round(2) %>" fill="<%= color %>" rx="0.5" />
|
||||
<% end %>
|
||||
</svg>
|
||||
|
||||
<div class="text-right">
|
||||
|
||||
@@ -29,6 +29,18 @@ class Goals::FundingAccountsBreakdownComponent < ApplicationComponent
|
||||
((balance.to_d / total) * 100).round
|
||||
end
|
||||
|
||||
# Shared Y-max across every account's sparkline so per-row amplitudes
|
||||
# are comparable at a glance. Without this each row scaled to its own
|
||||
# max and a $50 bump on an orange account rendered as tall as a $400
|
||||
# weekly peak on a pink one — the eye reads them as equal contribution
|
||||
# when the weight pills already say they aren't.
|
||||
def shared_spark_max
|
||||
@shared_spark_max ||= begin
|
||||
points = rows.flat_map { |r| r[:sparkline_points] }
|
||||
[ points.max.to_f, 1.0 ].max
|
||||
end
|
||||
end
|
||||
|
||||
# Label shown beneath the account name. Prefers the depository subtype
|
||||
# ("Savings", "HSA"…) over the bare accountable_type ("Depository") so the
|
||||
# subline carries useful signal. Falls back to the accountable type's i18n
|
||||
|
||||
Reference in New Issue
Block a user