跳到主要内容

裁剪区域

容器的 clip 属性定义一个矩形裁剪区域,超出部分不绘制。

用法​

使用 Konva 在裁剪区域内绘制内容,我们可以设置任何容器的 clip 属性, 包括组、图层或舞台。裁剪区域由 x、y、width 和 height 定义, 落在该矩形之外的部分不会被绘制。

在本教程中,我们将在应用于组的矩形裁剪区域内绘制不规则图形。

如果矩形不足以描述你要的裁剪形状,改用 裁剪函数。

<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/konva@10/konva.min.js"></script>
<meta charset="utf-8">
<title>Konva Simple Clipping Demo</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #F0F0F0;
}
</style>
</head>
<body>
<div id="container"></div>
<script>
var width = window.innerWidth;
var height = window.innerHeight;

var stage = new Konva.Stage({
container: 'container',
width: width,
height: height
});

var layer = new Konva.Layer();

var group = new Konva.Group({
clip: {
x : 100,
y : 40,
width : 200,
height : 100
},
draggable: true
});

var blueBlob = new Konva.Line({
points: [73, 140, 340, 23, 500, 109, 300, 170],
stroke: 'blue',
strokeWidth: 10,
fill: '#aaf',
tension: 0.8,
closed : true
});

var redBlob = new Konva.Line({
points: [73, 140, 340, 23, 500, 109],
stroke: 'red',
strokeWidth: 10,
fill: '#faa',
tension: 1.2,
scale: {x : 0.5, y : 0.5},
x: 100,
y: 50,
closed : true
});

group.add(blueBlob);
group.add(redBlob);
layer.add(group);

// add the layer to the stage
stage.add(layer);
</script>

</body>
</html>

常见问题​

裁剪区域的坐标是相对什么的?​

相对容器自身的坐标系。给一个 x: 100 的分组设 clip: { x: 0, ... }, 裁剪框的左边缘在舞台上的位置是 100,不是 0。

这和子节点的坐标是同一套参照系,所以「让裁剪框正好框住某个子节点」 可以直接用那个子节点的坐标,不需要换算。

被裁掉的部分还能点中吗?​

能。裁剪只影响绘制,不影响命中检测。

这经常导致意外:用户点在裁剪框外的空白处,却触发了那个「看不见」的图形。

要让命中也被裁剪,需要给被裁的节点自己加约束——例如把它们的 listening 按是否在可见范围内动态切换, 或者在事件处理里判断坐标是否落在裁剪区内。

给图形本身设 clip 有用吗?​

没用。clip 是容器的属性——只有 Stage、Layer、Group 支持。

要裁剪单个图形,把它放进一个分组,给分组设裁剪。 或者换个思路:用 Konva.Path 直接画出裁剪后的形状, 如果形状是固定的,这样更省。

性能提示​

裁剪本身的开销很小——它设置的是 canvas 的裁剪路径,由浏览器在光栅化阶段处理。

但它不会减少绘制调用。被裁掉的子节点仍然会执行完整的绘制流程, 只是最终像素被丢弃。上千个子节点里只有十个在可见区内, 那另外九百九十个的绘制成本照样要付。

真正要省这部分开销,需要视口剔除:自己判断哪些节点在可见范围内, 把范围外的设为 visible(false)。这在大画布、可滚动内容的场景里是必要的优化, Konva 没有内置,得自己实现。

判断依据:裁剪是为了视觉效果,视口剔除是为了性能。两者可以并存, 不要指望前者带来后者的收益。