gpt4 book ai didi

svg - 如何在Safari上使用简单的SVG过滤器并具有可接受的性能且不会崩溃?

转载 作者:行者123 更新时间:2023-12-05 01:18:53 25 4
gpt4 key购买 nike

免责声明:这篇文章是我在尝试找到解决方案时的实验的一半问题和一半报告。
任务:单色矩形上的简单SVG过滤器
在SVG中使用滤镜更改或修改单色形状的颜色非常简单。这是可以做到的:

<svg viewBox="0 0 460 130">
<defs>
<filter id="filter1">
<feColorMatrix values="0.5 0 0 0 0 0 0.5 0 0 0 0 0 0.5 0 0 0 0 0 1 0" />
</filter>
</defs>
<g transform="translate(20, 0)">
<text x="0" y="35">Original</text>
<rect x="0" y="50" width="200" height="80" fill="red" />
</g>
<g transform="translate(240, 0)">
<text x="0" y="35">Filtered</text>
<rect x="0" y="50" width="200" height="80" fill="red" filter="url(#filter1)" />
</g>
</svg>


问题:在Safari上速度很慢,在Safari Mobile上崩溃
这样做的小问题是,它在Safari上的运行速度确实很慢。在下面的代码段中,每半秒钟将一个新的经过过滤的rect添加到SVG。这最终会在10-80个周期后在Safari移动设备上崩溃,具体取决于您的设备。而且,它的速度实在令人难以忍受。为了进行比较,在运行Chrome的入门级Android手机上,该手机一开始几乎以50 fps的速度运行。

var rectCount = 1;
var svgRectElem = document.getElementById('svg-rect');
var rectCountElem = document.getElementById('rect-count');
var fpsElem = document.getElementById('fps');

(function insertRect() {
window.requestAnimationFrame(function() {
var start = new Date().getTime();

var clonedSvgRectElem = svgRectElem.cloneNode();

// insert cloned rect SVG element
svgRectElem.parentNode.appendChild(clonedSvgRectElem);

rectCountElem.textContent = ++rectCount;

window.requestAnimationFrame(function() {
var fps = Math.round(100000 / (new Date().getTime() - start)) / 100;
fpsElem.textContent = fps;
window.setTimeout(insertRect, 500);
}, 100);
});
})();
<p>SVG Rect Count: <span id="rect-count">1</span></p>
<p>fps: <span id="fps"></span></p>

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="512" viewBox="0,0,1024,1024">
<defs>
<filter id="filter-1">
<feColorMatrix values="0.5 0 0 0 0 0 0.5 0 0 0 0 0 0.5 0 0 0 0 0 1 0" />
</filter>
</defs>
<rect id="svg-rect" fill="red" filter="url(#filter-1)" x="0" y="0" width="1024" height="1024" />
</svg>

Snippet on CodePen

可能的解决方案:到目前为止我想到的是什么
我尝试了几种方法,但是如您所见。如您所见,其中一些适用于Safari,每个都有一个功能。

1.等待WebKit团队进行修复
tl; dr也许行得通,也许不行
那将是最方便的选择,但是如果您考虑到SVG过滤器是15年前推出的,那么我将不为所动,很快就可以解决此问题。是的,我写了一个错误报告。

2.使用 filterRestl; dr有效,但仅在下一个Safari版本发布之前
在SVG 1.1中,定义了 filterRes属性。这指定了滤镜的分辨率。值为1表示滤镜的源将被视为单个像素。因此,不必在所有像素上运行滤镜,而只需将滤镜应用于一个像素。由于我们使用单一颜色的矩形作为输入图像,因此在我们的情况下可以将整个图像视为一个像素。
在我们的示例中,过滤器将如下所示:
<filter id="filter1" filterRes="1">
<feColorMatrix values="0.5 0 0 0 0 0 0.5 0 0 0 0 0 0.5 0 0 0 0 0 1 0" />
</filter>
Snippet on CodePen
实际上,这可以大大提高性能,并且不会发生崩溃!
不幸的是,filterRes已从2.0版的SVG标准中删除。 WebKit很快适应了SVG 2.0的这一部分,并决定在下一版本中将其删除。如果我们依靠 filterRes,同样的问题很快就会再次出现。

