2011-04-28 136 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处理程序,并检查画布客户端的大小。