neural-network-playground / js /tab-manager.js
ameerazam08's picture
Upload 22 files
a895648 verified
// Tab Manager - Handles tab switching and ensures animations are properly initialized
document.addEventListener('DOMContentLoaded', () => {
console.log('Tab Manager Initialized');
const tabButtons = document.querySelectorAll('.tab-button');
const tabContents = document.querySelectorAll('.tab-content');
// Current active tab
let currentTab = 'network-design'; // Default tab
// Function to activate a tab
function activateTab(tabId) {
console.log(`Activating tab: ${tabId}`);
currentTab = tabId;
// Remove active class from all buttons and contents
tabButtons.forEach(btn => btn.classList.remove('active'));
tabContents.forEach(content => content.classList.remove('active'));
// Add active class to the requested tab button
const button = document.querySelector(`.tab-button[data-tab="${tabId}"]`);
if (button) {
button.classList.add('active');
}
// Add active class to the corresponding content
const tabContent = document.getElementById(`${tabId}-tab`);
if (tabContent) {
tabContent.classList.add('active');
}
// Dispatch a custom event to notify tab-specific scripts
document.dispatchEvent(new CustomEvent('tabSwitch', {
detail: { tab: tabId }
}));
// Initialize canvas for the appropriate tab
initializeTabContent(tabId);
}
// Function to initialize tab content, especially canvases
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');
// Fallback - directly draw on canvas if found
if (canvas) {
ctx = canvas.getContext('2d');
if (ctx) {
// Set canvas size to match container
const container = canvas.parentElement;
if (container) {
canvas.width = container.clientWidth;
canvas.height = container.clientHeight;
} else {
canvas.width = 800;
canvas.height = 400;
}
// Draw a placeholder network
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');
// Fallback - directly draw on canvas if found
if (canvas) {
ctx = canvas.getContext('2d');
if (ctx) {
// Set canvas size to match container
const container = canvas.parentElement;
if (container) {
canvas.width = container.clientWidth;
canvas.height = container.clientHeight;
} else {
canvas.width = 800;
canvas.height = 400;
}
// Draw a placeholder animation
drawPlaceholderNeurons(ctx, canvas.width, canvas.height);
}
}
}
break;
}
}
// Helper function to draw a placeholder neural network
function drawPlaceholderNetwork(ctx, width, height) {
// Clear canvas
ctx.clearRect(0, 0, width, height);
// Draw background
ctx.fillStyle = '#f8f9fa';
ctx.fillRect(0, 0, width, height);
// Define network layout
const layers = [3, 4, 2]; // Input, hidden, output layers
const neuronRadius = 20;
const layerSpacing = width / (layers.length + 1);
// Function to calculate neuron positions
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 };
}
// Draw connections first (so they appear behind neurons)
ctx.strokeStyle = '#aaa';
ctx.lineWidth = 1;
// For each layer except the last
for (let layerIndex = 0; layerIndex < layers.length - 1; layerIndex++) {
const sourceLayer = layers[layerIndex];
const targetLayer = layers[layerIndex + 1];
// Connect each neuron in source layer to each neuron in target layer
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);
// Draw connection
ctx.beginPath();
ctx.moveTo(source.x, source.y);
ctx.lineTo(target.x, target.y);
ctx.stroke();
}
}
}
// Draw neurons
const layerColors = ['#6495ED', '#7B68EE', '#9370DB']; // Different color for each layer
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);
// Draw neuron circle
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();
}
}
// Add text to explain placeholder
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);
}
// Helper function to draw placeholder neurons for background animation
function drawPlaceholderNeurons(ctx, width, height) {
// Clear canvas
ctx.clearRect(0, 0, width, height);
// Draw background
ctx.fillStyle = '#f8f9fa';
ctx.fillRect(0, 0, width, height);
// Create random neurons
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'
});
}
// Draw connections
ctx.strokeStyle = 'rgba(170, 170, 170, 0.3)';
ctx.lineWidth = 1;
for (let i = 0; i < neurons.length; i++) {
const source = neurons[i];
// Connect to nearby neurons
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)
);
// Only connect neurons that are close enough
if (distance < 100) {
ctx.beginPath();
ctx.moveTo(source.x, source.y);
ctx.lineTo(target.x, target.y);
ctx.stroke();
}
}
}
// Draw neurons
neurons.forEach(neuron => {
ctx.beginPath();
ctx.arc(neuron.x, neuron.y, neuron.radius, 0, Math.PI * 2);
ctx.fillStyle = neuron.color;
ctx.fill();
});
// Add text to explain placeholder
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);
}
// Add event listeners to tab buttons
tabButtons.forEach(button => {
button.addEventListener('click', () => {
const tabId = button.getAttribute('data-tab');
activateTab(tabId);
});
});
// Export the activateTab function to window for access from other scripts
window.activateTab = activateTab;
// Register initialization functions that each animation script should call
window.initBackpropCanvas = null;
window.initForwardPropCanvas = null;
window.initBackgroundCanvas = null;
// Monitor tab visibility for better animation performance
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
console.log('Page is now visible, refreshing current tab:', currentTab);
// Re-initialize the current tab when the page becomes visible again
initializeTabContent(currentTab);
}
});
// Check window resizing for canvas sizing
window.addEventListener('resize', () => {
console.log('Window resized, refreshing current tab:', currentTab);
initializeTabContent(currentTab);
});
});