tiffank1802
Add Dang Van and Thermal Diffusion apps
9f20e46
import { useEffect, useRef } from 'react';
export default function DangVanChart({ result }) {
const canvasRef = useRef(null);
useEffect(() => {
if (!result || !canvasRef.current) return;
const canvas = canvasRef.current;
const ctx = canvas.getContext('2d');
const { width, height } = canvas;
// Clear
ctx.fillStyle = '#1a1a2e';
ctx.fillRect(0, 0, width, height);
const padding = { left: 70, right: 40, top: 40, bottom: 60 };
const plotWidth = width - padding.left - padding.right;
const plotHeight = height - padding.top - padding.bottom;
// Calculer les bornes
const points = result.points || [];
const sigmaHValues = points.map(p => p.sigma_H);
const tauValues = points.map(p => p.tau_max);
// Inclure la ligne de critère dans les bornes
const criterionLine = result.criterion_line || [];
const allSigmaH = [...sigmaHValues, ...criterionLine.map(p => p.sigma_H)];
const allTau = [...tauValues, ...criterionLine.map(p => p.tau)];
const sigmaHMin = Math.min(...allSigmaH) * 1.1;
const sigmaHMax = Math.max(...allSigmaH) * 1.1;
const tauMin = 0;
const tauMax = Math.max(...allTau) * 1.2;
// Fonctions de transformation
const toX = (sigmaH) => padding.left + ((sigmaH - sigmaHMin) / (sigmaHMax - sigmaHMin)) * plotWidth;
const toY = (tau) => padding.top + plotHeight - ((tau - tauMin) / (tauMax - tauMin)) * plotHeight;
// Grille
ctx.strokeStyle = '#333';
ctx.lineWidth = 1;
ctx.setLineDash([5, 5]);
// Lignes verticales
const numGridLines = 5;
for (let i = 0; i <= numGridLines; i++) {
const sigmaH = sigmaHMin + (i / numGridLines) * (sigmaHMax - sigmaHMin);
const x = toX(sigmaH);
ctx.beginPath();
ctx.moveTo(x, padding.top);
ctx.lineTo(x, padding.top + plotHeight);
ctx.stroke();
}
// Lignes horizontales
for (let i = 0; i <= numGridLines; i++) {
const tau = tauMin + (i / numGridLines) * (tauMax - tauMin);
const y = toY(tau);
ctx.beginPath();
ctx.moveTo(padding.left, y);
ctx.lineTo(padding.left + plotWidth, y);
ctx.stroke();
}
ctx.setLineDash([]);
// Axes
ctx.strokeStyle = '#666';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(padding.left, padding.top);
ctx.lineTo(padding.left, padding.top + plotHeight);
ctx.lineTo(padding.left + plotWidth, padding.top + plotHeight);
ctx.stroke();
// Labels des axes
ctx.fillStyle = '#aaa';
ctx.font = '12px system-ui';
ctx.textAlign = 'center';
// Axe X
ctx.fillText('σH (MPa)', padding.left + plotWidth / 2, height - 15);
for (let i = 0; i <= numGridLines; i++) {
const sigmaH = sigmaHMin + (i / numGridLines) * (sigmaHMax - sigmaHMin);
const x = toX(sigmaH);
ctx.fillText(sigmaH.toFixed(0), x, padding.top + plotHeight + 20);
}
// Axe Y
ctx.save();
ctx.translate(20, padding.top + plotHeight / 2);
ctx.rotate(-Math.PI / 2);
ctx.fillText('τmax (MPa)', 0, 0);
ctx.restore();
ctx.textAlign = 'right';
for (let i = 0; i <= numGridLines; i++) {
const tau = tauMin + (i / numGridLines) * (tauMax - tauMin);
const y = toY(tau);
ctx.fillText(tau.toFixed(0), padding.left - 10, y + 4);
}
// Ligne de critère (zone dangereuse au-dessus)
if (criterionLine.length >= 2) {
const x1 = toX(criterionLine[0].sigma_H);
const y1 = toY(criterionLine[0].tau);
const x2 = toX(criterionLine[1].sigma_H);
const y2 = toY(criterionLine[1].tau);
// Zone dangereuse (au-dessus de la ligne)
ctx.fillStyle = 'rgba(255, 100, 100, 0.1)';
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.lineTo(x2, padding.top);
ctx.lineTo(x1, padding.top);
ctx.closePath();
ctx.fill();
// Zone sûre (en dessous)
ctx.fillStyle = 'rgba(100, 255, 150, 0.1)';
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.lineTo(x2, padding.top + plotHeight);
ctx.lineTo(x1, padding.top + plotHeight);
ctx.closePath();
ctx.fill();
// Ligne de critère
ctx.strokeStyle = '#ff6b6b';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
// Label de la ligne
ctx.fillStyle = '#ff6b6b';
ctx.font = 'bold 11px system-ui';
ctx.textAlign = 'left';
ctx.fillText(`τ = ${result.b} - ${result.a}σH`, x2 - 120, y2 - 10);
}
// Points (σH, τmax)
points.forEach((point, i) => {
const x = toX(point.sigma_H);
const y = toY(point.tau_max);
// Couleur selon si le point est critique ou non
const isCritical = point.dv > result.b;
ctx.beginPath();
ctx.arc(x, y, 4, 0, Math.PI * 2);
ctx.fillStyle = isCritical ? '#ff6b6b' : '#00d4ff';
ctx.fill();
// Marquer le point max
if (i === result.index_max) {
ctx.strokeStyle = '#ffd700';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.arc(x, y, 8, 0, Math.PI * 2);
ctx.stroke();
// Label
ctx.fillStyle = '#ffd700';
ctx.font = 'bold 10px system-ui';
ctx.textAlign = 'left';
ctx.fillText('MAX', x + 12, y + 4);
}
});
// Légende
const legendX = padding.left + 10;
const legendY = padding.top + 10;
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
ctx.fillRect(legendX, legendY, 150, 70);
ctx.font = '11px system-ui';
// Point sûr
ctx.beginPath();
ctx.arc(legendX + 10, legendY + 15, 4, 0, Math.PI * 2);
ctx.fillStyle = '#00d4ff';
ctx.fill();
ctx.fillStyle = '#aaa';
ctx.textAlign = 'left';
ctx.fillText('Points sûrs', legendX + 20, legendY + 19);
// Point critique
ctx.beginPath();
ctx.arc(legendX + 10, legendY + 35, 4, 0, Math.PI * 2);
ctx.fillStyle = '#ff6b6b';
ctx.fill();
ctx.fillStyle = '#aaa';
ctx.fillText('Points critiques', legendX + 20, legendY + 39);
// Ligne de critère
ctx.strokeStyle = '#ff6b6b';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(legendX + 5, legendY + 55);
ctx.lineTo(legendX + 15, legendY + 55);
ctx.stroke();
ctx.fillStyle = '#aaa';
ctx.fillText('Limite de Dang Van', legendX + 20, legendY + 59);
}, [result]);
return (
<div className="dangvan-chart">
<canvas
ref={canvasRef}
width={800}
height={500}
/>
<div className="chart-help">
Diagramme de Dang Van : τ<sub>max</sub> vs σ<sub>H</sub>
</div>
</div>
);
}