JS Canvas: 为什么文字渲染不流畅?

JS Canvas: Why is the text rendering not smooth?

为什么下面的JavaScriptcanvas例子中的文字渲染不流畅?

let canvas = document.getElementById('canvas');
let context = this.canvas.getContext('2d');
let tick = 0;

let loop = function() {
  context.clearRect(0, 0, canvas.width, canvas.height);
    
  let scale = 1 + tick * 0.005;
  context.save();
  context.scale(scale,scale)
    
  context.font = 'bold 50px Sans-serif';
  context.textBaseline = 'top';
  context.fillStyle = 'black';
  context.fillText('Hello, world!', 0, 0);
  
  
  context.restore();
  tick++;  
  window.requestAnimationFrame(loop);
}

window.requestAnimationFrame(loop);

演示https://jsfiddle.net/kemrf9p7/

y 位置始终完全相同,尽管未被代码更改。好像是 y +/- 1.

我已经测试了不同的方法来 sclae 文本而没有这种奇怪的行为,但找不到解决方案。比如我没有使用scale()而是直接改变了文字的大小。我还尝试了 textBaseline.

的不同值

这是解决问题的尝试。首先你可以在其他canvas上画一个canvas,所以我尝试创建一个5000*5000px canvas,用500px的字体大小在上面画文字。 但是一开始变大的时候不是很完美,所以我做了几个canvas然后一步一步把它们放在可见的canvas上。

只是想知道如何解决,不是优雅的方法。此示例的更好解决方案是 SVG!

let canvas = document.getElementById('canvas');
let context = this.canvas.getContext('2d');
let tick = 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.fillStyle = 'black';
    ctx.fillText('Hello, world!', 0, 0);
}

let loop = function() {
context.clearRect(0, 0, canvas.width, canvas.height);
    
let scale = 1 + tick * 0.005;
let index = scale < 4 ? Math.floor(scale-1) : 3;
context.save();
context.scale(scale,scale);
context.drawImage(canvases[index],0,0,scale_steps[index]
                   *500,scale_steps[index]*500,0,0,500,500);   
context.restore();
tick++;  
window.requestAnimationFrame(loop);
}

window.requestAnimationFrame(loop);
<canvas id="canvas" width="500" height="500"></canvas>

