有一个画布,在上面绘制文本。画布根据 requestAnimationFrame() 重新绘制,放大每一帧。问题:每次绘制的文本好像在不同的地方,有一个偏移量,结果它在动画上晃动。同时,简单的数字表现得很好。
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let w,h;
w = h = canvas.width = canvas.height = 500;
draw.t = 0;
function draw(){
ctx.clearRect(0, 0, w, h);
let scale = draw.t*draw.t * 0.00002;
ctx.save();
ctx.scale(scale, scale);
ctx.font = 'bold 50px Sans-serif';
ctx.textBaseline = 'top';
ctx.fillText('Am I shaking?', 0, 0);
ctx.fillRect(0,60,50,50);
ctx.beginPath();
ctx.arc(100, 85, 25, 0, Math.PI*2);
ctx.fill();
ctx.restore();
draw.t++;
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);
<canvas id="canvas"></canvas>
所以我正在努力解决这个问题。我首先将文本放在 5000 * 5000 的“隐藏”画布上,然后在每一帧中将图像传输到目标画布。但一开始,图像仍然“播放”,出现一些伪影:
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let w,h;
w = h = canvas.width = canvas.height = 500;
draw.t = 0;
canvas1 = document.createElement('canvas');
canvas1.width = canvas1.height = 5000;
let ctx1 = canvas1.getContext('2d');
ctx1.font = `bold 500px Sans-serif`;
ctx1.textBaseline = 'top';
ctx1.fillText('Am I shaking', 0, 0);
function draw(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
let scale = draw.t*draw.t * 0.00002;
let index = scale < 3 ? Math.floor(scale) : 3;
ctx.save();
ctx.scale(scale,scale);
ctx.drawImage(canvas1,0,0,5000,5000,0,0,500,500);
ctx.restore();
draw.t++;
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);
<canvas id="canvas"></canvas>
继续前行。我添加了几个“隐藏”画布以在不同的缩放阶段替换它们。结果已经比较顺利,但仍然不理想,解决方案不能称为优雅:
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let w,h;
w = h = canvas.width = canvas.height = 500;
draw.t = 0;
let scale_steps = [2,4,7,10];
let canvases = [];
for(let i=0; i < scale_steps.length; i++){
canvases[i] = document.createElement('canvas');
canvases[i].width = canvases[i].height = 500 * scale_steps[i];
let ctx = canvases[i].getContext('2d');
ctx.font = `bold ${scale_steps[i] * 50}px Sans-serif`;
ctx.textBaseline = 'top';
ctx.fillText('Am I shaking', 0, 0);
}
function draw(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
let scale = draw.t*draw.t * 0.00002;
let index = scale < 3 ? Math.floor(scale) : 3;
ctx.save();
ctx.scale(scale,scale);
ctx.drawImage(canvases[index],0,0,
scale_steps[index]*500,scale_steps[index]*500,0,0,500,500
);
ctx.restore();
draw.t++;
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);
<canvas id="canvas"></canvas>
很明显,在 SVG 的帮助下,只需 CSS 动画,您就可以轻松实现所需的效果。但是为什么它在 Canvas 中如此笨拙地工作,可以做些什么呢?是否可以在 Canvas 上呈现 SVG 内容?这会解决问题吗?
至少,使用 SVG 路径可以相当快地解决问题:
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let w,h;
w = h = canvas.width = canvas.height = 500;
draw.t = 0;
function draw(){
ctx.clearRect(0, 0, w, h);
let scale = draw.t * draw.t * 0.00002;
ctx.save();
ctx.scale(scale, scale);
ctx.fill(new Path2D("M27.49 32.81l-10.27 0 -1.62 4.64 -6.6 0 9.43 -25.47 7.83 0 9.43 25.47 -6.6 0 -1.6 -4.64zm-8.63 -4.72l6.97 0 -3.47 -10.13 -3.5 10.13zm37.65 -6.57c0.78,-1.19 1.69,-2.08 2.76,-2.71 1.06,-0.62 2.23,-0.92 3.5,-0.92 2.2,0 3.87,0.67 5.02,2.03 1.15,1.35 1.72,3.32 1.72,5.9l0 11.63 -6.15 0 0 -9.96c0.01,-0.14 0.02,-0.3 0.03,-0.45 0,-0.17 0.01,-0.4 0.01,-0.69 0,-1.35 -0.2,-2.33 -0.6,-2.94 -0.4,-0.61 -1.04,-0.91 -1.92,-0.91 -1.16,0 -2.06,0.48 -2.69,1.43 -0.63,0.96 -0.95,2.34 -0.98,4.14l0 9.38 -6.14 0 0 -9.96c0,-2.11 -0.19,-3.47 -0.55,-4.08 -0.36,-0.61 -1.01,-0.91 -1.94,-0.91 -1.17,0 -2.08,0.48 -2.71,1.44 -0.63,0.96 -0.95,2.33 -0.95,4.12l0 9.39 -6.15 0 0 -19.11 6.15 0 0 2.8c0.75,-1.08 1.61,-1.89 2.58,-2.44 0.97,-0.54 2.04,-0.81 3.22,-0.81 1.31,0 2.48,0.32 3.49,0.95 1.01,0.64 1.78,1.53 2.3,2.68zm31.14 -9.54l6.57 0 0 25.47 -6.57 0 0 -25.47zm39.8 6.96l0 4.64c-1.3,-0.54 -2.57,-0.96 -3.78,-1.23 -1.22,-0.28 -2.37,-0.41 -3.45,-0.41 -1.16,0 -2.02,0.15 -2.58,0.44 -0.57,0.29 -0.85,0.73 -0.85,1.34 0,0.49 0.22,0.86 0.65,1.13 0.42,0.25 1.19,0.45 2.3,0.57l1.07 0.16c3.13,0.39 5.23,1.05 6.31,1.96 1.08,0.91 1.62,2.34 1.62,4.28 0,2.03 -0.75,3.56 -2.25,4.58 -1.5,1.03 -3.74,1.54 -6.72,1.54 -1.27,0 -2.57,-0.1 -3.92,-0.3 -1.35,-0.19 -2.73,-0.49 -4.16,-0.89l0 -4.64c1.22,0.59 2.47,1.03 3.75,1.33 1.28,0.3 2.58,0.45 3.9,0.45 1.2,0 2.1,-0.16 2.7,-0.5 0.6,-0.33 0.9,-0.82 0.9,-1.47 0,-0.54 -0.21,-0.95 -0.62,-1.22 -0.41,-0.26 -1.24,-0.47 -2.48,-0.62l-1.08 -0.14c-2.72,-0.34 -4.62,-0.97 -5.71,-1.89 -1.09,-0.92 -1.64,-2.32 -1.64,-4.2 0,-2.02 0.7,-3.52 2.08,-4.5 1.39,-0.97 3.52,-1.46 6.38,-1.46 1.12,0 2.31,0.08 3.54,0.25 1.24,0.17 2.59,0.43 4.04,0.8zm25.09 6.88l0 11.63 -6.15 0 0 -1.89 0 -6.98c0,-1.67 -0.03,-2.81 -0.11,-3.44 -0.07,-0.63 -0.2,-1.09 -0.38,-1.38 -0.24,-0.4 -0.56,-0.71 -0.97,-0.93 -0.41,-0.22 -0.88,-0.33 -1.4,-0.33 -1.27,0 -2.27,0.49 -3,1.47 -0.73,0.99 -1.09,2.35 -1.09,4.09l0 9.39 -6.11 0 0 -26.55 6.11 0 0 10.24c0.92,-1.12 1.9,-1.94 2.94,-2.46 1.03,-0.53 2.17,-0.79 3.43,-0.79 2.2,0 3.87,0.67 5.02,2.03 1.14,1.35 1.71,3.32 1.71,5.9zm14.22 3.04c-1.28,0 -2.24,0.21 -2.88,0.64 -0.65,0.43 -0.97,1.08 -0.97,1.91 0,0.78 0.26,1.38 0.78,1.82 0.52,0.44 1.24,0.66 2.16,0.66 1.15,0 2.12,-0.42 2.91,-1.24 0.79,-0.82 1.18,-1.85 1.18,-3.09l0 -0.7 -3.18 0zm9.33 -2.31l0 10.9 -6.15 0 0 -2.83c-0.82,1.16 -1.75,2 -2.77,2.53 -1.02,0.53 -2.27,0.79 -3.73,0.79 -1.98,0 -3.59,-0.58 -4.82,-1.73 -1.24,-1.15 -1.86,-2.65 -1.86,-4.49 0,-2.24 0.77,-3.88 2.32,-4.93 1.53,-1.04 3.96,-1.57 7.25,-1.57l3.61 0 0 -0.47c0,-0.98 -0.38,-1.69 -1.15,-2.13 -0.76,-0.45 -1.95,-0.68 -3.56,-0.68 -1.31,0 -2.53,0.13 -3.65,0.39 -1.12,0.26 -2.17,0.66 -3.14,1.18l0 -4.64c1.31,-0.33 2.62,-0.57 3.94,-0.73 1.31,-0.17 2.64,-0.25 3.95,-0.25 3.44,0 5.94,0.68 7.46,2.04 1.53,1.36 2.3,3.56 2.3,6.62zm5.68 -15.65l6.12 0 0 14.45 7.02 -7.01 7.09 0 -9.32 8.77 10.06 10.34 -7.4 0 -7.45 -7.96 0 7.96 -6.12 0 0 -26.55zm23.24 7.44l6.11 0 0 19.11 -6.11 0 0 -19.11zm0 -7.44l6.11 0 0 5 -6.11 0 0 -5zm31.19 14.92l0 11.63 -6.15 0 0 -1.89 0 -7.01c0,-1.65 -0.03,-2.78 -0.11,-3.41 -0.07,-0.63 -0.2,-1.09 -0.38,-1.38 -0.24,-0.4 -0.56,-0.71 -0.97,-0.93 -0.41,-0.22 -0.88,-0.33 -1.4,-0.33 -1.27,0 -2.27,0.49 -3,1.47 -0.73,0.99 -1.09,2.35 -1.09,4.09l0 9.39 -6.11 0 0 -19.11 6.11 0 0 2.8c0.92,-1.12 1.9,-1.94 2.93,-2.46 1.04,-0.53 2.18,-0.79 3.44,-0.79 2.2,0 3.87,0.67 5.02,2.03 1.14,1.35 1.71,3.32 1.71,5.9zm18.65 8.38c-0.84,1.12 -1.77,1.94 -2.77,2.47 -1.02,0.52 -2.19,0.78 -3.52,0.78 -2.33,0 -4.26,-0.92 -5.78,-2.75 -1.52,-1.84 -2.29,-4.18 -2.29,-7.02 0,-2.86 0.77,-5.19 2.29,-7.02 1.52,-1.82 3.45,-2.74 5.78,-2.74 1.33,0 2.5,0.26 3.52,0.78 1,0.53 1.93,1.35 2.77,2.47l0 -2.83 6.15 0 0 17.18c0,3.07 -0.96,5.42 -2.9,7.04 -1.94,1.63 -4.76,2.44 -8.44,2.44 -1.19,0 -2.35,-0.09 -3.47,-0.28 -1.11,-0.18 -2.23,-0.46 -3.36,-0.84l0 -4.75c1.07,0.61 2.12,1.06 3.14,1.37 1.02,0.29 2.05,0.45 3.09,0.45 2,0 3.46,-0.44 4.4,-1.32 0.93,-0.87 1.39,-2.25 1.39,-4.11l0 -1.32zm-4.02 -11.88c-1.26,0 -2.25,0.47 -2.95,1.4 -0.71,0.93 -1.06,2.25 -1.06,3.96 0,1.75 0.34,3.08 1.02,3.98 0.68,0.9 1.68,1.36 2.99,1.36 1.27,0 2.26,-0.47 2.96,-1.4 0.71,-0.93 1.06,-2.25 1.06,-3.94 0,-1.71 -0.35,-3.03 -1.06,-3.96 -0.7,-0.93 -1.69,-1.4 -2.96,-1.4zm25.19 6.54l-6.15 0 0 -0.84c0,-0.93 0.19,-1.76 0.57,-2.48 0.37,-0.73 1.16,-1.64 2.37,-2.76l1.09 -0.99c0.65,-0.6 1.12,-1.15 1.42,-1.67 0.3,-0.53 0.46,-1.05 0.46,-1.58 0,-0.79 -0.28,-1.42 -0.83,-1.86 -0.54,-0.45 -1.3,-0.68 -2.28,-0.68 -0.92,0 -1.91,0.19 -2.99,0.57 -1.06,0.39 -2.18,0.95 -3.34,1.7l0 -5.35c1.38,-0.47 2.63,-0.82 3.77,-1.05 1.13,-0.23 2.24,-0.34 3.29,-0.34 2.77,0 4.89,0.56 6.34,1.69 1.46,1.14 2.18,2.79 2.18,4.96 0,1.11 -0.22,2.11 -0.66,2.99 -0.44,0.88 -1.2,1.82 -2.27,2.84l-1.1 0.97c-0.76,0.71 -1.27,1.27 -1.51,1.7 -0.24,0.42 -0.36,0.9 -0.36,1.41l0 0.77zm-6.15 2.51l6.15 0 0 6.08 -6.15 0 0 -6.08z"));
ctx.restore();
draw.t++;
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);
<canvas id="canvas"></canvas>
然而,文本就是文本,而作为文本的曲线又是另外一回事。文本可以很容易地编辑。
stackoverflow.com上的修改问题:JS Canvas:为什么文本渲染不流畅?
问题似乎是通过增加画布的分辨率来解决的......至少在Linux下的chrome中,它不会那样抽搐(我现在无法在其他浏览器和操作系统中检查,抱歉):
在示例中,分辨率加倍。如果这个问题只是部分地消除了,那么它可以增加更多。
这是一个四倍的例子: