2014-01-14 38 views
0

让我们把一些文字上的HTML5 <canvas>Zooming on HTML5 <canvas> and no pixelation for text?

var canvas = document.getElementById('myCanvas'), 
ctx = canvas.getContext('2d'), 
ctx.textBaseline = 'top'; 
ctx.textAlign = 'left'; 
ctx.font = '14px sans-serif'; 
ctx.fillText('Bonjour', 10, 10); 

当缩放文本在画布上,人们可以看到像素化

有没有在画布上缩放而不会对文本具有像素化的一种方式?

+0

如何缩放画布?你在谈论Web浏览器的内置缩放功能吗(Ctrl +鼠标滚轮)?还是你编程自己的缩放功能?当你完成后者时,你是如何实现它的?您是以更大规模绘制还是使用CSS调整画布大小? – Philipp

+0

我试着用CTRL + moueswheel,是否有更简洁的方式来实现画布缩放? @Philipp – Basj

+0

为了减少像素化,你将不得不听取大小调整事件。调整大小时,您必须缩放ctx.font(向上/向下)并重新绘制画布。 – markE

回答

1

当您在画布上显示fillText时,它会停止显示字母,并开始为字母形状的像素集合。放大时,像素会变大。这是一个画布的作品。

如果希望文字作为基于矢量的字体缩放而不是像素,请不要在画布上绘制它们。您可以创建<span>HTML元素,并使用CSS定位将它们放置在画布的顶部。这样,渲染引擎在放大时将呈现更高分辨率的字体,并且保持清晰。但是您在画布上绘制的任何东西都会相应地缩放。

或者,您可以覆盖浏览器缩放功能并创建您自己的缩放算法,但这将是一些工作。

当用户或窗外的放大,在window.onresize触发事件处理程序。您可以使用此触发器来调整画布css样式的宽度和高度(而不是画布的属性),这是内部呈现分辨率。更改样式的宽度和高度属性,这是它缩放到的分辨率网站)。

现在你有效地调整画布禁用用户的网页浏览器,并且也有一个地方,你可以在缩放输入事件作出反应。您可以使用它来调整画布的context.scale以更改您绘制的所有内容(包括字体)的大小。

下面是一个例子:

<!DOCTYPE html> 
<html> 
<head> 

    <script type="application/javascript"> 

     "use strict" 

     var canvas; 
     var context; 

     function redraw() { 
      // clears the canvas and draws a text label 
      context.clearRect(0, 0, context.canvas.width, context.canvas.height); 
      context.font = "60pt sans-serif"; 
      context.fillText("Hello World!", 100, 100); 
     } 

     function adjustSize() { 
      var width = window.innerWidth; 
      var height = window.innerHeight; 

      // resize the canvas to fill the whole screen 
      var style = canvas.style; 
      style.width = width + "px"; 
      style.height = height + "px"; 

      // backup the old current scaling factor 
      context.save(); 
      // change the scaling according to the new zoom factor 
      context.scale(1000/width, 1000/height); 
      // redraw the canvas 
      redraw(); 
      // restore the original scaling (important because multiple calls to scale are relative to the current scale factor) 
      context.restore(); 
     } 

     window.onload = function() { 
      canvas = document.getElementById("myCanvas"); 
      context = canvas.getContext("2d"); 
      adjustSize(); 
     } 

     window.onresize = adjustSize; 
    </script> 
</head> 

<body> 

<canvas id ="myCanvas" width = 1000 height = 1000 ></canvas> 

</body> 

</html> 
+0

我以前用尝试过,但问题是:当我有一个大量的文本框,在画布中滚动(与点击+拖动)是非常缓慢的...所以我认为这将是更好的 ... – Basj

+0

你会有一个例子@Philipp与'帆布'的'规模' ,我无法让它工作......? – Basj

+0

@Basj我添加了一个代码示例 – Philipp

1

如果你只需要缩放文本,你​​可以简单地缩放字体大小。

