模糊滤镜
模糊是最常用也最昂贵的滤镜。它的半径有上限,而且会让图形超出原来的包围盒。
用法
要使用滤镜在Konva.Image我们必须首先使用cache()函数
然后使用滤镜在filter()函数。
要使用Konva模糊图像,我们可以使用Konva.Filters.Blur滤镜
并使用blurRadius属性设置模糊量。
查看所有可用的滤镜,请查看滤镜文档。
说明:滑动控制以调整模糊半径。
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/konva@10/konva.min.js"></script>
<meta charset="utf-8">
<title>Konva Blur Image Demo</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #F0F0F0;
}
#slider {
position: absolute;
top: 20px;
left: 20px;
}
</style>
</head>
<body>
<div id="container"></div>
<input id="slider" type="range" min="0" max="40" step="0.05" value="20">
<script>
function loadImages(sources, callback) {
var images = {};
var loadedImages = 0;
var numImages = 0;
for(var src in sources) {
numImages++;
}
for(var src in sources) {
images[src] = new Image();
images[src].onload = function() {
if(++loadedImages >= numImages) {
callback(images);
}
};
images[src].src = sources[src];
}
}
function buildStage(images) {
var stage = new Konva.Stage({
container: 'container',
width: 300,
height: 200
});
var layer = new Konva.Layer();
var lion = new Konva.Image({
image: images.lion,
x: 80,
y: 30,
blurRadius: 20,
draggable: true
});
lion.cache();
lion.filters([Konva.Filters.Blur]);
layer.add(lion);
stage.add(layer);
var slider = document.getElementById('slider');
slider.onchange = function() {
lion.blurRadius(slider.value);
layer.batchDraw();
};
}
var sources = {
lion: '/assets/lion.png'
};
loadImages(sources, buildStage);
</script>
</body>
</html>
常见问题
为什么必须先 cache()?
滤镜作用在位图像素上,而不是矢量路径。Konva 需要先把节点渲染成一张位图, 才能逐像素处理。没有缓存就没有像素可处理,滤镜静默不生效。
这是所有 Konva.Filters 的共同前提,不只是模糊。忘记 cache() 是滤镜
「没反应」的头号原因——它不报错,只是什么都不发生。
blurRadius 能设多大?
Konva 10.4.0 起上限是 180,超过会被截断。该版本同时修复了一个问题: 此前过大的半径会产生一张全空的图像,表现为图形直接消失。
实际上很少需要接近上限的值。模糊开销随半径增长得很快, 半径 20 以上就该考虑是不是有更便宜的实现方式。
模糊之后图形边缘被切掉了?
因为缓存区域是按节点原本的包围盒算的,而模糊会向外扩散。
给 cache() 传 offset 把缓存区域扩大:
node.cache({ offset: blurRadius });
扩大的量至少要等于模糊半径。这会增加缓存位图的尺寸和内存占用, 是必要的代价。
性能提示
模糊是逐像素的卷积运算,开销大致随半径的平方增长。
静态模糊必须缓存后复用。缓存本来就是滤镜的前提,关键是不要反复重建——
每次 clearCache() + cache() 都要重跑一遍完整的模糊计算。
动画中改 blurRadius 代价极高。每一帧都是一次完整的重新模糊。 补间滤镜那一页演示了这个用法,但要清楚它的成本。
优先考虑 CSS 滤镜。filters: ['blur(6px)'] 由浏览器原生实现,
通常比 JavaScript 逐像素快得多。代价是可用效果受 CSS 规范限制,
详见 CSS 原生滤镜。