关闭 Perfect Drawing
「完美绘制」为了消除描边与填充交叠处的色差而引入一层缓冲画布。不需要它时可以关掉。
用法
在某些情况下,直接在canvas画布上绘图出现意外的结果。 例如,我们绘制一个形状, 并且同时设置了填充, 描边和透明度. 由于描边在填充的上面绘制,因此描边和填充交叉的部分, 会出现一条颜色加深的细线.
这可能这不是你所期望的, 所以KonvaJS使用缓冲区画布来修复了这种行为。
在这种情况下KonvaJS是这样做的:
- 在缓冲区画布上绘制形状
- 在没有设置透明度的情况下, 绘制描边和填充
- 将透明度设置到图层上
- 将缓冲区画布上绘制好的形状绘制到当前画布上
但是使用缓冲区画布可能会降低性能。你可以使用下面的代码来禁用它:
shape.perfectDrawEnabled(false);
看看有什么区别:
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/konva@10/konva.min.js"></script>
<meta charset="utf-8">
<title>Konva Disable Perfect Drawing 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();
stage.add(layer);
var group1 = new Konva.Group({
x : 50,
y : 50
});
layer.add(group1);
var lebel1 = new Konva.Text({
text : 'Shape with defaul drawing behaviour'
});
group1.add(lebel1)
var rect = new Konva.Rect({
y : 20,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 10,
opacity : 0.5
});
group1.add(rect);
var group1 = new Konva.Group({
x : 200,
y : 100
});
layer.add(group1);
var lebel1 = new Konva.Text({
text : 'Shape with perfectDrawEnabled = false'
});
group1.add(lebel1)
var rect = new Konva.Rect({
y : 20,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 10,
opacity : 0.5,
perfectDrawEnabled : false
});
group1.add(rect);
layer.draw();
</script>
</body>
</html>
常见问题
它到底在解决什么问题?
同时设置 fill、stroke 和 opacity 时,描边画在填充之上,
两者交叠的半个描边宽度内颜色会叠加,形成一条比预期更深的边。
Konva 的做法是先把图形画到一张离屏画布上,合成好之后再整体以指定透明度贴回来, 交叠处因此不会叠加。代价是多了一次离屏绘制和一次合成。
什么情况下可以安全关掉?
满足以下任一条件时,这层处理本就没有作用,关掉是净收益:
- 图形只有填充没有描边,或只有描边没有填充
- 图形不透明(
opacity为 1)——不透明时描边覆盖填充,本来就不会叠加
换句话说,只有「半透明 + 同时有填充和描边」这一种组合才需要它。
关掉之后会看到什么变化?
如果图形确实属于上面说的需要它的那类,关掉后会在填充与描边的交界处
看到一圈略深的轮廓。程度取决于透明度——opacity: 0.5 时最明显。
判断办法很直接:关掉,看一眼。看不出区别就说明本来就不需要。
性能提示
收益大小取决于图形数量与尺寸。每个启用完美绘制的图形,每帧都要多一次 离屏绘制加一次合成——离屏画布的尺寸与图形包围盒相关,大图形代价更高。
几个实用做法:
批量关闭。如果整个应用里没有半透明描边图形,可以在创建时统一设
perfectDrawEnabled: false,不必逐个判断。
优先照顾动态内容。静态图形通常已经被缓存,完美绘制只在建缓存时跑一次, 关不关差别不大。真正值得关的是每帧都在重绘的那些。
和描边优化一起做。描边绘制优化里的
strokeHitEnabled(false) 省的是命中图的开销,与这里省的绘制开销是两笔账,
两个一起关收益叠加。