dragonmnl dragonmnl - 3 months ago 5x
Javascript Question

Divide a canvas into spaces of same width and height

I want to have a canvas which covers the full page (apart from a top area and a left area) as shown in the image below (blue area).

I want to divide the canvas in squares/rectangles (yellow lines) each one with the same height and width in a way that I can add some fixed size rectangle (green rectangles) in the grid. Well, something similar to Windows 7 Desktop grid (or Windows 8 Metro) in which icons are aligned to the grid.

The way I guessed to implement it is:

  • draw the blue Canvas: get page height and width and subtract the grey area

  • divide the Canvas in equal dimensions rectangles in a way that when I drag and drop one of the green rectangle into it gets aligned to the grid: no idea here

  • drawing and dragging green rectangles (let's call them nodes): I'm going to use
    to add a Div for each rectangle, and using jQuery UI to drag them. This is already done. Here is an example: http://myownlibrary.altervista.org/es4/

  • One further step I would take is to make the canvas area extendable,that is, when all the rectangles contain some node, I want the canvas to "grow" in width/height (and it is going to be scrolled using horizontal and vertical scroll bars).

it says canvas and has a grid


Divide a canvas into spaces of same width and height

The first thing you need to determine is how you want to divide the space:

  1. By a fixed number of columns and rows
  2. By a predefined tile width and height.

For the latter you probably want to adjust the size to the closest, but to keep it simple lets stick to the first approach.


Lets say you want a fixed number of tiles:

var columns = 6,
    rows    = 4;

Then the size of each tile would be:

var tileWidth  = canvas.width / columns,
    tileHeight = canvas.height / rows;

This number may or may not be a float. If you need integer only values you simple round them:

var tileWidth  = Math.round(canvas.width / columns),
    tileHeight = Math.round(canvas.height / rows);

Now you can use indexes to determine the position for each tile:

var x = xIndex * tileWidth,
    y = yIndex * tileHeight;

This x and y can be used directly to set the position of a tile.

If you want to "snap" the tiles you need to use the mouse position relative to canvas:

canvas.onmousemove = function(e) {

    /// adjust mouse position to be relative to canvas
    var rect = canvas.getBoundingClientRect(),
        mx = e.clientX - rect.left,
        my = e.clientY - rect.top,

        /// get index from mouse position
        xIndex = Math.round(mx / tileWidth),
        yIndex = Math.round(my / tileHeight);

    /// calculate x and y based on previous formula

You may want to snap from the center of the tile and not the corner. Just subtract half the tile width and height from the mouse position to achieve that.

xIndex = Math.round((mx - tileWidth * 0.5) / tileWidth);
yIndex = Math.round((my - tileHeight * 0.5) / tileHeight);

You may want to check the index bounds (xIndex >= 0 && xIndex < columns etc.)