const canvas = document.getElementById('arch-canvas'); const ctx = canvas.getContext('2d'); const state = { users: 120, databaseLoad: 45, servers: [ { name: 'web-1', healthy: true, load: 34 }, { name: 'web-2', healthy: true, load: 28 }, { name: 'web-3', healthy: true, load: 31 }, ], }; function box(x, y, width, height, fill, stroke, label) { ctx.fillStyle = fill; ctx.strokeStyle = stroke; ctx.beginPath(); ctx.roundRect(x, y, width, height, 8); ctx.fill(); ctx.stroke(); ctx.fillStyle = '#102a43'; ctx.fillText(label, x + 12, y + height / 2 + 5); } function draw() { const healthy = state.servers.filter((server) => server.healthy); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = '#f8fafc'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.font = '14px Arial'; ctx.fillStyle = '#102a43'; ctx.fillText(`${state.users} simulated users`, 30, 36); box(240, 95, 110, 64, '#dbeafe', '#2563eb', 'Load balancer'); state.servers.forEach((server, index) => { const x = 440; const y = 40 + index * 68; server.load = server.healthy && healthy.length ? Math.min(100, Math.round(state.users / healthy.length / 6)) : 0; ctx.strokeStyle = '#9fb3c8'; ctx.beginPath(); ctx.moveTo(350, 127); ctx.lineTo(x, y + 24); ctx.stroke(); box(x, y, 120, 48, server.healthy ? '#e8fff1' : '#ffe8e8', server.healthy ? '#2f855a' : '#c53030', `${server.name} ${server.healthy ? server.load + '%' : 'down'}`); }); state.databaseLoad = Math.min(100, state.databaseLoad + state.users / 400); ctx.strokeStyle = '#9fb3c8'; ctx.beginPath(); ctx.moveTo(560, 127); ctx.lineTo(620, 127); ctx.stroke(); box(620, 95, 72, 64, state.databaseLoad > 80 ? '#fff5d6' : '#edf2f7', state.databaseLoad > 80 ? '#d69e2e' : '#52606d', `DB ${Math.round(state.databaseLoad)}%`); document.getElementById('arch-status').textContent = healthy.length ? `Traffic split across ${healthy.length} healthy web nodes.` : 'All web nodes are down. Auto-scaling is needed.'; } document.getElementById('add-users').addEventListener('click', () => { state.users += 220; state.databaseLoad += 10; draw(); }); document.getElementById('server-crash').addEventListener('click', () => { const server = state.servers.find((item) => item.healthy); if (server) server.healthy = false; draw(); }); document.getElementById('auto-scale').addEventListener('click', () => { state.servers.push({ name: `web-${state.servers.length + 1}`, healthy: true, load: 10 }); state.databaseLoad = Math.max(35, state.databaseLoad - 20); draw(); }); draw();