diff --git a/app/system/resources/dashboard/system_cpu_status.php b/app/system/resources/dashboard/system_cpu_status.php index 1e107573e4..ee6c35bea7 100644 --- a/app/system/resources/dashboard/system_cpu_status.php +++ b/app/system/resources/dashboard/system_cpu_status.php @@ -137,8 +137,9 @@ let cpu_history = Array.from({ length: num_cores }, () => new Array(max_points).fill(null)); let cpu_index = 0; - // Color palette (distinct and visually stacked) - const cpu_colors = ['#00bcd4', '#8bc34a', '#ffc107', '#e91e63']; + // Color palette (expandable for any number of cores) + const base_colors = ['#00bcd4', '#8bc34a', '#ffc107', '#e91e63', '#9c27b0', '#ff5722', '#607d8b', '#795548']; + const cpu_colors = Array.from({ length: num_cores }, (_, i) => base_colors[i % base_colors.length]); window.system_cpu_status_chart = new Chart( document.getElementById('system_cpu_status_chart').getContext('2d'), @@ -149,19 +150,25 @@ label: `CPU ${i}`, data: [], fill: true, - borderColor: cpu_colors[i % cpu_colors.length], - backgroundColor: (cpu_colors[i % cpu_colors.length]) + '33', // light fill + borderColor: cpu_colors[i], + backgroundColor: cpu_colors[i] + '33', // light fill tension: 0.3, pointRadius: 0, + pointHoverRadius: 4, + pointHoverBackgroundColor: cpu_colors[i], + pointHoverBorderColor: '#fff', + pointHoverBorderWidth: 2, spanGaps: true, - // enable stacking - stack: 'cpu', })) }, options: { animation: false, parsing: { xAxisKey: 'x', yAxisKey: 'y' }, maintainAspectRatio: false, + interaction: { + mode: 'index', + intersect: false + }, scales: { x: { type: 'realtime', @@ -174,25 +181,30 @@ ticks: { display: false }, title: { display: false } }, - y: { - beginAtZero: true, - stacked: true, - min: 0, - max: num_cores * 100, - ticks: { - stepSize: 100, - autoSkip: true, - callback: (v) => v + '%' - } + y: { + beginAtZero: true, + stacked: false, + min: 0, + max: 100, + ticks: { + stepSize: 25, + autoSkip: true, + callback: (v) => v + '%' } + } }, plugins: { legend: { display: false }, tooltip: { + enabled: true, mode: 'index', intersect: false, callbacks: { - label: (ctx) => `${ctx.dataset.label}: ${Math.round(ctx.parsed.y)}%` + label: (ctx) => { + const value = ctx.parsed.y; + if (value === null || value === undefined) return null; + return `${ctx.dataset.label}: ${Math.round(value)}%`; + } } }, } @@ -200,6 +212,13 @@ } ); + // Fix for chartjs-plugin-streaming tooltip compatibility issue + // The plugin tries to access tooltip._chart which doesn't exist in Chart.js v3+ + // We need to provide the chart reference to the tooltip + if (window.system_cpu_status_chart.tooltip) { + window.system_cpu_status_chart.tooltip._chart = window.system_cpu_status_chart; + } + connect_cpu_status_websocket(); @@ -273,7 +292,7 @@ // Update the row data const td_cpu_status = document.getElementById('td_system_cpu_status_chart'); if (!td_cpu_status) { return; } - td_cpu_status.textContent = `${payload.cpu_status}%`; + td_cpu_status.textContent = `${cpu_status}%`; } window.system_cpu_status_chart = new Chart( diff --git a/app/system/resources/dashboard/system_network_status.php b/app/system/resources/dashboard/system_network_status.php index feae693d97..6b50827a90 100644 --- a/app/system/resources/dashboard/system_network_status.php +++ b/app/system/resources/dashboard/system_network_status.php @@ -90,8 +90,8 @@ echo "\n"; const rxColor = dashboard_network_usage_chart_main_color[0]; const txColor = dashboard_network_usage_chart_main_color[1]; - // IMPORTANT: assign to window.system_network_status_chart - window.system_network_status_chart = new Chart(ctx, { + // IMPORTANT: assign to window.system_network_status_chart so that it is globally accessible + const chartConfig = { type: 'line', data: { datasets: [ @@ -102,6 +102,10 @@ echo "\n"; fill: true, tension: 0.3, pointRadius: 0, + pointHoverRadius: 4, + pointHoverBackgroundColor: rxColor, + pointHoverBorderColor: '#fff', + pointHoverBorderWidth: 2, spanGaps: true, data: [] }, @@ -112,16 +116,23 @@ echo "\n"; fill: true, tension: 0.3, pointRadius: 0, + pointHoverRadius: 4, + pointHoverBackgroundColor: txColor, + pointHoverBorderColor: '#fff', + pointHoverBorderWidth: 2, spanGaps: true, data: [] } ] }, options: { - // streaming usually looks best with animation off; tweak if you like a tiny slide animation: false, parsing: { xAxisKey: 'x', yAxisKey: 'y' }, maintainAspectRatio: false, + interaction: { + mode: 'index', + intersect: false + }, scales: { x: { type: 'realtime', @@ -129,7 +140,6 @@ echo "\n"; duration: 60000, // last 60s refresh: 1000, // redraw every 1s delay: 2000 // 2s render delay to handle late packets - // (no onRefresh: we push from your websocket callback) }, grid: {drawOnChartArea: false}, ticks: {display: false}, @@ -143,13 +153,22 @@ echo "\n"; plugins: { legend: {display: false}, tooltip: { + enabled: true, mode: 'index', intersect: false, - callbacks: {label: (ctx) => `${ctx.dataset.label}: ${format_bitrate(ctx.parsed.y)}`} + callbacks: { + label: (ctx) => `${ctx.dataset.label}: ${format_bitrate(ctx.parsed.y)}` + } } } } - }); + }; + + window.system_network_status_chart = new Chart(ctx, chartConfig); + + if (window.system_network_status_chart.tooltip) { + window.system_network_status_chart.tooltip._chart = window.system_network_status_chart; + } function update_network_chart(payload) { const chart = window.system_network_status_chart;