如何同时为多个图形应用透明度?
可以同时为多个图形设置不透明度吗?
可以使用 opacity 属性更改任意 Konva 节点的 Alpha 通道。由于 Canvas 的工作方式,每个图形都有独立的不透明度值。
这意味着,如果一个组包含多个图形,并且该组设置了 group.opacity(0.5),其外观将与以下设置完全相同:组内每个图形设置 shape.opacity(0.5),组设置 group.opacity(1)。因此,你会看到这些图形的重叠区域。
如果不想看到透明图形的重叠区域,该怎么办?
为组设置 isolated: true(需要 Konva 10.7.0 或更高版本)。隔离组会先在单独的 Canvas 上绘制其中的图形(不应用组的不透明度),然后将该图像绘制到图层上,并只应用一次不透明度。组的内容保持实时更新,因此你可以更改、动画化或拖动其中的图形。请参阅隔离组,了解隔离如何将混合模式限制在组内。
在旧版本中,请改用 group.cache() 缓存组。缓存组是一张快照:组内发生任何更改后,都必须再次调用 cache(),这项操作开销较大,不适合在动画中或每次 mousemove 时执行。
在以下示例中,左侧组使用默认行为,右侧组是隔离组。拖动两个组进行比较:左侧可以看到图形的重叠区域,而右侧组作为一个整体图像变透明。
- 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>