【问题标题】:Zooming SVG is blury or pixelated, not sharp缩放 SVG 模糊或像素化,不清晰
【发布时间】:2014-03-11 20:57:40
【问题描述】:

我在某种程度上知道这是一个已知问题,已在此处提出但从未回答,但我希望获得更多见解。

我在网页的 div 中有一个简单的 SVG 图像。我希望能够使用捏合手势缩放图像并使 SVG 呈现清晰。缩放过程中不需要很锐利,但手势完成后应该很锐利。

我正在一台装有触摸屏的 Windows 8.1 计算机、iPad 和旧的 Android Galaxy Tab 上进行测试。在主计算机上,我使用的是 IE11 和 Chrome。为了处理触摸手势,我使用的是 Hammer.js。我正在通过使用 jQuery css() 函数修改变换 CSS 来进行缩放(我正在设置 scale3d 和 translate3d)。

我电脑上的 IE11 完全按照我的意愿工作。它在整个捏缩放过程中保持 SVG 图像清晰,并且无论我何时设置 CSS,图像始终清晰。

当我使用双指缩放放大时,我计算机上的 Chrome 总是呈现 SVG 块状。它在变焦过程中是块状的,之后不会变得清晰。如果我在加载页面 (x13) 后添加缩放图像的调用,则图像很清晰。如果我使用 setTimeout() 调用来重置缩放,然后在捏缩放结束后重新缩放图像,则图像很清晰。

在 iPad 和 Android 平板电脑上,SVG 从不清晰渲染,无论我何时放大代码。

有没有人知道如何在捏缩放完成后可靠地以清晰的 SVG 渲染结束?有没有人有更好的解决方案?在手势期间使用 SVG viewBox 进行缩放和平移并不能为我们更复杂的 SVG 图像提供足够好的性能。我正在考虑尝试在手势期间使用硬件加速的 scale3d/translate3d,然后尝试将其转换为新的 SVG viewBox 设置,但这是一个挑战,我不确定在完成后平移是否能正常工作。非常感谢任何指针或想法。

【问题讨论】:

  • 神奇的建议:启动 GPU 以新的比例重新渲染 SVG,方法是向您的 SVG 添加一个具有非 GPU 可渲染样式的 CSS 类,然后打开和关闭该类缩放可能会为您做到。
  • 我发现了一些有趣的东西。看起来我遇到的问题无法通过 GPU 渲染解决,它是由它引起的。在我的简单测试中,如果我将所有的变换参数从 3D 版本切换到 2D 版本,一切都会保持清晰。然后我可以在缩放时使用 3D,然后在变换结束时切换到 2D。这在所有平台上都对我有效。现在我需要看看我是否可以使用它来提出一个真正的解决方案。如果是这样并且如果我没有得到其他回复,我将使用它来回答我自己的问题。感谢迈克尔的评论。
  • 是的,这肯定是由 GPU 渲染引起的。 GPU 只是缩放它渲染的纹理,而不是重新渲染它。所以你必须踢 GPU 重新渲染 - 或者做一些事情来保持 CPU 上的渲染(更慢,但非像素化)
  • 我无法找到一种方法来启动适用于 iOS 或 Android 平板电脑的 GPU。我可以在 Windows 下的 Chrome 上执行此操作,但是在平板电脑上添加或删除 TranslateZ 或 RotateZ 变换属性对我没有任何影响。我最终决定只在 iScroll 库中关闭 GPU 转换,这对我来说工作得相当好。

标签: javascript css svg touch hammer.js


【解决方案1】:

刚刚尝试回答您的另一个SVG Question,我将尝试这个。

Michael Mullany 认为 GPU 翻译永远不会为您提供清晰的图像。这是因为 GPU 只是将一个像素阵列映射到一个新的像素阵列。因为它没有线条或矩形的概念,所以分辨率是在 GPU 获取图像时设置的。 CPU 总是很难及时重新渲染以实现平滑拖动。

让某些浏览器生成清晰图像的原因在于,它们进行了巧妙的操作,例如渲染比所需更多的像素,因此可以在不损失分辨率的情况下进行一些缩放。然而,这些是完全不一致的,只是不可能依赖。 正如我所见,“正确”的解决方案是在捏合或缩放期间使用硬件加速转换进行转换和缩放,然后在转换完成时刷新视图框而不进行 CSS 转换。 需要克服的挑战是

  • css 转换将使用屏幕坐标,但 viewBox 操作将使用 SVG 坐标系。
  • screenCTM 和设备像素比存在浏览器不一致
  • 需要在两个系统中计算限制,以便人们不会拖动或缩放太远
  • 还需要在两者中计算捏合中心点
  • 为了进一步提高性能,css 转换将被包装到 requestAnimationFrame 循环的更新中。

我的工作解决方案是hammerhead2。我首先专注于台式机和安卓手机,它似乎正在为他们工作。为了简化问题,缩放始终以屏幕中心为中心。然而,我做的事情是这是目前唯一的解决方案之一。这是它的一个例子working

【讨论】: