aboutsummaryrefslogtreecommitdiffstats
path: root/widgets/hourly.lua
diff options
context:
space:
mode:
Diffstat (limited to 'widgets/hourly.lua')
-rw-r--r--widgets/hourly.lua93
1 files changed, 93 insertions, 0 deletions
diff --git a/widgets/hourly.lua b/widgets/hourly.lua
new file mode 100644
index 0000000..9566823
--- /dev/null
+++ b/widgets/hourly.lua
@@ -0,0 +1,93 @@
+-- Hourly: the next 24 hours as a temperature curve over rain-chance bars.
+--
+-- Adapted from the Conky-Mirage theme's hourly tile by alexsson-xexpanderx
+-- (see lib/weather.lua), redrawn in this repo's palette, glyphs and fonts.
+
+local card = require 'lib.card'
+local data = require 'lib.data'
+local weather = require 'lib.weather'
+
+local M = {}
+
+-- The band, top to bottom: glyph line, temperature line, curve, hour line.
+-- Every third hour is labelled; all 24 shape the curve.
+local function draw_curve(cr, x, y, w, h, colors, hours, S)
+ local n = #hours
+ local label = math.max(9, math.min(S * 0.30, h * 0.11))
+ local glyph = label * 1.5
+ local slot = w / n
+ local function px(i) return x + (i - 0.5) * slot end
+ local top = y + glyph + label * 1.6
+ local base = y + h - label * 1.6
+ if base - top < label * 2 then return end -- no room: no curve beats a broken one
+
+ local lo, hi = math.huge, -math.huge
+ for _, hr in ipairs(hours) do
+ if hr.temp then lo, hi = math.min(lo, hr.temp), math.max(hi, hr.temp) end
+ end
+ if lo > hi then return end
+ -- A flat day still needs a span to divide by; 1 degree keeps it mid-band.
+ local span = math.max(hi - lo, 1)
+ local function py(t) return base - (base - top) * (0.15 + 0.7 * (t - lo) / span) end
+
+ -- Rain chance as bars rising from the baseline, under the curve.
+ card.rgba(cr, colors.rule, 0.5)
+ for i, hr in ipairs(hours) do
+ if hr.precip and hr.precip > 0 then
+ local bh = (base - top) * 0.5 * hr.precip / 100
+ cairo_rectangle(cr, px(i) - slot * 0.3, base - bh, slot * 0.6, bh)
+ end
+ end
+ cairo_fill(cr)
+
+ card.rgba(cr, colors.rule, 0.6)
+ cairo_set_line_width(cr, 1)
+ cairo_move_to(cr, x, base)
+ cairo_line_to(cr, x + w, base)
+ cairo_stroke(cr)
+
+ -- The curve, broken where an hour has no temperature rather than bridged.
+ card.rgba(cr, colors.highlight)
+ cairo_set_line_width(cr, math.max(1.5, label * 0.15))
+ local pen = false
+ for i, hr in ipairs(hours) do
+ if hr.temp then
+ if pen then cairo_line_to(cr, px(i), py(hr.temp))
+ else cairo_move_to(cr, px(i), py(hr.temp)) end
+ pen = true
+ else
+ pen = false
+ end
+ end
+ cairo_stroke(cr)
+
+ for i = 1, n, 3 do
+ local hr = hours[i]
+ card.font(cr, card.FONT_MONO, glyph, false)
+ card.rgba(cr, colors.highlight)
+ card.text_centre(cr, px(i), y + glyph, weather.icon(hr.code, hr.is_day))
+ card.font(cr, card.FONT_MONO, label, false)
+ card.rgba(cr, colors.value)
+ card.text_centre(cr, px(i), y + glyph + label * 1.3, weather.deg(hr.temp))
+ card.rgba(cr, colors.label)
+ card.text_centre(cr, px(i), y + h - label * 0.2,
+ hr.t and os.date('%H', hr.t) or '--')
+ end
+end
+
+function M.draw(cr, rect, colors)
+ local inner = card.card(cr, rect, colors)
+ local w = weather.parse(data.slurp(weather.CACHE))
+ if not w then
+ card.notice(cr, inner, colors, 'NEXT 24H', 'no weather data', 'bin/weather-fetch.sh')
+ return
+ end
+ -- hours[1] is the current hour, so the big value is the one after it.
+ local y, S = card.standard(cr, inner, colors, {
+ icon = card.ICON.hourly, title = 'NEXT 24H',
+ big = weather.deg((w.hours[2] or {}).temp), share = 0.3,
+ })
+ draw_curve(cr, inner.x, y, inner.w, inner.y + inner.h - y, colors, w.hours, S)
+end
+
+return M