HTML5 Canvas:使用/缓存drawImage绘制的元素在缩放和/或移动时被平滑

HTML5 Canvas: Elements drawn with/cached for drawImage are smoothed when scaled and/or moved

本文关键字:缩放 移动 平滑 使用 Canvas 缓存 drawImage HTML5 绘制 元素      更新时间:2023-09-26

我确实知道drawImagexy的浮点/整数值的情况。但我需要的是一个平滑的动画,能够缓存我的形状。

    关于使用备份画布缓存复杂路径的文章
  • drawImage浮动参数的文章

例如,我想绘制一些复杂的形状(即SVG-tiger,转换为canvas-commands)到画布上,然后用ctx.translatectx.drawImage平滑地移动 。然后我需要浮点值,因为我得到的是一步一步的移动:

下面是JSFiddle的示例:

  • 1:速度快,将Math.floor应用于translate参数(xy等于以秒为单位乘以10):动画很奇怪(顺序,不流畅)。
  • 二:速度慢,Math.floor应用于translate参数(xy等于时间,以秒为单位):动画很奇怪(顺序,不流畅)。
  • 三:速度快,不舍入,浮点值(xy等于以秒为单位的时间乘以10)。速度很快,所以动画看起来很好。
  • :慢速,不舍入,浮点值(xy等于以秒为单位的时间)。速度慢,所以动画看起来脉动为什么?

最后一个案例让我感到困惑。我错了在我的尝试,有可能使这个缓存技巧工作好吗?

在Firefox中,有一个名为mozImageSmoothingEnabled的画布属性(见),但在其他浏览器中没有这个帮助。并且它还消除了路径平滑。

代码提取:

var shapeCanvas = null;
var w = 320, h = 240;
var startTime = 0;
function start() {
    startTime = Date.now();
    var docCanvas = document.getElementById('canvas');
    . . .
    shapeCanvas = document.createElement('canvas');
    . . .
    drawShape(shapeCanvas.getContext('2d'));
    drawNext(docCanvas.getContext('2d'));
}
function drawNext(ctx) {
    var msec = (Date.now() - startTime);
    var time = msec / 1000; // seconds passed from start
    ctx.clearRect(0, 0, w, h);
    ctx.save();
    // the lines to change: time | (time * 10) | Math.floor(time * 10)
    ctx.translate((time < 500) ? Math.floor(time * 10) : 500,
                  (time < 500) ? Math.floor(time * 10) : 500);
    ctx.drawImage(shapeCanvas, 0, 0);
    ctx.restore();
    __nextFrame(function() {
       drawNext(ctx);
    });
}
function drawShape(ctx) {
    . . .
}

我在你的第一个链接中写了教程。

Just to clear the air:

shapeCanvas.style.width = w + 'px';
shapeCanvas.style.height = h + 'px';

不值得做。如果它只是一个内存中的画布,那么设置样式就没有意义了,而且你不应该真的想要设置画布的宽度和高度style,它只会混淆事情。

ellisbben在评论中所说的几乎就是正在发生的事情。

我敢打赌,有一些粗俗的方法可以绕过它。一种方法可能是确保它永远不会绘制在整数像素上。另一种可能是在绘制任何东西之前使用ctx.scale(.99,.99),这样它总是反锯齿的。这里很难得到一致的解决方案,因为不同浏览器的抗锯齿实现是不同的。

以下是我自己的一些实验:

http://jsfiddle.net/KYZYT/29/

前两个是从画布和PNG中绘制的形状

后两个是同一对,但被.99,.99缩放

最后一个是真的。它仍然有点模糊,但看起来比使用图像清晰得多。

我的实验没有一个能终止你的脉动,至少在微观层面上没有。我认为,如果你想在半像素空间中动画化像素完美的图像,这就是你必须忍受的东西。

如果你真的觉得你不能只画完美的像素,那么你的(第二)最好的选择可能是找到一种方法,在任何时候都强制抗锯齿。确保您始终转换为非整数或稍微缩放它是不错的选择,但可能还有其他选择。

老实说,你最好不要缓存这些动画路径,直到你绝对需要它们的性能。缓存样式化的按钮和其他静态的东西,但如果你有动画路径,需要缓慢而精确地移动,看起来很好,你最好坚持真正的东西在我的缓存优化,除非你真的 需要它。

有点无耻的插头,但是:我已经在HTML5老虎机游戏中实现了流畅的动画。生成的缓存图像在小画布上绘制一次,然后我使用translate3d()与-moz-transform/-webkit-transform样式的画布移动,镜像和缩放图像。

Pregeneration

    <
  1. 创建图像/gh>
  2. 绘制图像内容
  3. 在DOM中创建画布对象

动画阶段
  1. 明确帆布
  2. 将缓存的图像绘制到画布
  3. 使用CSS3变换(scale3d和translate3d)来移动画布。