Skip to main content

HTML5 Canvas Isolated Groups - Group Opacity and Blend Modes

By default a Konva.Group only organizes its children. When the group is drawn, every child is drawn directly onto the layer canvas:

  • The group opacity is multiplied into each child, so you can see where the children overlap.
  • A child with a globalCompositeOperation such as multiply or destination-out blends with everything already drawn on the layer, not just with its siblings.

Set isolated: true to draw the group as one image. An isolated group draws its children into a separate transparent canvas first. Then it puts the result on the layer in one step, applying its own opacity and globalCompositeOperation once. This works like isolation: isolate in CSS and opacity on an SVG <g>.

const group = new Konva.Group({
isolated: true,
opacity: 0.6,
});

With isolation:

  • Group opacity applies to the whole image. Overlapping children don't show through each other.
  • Group blend modes apply to the whole image. group.globalCompositeOperation('multiply') blends the composed group with the content below it.
  • Child blend modes stay inside the group. A child with destination-out erases only the group's own content, not the rest of the layer.

Isolation requires Konva 10.7.0 or newer. For the full list of attributes, see the Konva.Group documentation.

Instructions: Drag both groups over the striped background. The left group is a regular group: its shapes show through each other, and the black circle with destination-out partly erases the stripes too. The right group is isolated: it fades as one image, and the hole shows the stripes behind it.

import Konva from 'konva';

const stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight,
});

const layer = new Konva.Layer();
stage.add(layer);

// stripes, to see what the groups let through
for (let x = 0; x < stage.width(); x += 40) {
layer.add(
new Konva.Rect({
x: x,
width: 20,
height: stage.height(),
fill: '#8ecae6',
})
);
}

function createGroup(x, isolated) {
const group = new Konva.Group({
x: x,
y: 40,
opacity: 0.6,
isolated: isolated,
draggable: true,
});
group.add(
new Konva.Rect({
width: 120,
height: 120,
fill: '#e63946',
})
);
group.add(
new Konva.Circle({
x: 120,
y: 120,
radius: 70,
fill: '#1d3557',
})
);
// erases everything under it: the whole layer, or only the isolated group
group.add(
new Konva.Circle({
x: 60,
y: 60,
radius: 30,
fill: 'black',
globalCompositeOperation: 'destination-out',
})
);
group.add(
new Konva.Text({
y: 205,
text: isolated ? 'isolated: true' : 'default group',
fontSize: 18,
})
);
layer.add(group);
}

createGroup(40, false);
createGroup(300, true);

Isolation or caching?

group.cache() also draws a group as one image, but it takes a snapshot. After you change a child, you have to call cache() again. An isolated group stays live: change any child, animate it, or drag it, and the next draw shows the result.

The price is a draw through a buffer canvas every time the layer is drawn. Konva keeps that buffer only as large as the visible part of the group, reuses it between isolated groups, and frees it when it is no longer used. Use isolation for content that changes. Use cache() for a complex group that rarely changes, or when you need filters.

Things to know

  • Konva sizes the buffer from the group's bounds. If a custom shape paints outside its width and height, describe the painted area with selfRectFunc, or that paint can be clipped.
  • Isolation changes only how the group looks. Hit detection is unchanged: a shape that is erased by a sibling still receives events.
  • A cached group keeps its snapshot. If you call cache() on an isolated group, the snapshot is drawn until you call clearCache().