3.过滤一个小矩形,然后按比例放大
tl; dr不起作用
上面的方法表明,在较小的区域上应用滤镜可以大大提高性能。在那里,我们将滤镜应用到一个小矩形上,然后将结果按比例缩放到所需的大小。为了缩放,我们使用 transform属性。如果将rect设置为所需大小的1/64,则将使用 transform="scale(64)"对其进行缩放,以实现最终大小1024。
Snippet on CodePen
不幸的是,这根本不起作用。性能保持不变,并且在Safari移动版上仍然崩溃。有趣的是,这不能仅归因于滤波器或变换。只有结合使用,它才会变慢并崩溃。

4过滤一个小矩形,然后使用 feTile填充目标矩形
tl; dr有点用,但是在Chrome上有人工制品
该方法与之前的方法类似。我们首先将滤镜应用于一个小矩形,然后使用另一个带有 feTile的滤镜填充目标矩形。
Snippet on CodePen
这适用于Safari移动版。不如 filterRes,但有很大的改进。
但是,对于这种方法 Chrome来说,是派对方。如果您在Chrome上缩放放大和缩小,则在某些缩放级别上会显示栅格。这是它的外观(正确的是一个大正方形):
enter image description here

5使用巨大的值作为过滤器的宽度和高度
tl; dr可以工作,但是被黑客入侵并在Internet Explorer上引起问题
这是一种非常相反的直观方法。将滤镜区域的宽度和高度设置为非常大的值将使滤镜变慢得多,因为必须处理成千上万的像素。但实际上情况恰恰相反。 WebKit上的筛选器速度大大提高,并且没有崩溃。
这是在我们的示例中实现此方法的方法:
<filter id="filter-1" x="0" y="0" width="102400" height="102400" filterUnits="userSpaceOnUse">
<feColorMatrix values="0.5 0 0 0 0 0 0.5 0 0 0 0 0 0.5 0 0 0 0 0 1 0" />
</filter>
Snippet on CodePen
我认为这里发生的事情是,滤镜首先按比例缩小原始滤镜区域,然后处理将在SVG的viewBox中可见的部分(在缩小后是很小的区域),然后再次将该区域放大。而且这似乎很快。
不幸的是确实是一个hack,我们现在不知道将来的浏览器版本将如何处理如此大的值的SVG。同样,这也会在Internet Explorer上引起问题,在Internet Explorer中,文档的滚动区域将变得很大(可能是因为筛选器的边界已计算到大小中),从而几乎无法进行滚动。并且,如果选择的值太小,Internet Explorer实际上将以过滤器边界的大小显示rect。

解决办法是什么?
其实我不知道。有一个使用 filterRes的简单解决方案,但是它很快就会过期(WebKit技术预览中已经不支持它),因此这不是一个选择。所有其他方法都会在其他浏览器上引起问题。
您能想到我可以尝试的其他方法吗?我不敢相信,在SVG 1.1规范发布15年后,跨浏览器使用SVG过滤器真是一次冒险。

最佳答案

尝试这个:

将所有矩形归为一组,然后将过滤器应用于该组。

var rectCount = 1;
var svgRectElem = document.getElementById('svg-rect');
var rectCountElem = document.getElementById('rect-count');
var fpsElem = document.getElementById('fps');

(function insertRect() {
window.requestAnimationFrame(function() {
var start = new Date().getTime();

var clonedSvgRectElem = svgRectElem.cloneNode();

// insert cloned rect SVG element
svgRectElem.parentNode.appendChild(clonedSvgRectElem);

rectCountElem.textContent = ++rectCount;

window.requestAnimationFrame(function() {
var fps = Math.round(100000 / (new Date().getTime() - start)) / 100;
fpsElem.textContent = fps;
window.setTimeout(insertRect, 500);
}, 100);
});
})();
<p>SVG Rect Count: <span id="rect-count">1</span></p>
<p>fps: <span id="fps"></span></p>

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="512" viewBox="0,0,1024,1024">
<defs>
<filter id="filter-1">
<feColorMatrix values="0.5 0 0 0 0 0 0.5 0 0 0 0 0 0.5 0 0 0 0 0 1 0" />
</filter>
</defs>
<g filter="url(#filter-1)">
<rect id="svg-rect" fill="red" x="0" y="0" width="1024" height="1024" />
</g>
</svg>

关于svg - 如何在Safari上使用简单的SVG过滤器并具有可接受的性能且不会崩溃?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53145883/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com