javascriptcanvaskonvajskonva

How to Apply a Grayscale Image as an Opacity Mask to a Group in Konva.js?


I've read and tried the solution in this thread: How to use Konva.Group with Mask, but I couldn't figure out how to make it work.

My goal is to apply a grayscale image as an opacity mask to a Konva.Group (or even an entire layer) so that the mask controls the transparency of the group based on the grayscale values of the image.

Here’s the structure of my "stack":

Konva.Stage
    Konva.Layer  // Background layer
        Konva.Image  // Background image
    Konva.Layer  // Main content layer
        Konva.Group  // Group #1 with shapes, images
        Konva.Group  // Group #2 with shapes, images
        Konva.Group  // ... (other groups)
    Konva.Layer  // Mask layer
        Konva.Image  // Grayscale image for masking

I want the grayscale image from the mask layer to act as a mask for the content in the main content layer or specific groups within it.

Thank you 🇫🇷


Solution

  • Yes, you can achieve this using just the Konva API, including using the globalCompositeOperation = destination-in for top mask image. Make sure to put the mask image in the same layer as content.

    const stage = new Konva.Stage({
      container: 'container',
      width: window.innerWidth,
      height: window.innerHeight,
    });
    
    const mainLayer = new Konva.Layer();
    stage.add(mainLayer);
    
    // Create the main group and content
    const group = new Konva.Group();
    mainLayer.add(group);
    
    for (let i = 0; i < 20; i++) {
      const circle = new Konva.Circle({
        x: Math.random() * stage.width(),
        y: Math.random() * stage.height(),
        radius: 50 + Math.random() * 30,
        fill: Konva.Util.getRandomColor(),
      });
      group.add(circle);
    }
    
    // Mask Image
    const maskImageObj = new Image();
    maskImageObj.src = 'https://konvajs.org/assets/lion.png'; // Grayscale image
    
    maskImageObj.onload = () => {
      const mask = new Konva.Image({
        image: maskImageObj,
        x: 50,
        y: 50,
        width: 200,
        height: 200,
        draggable: true,
        globalCompositeOperation: 'destination-in', // Blend mode
      });
    
      mainLayer.add(mask);
      mainLayer.batchDraw();
    };
    
    // Batch draw to update the stage with new content
    mainLayer.batchDraw();
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Konva Mask with Global Composite Operation</title>
        <script src="https://cdn.jsdelivr.net/npm/konva/konva.min.js"></script>
        <style>
            body {
                margin: 0;
            }
        </style>
    </head>
    <body>
      <div id="container"></div>
    </body>
    </html>