|
|
|
(function() { |
|
console.log('Animation Fixes Script Loaded'); |
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
console.log('Applying animation fixes'); |
|
|
|
|
|
const expectedCanvases = [ |
|
{ id: 'backprop-canvas', container: '.animation-container', tab: 'backpropagation-tab' }, |
|
{ id: 'forward-canvas', container: '.forward-visualization', tab: 'forward-propagation-tab' }, |
|
{ id: 'background-canvas', container: '.background-visualization', tab: 'background-animation-tab' } |
|
]; |
|
|
|
expectedCanvases.forEach(canvasInfo => { |
|
const canvas = document.getElementById(canvasInfo.id); |
|
const container = document.querySelector(`#${canvasInfo.tab} ${canvasInfo.container}`); |
|
|
|
if (!canvas && container) { |
|
console.log(`Creating missing canvas: ${canvasInfo.id}`); |
|
const newCanvas = document.createElement('canvas'); |
|
newCanvas.id = canvasInfo.id; |
|
newCanvas.className = 'animation-canvas'; |
|
newCanvas.width = container.clientWidth || 800; |
|
newCanvas.height = container.clientHeight || 400; |
|
|
|
container.prepend(newCanvas); |
|
|
|
|
|
const ctx = newCanvas.getContext('2d'); |
|
if (ctx) { |
|
ctx.fillStyle = 'rgba(200, 200, 255, 0.3)'; |
|
ctx.fillRect(0, 0, newCanvas.width, newCanvas.height); |
|
ctx.fillStyle = '#333'; |
|
ctx.font = '16px Arial'; |
|
ctx.textAlign = 'center'; |
|
ctx.fillText(`Canvas ${canvasInfo.id} initialized`, newCanvas.width/2, newCanvas.height/2); |
|
} |
|
} |
|
}); |
|
|
|
|
|
|
|
document.addEventListener('tabSwitch', function(e) { |
|
const tabId = e.detail.tab; |
|
console.log(`Tab switch detected to: ${tabId}`); |
|
|
|
setTimeout(() => { |
|
|
|
switch(tabId) { |
|
case 'backpropagation': |
|
initBackpropCanvas(); |
|
break; |
|
case 'forward-propagation': |
|
initForwardCanvas(); |
|
break; |
|
case 'background-animation': |
|
initBackgroundCanvas(); |
|
break; |
|
} |
|
}, 100); |
|
}); |
|
|
|
|
|
function initBackpropCanvas() { |
|
const canvas = document.getElementById('backprop-canvas'); |
|
if (!canvas) return; |
|
|
|
if (typeof window.initBackpropCanvas === 'function') { |
|
window.initBackpropCanvas(); |
|
} else { |
|
const ctx = canvas.getContext('2d'); |
|
if (ctx) { |
|
drawPlaceholderNetwork(ctx, canvas.width, canvas.height, 'Backpropagation'); |
|
} |
|
} |
|
} |
|
|
|
function initForwardCanvas() { |
|
const canvas = document.getElementById('forward-canvas'); |
|
if (!canvas) return; |
|
|
|
if (typeof window.initForwardPropCanvas === 'function') { |
|
window.initForwardPropCanvas(); |
|
} else { |
|
const ctx = canvas.getContext('2d'); |
|
if (ctx) { |
|
drawPlaceholderNetwork(ctx, canvas.width, canvas.height, 'Forward Propagation'); |
|
} |
|
} |
|
} |
|
|
|
function initBackgroundCanvas() { |
|
const canvas = document.getElementById('background-canvas'); |
|
if (!canvas) return; |
|
|
|
if (typeof window.initBackgroundCanvas === 'function') { |
|
window.initBackgroundCanvas(); |
|
} else { |
|
const ctx = canvas.getContext('2d'); |
|
if (ctx) { |
|
drawPlaceholderNeurons(ctx, canvas.width, canvas.height); |
|
} |
|
} |
|
} |
|
|
|
|
|
function drawPlaceholderNetwork(ctx, width, height, title) { |
|
|
|
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 = 'bold 20px Arial'; |
|
ctx.textAlign = 'center'; |
|
ctx.fillText(title + ' Animation', width/2, 40); |
|
|
|
|
|
ctx.font = '16px Arial'; |
|
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 = 'bold 20px Arial'; |
|
ctx.textAlign = 'center'; |
|
ctx.fillText('Neural Background Animation', width/2, 40); |
|
|
|
|
|
ctx.font = '16px Arial'; |
|
ctx.fillText('Animation placeholder - Check console for errors', width/2, height - 30); |
|
} |
|
|
|
|
|
const activeTabButton = document.querySelector('.tab-button.active'); |
|
if (activeTabButton) { |
|
const tabId = activeTabButton.getAttribute('data-tab'); |
|
console.log(`Initial active tab: ${tabId}`); |
|
|
|
|
|
if (window.activateTab) { |
|
window.activateTab(tabId); |
|
} else { |
|
|
|
document.dispatchEvent(new CustomEvent('tabSwitch', { |
|
detail: { tab: tabId } |
|
})); |
|
} |
|
} |
|
}); |
|
})(); |