Uncaught SyntaxError: missing ) after argument list (at script.js:147:5)Understand this error
fb6cd14
verified
| document.addEventListener('DOMContentLoaded', () => { | |
| // Components data structure | |
| const components = { | |
| magnets: [], | |
| coils: [], | |
| cores: [], | |
| wires: [], | |
| batteries: [], | |
| switches: [] | |
| }; | |
| let selectedComponent = null; | |
| let isDrawingWire = false; | |
| let wireStartPoint = null; | |
| let currentWirePoints = []; | |
| const canvas = document.getElementById('fieldCanvas'); | |
| if (!canvas) return; | |
| const ctx = canvas.getContext('2d'); | |
| const overlay = document.getElementById('component-overlay'); | |
| // Set canvas to full size of container | |
| function resizeCanvas() { | |
| const container = document.getElementById('visualization-container'); | |
| canvas.width = container.clientWidth; | |
| canvas.height = container.clientHeight; | |
| drawField(); | |
| } | |
| // Initial resize | |
| resizeCanvas(); | |
| window.addEventListener('resize', resizeCanvas); | |
| // Draw magnetic field lines and components | |
| function drawField() { | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| // Draw wires first (background) | |
| components.wires.forEach(wire => { | |
| if (wire.points.length < 2) return; | |
| ctx.strokeStyle = '#3b82f6'; | |
| ctx.lineWidth = 3; | |
| ctx.beginPath(); | |
| ctx.moveTo(wire.points[0].x, wire.points[0].y); | |
| for (let i = 1; i < wire.points.length; i++) { | |
| ctx.lineTo(wire.points[i].x, wire.points[i].y); | |
| } | |
| ctx.stroke(); | |
| }); | |
| // Draw other components | |
| [...components.magnets, ...components.coils, ...components.cores, | |
| ...components.batteries, ...components.switches].forEach(comp => { | |
| const x = comp.x * canvas.width; | |
| const y = comp.y * canvas.height; | |
| const radius = 20 + (comp.strength || 0.5) * 30; | |
| // Highlight selected component | |
| if (selectedComponent === comp) { | |
| ctx.strokeStyle = '#f59e0b'; | |
| ctx.lineWidth = 3; | |
| ctx.beginPath(); | |
| ctx.arc(x, y, radius + 5, 0, Math.PI * 2); | |
| ctx.stroke(); | |
| } | |
| // Component body | |
| ctx.fillStyle = getComponentColor(comp.type, comp); | |
| ctx.beginPath(); | |
| if (comp.type === 'magnet') { | |
| ctx.arc(x, y, radius, 0, Math.PI * 2); | |
| // Polarity indicator | |
| ctx.fillStyle = '#ffffff'; | |
| ctx.font = 'bold 16px Arial'; | |
| ctx.textAlign = 'center'; | |
| ctx.textBaseline = 'middle'; | |
| ctx.fillText(comp.polarity > 0 ? 'N' : 'S', x, y); | |
| } else if (comp.type === 'coil') { | |
| // Draw coil as concentric circles | |
| for (let i = 0; i < 3; i++) { | |
| ctx.beginPath(); | |
| ctx.arc(x, y, radius - i*5, 0, Math.PI * 2); | |
| ctx.stroke(); | |
| } | |
| } else { | |
| // Default rectangular component | |
| ctx.roundRect(x - radius, y - radius, radius*2, radius*2, 5); | |
| } | |
| ctx.fill(); | |
| }); | |
| // Draw field lines | |
| ctx.strokeStyle = 'rgba(16, 185, 129, 0.7)'; | |
| ctx.lineWidth = 2; | |
| const steps = 36; | |
| const lineSteps = 100; | |
| const stepSize = 5; | |
| for (let i = 0; i < steps; i++) { | |
| const angle = (i / steps) * Math.PI * 2; | |
| components.magnets.forEach(magnet => { | |
| let x = magnet.x * canvas.width + Math.cos(angle) * 30; | |
| let y = magnet.y * canvas.height + Math.sin(angle) * 30; | |
| ctx.beginPath(); | |
| ctx.moveTo(x, y); | |
| for (let j = 0; j < lineSteps; j++) { | |
| // Calculate field direction at this point | |
| let fx = 0, fy = 0; | |
| components.magnets.forEach(m => { | |
| const dx = x - m.x * canvas.width; | |
| const dy = y - m.y * canvas.height; | |
| const distSq = dx * dx + dy * dy; | |
| const dist = Math.sqrt(distSq); | |
| const force = m.strength * 1000 * m.polarity / (distSq + 100); | |
| fx += force * dx / dist; | |
| fy += force * dy / dist; | |
| }); | |
| // Normalize direction | |
| const len = Math.sqrt(fx * fx + fy * fy); | |
| if (len > 0) { | |
| fx = fx / len * stepSize; | |
| fy = fy / len * stepSize; | |
| } | |
| x += fx; | |
| y += fy; | |
| ctx.lineTo(x, y); | |
| // Stop if out of bounds | |
| if (x < 0 || x > canvas.width || y < 0 || y > canvas.height) break; | |
| } | |
| ctx.stroke(); | |
| }); | |
| } | |
| } | |
| // Initial draw | |
| window.requestAnimationFrame(drawField); | |
| function getComponentColor(type, component) { | |
| const colors = { | |
| magnet: component.polarity > 0 ? '#ef4444' : '#3b82f6', | |
| coil: '#f59e0b', | |
| core: '#6b7280', | |
| battery: '#10b981', | |
| switch: '#8b5cf6' | |
| }; | |
| return colors[type] || '#ffffff'; | |
| } | |
| // Handle component creation from palette | |
| document.addEventListener('component-selected', (e) => { | |
| if (e.detail.type === 'wire') { | |
| isDrawingWire = true; | |
| overlay.style.cursor = 'crosshair'; | |
| return; | |
| } | |
| const newComponent = { | |
| type: e.detail.type, | |
| x: 0.5, // Center of canvas | |
| y: 0.5, | |
| strength: 0.5, | |
| polarity: 1, | |
| turns: e.detail.type === 'coil' ? 5 : 0, | |
| isBeingDragged: true // Flag for new component being dragged | |
| }; | |
| components[e.detail.type + 's'].push(newComponent); | |
| selectedComponent = newComponent; | |
| drawField(); | |
| updateComponentDetails(); | |
| // Set up initial drag for newly created component | |
| const handleMouseMove = (moveEvent) => { | |
| const rect = canvas.getBoundingClientRect(); | |
| const x = moveEvent.clientX - rect.left; | |
| const y = moveEvent.clientY - rect.top; | |
| selectedComponent.x = x / canvas.width; | |
| selectedComponent.y = y / canvas.height; | |
| drawField(); | |
| updateComponentDetails(); | |
| }; | |
| const handleMouseUp = () => { | |
| document.removeEventListener('mousemove', handleMouseMove); | |
| document.removeEventListener('mouseup', handleMouseUp); | |
| selectedComponent.isBeingDragged = false; | |
| }; | |
| document.addEventListener('mousemove', handleMouseMove); | |
| document.addEventListener('mouseup', handleMouseUp); | |
| }); | |
| // Handle component deletion | |
| document.addEventListener('delete-selected', () => { | |
| if (selectedComponent) { | |
| const type = selectedComponent.type; | |
| const arr = components[type + 's']; | |
| const index = arr.indexOf(selectedComponent); | |
| if (index > -1) { | |
| arr.splice(index, 1); | |
| selectedComponent = null; | |
| drawField(); | |
| updateComponentDetails(); | |
| } | |
| } | |
| }); | |
| // Canvas interaction handlers | |
| canvas.addEventListener('mousedown', (e) => { | |
| const rect = canvas.getBoundingClientRect(); | |
| const x = e.clientX - rect.left; | |
| const y = e.clientY - rect.top; | |
| if (isDrawingWire) { | |
| wireStartPoint = { x, y }; | |
| currentWirePoints = [{ x, y }]; | |
| return; | |
| } | |
| // Check if clicking on a component | |
| const allComponents = [ | |
| ...components.magnets, | |
| ...components.coils, | |
| ...components.cores, | |
| ...components.batteries, | |
| ...components.switches | |
| ]; | |
| selectedComponent = null; | |
| for (const comp of allComponents) { | |
| const compX = comp.x * canvas.width; | |
| const compY = comp.y * canvas.height; | |
| const radius = 20 + (comp.strength || 0.5) * 30; | |
| if (Math.sqrt((x - compX) ** 2 + (y - compY) ** 2) < radius) { | |
| selectedComponent = comp; | |
| break; | |
| } | |
| } | |
| if (selectedComponent) { | |
| // Prevent text selection during drag | |
| e.preventDefault(); | |
| // Set up drag handlers | |
| const handleMouseMove = (moveEvent) => { | |
| const newX = moveEvent.clientX - rect.left; | |
| const newY = moveEvent.clientY - rect.top; | |
| selectedComponent.x = newX / canvas.width; | |
| selectedComponent.y = newY / canvas.height; | |
| drawField(); | |
| updateComponentDetails(); | |
| }; | |
| const handleMouseUp = () => { | |
| document.removeEventListener('mousemove', handleMouseMove); | |
| document.removeEventListener('mouseup', handleMouseUp); | |
| }; | |
| document.addEventListener('mousemove', handleMouseMove); | |
| document.addEventListener('mouseup', handleMouseUp); | |
| } | |
| drawField(); | |
| updateComponentDetails(); | |
| }); | |
| canvas.addEventListener('mousemove', (e) => { | |
| if (!isDrawingWire && !selectedComponent) return; | |
| const rect = canvas.getBoundingClientRect(); | |
| const x = e.clientX - rect.left; | |
| const y = e.clientY - rect.top; | |
| if (isDrawingWire && wireStartPoint) { | |
| currentWirePoints.push({ x, y }); | |
| drawField(); | |
| return; | |
| } | |
| if (selectedComponent) { | |
| selectedComponent.x = x / canvas.width; | |
| selectedComponent.y = y / canvas.height; | |
| drawField(); | |
| updateComponentDetails(); | |
| } | |
| }); | |
| canvas.addEventListener('mouseup', () => { | |
| if (isDrawingWire && wireStartPoint && currentWirePoints.length > 1) { | |
| components.wires.push({ | |
| type: 'wire', | |
| points: [...currentWirePoints], | |
| current: 0.5 | |
| }); | |
| isDrawingWire = false; | |
| overlay.style.cursor = 'default'; | |
| wireStartPoint = null; | |
| currentWirePoints = []; | |
| drawField(); | |
| } | |
| }); | |
| function updateComponentDetails() { | |
| const detailsPanel = document.getElementById('component-details'); | |
| if (!detailsPanel) return; | |
| if (!selectedComponent) { | |
| detailsPanel.innerHTML = '<p class="text-gray-400">No component selected</p>'; | |
| return; | |
| } | |
| detailsPanel.innerHTML = ` | |
| <h3 class="font-medium mb-2">${selectedComponent.type.toUpperCase()}</h3> | |
| <div class="grid grid-cols-2 gap-2"> | |
| <div>X:</div> | |
| <div>${selectedComponent.x.toFixed(2)}</div> | |
| <div>Y:</div> | |
| <div>${selectedComponent.y.toFixed(2)}</div> | |
| ${selectedComponent.strength ? ` | |
| <div>Strength:</div> | |
| <div>${selectedComponent.strength.toFixed(2)}</div> | |
| ` : ''} | |
| ${selectedComponent.polarity ? ` | |
| <div>Polarity:</div> | |
| <div>${selectedComponent.polarity > 0 ? 'North' : 'South'}</div> | |
| ` : ''} | |
| </div> | |
| `; | |
| } | |
| }); |