1

So I am working on a pathfinding algoritm in javascript, for fun and practice, I need a grid, and I am trying to let the user decide how wide and tall the canvas should be and to let them decide how many columns and rows the grid has using the prompt method. I have this code and it only draws the columns and not the rows, no matter what input I give the site

let grid = {
  width: 0,
  height: 0,
}

grid.width = Number(prompt("how many columns do you want? don't type zero if you care about your computer's health"));
grid.height = Number(prompt("how many rows do you want? don't type zero if you care about your computer's health"));
const canvasWidth = Number(prompt("how many pixels wide do you want the screen? i recomend around 1000 but it depends on your computer (i think)"));
const canvasHeight = Number(prompt("how many pixels high do you want the screen? i recomend aroun 500 but it depends on your computer (i think)"));

let canvas = document.createElement("CANVAS");
let ctx = canvas.getContext("2d");
canvas.width = canvasWidth;
canvas.height = canvasHeight;
canvas.style.border = "1px solid black"
ctx.beginPath();
ctx.lineWidth = 1;
ctx.lineStyle = "black";
for (let x = 0; x < canvasWidth; x += canvasWidth / grid.width) {
  ctx.moveTo(x, 0)
  ctx.lineTo(x, canvasHeight)
}
for (let y = 0; y < canvasHeight; y += canvasHeight / grid.heigth) {
  ctx.moveTo(0, y)
  ctx.lineTo(canvasWidth, y)
}
ctx.stroke();
document.body.appendChild(canvas);

1
  • I updated the first part of my response below, to address the blurry line issue. Commented Jul 2, 2020 at 11:22

2 Answers 2

2

The for loops are using incorrect values according to the orientation of the lines they are drawing.

Should be:

for(let x = 0; x < canvasHeight; x += canvasHeight / grid.height){
    ctx.moveTo(x, 0)
    ctx.lineTo(x, canvasHeight)
}
for(let y = 0; y < canvasWidth; y += canvasWidth / grid.width){
    ctx.moveTo(0, y)
    ctx.lineTo(canvasWidth, y)
}

Try this:

let grid = {
    width:0,
    height:0,
}

grid.width = Number(prompt("how many columns do you want? don't type zero if you care about your computer's health"));
grid.height = Number(prompt("how many rows do you want? don't type zero if you care about your computer's health"));
const canvasWidth = Number(prompt("how many pixels wide do you want the screen? i recomend around 1000 but it depends on your computer (i think)"));
const canvasHeight = Number(prompt("how many pixels high do you want the screen? i recomend aroun 500 but it depends on your computer (i think)"));

let canvas = document.createElement("CANVAS");
let ctx = canvas.getContext("2d");
canvas.width = canvasWidth;
canvas.height = canvasHeight;
canvas.style.border = "1px solid black"
ctx.beginPath();
ctx.lineWidth = 1;
ctx.lineStyle = "black";
for(let x = 0; x < canvasHeight; x += canvasHeight / grid.height){
    ctx.moveTo(x, 0)
    ctx.lineTo(x, canvasHeight)
}
for(let y = 0; y < canvasWidth; y += canvasWidth / grid.width){
    ctx.moveTo(0, y)
    ctx.lineTo(canvasWidth, y)
}
ctx.stroke();
document.body.appendChild(canvas);

2

I recommend you set up your flow like this. It becomes more readable and offers extensibility. Pass the user-defined values as options to a function that handles creating grids. I provided some default values for the grid options.

Also, I recommend rounding your offsets, before drawing to the canvas.


Edit: If you notice, you are drawing blurry lines. You can easily fix this by translating the context by (0.5, 0.5).

Q: Why did you start x and y at 0.5? Why not 0?

See: http://diveintohtml5.info/canvas.html#paths

const questions = [
  "How many columns do you want? Don't type zero if you care about your computer's health?",
  "How many rows do you want? Don't type zero if you care about your computer's health?",
  "How many pixels wide do you want the screen? I recommend around 1,000, but it depends on your computer (I think)?",
  "How many pixels high do you want the screen? I recommend around 500, but it depends on your computer (I think)?"
];

const options = {
  cols   : Number(prompt(questions[0])) || 10,
  rows   : Number(prompt(questions[1])) || 10,
  width  : Number(prompt(questions[2])) || 100,
  height : Number(prompt(questions[3])) || 100
};

document.body.appendChild(createCanvasGrid(options));

function createCanvasGrid(options) {
  let canvas = document.createElement("CANVAS");
  let ctx = canvas.getContext("2d");

  canvas.width = options.width;
  canvas.height = options.height;
  canvas.style.border = "1px solid red"

  ctx.translate(0.5, 0.5); // https://stackoverflow.com/a/13294650/1762224

  ctx.beginPath();
  ctx.lineWidth = 1;
  ctx.strokeStyle = "red";

  let offsetX = Math.floor(options.width / options.cols);
  let offsetY = Math.floor(options.height / options.rows);

  for (let x = offsetX; x < options.width; x += offsetX) {
    ctx.moveTo(x, 0);
    ctx.lineTo(x, options.height);
  }
  
  for (let y = offsetY; y < options.height; y += offsetY) {
    ctx.moveTo(0, y);
    ctx.lineTo(options.width, y);
  }
  
  ctx.stroke();

  return canvas;
}

Advanced Example

Here is an advanced example that is configurable.

const DEFAULT_OPTIONS = {
  cols       : 10,
  rows       : 10,
  width      : 100,
  height     : 100,
  weight     : 1,
  background : null,
  color      : '#000000'
};

const main = () => {
  addGrid({
    width      : 150,
    height     : 150,
    background : '#183',
    color      : '#999'
  });
  
  addGrid({
    width      : 240,
    height     : 120,
    weight     : 2,
    color      : '#DDD'
  });
}

const addGrid = (options) => {
  document.body.appendChild(createCanvasGrid(options));
};

const createCanvasGrid = (options) => {
  let opts = Object.assign({}, DEFAULT_OPTIONS, options);
  let canvas = document.createElement("CANVAS");
  let ctx = canvas.getContext("2d");

  canvas.width = opts.width;
  canvas.height = opts.height;
  
  let weight2 = opts.weight * 2;
  let weightHalf = opts.weight / 2;
  
  let availWidth =  opts.width - opts.weight;
  let availHeight = opts.height - opts.weight;
  
  let cellWidth = availWidth / opts.cols;
  let cellHeight = availHeight / opts.rows;

  if (options.background) {
    ctx.fillStyle = opts.background;
    ctx.fillRect(0, 0, opts.width, opts.height);
  }
  
  ctx.beginPath();
  ctx.strokeStyle = opts.color;
  ctx.lineWidth = opts.weight;
  
  for (let col = 0; col <= opts.cols; col++) {
    let newX = Math.floor(col * cellWidth) + weightHalf;
    ctx.moveTo(newX, 0);
    ctx.lineTo(newX, opts.height);
  }
  
  for (let row = 0; row <= opts.rows; row++) {
    let newY = (row * cellHeight) + weightHalf;
    ctx.moveTo(0, newY);
    ctx.lineTo(opts.width, newY);
  }
  
  ctx.stroke();

  return canvas;
};

main();
body {
  background: #222;
  margin: 0;
  padding: 0;
}

canvas {
  margin: 0.5em;
}

2
  • Thank you, your code is much more organized than mine Commented Jul 1, 2020 at 18:54
  • @user12904234 I added an advanced example below. Commented Jul 1, 2020 at 19:25

Not the answer you're looking for? Browse other questions tagged or ask your own question.