How to apply transparency for several shapes at once?
Is it possible to use opacity for several shapes at the same time?
You can use the opacity attribute to change the alpha channel of any Konva node. Due to how canvas works, all shapes have their own independent opacity values.
That means if you have a group with several shapes inside and that group has group.opacity(0.5), it will look exactly the same as if each shape inside the group has shape.opacity(0.5) and the group has group.opacity(1). This means you will see overlapping areas of those shapes.
What if we don't want to see overlapping areas of transparent shapes?
Set isolated: true on the group (Konva 10.7.0 or newer). An isolated group draws its shapes into a separate canvas without the group opacity, then draws that image onto the layer with the opacity applied once. Its content stays live, so you can change, animate or drag the shapes inside it. See Isolated Groups for how isolation also keeps blend modes inside the group.
In older versions, cache the group with group.cache() instead. A cached group is a snapshot: after any change inside it, you have to call cache() again, which is too expensive to do in animations or on every mousemove.
In the demo below, the left group has the default behavior and the right group is isolated. Drag both groups to compare them: on the left you can see where the shapes overlap, while the right group fades as one image.
- Vanilla
- React
- Vue
import Konva from 'konva';
// Stage setup
const width = window.innerWidth;
const height = window.innerHeight;
const stage = new Konva.Stage({
container: 'container',
width: width,
height: height,
});
const layer = new Konva.Layer();
stage.add(layer);
// lets create default group with two overlapping shapes
const group1 = new Konva.Group({
opacity: 0.5,
x: 50,
y: 50,
draggable: true,
});
group1.add(
new Konva.Rect({
width: 100,
height: 100,
fill: 'red',
})
);
group1.add(
new Konva.Circle({
x: 100,
y: 100,
radius: 70,
fill: 'green',
})
);
layer.add(group1);
// lets create the second group
const group2 = group1.clone({ x: 250 });
layer.add(group2);
// draw the whole group as one image, so opacity applies once
group2.isolated(true);
import { Stage, Layer, Group, Rect, Circle } from 'react-konva';
import { useState } from 'react';
const App = () => {
const [groups, setGroups] = useState({
default: { x: 50, y: 50 },
isolated: { x: 250, y: 50 },
});
const sharedGroupProps = {
opacity: 0.5,
draggable: true,
};
const handleDragEnd = (id, e) => {
setGroups((current) => ({
...current,
[id]: e.target.position(),
}));
};
const renderGroup = (id) => (
<Group
{...sharedGroupProps}
x={groups[id].x}
y={groups[id].y}
isolated={id === 'isolated'}
onDragEnd={(e) => handleDragEnd(id, e)}
>
<Rect width={100} height={100} fill="red" />
<Circle x={100} y={100} radius={70} fill="green" />
</Group>
);
return (
<Stage width={window.innerWidth} height={400}>
<Layer>
{/* Default group with overlapping shapes */}
{renderGroup('default')}
{/* Isolated group: opacity applies to the whole group */}
{renderGroup('isolated')}
</Layer>
</Stage>
);
};
export default App;
<template>
<v-stage :config="stageConfig">
<v-layer>
<!-- Default group with overlapping shapes -->
<v-group :config="{ ...groupConfig, x: 50 }">
<v-rect :config="rectConfig" />
<v-circle :config="circleConfig" />
</v-group>
<!-- Isolated group: opacity applies to the whole group -->
<v-group :config="{ ...groupConfig, x: 250, isolated: true }">
<v-rect :config="rectConfig" />
<v-circle :config="circleConfig" />
</v-group>
</v-layer>
</v-stage>
</template>
<script setup>
const stageConfig = {
width: window.innerWidth,
height: 400,
};
const groupConfig = {
opacity: 0.5,
y: 50,
draggable: true,
};
const rectConfig = {
width: 100,
height: 100,
fill: 'red',
};
const circleConfig = {
x: 100,
y: 100,
radius: 70,
fill: 'green',
};
</script>