feat: E1002 六色版改为 k=1 原字号重排版+启用黄绿蓝语义色并恢复 30 天趋势图

- 放弃 k=2 整数倍放大(字太大),字号与 400×300 三色版一致,靠四倍面积重排:顶部时钟/天气不变,中段 Claude Usage 与橘喵今日实时左右并排,下段全宽恢复三色版隐藏的 30 天趋势图
- 六色各有唯一语义:红=预警/涨/定位/太阳闪电/流水线,黄=用量「注意」档填充(USAGE_CAUTION,默认 60,仅六色版),绿=毛利线,蓝=单量线与雨滴雪花
- renderer 基类新增 _usage_colors 配色钩子与 _weather_icon 的 wet 参数、_section 支持自定义横向范围,三色版行为不变
- data 为趋势追加 totals 合计(现算不进缓存),usage 增加 caution 阈值
- 底部六色测试色条改由 E1002_COLOR_STRIP 控制,默认关闭;同步更新 CLAUDE.md

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-10 14:11:35 +08:00
parent eab90bf3b5
commit d7ae193f56
5 changed files with 184 additions and 86 deletions

View File

@@ -110,15 +110,18 @@ class DashboardRenderer:
self.tri(x + trw / 2, y + 8.5 * k, 7 * k, up=up, fill=val_color); x += trw + tgap
self.text(x, y, val, self.F12, fill=val_color)
def _label(self, y, title, right=None):
def _label(self, y, title, right=None, x0=None, x1=None):
"""区块标题(两区块统一,对齐主分支 _title_bar 风格):
■ 方块装饰(8px与 F12 标题墨迹竖直居中) + 标题(F12,常规字重) + 可选右侧信息。"""
■ 方块装饰(8px与 F12 标题墨迹竖直居中) + 标题(F12,常规字重) + 可选右侧信息。
x0/x1标题起点 / 右侧信息右端,默认为页边距 10宽版并排两块时可各自指定"""
k = self.k
SQ, M = 8 * k, 10 * k # 方块边长 / 左右页边距
self.d.rectangle([M, y + 4 * k, M + SQ, y + 4 * k + SQ], fill=BLACK) # 中心≈y+8对齐 F12 墨迹中心(≈y+8.5)
self.text(M + SQ + 6 * k, y, title, self.F12)
x0 = M if x0 is None else x0
x1 = self.W - M if x1 is None else x1
self.d.rectangle([x0, y + 4 * k, x0 + SQ, y + 4 * k + SQ], fill=BLACK) # 中心≈y+8对齐 F12 墨迹中心(≈y+8.5)
self.text(x0 + SQ + 6 * k, y, title, self.F12)
if right:
self.rtext(self.W - M, y, right, self.F12)
self.rtext(x1, y, right, self.F12)
def _mid(self, x, cy, s, ft, fill=BLACK, bold=0, align="l", track=0):
"""按字符串「墨迹竖直中心」对齐到 cy 绘制——跨字号(F12/F24)也能真正居中,
@@ -154,7 +157,7 @@ class DashboardRenderer:
raw = bar.get("pct")
ok = isinstance(raw, (int, float)) # None/缺失 → 显示 "--"
pct = max(0, min(100, int(raw))) if ok else 0
color = RED if (ok and pct >= warn) else BLACK
fill, outline, color = self._usage_colors(ok, pct, warn, bar)
k = self.k
LABEL_W, G1, G2, H = 26 * k, 13 * k, 8 * k, 15 * k # G1 进度条↔百分比、G2 百分比↔pace视觉约 12/11
PCT_TRACK = 2 * k # F16(16/12x 非整数倍缩放)数字墨迹无侧边距、紧贴,手动加字符间距
@@ -170,10 +173,15 @@ class DashboardRenderer:
bx0 = x0 + LABEL_W
bx1 = pct_r - self._tw(pct_txt, self.F16, PCT_TRACK) - G1
by = cy - H // 2
self.d.rectangle([bx0, by, bx1, by + H], outline=color, width=k) # 轨道边框随条色
self.d.rectangle([bx0, by, bx1, by + H], outline=outline, width=k) # 轨道边框随条色
fw = (bx1 - bx0) * pct / 100.0
if fw >= 2:
self.d.rectangle([bx0, by, bx0 + fw, by + H], fill=color)
self.d.rectangle([bx0, by, bx0 + fw, by + H], fill=fill)
def _usage_colors(self, ok, pct, warn, bar):
"""用量行配色钩子 → 进度条填充轨道边框百分比文字。三色版≥warn 整体红,否则黑。"""
c = RED if (ok and pct >= warn) else BLACK
return c, c, c
def _loc_pin(self, x, y, w=8, fg=BLACK, bg=WHITE):
"""定位图标:实心水滴(圆头+尖尾) + 白色挖孔1-bit 下轮廓清晰。
@@ -232,11 +240,13 @@ class DashboardRenderer:
self.d.arc([x + S(12), cy - S(10), x + S(36), cy + S(14)], 270, 90, fill=fg, width=2)
self.d.line([x + S(9), cy + S(13), x + S(29), cy + S(13)], fill=fg, width=2)
def _weather_icon(self, x, y, category, s=1.0, fg=BLACK, bg=WHITE, accent=None):
def _weather_icon(self, x, y, category, s=1.0, fg=BLACK, bg=WHITE, accent=None, wet=None):
"""按天气类别画图标s 为缩放系数,原生约 36x38左上角 x,y
accent 用于「有能量」的元素——太阳、闪电——着红;云/雨/雪/雾/月保持 fg(黑)。"""
accent 用于「有能量」的元素——太阳、闪电——着红;wet 用于雨滴/雪花(六色版给蓝),默认随 fg
云/雾/月保持 fg"""
S = lambda v: v * s
accent = accent or fg
wet = wet or fg
if category == "sunny":
self._sun(x + S(18), y + S(19), S(11), s, accent)
@@ -269,14 +279,14 @@ class DashboardRenderer:
self._cloud(x, y + S(15), s, fg, bg)
if category == "rain":
for dx in (9, 18, 27):
self.d.line([x + S(dx) + S(3), cb + S(3), x + S(dx) - S(1), cb + S(10)], fill=fg, width=2)
self.d.line([x + S(dx) + S(3), cb + S(3), x + S(dx) - S(1), cb + S(10)], fill=wet, width=2)
elif category == "snow":
for dx in (10, 19, 28):
fx, fy, rr = x + S(dx), cb + S(7), S(4)
for a in (0, 60, 120):
rad = math.radians(a)
self.d.line([fx - math.cos(rad) * rr, fy - math.sin(rad) * rr,
fx + math.cos(rad) * rr, fy + math.sin(rad) * rr], fill=fg, width=1)
fx + math.cos(rad) * rr, fy + math.sin(rad) * rr], fill=wet, width=1)
elif category == "thunder":
bx = x + S(18)
self.d.polygon([(bx - S(1), cb + S(2)), (bx + S(5), cb + S(2)), (bx + S(1), cb + S(8)),