Shannon Hochkins
Shannon Hochkins

Reputation: 12176

Apply a gradient as a mask to a gradient fill in canvas?

I need a horizontal gradient with multiple color stops, and then i wanted to apply a black -> transparent vertical gradient as a mask to fade the gradient out vertically, is this even possible?

const topPoint = [...dataset.data].sort((a, b) => b.y - a.y);
const startY = yAxis.getPixelForValue(topPoint[0].y, index, 0);
// gradient is drawn from the highest peak to the bottom of the graph
const gradient = ctx.createLinearGradient(0, startY, 0, yAxis.bottom);
gradient.addColorStop(0, customGradientFill.gradientColor1);
gradient.addColorStop(1, customGradientFill.gradientColor2);

The above draws a vertical gradient fading to transparent, however this is just one colour so i was hoping to have a horizontal gradient, and a vertical gradient mask

enter image description here

Upvotes: 0

Views: 223

Answers (1)

Kaiido
Kaiido

Reputation: 137006

Draw it in two passes, first the horizontal color, then the shade of white over:

const canvas = document.getElementById( "canvas" );
const ctx = canvas.getContext( "2d" );
const data = [];
for( let x = 0; x <= canvas.width; x += 10 ) {
  const y = Math.random() * (canvas.height / 3);
  data.push( { x, y } );
}
// draw the graph
ctx.beginPath();
data.forEach( ({x, y}) => ctx.lineTo( x, y ) );
ctx.lineTo( canvas.width, canvas.height );
ctx.lineTo( 0, canvas.height );
ctx.closePath();

// declare the gradients
const color_grad = ctx.createLinearGradient( 0, 0, canvas.width, 0 );
color_grad.addColorStop( 0.15, "red" );
color_grad.addColorStop( 0.15, "orange" );

const shade_grad = ctx.createLinearGradient( 0, 0, 0, canvas.height );
shade_grad.addColorStop( 0, "transparent" );
shade_grad.addColorStop( 1, "white" );

// first pass
ctx.fillStyle = color_grad;
ctx.fill();
// second pass
ctx.fillStyle = shade_grad;
ctx.fill();
<canvas id="canvas"></canvas>

If you need transparency, you can use compositing for the second pass:

const canvas = document.getElementById( "canvas" );
const ctx = canvas.getContext( "2d" );
const data = [];
for( let x = 0; x <= canvas.width; x += 10 ) {
  const y = Math.random() * (canvas.height / 3);
  data.push( { x, y } );
}
// draw the graph
ctx.beginPath();
data.forEach( ({x, y}) => ctx.lineTo( x, y ) );
ctx.lineTo( canvas.width, canvas.height );
ctx.lineTo( 0, canvas.height );
ctx.closePath();

// declare the gradients
const color_grad = ctx.createLinearGradient( 0, 0, canvas.width, 0 );
color_grad.addColorStop( 0.15, "red" );
color_grad.addColorStop( 0.15, "orange" );

const shade_grad = ctx.createLinearGradient( 0, 0, 0, canvas.height );
shade_grad.addColorStop( 0, "transparent" );
shade_grad.addColorStop( 1, "white" );

// first pass
ctx.fillStyle = color_grad;
ctx.fill();

// second pass
ctx.fillStyle = shade_grad;
// new opaque pixels "erase" previous content
ctx.globalCompositeOperation = "destination-out";
ctx.fill();
body { background: #AAA; }
<canvas id="canvas"></canvas>

Upvotes: 1

Related Questions