user3719454
user3719454

Reputation: 1024

How to draw matrix with canvas gradient?

I can draw color transition with createLinearGradient() but this works either horizontally or vertically.

Now I have a matrix where each cell contains a color code. How to draw the entire matrix with gradient colors?

EDIT: Consider the following code:

    var c = document.getElementById("myCanvas");
    var ctx = c.getContext("2d");

    var grd = ctx.createLinearGradient(0, 0, 170, 0);
    grd.addColorStop(0, "red");
    grd.addColorStop(1, "green");

    ctx.fillStyle = grd;
    ctx.fillRect(20, 20, 150, 50);

    grd = ctx.createLinearGradient(0, 0, 170, 0);
    grd.addColorStop(0, "blue");
    grd.addColorStop(1, "yellow");

    ctx.fillStyle = grd;
    ctx.fillRect(20, 70, 150, 50);

I'm drawing the first gradient (red->green) then the second gradient (blue->yellow). But I would like to see the transition also from red->blue and green->yellow. Is it possible somehow?

Upvotes: 0

Views: 488

Answers (1)

JstnPwll
JstnPwll

Reputation: 8685

You can render any gradients you need to blend off-screen and then change the composite operation to draw a mask over it. Then, copy it back onto the onscreen canvas. See the example below. I've created a function where you can pass a two-dimensional array of colors as your matrix, and a sharpness setting which defines how tight to make the gradient blends. (0 is full blending between adjacent colors, 1 is a hard line between adjacent colors)

var addColorStops = function(row, gradient, sharpness){
  var colWidth = 1/row.length, step = 1/(row.length-1);
  gradient.addColorStop(0, row[0]);
  for(var i=0; i<row.length; ++i){
    if(i==0){
      if(sharpness > 0)gradient.addColorStop(colWidth*sharpness, row[i]);
    }else if(i == row.length-1){
      if(sharpness > 0)gradient.addColorStop(1-(colWidth*sharpness), row[i]);
    }else{
      if(sharpness > 0)gradient.addColorStop(step*i-colWidth/2*sharpness, row[i]);
      gradient.addColorStop(step*i, row[i]);
      if(sharpness > 0)gradient.addColorStop(step*i+colWidth/2*sharpness, row[i]);
    }
  }
  gradient.addColorStop(1, row[row.length-1]);
}
var drawRow = function(ctx, canvas, row, sharpness){
  var gradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
  addColorStops(row, gradient, sharpness)
  ctx.fillStyle = gradient;
  ctx.fillRect(0, 0, canvas.width, canvas.height);
}
var drawMask = function(ctx, canvas, matrix, rowIndex, sharpness){
  var mask = ctx.createLinearGradient(0, 0, 0, canvas.height);
  addColorStops(matrix.map(function(row,i){return i==rowIndex?'rgba(255,255,255,0)':'rgba(255,255,255,1)'}), mask, sharpness)
  ctx.fillStyle = mask;
  ctx.globalCompositeOperation = 'destination-out';
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  ctx.globalCompositeOperation = 'source-over';
}
var drawMatrixGradient = function(matrix, sharpness){
  sharpness = Math.min(1, Math.max(0, sharpness||0))
  var onscreen = document.getElementById('canvas');
  var ctx = onscreen.getContext('2d');
  var offScreen = document.createElement('canvas');
  offScreen.width = onscreen.width;
  offScreen.height = onscreen.height;
  var ctx2 = offScreen.getContext('2d');
  
  //Draw the first row
  drawRow(ctx, onscreen, matrix[0], sharpness)
  
  //Now draw the rest
  for(var i=1; i<matrix.length; ++i){
    drawRow(ctx2, offScreen, matrix[i], sharpness)
    drawMask(ctx2, offScreen, matrix, i, sharpness);
    ctx.drawImage(offScreen, 0, 0, canvas.width, canvas.height);
  }
}


drawMatrixGradient([['red','green','blue'],['yellow','purple','orange'],['magenta','aqua','white']], 0.5)
<canvas id="canvas" width="250" height="250"></canvas>

Upvotes: 2

Related Questions