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. need to preserve that clicking functionality to draw lines on grid. try integrate all described above but preserve mouse clicking on points that draw lines between 3d matrix grid points. output full javascript code, without shortages, but without html code included.: <!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>