|
|
|
document.addEventListener('DOMContentLoaded', () => { |
|
console.log('Tab Manager Initialized'); |
|
|
|
const tabButtons = document.querySelectorAll('.tab-button'); |
|
const tabContents = document.querySelectorAll('.tab-content'); |
|
|
|
|
|
let currentTab = 'network-design'; |
|
|
|
|
|
function activateTab(tabId) { |
|
console.log(`Activating tab: ${tabId}`); |
|
currentTab = tabId; |
|
|
|
|
|
tabButtons.forEach(btn => btn.classList.remove('active')); |
|
tabContents.forEach(content => content.classList.remove('active')); |
|
|
|
|
|
const button = document.querySelector(`.tab-button[data-tab="${tabId}"]`); |
|
if (button) { |
|
button.classList.add('active'); |
|
} |
|
|
|
|
|
const tabContent = document.getElementById(`${tabId}-tab`); |
|
if (tabContent) { |
|
tabContent.classList.add('active'); |
|
} |
|
|
|
|
|
document.dispatchEvent(new CustomEvent('tabSwitch', { |
|
detail: { tab: tabId } |
|
})); |
|
|
|
|
|
initializeTabContent(tabId); |
|
} |
|
|
|
|
|
function initializeTabContent(tabId) { |
|
let canvas, ctx; |
|
|
|
switch(tabId) { |
|
case 'backpropagation': |
|
canvas = document.getElementById('backprop-canvas'); |
|
if (canvas && typeof window.initBackpropCanvas === 'function') { |
|
console.log('Initializing backpropagation canvas'); |
|
window.initBackpropCanvas(); |
|
} else { |
|
console.warn('Could not initialize backpropagation canvas'); |
|
} |
|
break; |
|
|
|
case 'forward-propagation': |
|
canvas = document.getElementById('forward-canvas'); |
|
if (canvas && typeof window.initForwardPropCanvas === 'function') { |
|
console.log('Initializing forward propagation canvas'); |
|
window.initForwardPropCanvas(); |
|
} else { |
|
console.warn('Could not initialize forward propagation canvas'); |
|
|
|
|
|
if (canvas) { |
|
ctx = canvas.getContext('2d'); |
|
if (ctx) { |
|
|
|
const container = canvas.parentElement; |
|
if (container) { |
|
canvas.width = container.clientWidth; |
|
canvas.height = container.clientHeight; |
|
} else { |
|
canvas.width = 800; |
|
canvas.height = 400; |
|
} |
|
|
|
|
|
drawPlaceholderNetwork(ctx, canvas.width, canvas.height); |
|
} |
|
} |
|
} |
|
break; |
|
|
|
case 'background-animation': |
|
canvas = document.getElementById('background-canvas'); |
|
if (canvas && typeof window.initBackgroundCanvas === 'function') { |
|
console.log('Initializing background animation canvas'); |
|
window.initBackgroundCanvas(); |
|
} else { |
|
console.warn('Could not initialize background animation canvas'); |
|
|
|
|
|
if (canvas) { |
|
ctx = canvas.getContext('2d'); |
|
if (ctx) { |
|
|
|
const container = canvas.parentElement; |
|
if (container) { |
|
canvas.width = container.clientWidth; |
|
canvas.height = container.clientHeight; |
|
} else { |
|
canvas.width = 800; |
|
canvas.height = 400; |
|
} |
|
|
|
|
|
drawPlaceholderNeurons(ctx, canvas.width, canvas.height); |
|
} |
|
} |
|
} |
|
break; |
|
} |
|
} |
|
|
|
|
|
function drawPlaceholderNetwork(ctx, width, height) { |
|
|
|
ctx.clearRect(0, 0, width, height); |
|
|
|
|
|
ctx.fillStyle = '#f8f9fa'; |
|
ctx.fillRect(0, 0, width, height); |
|
|
|
|
|
const layers = [3, 4, 2]; |
|
const neuronRadius = 20; |
|
const layerSpacing = width / (layers.length + 1); |
|
|
|
|
|
function getNeuronPosition(layerIndex, neuronIndex, totalNeurons) { |
|
const x = layerSpacing * (layerIndex + 1); |
|
const layerHeight = totalNeurons * (neuronRadius * 2 + 10); |
|
const startY = (height - layerHeight) / 2 + neuronRadius; |
|
const y = startY + neuronIndex * (neuronRadius * 2 + 10); |
|
return { x, y }; |
|
} |
|
|
|
|
|
ctx.strokeStyle = '#aaa'; |
|
ctx.lineWidth = 1; |
|
|
|
|
|
for (let layerIndex = 0; layerIndex < layers.length - 1; layerIndex++) { |
|
const sourceLayer = layers[layerIndex]; |
|
const targetLayer = layers[layerIndex + 1]; |
|
|
|
|
|
for (let sourceNeuron = 0; sourceNeuron < sourceLayer; sourceNeuron++) { |
|
const source = getNeuronPosition(layerIndex, sourceNeuron, sourceLayer); |
|
|
|
for (let targetNeuron = 0; targetNeuron < targetLayer; targetNeuron++) { |
|
const target = getNeuronPosition(layerIndex + 1, targetNeuron, targetLayer); |
|
|
|
|
|
ctx.beginPath(); |
|
ctx.moveTo(source.x, source.y); |
|
ctx.lineTo(target.x, target.y); |
|
ctx.stroke(); |
|
} |
|
} |
|
} |
|
|
|
|
|
const layerColors = ['#6495ED', '#7B68EE', '#9370DB']; |
|
|
|
for (let layerIndex = 0; layerIndex < layers.length; layerIndex++) { |
|
const neuronsInLayer = layers[layerIndex]; |
|
|
|
for (let neuronIndex = 0; neuronIndex < neuronsInLayer; neuronIndex++) { |
|
const { x, y } = getNeuronPosition(layerIndex, neuronIndex, neuronsInLayer); |
|
|
|
|
|
ctx.beginPath(); |
|
ctx.arc(x, y, neuronRadius, 0, Math.PI * 2); |
|
ctx.fillStyle = layerColors[layerIndex]; |
|
ctx.fill(); |
|
ctx.strokeStyle = '#fff'; |
|
ctx.lineWidth = 2; |
|
ctx.stroke(); |
|
} |
|
} |
|
|
|
|
|
ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'; |
|
ctx.font = '18px Arial'; |
|
ctx.textAlign = 'center'; |
|
ctx.fillText('Animation Placeholder - Check Console for Errors', width/2, height - 30); |
|
} |
|
|
|
|
|
function drawPlaceholderNeurons(ctx, width, height) { |
|
|
|
ctx.clearRect(0, 0, width, height); |
|
|
|
|
|
ctx.fillStyle = '#f8f9fa'; |
|
ctx.fillRect(0, 0, width, height); |
|
|
|
|
|
const neurons = []; |
|
const neuronCount = 50; |
|
|
|
for (let i = 0; i < neuronCount; i++) { |
|
neurons.push({ |
|
x: Math.random() * width, |
|
y: Math.random() * height, |
|
radius: 3 + Math.random() * 5, |
|
color: Math.random() > 0.8 ? '#6495ED' : '#aaaaaa' |
|
}); |
|
} |
|
|
|
|
|
ctx.strokeStyle = 'rgba(170, 170, 170, 0.3)'; |
|
ctx.lineWidth = 1; |
|
|
|
for (let i = 0; i < neurons.length; i++) { |
|
const source = neurons[i]; |
|
|
|
|
|
for (let j = i + 1; j < neurons.length; j++) { |
|
const target = neurons[j]; |
|
const distance = Math.sqrt( |
|
Math.pow(target.x - source.x, 2) + |
|
Math.pow(target.y - source.y, 2) |
|
); |
|
|
|
|
|
if (distance < 100) { |
|
ctx.beginPath(); |
|
ctx.moveTo(source.x, source.y); |
|
ctx.lineTo(target.x, target.y); |
|
ctx.stroke(); |
|
} |
|
} |
|
} |
|
|
|
|
|
neurons.forEach(neuron => { |
|
ctx.beginPath(); |
|
ctx.arc(neuron.x, neuron.y, neuron.radius, 0, Math.PI * 2); |
|
ctx.fillStyle = neuron.color; |
|
ctx.fill(); |
|
}); |
|
|
|
|
|
ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'; |
|
ctx.font = '18px Arial'; |
|
ctx.textAlign = 'center'; |
|
ctx.fillText('Animation Placeholder - Check Console for Errors', width/2, height - 30); |
|
} |
|
|
|
|
|
tabButtons.forEach(button => { |
|
button.addEventListener('click', () => { |
|
const tabId = button.getAttribute('data-tab'); |
|
activateTab(tabId); |
|
}); |
|
}); |
|
|
|
|
|
window.activateTab = activateTab; |
|
|
|
|
|
window.initBackpropCanvas = null; |
|
window.initForwardPropCanvas = null; |
|
window.initBackgroundCanvas = null; |
|
|
|
|
|
document.addEventListener('visibilitychange', () => { |
|
if (document.visibilityState === 'visible') { |
|
console.log('Page is now visible, refreshing current tab:', currentTab); |
|
|
|
initializeTabContent(currentTab); |
|
} |
|
}); |
|
|
|
|
|
window.addEventListener('resize', () => { |
|
console.log('Window resized, refreshing current tab:', currentTab); |
|
initializeTabContent(currentTab); |
|
}); |
|
}); |