From 0948a8da244422200938d36c48ffc1bc6159b10e Mon Sep 17 00:00:00 2001 From: sorcier Date: Wed, 4 Nov 2026 09:40:33 +0100 Subject: [PATCH] =?UTF-8?q?feat(charts):=20smooth=20CPU/RAM=20and=20Networ?= =?UTF-8?q?k=20curves=20using=20cubic=20B=C3=A9zier=20splines=20(v1.4.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/api.php | 2 +- public/assets/app.js | 70 +++++++++++++++++++++++++++++++++----------- public/index.php | 2 +- version.json | 8 ++--- 4 files changed, 59 insertions(+), 23 deletions(-) diff --git a/public/api.php b/public/api.php index 0c93022..6da77a6 100644 --- a/public/api.php +++ b/public/api.php @@ -140,7 +140,7 @@ try { $installedVerData = file_exists("{$appDir}/version.json") ? json_decode((string)file_get_contents("{$appDir}/version.json"), true) : []; - $installedVer = $installedVerData['version'] ?? '1.3.9'; + $installedVer = $installedVerData['version'] ?? '1.4.0'; echo json_encode([ 'success' => true, diff --git a/public/assets/app.js b/public/assets/app.js index bb03d66..f903a1d 100644 --- a/public/assets/app.js +++ b/public/assets/app.js @@ -629,20 +629,56 @@ function drawDualAreaChart(svgId, seriesA, seriesB, maxVal, colorA, colorB, unit const padTop = 14; const padBottom = 18; const plotH = height - padTop - padBottom; + const baselineY = padTop + plotH; const safeMax = maxVal > 0 ? maxVal : 100; - const toPoints = (arr) => arr.map((val, idx) => { - const x = (idx / (arr.length - 1)) * width; - const ratio = Math.max(0, Math.min(1, val / safeMax)); - const y = padTop + plotH - (ratio * plotH); - return `${x.toFixed(1)},${y.toFixed(1)}`; - }); + const clampY = (y) => Math.max(padTop, Math.min(baselineY, y)); - const ptsA = toPoints(seriesA); - const ptsB = toPoints(seriesB); + // Génération de courbes splines adoucies (Catmull-Rom / Bézier cubique) pour éliminer les angles pointus + const computeSmoothPaths = (arr, tension = 0.2) => { + if (!arr || arr.length === 0) return { line: '', area: '' }; - const areaA = `0,${padTop + plotH} ` + ptsA.join(' ') + ` ${width},${padTop + plotH}`; - const areaB = `0,${padTop + plotH} ` + ptsB.join(' ') + ` ${width},${padTop + plotH}`; + const points = arr.map((val, idx) => { + const x = (idx / (arr.length - 1)) * width; + const ratio = Math.max(0, Math.min(1, val / safeMax)); + const y = baselineY - (ratio * plotH); + return { x, y }; + }); + + if (points.length === 1) { + return { + line: `M ${points[0].x.toFixed(1)},${points[0].y.toFixed(1)}`, + area: `M 0,${baselineY} L ${points[0].x.toFixed(1)},${points[0].y.toFixed(1)} L ${width},${baselineY} Z` + }; + } + + let line = `M ${points[0].x.toFixed(1)},${points[0].y.toFixed(1)}`; + + for (let i = 0; i < points.length - 1; i++) { + const p0 = points[i === 0 ? i : i - 1]; + const p1 = points[i]; + const p2 = points[i + 1]; + const p3 = points[i + 2 < points.length ? i + 2 : i + 1]; + + let cp1x = p1.x + (p2.x - p0.x) * tension; + let cp1y = p1.y + (p2.y - p0.y) * tension; + + let cp2x = p2.x - (p3.x - p1.x) * tension; + let cp2y = p2.y - (p3.y - p1.y) * tension; + + // Clamping vertical pour garantir que la courbe ne déborde pas sous l'axe ni au-dessus du max + cp1y = clampY(cp1y); + cp2y = clampY(cp2y); + + line += ` C ${cp1x.toFixed(1)},${cp1y.toFixed(1)} ${cp2x.toFixed(1)},${cp2y.toFixed(1)} ${p2.x.toFixed(1)},${p2.y.toFixed(1)}`; + } + + const area = `${line} L ${width},${baselineY} L 0,${baselineY} Z`; + return { line, area }; + }; + + const pathA = computeSmoothPaths(seriesA); + const pathB = computeSmoothPaths(seriesB); const gradIdA = `${svgId}-grad-a`; const gradIdB = `${svgId}-grad-b`; @@ -662,18 +698,18 @@ function drawDualAreaChart(svgId, seriesA, seriesB, maxVal, colorA, colorB, unit - + ${Math.round(safeMax)} ${unitLabel} ${Math.round(safeMax / 2)} ${unitLabel} - - - + + + - - - + + + `; } diff --git a/public/index.php b/public/index.php index 8a77a39..5b7c3b8 100644 --- a/public/index.php +++ b/public/index.php @@ -12,7 +12,7 @@ $isAuth = Auth::isAuthenticated(); $currentUser = Auth::getUsername(); $appVerData = file_exists(__DIR__ . '/../version.json') ? json_decode((string)file_get_contents(__DIR__ . '/../version.json'), true) : []; -$appVersion = $appVerData['version'] ?? '1.3.9'; +$appVersion = $appVerData['version'] ?? '1.4.0'; ?> diff --git a/version.json b/version.json index f6a8455..0cc6f21 100644 --- a/version.json +++ b/version.json @@ -1,12 +1,12 @@ { - "version": "1.3.9", + "version": "1.4.0", "codename": "Helios", "release_date": "2026-11-04", "min_php_version": "8.2", "changelog": [ + "Lissage élégant des graphiques CPU/RAM et Réseau (splines Bézier cubiques sans angles vifs)", + "Amélioration des transitions et gradients dynamiques sur les graphiques du tableau de bord", "Mise à jour instantanée du numéro de version sur tous les badges sans aucun délai de cache navigateur", - "Invalidation automatique du cache local et rechargement propre anti-cache après chaque mise à jour", - "Affichage serveur natif du numéro de version installée directement dans le HTML généré", - "Suppression définitive de l'indication des identifiants et mot de passe par défaut sur l'écran de connexion" + "Invalidation automatique du cache local et rechargement propre anti-cache après chaque mise à jour" ] }