class ChartViz extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); } connectedCallback() { this.render(); this.initChart(); } render() { this.shadowRoot.innerHTML = ` `; } initChart() { const canvas = this.shadowRoot.getElementById('chartCanvas'); const ctx = canvas.getContext('2d'); const type = this.getAttribute('type') || 'line'; let width, height; const resize = () => { width = canvas.width = canvas.offsetWidth; height = canvas.height = canvas.offsetHeight; }; new ResizeObserver(resize).observe(this); // Data generation const generateData = (points) => { return Array.from({ length: points }, (_, i) => ({ x: i, y: Math.random() * 0.5 + 0.25 + Math.sin(i * 0.1) * 0.15 })); }; let data = generateData(type === 'training' ? 100 : 24); let offset = 0; const drawLineChart = () => { ctx.clearRect(0, 0, width, height); // Grid ctx.strokeStyle = '#1e293b'; ctx.lineWidth = 1; for (let i = 0; i < 5; i++) { const y = (height / 4) * i; ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(width, y); ctx.stroke(); } // Line ctx.beginPath(); ctx.strokeStyle = '#10b981'; ctx.lineWidth = 2; data.forEach((point, i) => { const x = (i / (data.length - 1)) * width; const y = height - (point.y * height * 0.8 + height * 0.1); if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y); }); ctx.stroke(); // Gradient fill const gradient = ctx.createLinearGradient(0, 0, 0, height); gradient.addColorStop(0, 'rgba(16, 185, 129, 0.3)'); gradient.addColorStop(1, 'rgba(16, 185, 129, 0)'); ctx.lineTo(width, height); ctx.lineTo(0, height); ctx.fillStyle = gradient; ctx.fill(); // Points data.forEach((point, i) => { if (i % 4 === 0) { const x = (i / (data.length - 1)) * width; const y = height - (point.y * height * 0.8 + height * 0.1); ctx.beginPath(); ctx.arc(x, y, 4, 0, Math.PI * 2); ctx.fillStyle = '#10b981'; ctx.fill(); } }); }; const drawBarChart = () => { ctx.clearRect(0, 0, width, height); const barWidth = width / data.length - 4; data.forEach((point, i) => { const x = i * (width / data.length) + 2; const barHeight = point.y * height * 0.8; const y = height - barHeight; // Color based on value const hue = 120 + (1 - point.y) * 60; // Green to yellow ctx.fillStyle = `hsl(${hue}, 70%, 50%)`; // Rounded top bars ctx.beginPath(); ctx.roundRect(x, y, barWidth, barHeight, [4, 4, 0, 0]); ctx.fill(); }); }; const drawTrainingChart = () => { ctx.clearRect(0, 0, width, height); // Loss line (decreasing) ctx.beginPath(); ctx.strokeStyle = '#f97316'; ctx.lineWidth = 2; data.forEach((point, i) => { const x = (i / (data.length - 1)) * width; const normalizedLoss = 1 - (i / data.length) * 0.8 + Math.random() * 0.05; const y = height - (normalizedLoss * height * 0.7 + height * 0.15); if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y); }); ctx.stroke(); // Accuracy line (increasing) ctx.beginPath(); ctx.strokeStyle = '#3b82f6'; ctx.lineWidth = 2; data.forEach((point, i) => { const x = (i / (data.length - 1)) * width; const normalizedAcc = 0.5 + (i / data.length) * 0.48 + Math.random() * 0.02; const y = height - (normalizedAcc * height * 0.7 + height * 0.15); if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y); }); ctx.stroke(); // Legend ctx.fillStyle = '#f97316'; ctx.fillRect(10, 10, 12, 12); ctx.fillStyle = '#94a3b8'; ctx.font = '11px sans-serif'; ctx.fillText('Loss', 28, 20); ctx.fillStyle = '#3b82f6'; ctx.fillRect(80, 10, 12, 12); ctx.fillStyle = '#94a3b8'; ctx.fillText('Accuracy', 98, 20); }; const animate = () => { if (type === 'training') { // Update data occasionally offset++; if (offset % 60 === 0) { data = data.map((point, i) => ({ ...point, y: Math.random() * 0.5 + 0.25 + Math.sin(i * 0.1 + offset * 0.01) * 0.15 })); } } else if (type === 'line') { // Shift data for real-time effect if (offset % 10 === 0) { data.shift(); data.push({ x: data.length, y: Math.random() * 0.5 + 0.25 + Math.sin(offset * 0.1) * 0.15 }); } offset++; } if (type === 'line' || type === 'training') { type === 'training' ? drawTrainingChart() : drawLineChart(); } else { drawBarChart(); } requestAnimationFrame(animate); }; resize(); animate(); } } customElements.define('chart-viz', ChartViz);