const GRID_HEIGHT = 10
const GRID_WIDTH = 10
const CELLSIZE = 32
const OUTLINE_COLOUR = 'green';
const FILL_COLOUR = 'red'
const RAY_COLOUR = 'blue';
const X = 0;
const Y = 1;
const canvas = document.getElementById('demo');
const ctx = canvas.getContext('2d');
var mouseVector = new Vector2D([0, 0], [0, 0]);
canvas.height = GRID_HEIGHT * CELLSIZE;
canvas.width = GRID_WIDTH * CELLSIZE
canvas.addEventListener("mousemove", updateMouseVector);
canvas.addEventListener("click", setMouseVectorOrigin);
function Vector2D(point1, point2)
{
if (point2 != undefined)
{
this.p1 = point1;
this.p2 = point2;
}
else
{
this.p1 = [0, 0];
this.p2 = point1;
};
};
function drawCellOutline(cx, cy)
{
ctx.fillStyle = OUTLINE_COLOUR;
ctx.strokeRect(cx * CELLSIZE, cy * CELLSIZE, CELLSIZE, CELLSIZE);
};
function fillCell(cx, cy)
{
ctx.fillStyle = FILL_COLOUR;
ctx.fillRect(Math.floor(cx) * CELLSIZE, Math.floor(cy) * CELLSIZE, CELLSIZE, CELLSIZE);
};
function drawGrid()
{
for (let y = 0; y < GRID_HEIGHT; y++)
{
for (let x = 0; x < GRID_WIDTH; x++)
{
drawCellOutline(x, y);
};
};
};
function clearCanvas()
{
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
};
function getMouseCoordinates(e)
{
let mouseX, mouseY;
if (e.offsetX) {
mouseX = e.offsetX;
mouseY = e.offsetY;
} else if (e.layerX) {
mouseX = e.layerX;
mouseY = e.layerY;
}
return [mouseX, mouseY]
}
function updateMouseVector(e)
{
let mousePos = getMouseCoordinates(e);
mouseVector.p2[0] = mousePos[0]// + 0.5;
mouseVector.p2[1] = mousePos[1]// + 0.5;
}
function setMouseVectorOrigin(e)
{
let mousePos = getMouseCoordinates(e);
mouseVector.p1[0] = mousePos[0]// + 0.5;
mouseVector.p1[1] = mousePos[1]// + 0.5;
};
function drawRay(rayVector)
{
ctx.fillStyle = RAY_COLOUR;
ctx.beginPath();
ctx.moveTo(rayVector.p1[0], rayVector.p1[1]);
ctx.lineTo(rayVector.p2[0], rayVector.p2[1]);
ctx.stroke();
}
function rayMarch(rayVector)
{
let cellVector = {p1: [rayVector.p1[X] / CELLSIZE, rayVector.p1[Y] / CELLSIZE],
p2: [rayVector.p2[X] / CELLSIZE, rayVector.p2[Y] / CELLSIZE]};
let x0 = cellVector.p1[X];
let x1 = cellVector.p2[X];
let y0 = cellVector.p1[Y];
let y1 = cellVector.p2[Y];
let dx = x1 - x0;
let dy = y1 - y0;
dx = Math.abs(dx);
dy = Math.abs(dy);
//adjust dx / dy to avoid div-by-zero
let dtDx = 1.0 / dx;
let dtDy = 1.0 / dy;
let xInc = 0//dx / steps;
let yInc = 0//dy / steps;
let txNext = 0;
let tyNext = 0;
let x = Math.floor(x0);
let y = Math.floor(y0);
let n = 1;
if (dx == 0)
{
xInc = 0;
txNext = dtDx; // infinity
}
else if (x1 > x0)
{
xInc = 1;
n += Math.floor(x1) - x;
txNext = (Math.floor(x0) + 1 - x0) * dtDx;
}
else
{
xInc = -1;
n += x - Math.floor(x1);
txNext = (x0 - Math.floor(x0)) * dtDx;
}
if (dy == 0)
{
yInc = 0;
tyNext = dtDy; // infinity
}
else if (y1 > y0)
{
yInc = 1;
n += Math.floor(y1) - y;
tyNext = (Math.floor(y0) + 1 - y0) * dtDy;
}
else
{
yInc = -1;
n += y - Math.floor(y1);
tyNext = (y0 - Math.floor(y0)) * dtDy;
}
let t = 0;
for (; n > 0; --n)
{
fillCell(x, y);
if (tyNext < txNext)
{
y += yInc;
t = tyNext
tyNext += dtDy;
}
else
{
x += xInc;
t = txNext;
txNext += dtDx;
}
}
};
function main()
{
clearCanvas();
drawGrid();
rayMarch(mouseVector);
drawRay(mouseVector);
requestAnimationFrame(main);
};
requestAnimationFrame(main);
<canvas id="demo"></canvas>
See also working fiddle. For your future reference: