feat(charts): smooth CPU/RAM and Network curves using cubic Bézier splines (v1.4.0)

This commit is contained in:
sorcier committed 2026-11-04 09:40:33 +01:00
1 parent c5eb849095
commit 29ebedf2cb
4 files changed
+56 -20

No files matched your search

+1 -1
View File
@@ -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,
+50 -14
View File
@@ -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 clampY = (y) => Math.max(padTop, Math.min(baselineY, y));
// 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 points = 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 y = baselineY - (ratio * plotH);
return { x, y };
});
const ptsA = toPoints(seriesA);
const ptsB = toPoints(seriesB);
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`
};
}
const areaA = `0,${padTop + plotH} ` + ptsA.join(' ') + ` ${width},${padTop + plotH}`;
const areaB = `0,${padTop + plotH} ` + ptsB.join(' ') + ` ${width},${padTop + plotH}`;
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
<!-- Lignes de grille horizontales -->
<line x1="0" y1="${padTop}" x2="${width}" y2="${padTop}" stroke="#2c323f" stroke-dasharray="3,3" stroke-width="1"/>
<line x1="0" y1="${padTop + plotH / 2}" x2="${width}" y2="${padTop + plotH / 2}" stroke="#2c323f" stroke-dasharray="3,3" stroke-width="1"/>
<line x1="0" y1="${padTop + plotH}" x2="${width}" y2="${padTop + plotH}" stroke="#3d4657" stroke-width="1"/>
<line x1="0" y1="${baselineY}" x2="${width}" y2="${baselineY}" stroke="#3d4657" stroke-width="1"/>
<text x="6" y="${padTop + 10}" fill="#94a3b8" font-size="10" font-family="monospace">${Math.round(safeMax)} ${unitLabel}</text>
<text x="6" y="${padTop + plotH / 2 - 4}" fill="#64748b" font-size="10" font-family="monospace">${Math.round(safeMax / 2)} ${unitLabel}</text>
<!-- Courbe B -->
<polygon points="${areaB}" fill="url(#${gradIdB})"/>
<polyline fill="none" stroke="${colorB}" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" points="${ptsB.join(' ')}"/>
<!-- Courbe B lissée avec dégradé -->
<path d="${pathB.area}" fill="url(#${gradIdB})"/>
<path d="${pathB.line}" fill="none" stroke="${colorB}" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<!-- Courbe A -->
<polygon points="${areaA}" fill="url(#${gradIdA})"/>
<polyline fill="none" stroke="${colorA}" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" points="${ptsA.join(' ')}"/>
<!-- Courbe A lissée avec dégradé -->
<path d="${pathA.area}" fill="url(#${gradIdA})"/>
<path d="${pathA.line}" fill="none" stroke="${colorA}" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
`;
}
+1 -1
View File
@@ -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';
?>
<!DOCTYPE html>
<html lang="fr" class="h-full">
+4 -4
View File
@@ -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"
]
}