Canvas内奇怪的Viewbox字体大小调整行为

时间:2018-12-05 16:09:32

标签: html5-canvas requestanimationframe viewport-units

https://jsfiddle.net/diegojsrw/od12s9b4/14/

c.font = "100vh sans-serif";
c.fillStyle = "white";
c.fillText(fps.toFixed(0), w/2, 0);

最初,文本的高度看起来不错。

但是,当我调整窗口大小时,文本不会一起调整大小。文本不断地在画布上绘制(使用requestAnimationFrame)。

仅当我切换到另一个标签然后再切换回该标签时,才重新调整文本大小。

有任何线索吗?

1 个答案:

答案 0 :(得分:1)

您正面临Webkit错误。最新的Chrome和Safari都受到关注。

在Canvas2D API中,应该在设置时计算相对单位/值,并且此计算值将被保存和使用。

这意味着您的相对100vw值将以绝对的px单位计算为其对应的值。

这是建议始终使用canvas API中的绝对单位的原因之一(尤其是舍入调整等)。

但是,如果您确实要使用此单元,则每次更改它时都必须对其进行设置,因此您可以盲目地进入循环,只需在调用ctx.font之前再次设置fillText(),但是为了提高性能,我建议您使用脏标志,该标志会在窗口的resize事件中引发,并且仅在引发该标志时更新ctx.font属性。 / p>

但这仅适用于遵循规范的浏览器...

我不确定Webkit浏览器何时计算该值,因为即使将font属性重置为其他值也无法做到,甚至将其设置为其他值(例如,在20vh和21vh)都不做...

所以我现在唯一能看到的解决方法是实际计算自己这个值。对于视口大小,这并不难(innerWidth / (100 / vw_val)),但是即使对于其他相对单位,您实际上也可以直接在画布上设置此fontSize并在画布上调用getComputedStyle()

let dirtySize = true; // this is our resize flag
const ctx = canvas.getContext('2d');
let fontStyle = ' Arial, sans-serif';

anim(0);
// the animation loop
function anim(time) {
  // call the drawing methods
  draw(Math.round(time/1e2));
  // lwoer the flags
  dirtySize = false;
  // do it again next frame
  requestAnimationFrame(anim);
}

function draw(txt) {
  // clear
  ctx.clearRect(0,0,canvas.width, canvas.height);
  // only if needed
  if(dirtySize) {
    // get the cpmputed style from our DOM element
    const fontSize = getComputedStyle(canvas).fontSize;
    // or could be 
    // const fontSize = (innerWidth / (100 / 20)) + 'px';

    ctx.font = fontSize + fontStyle;
  }
  // draw everytime
  ctx.fillText(txt, 0, 100);
}
// on window's resize event
window.addEventListener('resize',
  evt => dirtySize = true, // raise our flag
  { passive: true }
);
#canvas {
  font-size: 20vw;
}
<canvas id="canvas"></canvas>