fix(kpi): reserve label headroom in monthly result bars so the endpoint value never clips (#2092)
The Resultat per manad pane scaled positive bars to 55% of the chart height with a fixed 62%-height baseline whenever any month was negative, leaving ~8px above the tallest bar: the value label drawn 5px above it rendered half outside the viewBox. A dominant negative month overflowed the bottom edge the same way. Replace the fixed baseline with one px-per-krona scale for both signs and place the baseline from the actual positive/negative maxima, with 16px reserved on any side that can carry the endpoint label. Claude-Session: https://claude.ai/code/session_01KtnsULW2jszA9uBnkMGnad Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -76,10 +76,17 @@ function ResultBarsPane({ report }: { report: KPIReport }) {
|
||||
|
||||
const W = 320
|
||||
const H = 120
|
||||
const maxAbs = Math.max(...months.map((m) => Math.abs(m.net)), 1)
|
||||
// Baseline sits lower when no month is negative, so positive bars get the room.
|
||||
const hasNegative = months.some((m) => m.net < 0)
|
||||
const baseline = hasNegative ? H * 0.62 : H - 4
|
||||
// Fixed headroom above (and below, when negatives exist) keeps the endpoint
|
||||
// label inside the viewBox even when a single month dominates the scale.
|
||||
const topPad = 16
|
||||
const bottomPad = hasNegative ? 16 : 4
|
||||
const maxPos = Math.max(...months.map((m) => Math.max(0, m.net)), 0)
|
||||
const maxNeg = Math.max(...months.map((m) => Math.max(0, -m.net)), 0)
|
||||
// One px-per-krona scale for both signs, so bar heights stay comparable.
|
||||
const pxPerKr = (H - topPad - bottomPad) / Math.max(maxPos + maxNeg, 1)
|
||||
// All-zero months keep the baseline at the bottom instead of the top.
|
||||
const baseline = maxPos + maxNeg === 0 ? H - bottomPad : topPad + maxPos * pxPerKr
|
||||
const slot = W / months.length
|
||||
const barW = Math.min(30, slot * 0.62)
|
||||
|
||||
@@ -95,7 +102,7 @@ function ResultBarsPane({ report }: { report: KPIReport }) {
|
||||
})}
|
||||
>
|
||||
{months.map((m, i) => {
|
||||
const scaled = (Math.abs(m.net) / maxAbs) * (hasNegative ? H * 0.55 : H - 26)
|
||||
const scaled = Math.abs(m.net) * pxPerKr
|
||||
const h = m.net === 0 ? 2 : Math.max(3, scaled)
|
||||
const x = i * slot + (slot - barW) / 2
|
||||
const y = m.net >= 0 ? baseline - h : baseline
|
||||
|
||||
Reference in New Issue
Block a user