mirror of
https://github.com/tiennm99/ghstats.git
synced 2026-06-03 18:13:27 +00:00
fix(card): make heatmap cells 3× taller — width was tight, height had room (#21)
Cells were 4 × 4 with 1 px gap: the grid used 35 of 140 available vertical pixels (25 %) and ~80 px of dead space below. Widening the cells isn't an option — 53 weeks already consume every horizontal pixel past the weekday-label gutter. So stretch vertically instead: cellW = 4 (unchanged) cellH = 12 cellGap = 1 Grid footprint is now 265 × 91 px inside a 340 × 200 frame, with a 32 px gap below the grid for the legend. Each weekday reads as a distinct horizontal band instead of a cramped postage-stamp row. Legend keeps 8 × 8 SQUARE swatches so the "Less ▢▢▢▢▢ More" row is still recognisable as an intensity legend rather than a stretched echo of the data cells. Label baseline offset switches from `cellSize - 1` to `cellH - 3` so "Mon"/"Wed"/"Fri" sit visually centred in the taller rows.
This commit is contained in:
@@ -78,7 +78,8 @@ When there's **exactly one slice** (one language at 100%), the renderer emits tw
|
||||
| Metric | Value |
|
||||
| --- | --- |
|
||||
| Grid | 7 rows × 53 columns (Sunday → Saturday, oldest week → newest) |
|
||||
| Cell size | 4 × 4 px, 1 px gap. Grid footprint = `53 × 5 = 265 px`; `leftPad(30) + 265 = 295 px`, leaving a 45 px right gutter so the grid doesn't bleed into the frame border |
|
||||
| Cell size | 4 wide × 12 tall, 1 px gap. Width is constrained (`leftPad 30 + 53 × 5 = 295 px`, 45 px right gutter); height has headroom so cells are rectangular — makes each weekday row a distinct horizontal band instead of a postage-stamp blur |
|
||||
| Grid y-range | `topPad(62) .. 62 + 7 × 13 = 153 px`; 32 px gap to the legend at y ≈ 185 |
|
||||
| Cell colour | 5-bucket ramp `mixHex(Background, Accent, k/4)` for `k ∈ 0..4` — no dedicated ramp field on the theme schema |
|
||||
| Weekday labels | Mon / Wed / Fri only, right-anchored in the `leftPad` gutter |
|
||||
| Month labels | Printed above the first week where a 1st-of-month day falls; skipped when `x > width − 20` so `Dec` / `Apr` can't spill past the frame |
|
||||
|
||||
@@ -22,17 +22,26 @@ func (contributionsHeatmapCard) SVG(p *github.Profile, t theme.Theme) ([]byte, e
|
||||
// theme.Accent in four intensity buckets so every palette inherits a usable
|
||||
// heatmap without a separate color ramp in the theme schema.
|
||||
//
|
||||
// Geometry: 4 px cells + 1 px gap = 5 px per week column × 53 weeks = 265 px.
|
||||
// Left pad 30 (weekday labels), right pad 45 — both well clear of the frame
|
||||
// so the grid doesn't read as "bleeding" off the card.
|
||||
// Cells are intentionally rectangular: width is constrained by 53 weeks
|
||||
// fitting in 340 − leftPad − rightPad, but height has lots of spare card
|
||||
// real estate, so we make cells ~3× taller than wide. That turns the grid
|
||||
// into distinct horizontal bands instead of a cramped postage-stamp.
|
||||
//
|
||||
// Geometry:
|
||||
//
|
||||
// width per column = cellW + cellGap = 4 + 1 = 5 px → 53 * 5 = 265 px
|
||||
// leftPad 30 + 265 = 295 px grid right edge, 45 px right gutter
|
||||
// height per row = cellH + cellGap = 12 + 1 = 13 px → 7 * 13 = 91 px
|
||||
// grid y-range: 62 .. 153 (leaves 32 px gap to the legend at y ≈ 185)
|
||||
func renderHeatmap(title string, days []github.DailyContribution, t theme.Theme) []byte {
|
||||
const (
|
||||
width = 340
|
||||
height = 200
|
||||
cellSize = 4
|
||||
cellGap = 1
|
||||
leftPad = 30
|
||||
topPad = 62
|
||||
width = 340
|
||||
height = 200
|
||||
cellW = 4
|
||||
cellH = 12
|
||||
cellGap = 1
|
||||
leftPad = 30
|
||||
topPad = 62
|
||||
)
|
||||
|
||||
var b strings.Builder
|
||||
@@ -65,7 +74,7 @@ func renderHeatmap(title string, days []github.DailyContribution, t theme.Theme)
|
||||
if label == "" {
|
||||
continue
|
||||
}
|
||||
y := topPad + i*(cellSize+cellGap) + cellSize - 1
|
||||
y := topPad + i*(cellH+cellGap) + cellH - 3
|
||||
fmt.Fprintf(&b, `
|
||||
<text x="%d" y="%d" font-size="9" fill="%s" text-anchor="end">%s</text>`,
|
||||
leftPad-4, y, t.Muted, label)
|
||||
@@ -86,7 +95,7 @@ func renderHeatmap(title string, days []github.DailyContribution, t theme.Theme)
|
||||
continue
|
||||
}
|
||||
lastMonth = first.Month()
|
||||
x := leftPad + w*(cellSize+cellGap)
|
||||
x := leftPad + w*(cellW+cellGap)
|
||||
if x > monthLabelMaxX {
|
||||
continue
|
||||
}
|
||||
@@ -103,28 +112,31 @@ func renderHeatmap(title string, days []github.DailyContribution, t theme.Theme)
|
||||
continue // padding slot before the first real day
|
||||
}
|
||||
fill := ramp[bucketFor(cell.Count, buckets)]
|
||||
x := leftPad + w*(cellSize+cellGap)
|
||||
y := topPad + d*(cellSize+cellGap)
|
||||
x := leftPad + w*(cellW+cellGap)
|
||||
y := topPad + d*(cellH+cellGap)
|
||||
fmt.Fprintf(&b, `
|
||||
<rect x="%d" y="%d" width="%d" height="%d" rx="2" fill="%s"><title>%s — %d</title></rect>`,
|
||||
x, y, cellSize, cellSize, fill,
|
||||
<rect x="%d" y="%d" width="%d" height="%d" rx="1.5" fill="%s"><title>%s — %d</title></rect>`,
|
||||
x, y, cellW, cellH, fill,
|
||||
cell.Date.Format("2006-01-02"), cell.Count)
|
||||
}
|
||||
}
|
||||
|
||||
// Legend: "Less ▢▢▢▢▢ More" at bottom right.
|
||||
// Legend at the bottom right uses square swatches so "Less ▢▢▢▢▢ More"
|
||||
// reads as a classic intensity legend rather than a stretched echo of the
|
||||
// rectangular data cells.
|
||||
const legendCell = 8
|
||||
legendX := width - 110
|
||||
legendY := height - 15
|
||||
fmt.Fprintf(&b, `
|
||||
<text x="%d" y="%d" font-size="9" fill="%s">Less</text>`, legendX, legendY, t.Muted)
|
||||
for i, c := range ramp {
|
||||
fmt.Fprintf(&b, `
|
||||
<rect x="%d" y="%d" width="%d" height="%d" rx="2" fill="%s"/>`,
|
||||
legendX+28+i*(cellSize+2), legendY-cellSize+2, cellSize, cellSize, c)
|
||||
<rect x="%d" y="%d" width="%d" height="%d" rx="1.5" fill="%s"/>`,
|
||||
legendX+28+i*(legendCell+2), legendY-legendCell+2, legendCell, legendCell, c)
|
||||
}
|
||||
fmt.Fprintf(&b, `
|
||||
<text x="%d" y="%d" font-size="9" fill="%s">More</text>`,
|
||||
legendX+28+5*(cellSize+2)+2, legendY, t.Muted)
|
||||
legendX+28+5*(legendCell+2)+2, legendY, t.Muted)
|
||||
|
||||
b.WriteString(footer)
|
||||
return []byte(b.String())
|
||||
|
||||
Reference in New Issue
Block a user