上但有两点要注意:字体,或字体,不只是简单的规模意味着你不会得到顺利进行。这是因为字体通常针对特定尺寸进行了优化,所以可以说这些尺寸之间的尺寸是前一个尺寸和下一个尺寸的结果。这可以使字体看起来像是在扩大规模时正在移动,并且是正常的和预期的。

这里的方法使用简单的尺寸比例。如果你需要一个绝对平滑的比例尺用于动画目的,你将不得不使用一种非常不同的技术。

简单的方法是:

ctx.font = (fontSize * scale).toFixed(0) + 'px sans-serif'; 

online demo here

出于动画目的,你需要做到以下几点:

  • 渲染更大尺寸的屏幕外的画布上,然后用来绘制不同尺寸
  • 当差值过大,你会遇到内插问题,你将不得不以密钥大小渲染这些缓存文本图像中的几个,以便在缩放因子超过某个阈值时可以在它们之间切换。

In this demo你可以看到,在小尺寸的像素变得有点“块状”但在其他方面是比纯文本方式更加顺畅。

这是因为浏览器使用双线性插值而不是使用双立方体与画布(这可能会或可能不会在将来改变),所以当差异变大时它不能正确插值(请参阅下面的解决方案与这个问题)。

相反的情况发生在大尺寸的情况下,由于插值,文字变得模糊。

这是我们不得不切换到更小(或更大)缓存版本的地方,然后在我们再次切换之前在一定范围内进行缩放。

该演示简化为仅显示单个缓存版本。你可以看到一半,这工作正常。原理将采用完整的解决方案(尺寸仅为示例):

更新Here is a demo在缩放期间的切换图像)。

-- Cached image (100px) 
    -- Draw cached image above scaled based on zoom between 51-100 pixels 

-- Cached image (50px) generated from 100px version/2 
    -- Draw cached image above scaled based on zoom between 26-50 pixels 

-- Cached image (25px) generated from 50px version/2 
    -- Draw cached image above scaled based on zoom between 1-25 pixels 

然后用“甜蜜点”(你通过实验一点点找到),把他们拉来筛选前的缓存版本之间切换。

var ctx = canvas.getContext('2d'), 
    scale = 1,    /// initial scale 
    initialFactor = 6,  /// fixed reduction scale of cached image 
    sweetSpot = 1,   /// threshold to switch the cached images 

    /// create two off-screen canvases 
    ocanvas = document.createElement('canvas'), 
    octx = ocanvas.getContext('2d'), 
    ocanvas2 = document.createElement('canvas'), 
    octx2 = ocanvas2.getContext('2d'); 

ocanvas.width = 800; 
ocanvas.height = 150; 
ocanvas2.width = 400; /// 50% here, but maybe 75% in your case 
ocanvas2.height = 75; /// experiment to find ideal size.. 

/// draw a big version of text to first off-screen canvas 
octx.textBaseline = 'top'; 
octx.font = '140px sans-serif'; 
octx.fillText('Cached text on canvas', 10, 10); 

/// draw a reduced version of that to second (50%) 
octx2.drawImage(ocanvas, 0, 0, 400, 75); 

现在,我们只需要检查甜蜜点值,找出什么时候这些版本之间切换:

function draw() { 

    /// calc dimensions 
    var w = ocanvas.width/initialFactor * scale, 
     h = ocanvas.height/initialFactor * scale; 

    ctx.clearRect(0, 0, canvas.width, canvas.height); 

    if (scale >= sweetSpot) { 
     ctx.drawImage(ocanvas, 10, 10, w, h); /// use cached image 1 

    } else { 
     ctx.drawImage(ocanvas2, 10, 10, w, h); /// use cached image 2 
    } 
} 

那么为什么不直接绘制第二缓存的图片与字体?你可以做到这一点,但随后你又回到了字体为特定大小进行优化的问题,并且在缩放时会产生一个小小的跳跃。如果你能忍受这一点,那么使用它,因为它会提供更好的质量(特别是小尺寸)。如果你需要流畅的动画,你将不得不减小一个更大的缓存版本,以保持100%的比例。

你可以看到this answer关于如何在没有内插问题的情况下调整大图像大小。

希望这会有所帮助。