2014-01-14 61 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關於如何在沒有內插問題的情況下調整大圖像大小。

希望這會有所幫助。