stuff
This commit is contained in:
1 parent
1275e5a821
commit
ff9860023b
3 files changed
+50
-6
No files matched your search
@@ -157,7 +157,7 @@ func (s *server) handleIndex(w http.ResponseWriter, r *http.Request) {
|
|||||||
updatedLabel = updatedAt.Format("02.01.2006 15:04:05")
|
updatedLabel = updatedAt.Format("02.01.2006 15:04:05")
|
||||||
}
|
}
|
||||||
if err := page.Execute(w, map[string]any{
|
if err := page.Execute(w, map[string]any{
|
||||||
"Watts": watts,
|
"Watts": formatGermanNumber(watts),
|
||||||
"UpdatedAt": updatedLabel,
|
"UpdatedAt": updatedLabel,
|
||||||
"HistoryChart": buildHistoryChart(history, s.chartMax),
|
"HistoryChart": buildHistoryChart(history, s.chartMax),
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@@ -165,6 +165,34 @@ func (s *server) handleIndex(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func formatGermanNumber(n int) string {
|
||||||
|
s := strconv.Itoa(n)
|
||||||
|
if len(s) <= 3 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
neg := false
|
||||||
|
if s[0] == '-' {
|
||||||
|
neg = true
|
||||||
|
s = s[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
var b strings.Builder
|
||||||
|
if neg {
|
||||||
|
b.WriteByte('-')
|
||||||
|
}
|
||||||
|
rem := len(s) % 3
|
||||||
|
if rem == 0 {
|
||||||
|
rem = 3
|
||||||
|
}
|
||||||
|
b.WriteString(s[:rem])
|
||||||
|
for i := rem; i < len(s); i += 3 {
|
||||||
|
b.WriteByte('.')
|
||||||
|
b.WriteString(s[i : i+3])
|
||||||
|
}
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
func buildHistoryChart(history []sample, maxWatts int) template.HTML {
|
func buildHistoryChart(history []sample, maxWatts int) template.HTML {
|
||||||
const (
|
const (
|
||||||
width = 640
|
width = 640
|
||||||
@@ -242,8 +270,8 @@ func buildHistoryChart(history []sample, maxWatts int) template.HTML {
|
|||||||
fmt.Fprintf(&b, `<path d="M %.1f %.1f V %.1f"/>`, x1, yTop, yBottom)
|
fmt.Fprintf(&b, `<path d="M %.1f %.1f V %.1f"/>`, x1, yTop, yBottom)
|
||||||
b.WriteString(`</g>`)
|
b.WriteString(`</g>`)
|
||||||
b.WriteString(`<g fill="#64748b" font-size="12" font-family="system-ui, sans-serif">`)
|
b.WriteString(`<g fill="#64748b" font-size="12" font-family="system-ui, sans-serif">`)
|
||||||
fmt.Fprintf(&b, `<text x="%.1f" y="%d" text-anchor="end">%d W</text>`, x0-10, int(yTop)+14, maxV)
|
fmt.Fprintf(&b, `<text x="%.1f" y="%d" text-anchor="end">%s W</text>`, x0-10, int(yTop)+14, formatGermanNumber(maxV))
|
||||||
fmt.Fprintf(&b, `<text x="%.1f" y="%d" text-anchor="end">%d W</text>`, x0-10, int(yMid)+14, midV)
|
fmt.Fprintf(&b, `<text x="%.1f" y="%d" text-anchor="end">%s W</text>`, x0-10, int(yMid)+14, formatGermanNumber(midV))
|
||||||
fmt.Fprintf(&b, `<text x="%.1f" y="%d" text-anchor="end">0 W</text>`, x0-10, int(yBottom)+14)
|
fmt.Fprintf(&b, `<text x="%.1f" y="%d" text-anchor="end">0 W</text>`, x0-10, int(yBottom)+14)
|
||||||
fmt.Fprintf(&b, `<text x="%.1f" y="%d" text-anchor="middle">%s</text>`, x0, int(height)-10, start.Format("15:04"))
|
fmt.Fprintf(&b, `<text x="%.1f" y="%d" text-anchor="middle">%s</text>`, x0, int(height)-10, start.Format("15:04"))
|
||||||
fmt.Fprintf(&b, `<text x="%.1f" y="%d" text-anchor="middle">%s</text>`, x0+(plotW/2), int(height)-10, midT.Format("15:04"))
|
fmt.Fprintf(&b, `<text x="%.1f" y="%d" text-anchor="middle">%s</text>`, x0+(plotW/2), int(height)-10, midT.Format("15:04"))
|
||||||
|
|||||||
+18
-1
@@ -31,6 +31,23 @@ func TestHandleIndexRendersWatts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFormatGermanNumber(t *testing.T) {
|
||||||
|
tests := map[int]string{
|
||||||
|
0: "0",
|
||||||
|
12: "12",
|
||||||
|
999: "999",
|
||||||
|
1000: "1.000",
|
||||||
|
10000: "10.000",
|
||||||
|
1234567: "1.234.567",
|
||||||
|
-1000: "-1.000",
|
||||||
|
}
|
||||||
|
for input, want := range tests {
|
||||||
|
if got := formatGermanNumber(input); got != want {
|
||||||
|
t.Fatalf("formatGermanNumber(%d) = %q, want %q", input, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestHandleWriteRequiresSecret(t *testing.T) {
|
func TestHandleWriteRequiresSecret(t *testing.T) {
|
||||||
srv := &server{secret: "secret", store: &store{}}
|
srv := &server{secret: "secret", store: &store{}}
|
||||||
req := httptest.NewRequest(http.MethodPost, "/write", bytes.NewBufferString(`{"watts":456}`))
|
req := httptest.NewRequest(http.MethodPost, "/write", bytes.NewBufferString(`{"watts":456}`))
|
||||||
@@ -116,7 +133,7 @@ func TestBuildHistoryChartRendersPolyline(t *testing.T) {
|
|||||||
func TestBuildHistoryChartUsesConfiguredMax(t *testing.T) {
|
func TestBuildHistoryChartUsesConfiguredMax(t *testing.T) {
|
||||||
history := []sample{{at: time.Date(2026, 4, 20, 12, 0, 0, 0, time.UTC), value: 250}}
|
history := []sample{{at: time.Date(2026, 4, 20, 12, 0, 0, 0, time.UTC), value: 250}}
|
||||||
chart := buildHistoryChart(history, 1000)
|
chart := buildHistoryChart(history, 1000)
|
||||||
if !strings.Contains(string(chart), "1000 W") {
|
if !strings.Contains(string(chart), "1.000 W") {
|
||||||
t.Fatalf("chart did not include configured max: %s", string(chart))
|
t.Fatalf("chart did not include configured max: %s", string(chart))
|
||||||
}
|
}
|
||||||
if strings.Contains(string(chart), "250 W") {
|
if strings.Contains(string(chart), "250 W") {
|
||||||
|
|||||||
+1
-2
@@ -18,8 +18,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<main>
|
<main>
|
||||||
<div class="value">{{.Watts}}</div>
|
<div class="value">{{.Watts}} W</div>
|
||||||
<div class="unit">watts</div>
|
|
||||||
<div class="updated-at">Last updated: {{.UpdatedAt}}</div>
|
<div class="updated-at">Last updated: {{.UpdatedAt}}</div>
|
||||||
<div class="chart">{{.HistoryChart}}</div>
|
<div class="chart">{{.HistoryChart}}</div>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
Reference in new issue
Block a user