Javascript HTML5画布:在缩放和/或移动时,使用/缓存drawImage绘制的元素会平滑

Javascript HTML5画布:在缩放和/或移动时,使用/缓存drawImage绘制的元素会平滑,javascript,html,canvas,Javascript,Html,Canvas,我确实知道drawImage的x和y的浮点/整数值的情况。但我需要的是一个平滑的动画,能够缓存我的形状 例如,我想在画布上画一次复杂的形状(如SVG tiger),然后用ctx.translate和ctx.drawImage平滑地移动它。我需要浮点值,因为我得到的是一步一步的移动: 以下是JSFIDLE的示例: :速度快,将Math.floor应用于translate参数(x和y等于以秒为单位的时间乘以10):动画奇怪(顺序,不平滑) :慢速,将Math.floor应用于transla

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

例如,我想在画布上画一次复杂的形状(如SVG tiger),然后用
ctx.translate
ctx.drawImage
平滑地移动它。我需要浮点值,因为我得到的是一步一步的移动:

以下是JSFIDLE的示例:

  • :速度快,将
    Math.floor
    应用于
    translate
    参数(
    x
    y
    等于以秒为单位的时间乘以
    10
    ):动画奇怪(顺序,不平滑)
  • :慢速,将
    Math.floor
    应用于
    translate
    参数(
    x
    y
    等于以秒为单位的时间):动画怪异(连续,不平滑)
  • :快速、无舍入、浮点值(
    x
    y
    等于时间(秒)乘以
    10
    )。速度很快,所以动画看起来不错
  • :低速、无舍入、浮点值(
    x
    y
    等于时间,单位为秒)。速度很慢,所以动画看起来是脉动的为什么?
最后一个案例让我感到困惑。我的尝试错了吗?有可能让这个缓存技巧很好地工作吗

在Firefox中,canvas有一个名为
mozimagesoothingEnabled
()的属性,但在其他浏览器中没有该属性的帮助。而且它还消除了路径平滑

代码摘录:

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) {
    . . .
}
var shapeCanvas=null;
var w=320,h=240;
var startTime=0;
函数start(){
startTime=Date.now();
var docCanvas=document.getElementById('canvas');
. . .
shapeCanvas=document.createElement('canvas');
. . .
drawShape(shapeCanvas.getContext('2d');
drawNext(docCanvas.getContext('2d');
}
函数drawNext(ctx){
var msec=(Date.now()-startTime);
var time=msec/1000;//从开始到结束的时间为秒
ctx.clearRect(0,0,w,h);
ctx.save();
//要更改的行:time |(time*10)| Math.floor(time*10)
ctx.翻译(时间<500)?数学地板(时间*10):500,
(时间<500)?数学地板(时间*10):500;
ctx.drawImage(shapeCanvas,0,0);
ctx.restore();
__下一帧(函数(){
下一步(ctx);
});
}
函数drawShape(ctx){
. . .
}

我在您的第一个链接中编写了教程

只是想澄清一下:

shapeCanvas.style.width = w + 'px';
shapeCanvas.style.height = h + 'px';
这真的不值得做。如果只是一个内存中的画布,那么设置样式就没有意义了,而且你不应该真的想设置画布的宽度和高度样式,它只是让事情变得混乱

埃利斯本在评论中所说的几乎就是正在发生的事情

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

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

前两个是从画布绘制的形状,也从PNG绘制

第二对是同一对,但按
.99、.99

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

我的任何实验都不会结束你的脉动,至少在微观层面上不会。我认为,如果你想在半像素空间上制作像素级完美图像的动画,这就是你必须接受的东西

如果你真的觉得你不能只画完美的像素,那么你的(第二)最佳一致性选择可能是找到一种方法,在任何时候强制消除混叠。确保您总是转换为非整数,或者稍微调整它,这是不错的选择,但可能还有其他选择


老实说,在绝对需要这些动画路径的性能之前,最好不要缓存这些动画路径。缓存你制作的样式化按钮和其他静态东西,但是如果你有需要缓慢精确移动的动画路径,并且看起来非常好,除非你真的需要我的缓存优化,否则你最好还是坚持使用真实的东西。

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

代前

  • 创造形象
  • 绘制图像内容
  • 在DOM中创建画布对象
  • 动画阶段

  • 透明帆布
  • 将缓存的图像绘制到画布
  • 使用CSS3变换(scale3d和translate3d)移动画布

  • 路径通过抗锯齿在
    shapeCanvas
    上呈现。在画布上非整数位置绘制具有抗锯齿的图像时,在抗锯齿的基础上获得抗锯齿。在整数像素位置中间绘制图像时,笔划的脉动模糊边缘变得最厚,而在整数像素位置上精确绘制图像时,笔划的脉动模糊边缘消失。向上投票:1)令人沮丧的样式宽度和高度2)令人沮丧的缓存。非常感谢,您的答案是最详细的。至少现在我知道问题不在我的代码中,而且,这是一个有趣的实验)。也许我会放弃这种缓存方式,我需要考虑更多的时间。我认为我的缓存方式很好,如果你有像fancy button这样的静态东西