mathmagic-visualizer / math-visualizer.js
Fadlhasn's picture
اجعل هذا الغراف اكثر ديناميكا وتحكم ومعلومات
daf20e7 verified
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;
});
});