跳到主要内容

Shadow 阴影

阴影是 Canvas 上最昂贵的绘制操作之一。用它之前值得先想清楚代价。

用法​

要使用Konva绘制阴影,我们可以在实例化形状时设置shadowColor,shadowOffset,shadowBlur和shadowOpacity属性。

我们可以通过使用shadowColor(),shadowOffset(),shadowBlur()和shadowOpacity()方法来调整实例化后的阴影属性。

<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/konva@10/konva.min.js"></script>
<meta charset="utf-8">
<title>Konva Shadow 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 text = new Konva.Text({
text: 'Text Shadow!',
fontFamily: 'Calibri',
fontSize: 40,
x: 20,
y: 20,
stroke: 'red',
strokeWidth: 2,
shadowColor: 'black',
shadowBlur: 0,
shadowOffset: {x : 10, y : 10},
shadowOpacity: 0.5
});

var line = new Konva.Line({
stroke: 'green',
strokeWidth: 10,
lineJoin: 'round',
lineCap: 'round',
points: [50, 140, 250, 160],
shadowColor: 'black',
shadowBlur: 10,
shadowOffset: {x : 10, y : 10},
shadowOpacity: 0.5
});

var rect = new Konva.Rect({
x: 100,
y: 120,
width: 100,
height: 50,
fill: '#00D2FF',
stroke: 'black',
strokeWidth: 4,
shadowColor: 'black',
shadowBlur: 10,
shadowOffset: {x : 10, y : 10},
shadowOpacity: 0.5
});

layer.add(text);
layer.add(line);
layer.add(rect);

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

</body>
</html>

常见问题​

阴影为什么这么慢?​

浏览器要先把图形画一遍、做高斯模糊、再按偏移贴回去。模糊是逐像素的卷积运算, 开销随 shadowBlur 的平方增长。

一个带阴影的图形,每帧的绘制成本可能是不带阴影的好几倍。几十个这样的图形同时动起来,掉帧几乎是必然的。

怎么只给填充加阴影,不给描边加?​

设 shadowForStrokeEnabled: false。

默认情况下描边也会产生阴影,这通常不是想要的效果——描边的阴影会让轮廓显得脏。关掉之后只有填充区域投影,视觉上更干净, 同时也省掉了一部分模糊计算。

阴影让包围盒变大了?​

会。getClientRect() 包含阴影范围,shadowBlur 和 shadowOffset 都会让它扩大。

这在缓存时尤其要注意: 缓存区域按包围盒计算,带大模糊阴影的节点,缓存位图会比图形本身大很多, 内存占用相应增加。

只要几何尺寸用 getSelfRect()。

性能提示​

阴影的处理原则很明确:能静态化就静态化。

静态阴影必须缓存。不动的带阴影图形,cache() 一次之后每帧只是贴图, 模糊计算只做一遍。这是收益最大的一项优化。

动态阴影考虑替代方案。如果图形每帧都在动,缓存会不断重建反而更慢。 这种情况下可以考虑:用一个预先做好的半透明模糊图片跟随图形移动, 或者干脆用一层半透明的同形状图形做偏移,模拟出「硬阴影」的效果。

控制 shadowBlur。开销随它的平方增长,从 20 降到 10 能省四分之三。 视觉上往往看不出多大差别。

关掉描边阴影。shadowForStrokeEnabled: false 是零风险的改动。