Spaces:
Running
Running
| document.addEventListener('DOMContentLoaded', () => { | |
| // Function Graph Visualization with enhanced controls | |
| const functionCtx = document.getElementById('functionGraph').getContext('2d'); | |
| let xMin = -10, xMax = 10, yMin = -5, yMax = 5; | |
| const algebraCtx = document.getElementById('algebraGraph').getContext('2d'); | |
| // Initialize function graph | |
| const functionGraph = new Chart(functionCtx, { | |
| type: 'line', | |
| data: { | |
| datasets: [{ | |
| label: 'Function', | |
| borderColor: '#7c3aed', | |
| backgroundColor: 'rgba(124, 58, 237, 0.1)', | |
| borderWidth: 2, | |
| pointRadius: 0, | |
| fill: true | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| scales: { | |
| x: { | |
| type: 'linear', | |
| position: 'center', | |
| min: xMin, | |
| max: xMax, | |
| title: { | |
| display: true, | |
| text: 'x-axis', | |
| font: { | |
| weight: 'bold' | |
| } | |
| }, | |
| grid: { | |
| color: (ctx) => ctx.tick.value === 0 ? '#000' : 'rgba(0, 0, 0, 0.1)' | |
| } | |
| }, | |
| y: { | |
| type: 'linear', | |
| position: 'center', | |
| min: yMin, | |
| max: yMax, | |
| title: { | |
| display: true, | |
| text: 'y-axis', | |
| font: { | |
| weight: 'bold' | |
| } | |
| }, | |
| grid: { | |
| color: (ctx) => ctx.tick.value === 0 ? '#000' : 'rgba(0, 0, 0, 0.1)' | |
| } | |
| } | |
| }, | |
| plugins: { | |
| tooltip: { | |
| mode: 'nearest', | |
| intersect: false, | |
| callbacks: { | |
| label: (context) => { | |
| return `f(${context.parsed.x.toFixed(2)}) = ${context.parsed.y.toFixed(2)}`; | |
| } | |
| } | |
| }, | |
| legend: { | |
| display: false | |
| }, | |
| zoom: { | |
| pan: { | |
| enabled: true, | |
| mode: 'xy' | |
| }, | |
| zoom: { | |
| wheel: { | |
| enabled: true | |
| }, | |
| pinch: { | |
| enabled: true | |
| }, | |
| mode: 'xy' | |
| } | |
| } | |
| }, | |
| interaction: { | |
| mode: 'nearest', | |
| intersect: false | |
| } | |
| } | |
| }); | |
| // Initialize algebra graph | |
| const algebraGraph = new Chart(algebraCtx, { | |
| type: 'line', | |
| data: { | |
| datasets: [{ | |
| label: 'Linear Equation', | |
| borderColor: '#0ea5e9', | |
| backgroundColor: 'rgba(14, 165, 233, 0.1)', | |
| borderWidth: 2, | |
| pointRadius: 0 | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| scales: { | |
| x: { | |
| type: 'linear', | |
| position: 'center', | |
| min: -10, | |
| max: 10 | |
| }, | |
| y: { | |
| type: 'linear', | |
| position: 'center', | |
| min: -10, | |
| max: 10 | |
| } | |
| } | |
| } | |
| }); | |
| // Add zoom and pan controls | |
| document.getElementById('zoomIn').addEventListener('click', () => { | |
| xMin *= 0.8; | |
| xMax *= 0.8; | |
| yMin *= 0.8; | |
| yMax *= 0.8; | |
| updateGraphScale(); | |
| }); | |
| document.getElementById('zoomOut').addEventListener('click', () => { | |
| xMin *= 1.2; | |
| xMax *= 1.2; | |
| yMin *= 1.2; | |
| yMax *= 1.2; | |
| updateGraphScale(); | |
| }); | |
| document.getElementById('resetView').addEventListener('click', () => { | |
| xMin = -10; xMax = 10; | |
| yMin = -5; yMax = 5; | |
| updateGraphScale(); | |
| }); | |
| function updateGraphScale() { | |
| functionGraph.options.scales.x.min = xMin; | |
| functionGraph.options.scales.x.max = xMax; | |
| functionGraph.options.scales.y.min = yMin; | |
| functionGraph.options.scales.y.max = yMax; | |
| functionGraph.update(); | |
| } | |
| // Update function graph when input changes | |
| document.getElementById('functionInput').addEventListener('input', function() { | |
| updateFunctionGraph(); | |
| }); | |
| // Mouse move coordinates display | |
| const coordDisplay = document.getElementById('coordinatesDisplay'); | |
| document.getElementById('functionGraph').addEventListener('mousemove', (e) => { | |
| const rect = e.target.getBoundingClientRect(); | |
| const x = xMin + (xMax - xMin) * (e.clientX - rect.left) / rect.width; | |
| const y = yMax - (yMax - yMin) * (e.clientY - rect.top) / rect.height; | |
| coordDisplay.textContent = `x: ${x.toFixed(2)}, y: ${y.toFixed(2)}`; | |
| }); | |
| function updateFunctionGraph() { | |
| const func = document.getElementById('functionInput').value; | |
| const data = []; | |
| let isValid = true; | |
| for (let x = xMin; x <= xMax; x += (xMax - xMin)/200) { | |
| try { | |
| const y = math.evaluate(func, {x: x}); | |
| if (!isNaN(y) && isFinite(y)) { | |
| data.push({x: x, y: y}); | |
| } else { | |
| isValid = false; | |
| } | |
| } catch (e) { | |
| console.error("Error evaluating function:", e); | |
| isValid = false; | |
| } | |
| } | |
| // Update line color based on validity | |
| functionGraph.data.datasets[0].borderColor = isValid ? '#7c3aed' : '#ef4444'; | |
| functionGraph.data.datasets[0].data = data; | |
| functionGraph.update(); | |
| } | |
| // Update algebra graph with sliders | |
| document.getElementById('sliderM').addEventListener('input', updateAlgebraGraph); | |
| document.getElementById('sliderB').addEventListener('input', updateAlgebraGraph); | |
| function updateAlgebraGraph() { | |
| const m = parseFloat(document.getElementById('sliderM').value); | |
| const b = parseFloat(document.getElementById('sliderB').value); | |
| const data = [ | |
| {x: -10, y: m*-10 + b}, | |
| {x: 10, y: m*10 + b} | |
| ]; | |
| algebraGraph.data.datasets[0].data = data; | |
| algebraGraph.update(); | |
| } | |
| // Initialize graphs | |
| updateFunctionGraph(); | |
| updateAlgebraGraph(); | |
| // Geometry Canvas Interaction | |
| const geometryCanvas = document.getElementById('geometryCanvas'); | |
| let isDrawing = false; | |
| let currentShape = null; | |
| let startX, startY; | |
| document.getElementById('drawLine').addEventListener('click', () => setShapeMode('line')); | |
| document.getElementById('drawCircle').addEventListener('click', () => setShapeMode('circle')); | |
| document.getElementById('drawRectangle').addEventListener('click', () => setShapeMode('rectangle')); | |
| document.getElementById('drawTriangle').addEventListener('click', () => setShapeMode('triangle')); | |
| function setShapeMode(shape) { | |
| currentShape = shape; | |
| clearGeometryCanvas(); | |
| } | |
| function clearGeometryCanvas() { | |
| geometryCanvas.innerHTML = '<div class="absolute inset-0 flex items-center justify-center text-gray-400">Draw shapes here</div>'; | |
| } | |
| geometryCanvas.addEventListener('mousedown', (e) => { | |
| if (!currentShape) return; | |
| isDrawing = true; | |
| const rect = geometryCanvas.getBoundingClientRect(); | |
| startX = e.clientX - rect.left; | |
| startY = e.clientY - rect.top; | |
| // Clear instructions if present | |
| if (geometryCanvas.querySelector('div')) { | |
| geometryCanvas.innerHTML = ''; | |
| } | |
| }); | |
| geometryCanvas.addEventListener('mousemove', (e) => { | |
| if (!isDrawing || !currentShape) return; | |
| const rect = geometryCanvas.getBoundingClientRect(); | |
| const endX = e.clientX - rect.left; | |
| const endY = e.clientY - rect.top; | |
| // Clear previous shape | |
| geometryCanvas.innerHTML = ''; | |
| // Draw new shape | |
| const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); | |
| svg.setAttribute('width', '100%'); | |
| svg.setAttribute('height', '100%'); | |
| svg.style.position = 'absolute'; | |
| let shape; | |
| switch (currentShape) { | |
| case 'line': | |
| shape = document.createElementNS("http://www.w3.org/2000/svg", "line"); | |
| shape.setAttribute('x1', startX); | |
| shape.setAttribute('y1', startY); | |
| shape.setAttribute('x2', endX); | |
| shape.setAttribute('y2', endY); | |
| shape.setAttribute('stroke', '#7c3aed'); | |
| shape.setAttribute('stroke-width', '2'); | |
| break; | |
| case 'circle': | |
| const radius = Math.sqrt(Math.pow(endX - startX, 2) + Math.pow(endY - startY, 2)); | |
| shape = document.createElementNS("http://www.w3.org/2000/svg", "circle"); | |
| shape.setAttribute('cx', startX); | |
| shape.setAttribute('cy', startY); | |
| shape.setAttribute('r', radius); | |
| shape.setAttribute('fill', 'rgba(124, 58, 237, 0.2)'); | |
| shape.setAttribute('stroke', '#7c3aed'); | |
| shape.setAttribute('stroke-width', '2'); | |
| break; | |
| case 'rectangle': | |
| shape = document.createElementNS("http://www.w3.org/2000/svg", "rect"); | |
| shape.setAttribute('x', Math.min(startX, endX)); | |
| shape.setAttribute('y', Math.min(startY, endY)); | |
| shape.setAttribute('width', Math.abs(endX - startX)); | |
| shape.setAttribute('height', Math.abs(endY - startY)); | |
| shape.setAttribute('fill', 'rgba(124, 58, 237, 0.2)'); | |
| shape.setAttribute('stroke', '#7c3aed'); | |
| shape.setAttribute('stroke-width', '2'); | |
| break; | |
| case 'triangle': | |
| shape = document.createElementNS("http://www.w3.org/2000/svg", "polygon"); | |
| const points = `${startX},${startY} ${endX},${endY} ${startX},${endY}`; | |
| shape.setAttribute('points', points); | |
| shape.setAttribute('fill', 'rgba(124, 58, 237, 0.2)'); | |
| shape.setAttribute('stroke', '#7c3aed'); | |
| shape.setAttribute('stroke-width', '2'); | |
| break; | |
| } | |
| svg.appendChild(shape); | |
| geometryCanvas.appendChild(svg); | |
| }); | |
| geometryCanvas.addEventListener('mouseup', () => { | |
| isDrawing = false; | |
| }); | |
| geometryCanvas.addEventListener('mouseleave', () => { | |
| isDrawing = false; | |
| }); | |
| }); |