2011-04-28 103 views
15

看起來,更改畫布的尺寸會清除已在該畫布上完成的任何圖形。調整畫布大小的JavaScript事件

是否有一個事件在畫布上調整大小,所以我可以掛鉤它並在發生時重繪?

+0

您的代碼中有多少個不同的地方是您重新調整畫布大小?你能不能在你改變尺寸後調用你的重繪函數? – robertc 2011-04-28 23:03:40

+0

我不想斷言我是唯一一個調整特定畫布的大小。 – rampion 2011-04-29 02:30:17

+1

我不知道它是否適合你,但我使用'requestAnimationFrame()'重繪每一幀 - 我得到60fps,我不必擔心重新調整時它的尺寸調整 – Zac 2016-07-04 14:07:47

回答

10

您通常不希望嚴格檢查resize事件,因爲當您執行動態調整大小時,會觸發大量事件,例如jQuery中的$(window).resize,並且據我所知,沒有本地調整大小元素事件(there is on window)。我會檢查它的時間間隔,而不是:

function onResize(element, callback){ 
    var elementHeight = element.height, 
     elementWidth = element.width; 
    setInterval(function(){ 
     if(element.height !== elementHeight || element.width !== elementWidth){ 
     elementHeight = element.height; 
     elementWidth = element.width; 
     callback(); 
     } 
    }, 300); 
} 

var element = document.getElementsByTagName("canvas")[0]; 
onResize(element, function(){ alert("Woo!"); }); 
+2

足夠好,我假設。使用'setInterval()'應該是交互式的東西,但每次都會讓我感到不寒而慄。 – rampion 2011-04-28 22:20:38

+5

實際連接到resize()事件並在每次觸發時重新啓動重繪計時器會更好。只有在重繪計時器用完時,圖像纔會被繪製。 – paniq 2011-08-11 14:25:45

+0

這實際上工作嗎? MDN表示只有'window'觸發了一個resize事件 – oberhamsi 2013-02-05 19:59:01

1

畫布狀態保存爲的imageData,然後調整

var imgDat=ctx.getImageData(0,0,ctx.canvas.width,ctx.canvas.height) 

後重繪調整後

ctx.putImageData(imgDat,0,0) 
+0

該問題正在檢測調整大小發生的時間。 – rampion 2011-04-29 02:29:20

5

套件桑德的回答會做很多不必要的工作,而瀏覽器窗口沒有調整大小。最好檢查事件是否響應瀏覽器事件而調整大小,然後在給定時間內忽略調整大小事件,然後再次執行檢查(這會在連續快速連接後導致兩次檢查並且代碼可能是改進以防止這種情況發生,但你可能會明白)。

(function(){ 
     var doCheck = true; 
     var check = function(){ 
      //do the check here and call some external event function or something. 
     }; 
     window.addEventListener("resize",function(){ 
      if(doCheck){ 
       check(); 
       doCheck = false; 
       setTimeout(function(){ 
        doCheck = true; 
        check(); 
       },500) 
      } 
     }); 
})(); 

請注意,上面的代碼是盲目輸入的,沒有檢查。

6

大衛Mulder的回答是一個進步,但它看起來像它會在第一 resize事件後等待超時毫秒後觸發。換句話說,如果在超時之前發生更多大小調整,它不會重置計時器。我在尋找相反的東西;我想要一些等待一小段時間讓調整大小事件停止的事情,然後在經過一段時間後在一段時間後觸發。下面的代碼就是這樣做的。

任何當前正在運行的計時器的ID將在timer_id中。所以,無論何時調整大小,它都會檢查是否已經有一段時間在運行。如果是這樣,它就取消那個並開始一個新的。

function setResizeHandler(callback, timeout) { 
    var timer_id = undefined; 
    window.addEventListener("resize", function() { 
     if(timer_id != undefined) { 
      clearTimeout(timer_id); 
      timer_id = undefined; 
     } 
     timer_id = setTimeout(function() { 
      timer_id = undefined; 
      callback(); 
     }, timeout); 
    }); 
} 

function callback() { 
    // Here's where you fire-after-resize code goes. 
    alert("Got called!"); 
} 
setResizeHandler(callback, 1500); 
1

我沒有發現任何內置事件來檢測新的畫布尺寸,所以我試圖找到兩種方案的解決方法。

function onresize() 
{ 
    // handle canvas resize event here 
} 

var _savedWidth = canvas.clientWidth; 
var _savedHeight = canvas.clientHeight; 
function isResized() 
{ 
    if(_savedWidth != canvas.clientWidth || _savedHeight != canvas.clientHeight) 
    { 
     _savedWidth = canvas.clientWidth; 
     _savedHeight = canvas.clientHeight; 
     onresize(); 
    } 
} 

window.addEventListener("resize", isResized); 

(new MutationObserver(function(mutations) 
{ 
    if(mutations.length > 0) { isResized(); } 
})).observe(canvas, { attributes : true, attributeFilter : ['style'] }); 
  1. 爲了檢測任何JavaScript canvas.style變化,MutationObserver API是良好的。它不檢測特定的樣式屬性,但在這種情況下,檢測canvas.clientWidth和canvas.clientHeight是否已更改就足夠了。

  2. 如果使用百分比單位在style-tag中聲明畫布大小,那麼使用JavaScript正確解釋css選擇器(>,*,:: before,...)會有問題。我認爲在這種情況下,最好的方法是設置一個window.resize處理程序,並檢查畫布客戶端的大小。