do zoom ability in here, to zoom in and out inside that cube grid with mouse wheel. also, do some rotation on all axis by mous dragging in empty space, set flag for auto-rotation to false. also, try to fit the entire 3d matrix grid on full canvas automatically, independent of gridSize or gridSpacing, with some small empty space around borders: <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>drawacube</title>
    <style>
        canvas {
            display: block;
            margin: auto;
        }
    </style>
</head>
<body>
    <canvas id="canvas"></canvas>
  <script>
  const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

const rotationSpeed = 0.001;
const gridSize = 50;
const gridSpacing = 25;

let grid = [];
for (let x = -gridSize; x <= gridSize; x += gridSpacing) {
    for (let y = -gridSize; y <= gridSize; y += gridSpacing) {
        for (let z = -gridSize; z <= gridSize; z += gridSpacing) {
            grid.push({ x, y, z });
        }
    }
}
let lastClickedPoint = null;
const clickedPoints = [];
let angleX = 0;
let angleY = 0;

function rotate(point, angleX, angleY) {
    const { x, y, z } = point;
    const cosX = Math.cos(angleX);
    const sinX = Math.sin(angleX);
    const cosY = Math.cos(angleY);
    const sinY = Math.sin(angleY);

    const newY = y * cosX - z * sinX;
    const newZ = y * sinX + z * cosX;
    const newX = x * cosY - newZ * sinY;
    const newZ2 = x * sinY + newZ * cosY;

    return { x: newX, y: newY, z: newZ2 };
}

function project(point, width, height) {
    const { x, y, z } = point;

    const scale = 800 / (400 + z);
    const newX = x * scale + width / 2;
    const newY = y * scale + height / 2;

    return { x: newX, y: newY };
}

function findClosestPoint(point) {
    const threshold = 20; // Adjust this value to set the click tolerance
    let minDist = Infinity;
    let minIndex = -1;

    for (let i = 0; i < grid.length; i++) {
        const projected = project(rotate(grid[i], angleX, angleY), canvas.width, canvas.height);
        const dx = point.x - projected.x;
        const dy = point.y - projected.y;
        const dist = Math.sqrt(dx * dx + dy * dy);

        if (dist < minDist && dist <= threshold) {
            minDist = dist;
            minIndex = i;
        }
    }

    return minIndex !== -1 ? grid[minIndex] : null;
}

let mouseDown = false;
let activeLine = null;
const lines = [];

canvas.addEventListener("mousedown", (e) => {
    mouseDown = true;
    const canvasRect = canvas.getBoundingClientRect();
    const mouseX = e.clientX - canvasRect.left;
    const mouseY = e.clientY - canvasRect.top;
    const startPoint = findClosestPoint({ x: mouseX, y: mouseY });

    activeLine = [startPoint];
});
canvas.addEventListener("mousedown", (e) => {
    mouseDown = true;
    const canvasRect = canvas.getBoundingClientRect();
    const mouseX = e.clientX - canvasRect.left;
    const mouseY = e.clientY - canvasRect.top;
    const startPoint = findClosestPoint({ x: mouseX, y: mouseY });

    activeLine = [startPoint];
});

canvas.addEventListener("mouseup", (e) => {
    mouseDown = false;

    if (activeLine !== null) {
        const canvasRect = canvas.getBoundingClientRect();
        const mouseX = e.clientX - canvasRect.left;
        const mouseY = e.clientY - canvasRect.top;
        const endPoint = findClosestPoint({ x: mouseX, y: mouseY });

        if (endPoint !== activeLine[activeLine.length - 1]) {
            activeLine.push(endPoint);
            lines.push(activeLine);
        }
        activeLine = null;
    }

    if (lastClickedPoint !== null) {
        const canvasRect = canvas.getBoundingClientRect();
        const mouseX = e.clientX - canvasRect.left;
        const mouseY = e.clientY - canvasRect.top;
        const clickedPoint = findClosestPoint({ x: mouseX, y: mouseY });

        if (clickedPoint !== null) {
            if (lastClickedPoint === clickedPoint) {
                lastClickedPoint = null;
            } else {
                lines.push([lastClickedPoint, clickedPoint]);
                clickedPoints.push(clickedPoint);
                lastClickedPoint = null;
            }
        }
    } else {
        const canvasRect = canvas.getBoundingClientRect();
        const mouseX = e.clientX - canvasRect.left;
        const mouseY = e.clientY - canvasRect.top;
        const clickedPoint = findClosestPoint({ x: mouseX, y: mouseY });

        if (clickedPoint !== null) {
            lastClickedPoint = clickedPoint;
            clickedPoints.push(clickedPoint);
        }
    }
});
function drawLine(line) {
    ctx.beginPath();

    for (let i = 0; i < line.length - 1; i++) {
        const projectedStart = project(rotate(line[i], angleX, angleY), canvas.width, canvas.height);
        const projectedEnd = project(rotate(line[i + 1], angleX, angleY), canvas.width, canvas.height);

        ctx.moveTo(projectedStart.x, projectedStart.y);
        ctx.lineTo(projectedEnd.x, projectedEnd.y);
    }

    ctx.strokeStyle = "rgba(25,200,25,0.2)";
    ctx.lineWidth = 2;
    ctx.stroke();
}

function draw() {
    ctx.fillStyle = "rgba(1,2,1,0.8)";
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    for (const point of grid) {
        const rotated = rotate(point, angleX, angleY);
        const projected = project(rotated, canvas.width, canvas.height);

        ctx.beginPath();
        ctx.arc(projected.x, projected.y, 2, 0, Math.PI * 2);
        ctx.closePath();
        ctx.fillStyle = "rgba(55,155,255,0.8)";
        ctx.fill();
    }

    // Drawing clicked points in green
    ctx.fillStyle = "rgba(255,200,50,0.8)";
    for (const clickedPoint of clickedPoints) {
        const rotated = rotate(clickedPoint, angleX, angleY);
        const projected = project(rotated, canvas.width, canvas.height);

        ctx.beginPath();
        ctx.arc(projected.x, projected.y, 4, 0, Math.PI * 2);
        ctx.closePath();
        ctx.fill();
    }

    for (const line of lines) {
        drawLine(line);
    }

    if (activeLine !== null) {
        drawLine(activeLine);
    }

    angleX += rotationSpeed;
    angleY += rotationSpeed;

    requestAnimationFrame(draw);
}

draw();
  </script>
</body>
</html>