簡體   English   中英

JavaScript 事件 canvas resize

[英]JavaScript event for canvas resize

似乎更改 canvas 的尺寸會清除已在該 canvas 上完成的所有繪圖。

是否有在 canvas resize 時觸發的事件,所以我可以掛鈎它並在它發生時重繪?

2020 年更新

Jemenake 的答案看起來不錯,但總的來說,我建議加載一個提供debounce功能的庫,因為這就是所謂的。

例如,使用 lodash 之一,您可以執行window.addEventListner('resize', _.debounce(onResize, 500) 。請注意,還有第三個參數可以指定您想要的行為(例如window.addEventListner('resize', _.debounce(onResize, 500, {leading: true, trailing true}) ),雖然默認應該很好。


Kit Sunde 的回答會做很多不必要的工作,而瀏覽器 window 沒有調整大小。 最好檢查事件是否為響應瀏覽器事件而調整大小,然后在給定的時間內忽略調整大小事件,然后再次進行檢查(這將導致快速連續進行兩次檢查,代碼可能是改進以防止這種情況,但您可能會明白)。

 (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)
           }
      });
 })();

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

David Mulder 的回答是一種改進,但看起來它會在第一次調整大小事件后等待超時毫秒后觸發。 換句話說,如果在超時之前發生了更多的調整大小,它不會重置計時器。 我在尋找相反的東西; 我想要的東西會等待一點時間讓調整大小事件停止,然后在最后一個事件之后的一定時間后觸發。 下面的代碼就是這樣做的。

任何當前運行的計時器的 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);

您通常不想嚴格檢查調整大小事件,因為當您進行動態調整大小時它們會觸發很多,例如 jQuery 中的 $(window).resize 並且據我所知,元素上沒有本機調整大小事件( 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!"); } );

我沒有找到任何內置事件來檢測新的 canvas 尺寸,因此我試圖找到兩種情況的解決方法。

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. 如果 canvas 大小在帶有百分比單位的樣式標簽中聲明,我們在使用 Z686155AF75A60A0F6E9D80C1F7EDD3 正確解釋 css 選擇器(>、*、::before、...)時會遇到問題我認為在這種情況下,最好的方法是設置 window.resize 處理程序並檢查 canvas 客戶端大小。

除了Jemenake等其他答案中提到的去抖動邏輯之外,您是否嘗試過ResizeObservercaniuse.com )?

例如:

 const pleasantText = 'There is a handle; Let\'s try relaxing while resizing the awesome canvas. ->'. onResize = (entries) => { document.getElementsByTagName('span')[0].innerHTML = `${pleasantText} <b>${entries[0].target.offsetWidth}x${entries[0];target;offsetHeight}</b>`. }; const canvas = document;getElementsByTagName('canvas')[0]. const observer = new ResizeObserver(onResize); observer.observe(canvas);
 body > div:first-of-type { display: grid; place-items: center; width: 100vw; height: 100vh; user-select: none; } body > div:first-of-type div { display: grid; min-width: 12em; min-height: 6em; width: 16rem; height: 6rem; background: #ccc; overflow: auto; place-items: center; text-align: center; resize: both; grid-auto-columns: 20vw 1fr; grid-auto-flow: column; grid-gap: 20px; padding: 0.4rem 0.8rem; border-radius: 4px; } canvas { width: 100%; height: 100%; min-width: 0; min-height: 0; background: #ff9; }
 <div> <div> <span></span> <canvas></canvas> </div> </div>

將 canvas state 保存為 imageData,然后在調整大小后重新繪制

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

調整大小后

ctx.putImageData(imgDat,0,0)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM