Eric
Eric

Reputation: 5091

HTML canvas : how to create a polygon filled with a grid

I order to build a HTML 5 datacenter floor plan, I would like to create a polygon filled with a grid. This grid must not be a picture pattern as I would like to be able to zoom or rotate the floor plan without having pixelization. I would like to be able to create this kind of output :

enter image description here

How can I do that ?

Upvotes: 0

Views: 389

Answers (1)

Kaiido
Kaiido

Reputation: 136638

There are multiple ways, like

var ctx = c.getContext('2d');
drawShape();
ctx.stroke();
ctx.save(); // so we can remove the clipping
ctx.clip();
drawGrid();
ctx.restore(); // remove the clipping

function drawShape() {
  ctx.beginPath();
  var pts = [
    20, 20,
    80, 20,
    90, 50,
    120, 90,
    30, 80,
    20,20
  ];
  for(var i=0;i<pts.length;i+=2){
    ctx.lineTo(pts[i], pts[i+1]);
  }
}
function drawGrid() {
  ctx.beginPath();
  for(var x=-.5; x<c.width; x+=20) {
    ctx.moveTo(x, 0);
    ctx.lineTo(x, c.height);
  }
  for(var y=-.5; y<c.height; y+=20) {
    ctx.moveTo(0, y);
    ctx.lineTo(c.width, y);
  }
  ctx.stroke();
}
    
<canvas id="c"></canvas>

var ctx = c.getContext('2d');
drawGrid();
ctx.globalCompositeOperation = 'destination-in';
drawShape();
ctx.fill();
ctx.globalCompositeOperation = 'source-over';
ctx.stroke();

function drawShape() {
  ctx.beginPath();
  var pts = [
    20, 20,
    80, 20,
    90, 50,
    120, 90,
    30, 80,
    20,20
  ];
  for(var i=0;i<pts.length;i+=2){
    ctx.lineTo(pts[i], pts[i+1]);
  }
}
function drawGrid() {
  ctx.beginPath();
  for(var x=-.5; x<c.width; x+=20) {
    ctx.moveTo(x, 0);
    ctx.lineTo(x, c.height);
  }
  for(var y=-.5; y<c.height; y+=20) {
    ctx.moveTo(0, y);
    ctx.lineTo(c.width, y);
  }
  ctx.stroke();
}
    
<canvas id="c"></canvas>

But in your case, a regular grid, it might actually be better to use a pattern.

Indeed, you'd have to only draw one cell every time you change the scale of your grid, for translations, this can be done internally.
So I didn't do the performance tests myself, and thus encourage you to double check it's worth it, but theoretically, it might be faster and esaier to manage than redrawing the grid every time.

var ctx = c.getContext('2d');
var pat_ctx = document.createElement('canvas').getContext('2d');
var cell_size = 20;

// just a basic drawing example
// first we generate the grid as a pattern
ctx.fillStyle = generatePattern(cell_size, cell_size);
drawShape();
ctx.stroke();
// we move the pattern by half a cell because we actually drawn only a cross
ctx.translate(-cell_size / 2, -cell_size / 2);
ctx.fill();


// make the grid follow the mouse
// without having to redraw ourself the grid
onmousemove = function(e) {
  ctx.setTransform(1, 0, 0, 1, 0, 0);
  ctx.clearRect(0, 0, c.width, c.height);
  drawShape();
  ctx.stroke();
  // move the grid
  ctx.translate(e.clientX - cell_size / 2, e.clientY - -cell_size / 2);
  ctx.fill();
}
// click to zoom (+shift to zoom out)
onclick = function(e) {
  if (e.shiftKey) cell_size--;
  else cell_size++;
  ctx.fillStyle = generatePattern(cell_size, cell_size);
  onmousemove(e);
}
// dimply draws a cross
function generatePattern(w, h) {
  var canvas = pat_ctx.canvas;
  canvas.width = w;
  canvas.height = h;
  pat_ctx.moveTo(w / 2, 0);
  pat_ctx.lineTo(w / 2, h);
  pat_ctx.moveTo(0, h / 2);
  pat_ctx.lineTo(w, h / 2);
  pat_ctx.stroke();
  return pat_ctx.createPattern(canvas, 'repeat');
}

function drawShape() {
  ctx.beginPath();
  var pts = [
    20, 20,
    80, 20,
    90, 50,
    120, 90,
    30, 80,
    20, 20
  ];
  for (var i = 0; i < pts.length; i += 2) {
    ctx.lineTo(pts[i], pts[i + 1]);
  }
}
<canvas id="c"></canvas>

Upvotes: 1

Related Questions