From 509723c197e09571e7563f64a2c76bf82ec53f05 Mon Sep 17 00:00:00 2001 From: OpenClaw Sub-agent Date: Sun, 2 Aug 2026 08:28:05 +1000 Subject: [PATCH] =?UTF-8?q?fix(invest):=20mobile=20chart=20=E2=80=94=20fix?= =?UTF-8?q?ed=20height,=20sane=20scales,=20horizontal=20x=20labels,=20comp?= =?UTF-8?q?act=20legend/points,=20Chinese=20help?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause of the squashed chart: canvas had a fixed height=90 attr and no container, so on narrow viewports Chart.js compressed everything — legend overlapped the plot, x labels tilted 45deg, y ticks degenerated (-1000% scale). Fix: relative h-72/h-80 container + maintainAspectRatio:false, grace 5%, maxTicksLimit, maxRotation:0, smaller points (r2/1.5), compact legend/tooltip, Chinese help text. --- invest/services.py | 4 +-- invest/templates/invest/dashboard.html | 38 ++++++++++++++++++++------ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/invest/services.py b/invest/services.py index 070f25b..36aa42e 100644 --- a/invest/services.py +++ b/invest/services.py @@ -746,8 +746,8 @@ def _line_dataset(label: str, data: list, color: str, dashed: bool = False, widt 'borderColor': color, 'backgroundColor': color, 'borderWidth': width, - 'pointRadius': 4 if not dashed else 3, - 'pointHoverRadius': 7 if not dashed else 5, + 'pointRadius': 2 if not dashed else 1.5, + 'pointHoverRadius': 4 if not dashed else 3, 'tension': 0.3, 'borderDash': [5, 5] if dashed else [], 'fill': False, diff --git a/invest/templates/invest/dashboard.html b/invest/templates/invest/dashboard.html index bd7c837..627dd42 100644 --- a/invest/templates/invest/dashboard.html +++ b/invest/templates/invest/dashboard.html @@ -125,7 +125,7 @@

{{ fy_label }} Performance vs Benchmarks

-

Toggle between percentage return and dollar-value growth from the baseline date.

+

切换涨跌幅百分比与金额两种视图。

@@ -142,7 +142,9 @@
- +
+ +
{% endif %} @@ -363,14 +365,32 @@ const unit = currentData().unit; return { responsive: true, + maintainAspectRatio: false, interaction: { mode: 'index', intersect: false }, plugins: { - legend: { position: 'top', align: 'start', labels: { usePointStyle: true, pointStyle: 'rect', pointStyleWidth: 14, padding: 20, font: { size: 12, weight: '600' } } }, - tooltip: { callbacks: { label: function (ctx) { const v = ctx.parsed.y; if (v === null || v === undefined) return ctx.dataset.label + ': —'; return ctx.dataset.label + ': ' + (unit === 'currency' ? formatCurrency(v) : formatPercent(v)); } } }, + legend: { + position: 'top', + align: 'start', + labels: { usePointStyle: true, pointStyle: 'rect', pointStyleWidth: 10, padding: 10, boxWidth: 10, font: { size: 11, weight: '600' } }, + }, + tooltip: { + position: 'nearest', + padding: 8, + titleFont: { size: 11 }, + bodyFont: { size: 10 }, + callbacks: { label: function (ctx) { const v = ctx.parsed.y; if (v === null || v === undefined) return ctx.dataset.label + ': —'; return ctx.dataset.label + ': ' + (unit === 'currency' ? formatCurrency(v) : formatPercent(v)); } }, + }, }, scales: { - y: { ticks: { callback: function (v) { return unit === 'currency' ? formatCurrency(Number(v)) : formatPercent(Number(v)); }, font: { size: 11 } }, grid: { color: '#f5f5f4' } }, - x: { grid: { display: false }, ticks: { font: { size: 11 } } }, + y: { + grace: '5%', + ticks: { maxTicksLimit: 6, callback: function (v) { return unit === 'currency' ? formatCurrency(Number(v)) : formatPercent(Number(v)); }, font: { size: 10 } }, + grid: { color: '#f5f5f4' }, + }, + x: { + grid: { display: false }, + ticks: { autoSkip: true, maxRotation: 0, maxTicksLimit: 8, font: { size: 10 } }, + }, }, }; } @@ -386,10 +406,10 @@ chart.options = chartOptions(); chart.update(); if (help) { - const baseline = currentData().baseline || 'the baseline date'; + const baseline = currentData().baseline || '基准日'; help.textContent = currentMode === 'value' - ? `Dollar mode: actual total portfolio value vs SPY/QQQ benchmark value from ${baseline}.` - : `Percentage mode: growth/decline since ${baseline}; cash-flow-adjusted metrics are shown in the cards above.`; + ? `金额视图:组合总市值 vs SPY/QQQ 基准(自 ${baseline})` + : `涨跌幅视图:自 ${baseline} 以来的涨跌幅;卡片上方为现金流调整指标`; } }