您也可以将文本添加为​​ 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 = 1 + draw.t * 0.005;
    ctx.save();
    ctx.scale(scale, scale);

    ctx.fill(new Path2D("M0 0.72l10.42 0 0 15.41 15.36 0 0 -15.41 10.42 0 0 40.41 -10.42 0 0 -17.13 -15.36 0 0 17.13 -10.42 0 0 -40.41zm76.21 25.17l0 2.77 -22.67 0c0.23,2.27 1.05,3.97 2.46,5.11 1.41,1.13 3.38,1.7 5.91,1.7 2.04,0 4.13,-0.3 6.26,-0.9 2.14,-0.61 4.34,-1.53 6.6,-2.75l0 7.48c-2.29,0.86 -4.58,1.5 -6.88,1.95 -2.29,0.43 -4.58,0.65 -6.87,0.65 -5.49,0 -9.75,-1.39 -12.78,-4.17 -3.04,-2.79 -4.57,-6.7 -4.57,-11.73 0,-4.95 1.5,-8.84 4.48,-11.66 2.99,-2.84 7.1,-4.25 12.34,-4.25 4.75,0 8.57,1.43 11.43,4.3 2.86,2.87 4.29,6.7 4.29,11.5zm-9.98 -3.22c0,-1.85 -0.53,-3.33 -1.61,-4.46 -1.08,-1.13 -2.47,-1.69 -4.21,-1.69 -1.87,0 -3.4,0.52 -4.57,1.59 -1.17,1.05 -1.9,2.57 -2.19,4.56l12.58 0zm17.31 -23.67l9.7 0 0 42.13 -9.7 0 0 -42.13zm19 0l9.7 0 0 42.13 -9.7 0 0 -42.13zm33.43 18.02c-2.15,0 -3.79,0.76 -4.92,2.31 -1.13,1.54 -1.69,3.76 -1.69,6.67 0,2.9 0.56,5.12 1.69,6.67 1.13,1.54 2.77,2.31 4.92,2.31 2.11,0 3.73,-0.77 4.85,-2.31 1.11,-1.55 1.68,-3.77 1.68,-6.67 0,-2.91 -0.57,-5.13 -1.68,-6.67 -1.12,-1.55 -2.74,-2.31 -4.85,-2.31zm0 -6.93c5.22,0 9.29,1.4 12.22,4.22 2.93,2.81 4.4,6.71 4.4,11.69 0,4.98 -1.47,8.87 -4.4,11.68 -2.93,2.82 -7,4.22 -12.22,4.22 -5.23,0 -9.33,-1.4 -12.27,-4.22 -2.95,-2.81 -4.43,-6.7 -4.43,-11.68 0,-4.98 1.48,-8.88 4.43,-11.69 2.94,-2.82 7.04,-4.22 12.27,-4.22zm24.65 20.56l9.76 0 0 8.25 -6.71 10.1 -5.76 0 2.71 -10.1 0 -8.25zm36.64 -19.84l9.43 0 5.08 20.9 5.12 -20.9 8.09 0 5.09 20.68 5.11 -20.68 9.42 0 -7.98 30.32 -10.59 0 -5.11 -20.84 -5.09 20.84 -10.58 0 -7.99 -30.32zm68.35 6.21c-2.14,0 -3.79,0.76 -4.91,2.31 -1.13,1.54 -1.69,3.76 -1.69,6.67 0,2.9 0.56,5.12 1.69,6.67 1.12,1.54 2.77,2.31 4.91,2.31 2.12,0 3.73,-0.77 4.85,-2.31 1.12,-1.55 1.68,-3.77 1.68,-6.67 0,-2.91 -0.56,-5.13 -1.68,-6.67 -1.12,-1.55 -2.73,-2.31 -4.85,-2.31zm0 -6.93c5.22,0 9.3,1.4 12.23,4.22 2.92,2.81 4.39,6.71 4.39,11.69 0,4.98 -1.47,8.87 -4.39,11.68 -2.93,2.82 -7.01,4.22 -12.23,4.22 -5.23,0 -9.32,-1.4 -12.27,-4.22 -2.94,-2.81 -4.42,-6.7 -4.42,-11.68 0,-4.98 1.48,-8.88 4.42,-11.69 2.95,-2.82 7.04,-4.22 12.27,-4.22zm46.17 8.98c-0.85,-0.4 -1.69,-0.7 -2.53,-0.88 -0.83,-0.19 -1.68,-0.29 -2.53,-0.29 -2.48,0 -4.39,0.8 -5.73,2.39 -1.34,1.6 -2.02,3.89 -2.02,6.87l0 13.97 -9.7 0 0 -30.32 9.7 0 0 4.99c1.25,-1.99 2.67,-3.44 4.28,-4.35 1.62,-0.91 3.55,-1.36 5.8,-1.36 0.33,0 0.68,0.01 1.06,0.03 0.37,0.03 0.92,0.1 1.64,0.18l0.03 8.77zm4.83 -20.07l9.7 0 0 42.13 -9.7 0 0 -42.13zm39.62 16.24l0 -16.24 9.76 0 0 42.13 -9.76 0 0 -4.38c-1.33,1.78 -2.8,3.09 -4.4,3.92 -1.61,0.82 -3.47,1.23 -5.58,1.23 -3.74,0 -6.8,-1.48 -9.2,-4.45 -2.4,-2.96 -3.6,-6.78 -3.6,-11.45 0,-4.68 1.2,-8.49 3.6,-11.46 2.4,-2.97 5.46,-4.45 9.2,-4.45 2.09,0 3.94,0.41 5.56,1.25 1.62,0.83 3.09,2.14 4.42,3.9zm-6.38 19.63c2.07,0 3.66,-0.76 4.75,-2.28 1.09,-1.51 1.63,-3.71 1.63,-6.59 0,-2.89 -0.54,-5.08 -1.63,-6.6 -1.09,-1.52 -2.68,-2.27 -4.75,-2.27 -2.06,0 -3.64,0.75 -4.73,2.27 -1.09,1.52 -1.63,3.71 -1.63,6.6 0,2.88 0.54,5.08 1.63,6.59 1.09,1.52 2.67,2.28 4.73,2.28zm28.55 -34.15l9.76 0 0 15.51 -1.39 11.32 -6.99 0 -1.38 -11.32 0 -15.51zm0 30.76l9.76 0 0 9.65 -9.76 0 0 -9.65z"));

    ctx.restore();
    draw.t++;  
    window.requestAnimationFrame(draw);
}

window.requestAnimationFrame(draw);
<canvas id="canvas"></canvas>