RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1306494
Accepted
Leonid
Leonid
Asked:2022-07-19 03:12:58 +0000 UTC2022-07-19 03:12:58 +0000 UTC 2022-07-19 03:12:58 +0000 UTC

画布上的文字突然缩放,我怎样才能使效果更平滑?

  • 772

有一个画布,在上面绘制文本。画布根据 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:为什么文本渲染不流畅?

javascript
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    yar85
    2022-07-19T04:17:30Z2022-07-19T04:17:30Z

    问题似乎是通过增加画布的分辨率来解决的......至少在Linux下的chrome中,它不会那样抽搐(我现在无法在其他浏览器和操作系统中检查,抱歉):

    const text = 'Am I shaking?',
          canvas = document.getElementById('canvas');
    let w, h;
    w = h = canvas.width = canvas.height = 1e3;  // разрешение x2
    canvas.style.width = `${w / 2}px`;           // соотв. масштабируем "вниз" ширину...
    canvas.style.height = `${h / 2}px`;          // ...и высоту аналогично
    
    const ctx = canvas.getContext('2d');         // контекст вроде надо получать после изменения размеров, но точно не помню
    ctx.font = 'bold 50px Sans-serif';           // тут это лучше поместить...
    ctx.textBaseline = 'top';                    // ...вне цикла, чтобы зря не мучить кампутеръ
    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.fillText(text, 0, 0);
      
      ctx.fillRect(0, 60, 50, 50);
    
      ctx.beginPath();
      ctx.arc(100, 85, 25, 0, Math.PI * 2);
      ctx.fill();
    
      ctx.restore();
      if (++draw.t > 1e3) return;  // завершение цикла не лишним будет, м?
      window.requestAnimationFrame(draw);
    }
    
    window.requestAnimationFrame(draw);
    <canvas id="canvas"></canvas>

    在示例中,分辨率加倍。如果这个问题只是部分地消除了,那么它可以增加更多。
    这是一个四倍的例子:

    const text = 'Am I shaking?',
          canvas = document.getElementById('canvas');
    let w, h;
    w = h = canvas.width = canvas.height = 2e3;  // 
    canvas.style.width = `${w / 4}px`;           // разрешение x4
    canvas.style.height = `${h / 4}px`;          //
    
    const ctx = canvas.getContext('2d');
    ctx.font = 'bold 50px Sans-serif';
    ctx.textBaseline = 'top';
    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.fillText(text, 0, 0);
      
      ctx.fillRect(0, 60, 50, 50);
    
      ctx.beginPath();
      ctx.arc(100, 85, 25, 0, Math.PI * 2);
      ctx.fill();
    
      ctx.restore();
      if (++draw.t > 1e3) return;
      window.requestAnimationFrame(draw);
    }
    
    window.requestAnimationFrame(draw);
    <canvas id="canvas"></canvas>

    • 3

相关问题

  • 第二个 Instagram 按钮的 CSS 属性

  • 由于模糊,内容不可见

  • 弹出队列。消息显示不正确

  • 是否可以在 for 循环中插入提示?

  • 如何将 JSON 请求中的信息输出到数据表 Vuetify vue.js?

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    表格填充不起作用

    • 2 个回答
  • Marko Smith

    提示 50/50,有两个,其中一个是正确的

    • 1 个回答
  • Marko Smith

    在 PyQt5 中停止进程

    • 1 个回答
  • Marko Smith

    我的脚本不工作

    • 1 个回答
  • Marko Smith

    在文本文件中写入和读取列表

    • 2 个回答
  • Marko Smith

    如何像屏幕截图中那样并排排列这些块?

    • 1 个回答
  • Marko Smith

    确定文本文件中每一行的字符数

    • 2 个回答
  • Marko Smith

    将接口对象传递给 JAVA 构造函数

    • 1 个回答
  • Marko Smith

    正确更新数据库中的数据

    • 1 个回答
  • Marko Smith

    Python解析不是css

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5