<div id="graph-container">
<canvas id="graph" width="600" height="600"></canvas>
</div>
<script>
const canvas = document.getElementById("graph");
const ctx = canvas.getContext("2d");
const width = canvas.width;
const height = canvas.height;
const scale = 50; // px / unit
function drawGrid() {
ctx.clearRect(0, 0, width, height);
ctx.strokeStyle = "#333";
ctx.lineWidth = 1;
for (let x = 0; x <= width; x += scale) {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, height);
ctx.stroke();
}
for (let y = 0; y <= height; y += scale) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(width, y);
ctx.stroke();
}
// Axes
ctx.strokeStyle = "#888";
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(width / 2, 0);
ctx.lineTo(width / 2, height);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(0, height / 2);
ctx.lineTo(width, height / 2);
ctx.stroke();
}
function draw() {
drawGrid();
let eq = document.getElementById("equation").value;
if (!eq.includes("=")) return;
let expr = eq.split("=")[1];
expr = expr
.replace(/\^/g, "**")
.replace(/sin/g, "Math.sin")
.replace(/cos/g, "Math.cos")
.replace(/tan/g, "Math.tan");
expr = addImplicitMultiplication(expr);
ctx.strokeStyle = "#00ffcc";
ctx.lineWidth = 2;
ctx.beginPath();
let first = true;
// Sample x in small steps (not 1 pixel per step) to avoid stair-step artifacts
const step = 0.1; // pixels; reduce to 0.5 or 0.25 for smoother curves
for (let px = -width / 2; px < width / 2; px += step) {
let x = px / scale;
let y;
// Break the path on invalid or extreme values to avoid vertical jumps
try {
y = eval(expr);
} catch {
return;
}
if (!isFinite(y) || Math.abs(y) > 1e6) {
first = true;
continue;
}
let py = -y * scale;
let cx = width / 2 + px;
let cy = height / 2 + py;
if (first) {
ctx.moveTo(cx, cy);
first = false;
} else {
ctx.lineTo(cx, cy);
}
}
ctx.stroke();
}
function addImplicitMultiplication(expr) {
// 2a -> 2*a
expr = expr.replace(/(\d)(x)/g, "$1*$2");
// xb -> x*b