Is it possible to make a gradient-transparent/layer masking image using canvas?

Viewed 23216

I've been following the lessons about transparency and gradients on the Mozilla site: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Applying_styles_and_colors but I have not been able to figure this one out.

I know I can achieve these effects with a png image; however, in the program I am working on the gradient will change constantly according to where the image is moved.

Here's an example of the effect I'm looking for. http://home.insightbb.com/~epyonxl1/gradientex.jpg

5 Answers

I have modernized Alnitak's response by incorporating asynchronous loading of the images.

I also got rid of magic numbers.

const imageUrls = [
  // Base image
  'http://www.netstate.com/states/symb/flowers/images/apple_blossoms.jpg',
  // Gradient image
  'http://www.netstate.com/states/symb/flowers/images/oklahoma_rose.jpg'
];

const main = async () => {
  const ctx = document.getElementById('cv').getContext('2d'),
    baseImg = await loadImage(imageUrls[0]),
    gradImg = await loadImage(imageUrls[1]);

  draw(ctx, baseImg, gradImg);
};

/**
 * Loads an Image object via a Promise.
 * @param {String} url - Location of an image file
 * @return {Promise<Image>} Returns a promise that resolves to an Image.
 */
const loadImage = (url) => new Promise((resolve, reject) => {
  const img = new Image();
  img.addEventListener('load', () => resolve(img));
  img.addEventListener('error', reject);
  img.src = url;
});

/**
 * Draws an image, as a gradient applied to it, above another image.
 * @param {Image} baseImg - Image that is applied under the gradient
 * @param {Image} gradImg - Image to be applied as a gradient
 */
const draw = (ctx, baseImg, gradImg) => {
  const {width, height} = baseImg,
      originX = Math.floor(width / 2),
      originY = Math.floor(height / 2),
      radius = Math.min(originX, originY);

  const offScreen = document.createElement('canvas');
  offScreen.width = offScreen.height = width;
  const ctx2 = offScreen.getContext('2d');

  ctx2.drawImage(gradImg, 0, 0, width, height);
  const gradient = ctx2.createRadialGradient(originX, originY, 0, originX, originY, radius);

  gradient.addColorStop(0, 'rgba(255, 255, 255, 0)');
  gradient.addColorStop(1, 'rgba(255, 255, 255, 1)');

  ctx2.fillStyle = gradient;
  ctx2.globalCompositeOperation = 'destination-out';
  ctx2.fillRect(0, 0, width, height);

  ctx.drawImage(baseImg, 0, 0, width, height);
  ctx.drawImage(offScreen, 0, 0, width, height);
};

main();
<canvas id="cv" width="300" height="300"></canvas>

Related