滤镜效果
滤镜参数是数值,因此可以补间。但每一帧都要重新跑一遍滤镜,代价需要心里有数。
用法
要使用Konva创建一个改变滤镜效果的tween动画, 我们可以通过给滤镜上绑定的属性添加过渡效果来实现.
在本教程中,我们将为滤镜的blurRadius属性添加过渡效果,使图像的模糊度在动画中发生改变。
说明:将鼠标悬停在图像上以获得焦点。
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/konva@10/konva.min.js"></script>
<meta charset="utf-8">
<title>Konva Tween Filter 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 lion = new Konva.Image({
x: 80,
y: 30,
draggable: true
});
layer.add(lion);
stage.add(layer);
var image = new Image();
image.onload = function() {
lion.image(image);
lion.cache();
lion.filters([Konva.Filters.Blur]);
lion.blurRadius(10);
layer.draw();
// the tween has to be created after the node has been added to the layer
var tween = new Konva.Tween({
node: lion,
duration: 0.6,
blurRadius: 0,
easing: Konva.Easings.EaseInOut
});
lion.on('mouseover', function() {
tween.play();
});
lion.on('mouseout', function() {
tween.reverse();
});
};
image.src = '/assets/lion.png';
</script>
</body>
</html>
常见问题
补间滤镜之前要做什么?
节点必须已经 cache(),并且 filters 已经设好。补间改的只是参数,
不能用它来「添加」滤镜。
node.filters([Konva.Filters.Blur]);
node.cache();
node.to({ blurRadius: 20, duration: 1 });
为什么补间滤镜特别卡?
因为每一帧都要重新执行一遍滤镜计算。普通属性补间只是写个数字, 滤镜补间是整张位图重新处理。
模糊尤其贵——开销随半径的平方增长, 从 0 补到 20 的过程中,后期每帧的成本是前期的几十倍。
CSS 滤镜字符串能补间吗?
不能。补间需要数值,而 CSS 滤镜是字符串。
想要类似效果,可以用 Konva.Animation 每帧重新拼字符串:
new Konva.Animation((frame) => {
const r = (frame.time / 1000) * 10;
node.filters([`blur(${r}px)`]);
}, layer);
注意这样每帧都要重设 filters 并重建缓存,比数值补间更贵。
性能提示
滤镜补间是「明知很贵但效果需要」的典型场景,可以做的是尽量压缩成本。
降低缓存分辨率。node.cache({ pixelRatio: 0.5 }) 让处理的像素数减到四分之一。
模糊这类本来就在抹细节的滤镜,分辨率降低几乎看不出来。
缩短时长、减少帧数。半秒的滤镜过渡和两秒的,观感差别不大,成本差四倍。
考虑用不透明度代替。想要「从模糊到清晰」的效果,
可以准备清晰和模糊两个静态节点,补间它们的 opacity 做交叉淡入。
滤镜只在初始化时算两次,动画过程零滤镜开销。这个办法在多数场景下
视觉上难以分辨,性能却是数量级的差距。