画布调整的JavaScript事件

画布调整的JavaScript事件,javascript,html,canvas,Javascript,Html,Canvas,似乎更改画布的尺寸会清除该画布上已完成的任何图形 是否有在画布上触发调整大小的事件,以便我可以在事件发生时钩住它并重新绘制?您通常不想严格检查调整大小事件,因为在执行动态调整大小时,它们会触发很多事件,如$(window)。在jQuery中调整大小,据我所知,在元素()上没有本机调整大小事件。我会每隔一段时间检查一次: function onResize( element, callback ){ var elementHeight = element.height, eleme

似乎更改画布的尺寸会清除该画布上已完成的任何图形


是否有在画布上触发调整大小的事件,以便我可以在事件发生时钩住它并重新绘制?

您通常不想严格检查调整大小事件,因为在执行动态调整大小时,它们会触发很多事件,如$(window)。在jQuery中调整大小,据我所知,在元素()上没有本机调整大小事件。我会每隔一段时间检查一次:

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!"); } );

将画布状态保存为imageData,然后在调整大小后重新绘制

var imgDat=ctx.getImageData(0,0,ctx.canvas.width,ctx.canvas.height)
调整大小后

ctx.putImageData(imgDat,0,0)
更新2020 Jemenake的答案看起来不错,但总的来说,我建议加载到一个提供
debounce
功能的库中,因为这就是所谓的

例如,对于lodash one,您可以执行
window.addEventListner('resize',_u.debounce(onResize,500)
。请注意,还有第三个参数可以指定您想要的行为(例如
window.addEventListner('resize',_EventListner(onResize,500,{leading:true,training true})
),尽管默认值应该相当好


Kit Sunde的答案将在浏览器窗口未调整大小时执行大量不必要的工作。最好检查事件是否已调整大小以响应浏览器事件,然后在给定的时间内忽略调整大小事件,然后再次进行检查(这将导致两次检查后,对方在快速连续和代码可以加以改进,以防止这种情况,但你可能得到的想法)


请注意,上面的代码是盲目输入的,没有经过检查。

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

我没有找到任何内置事件来检测新的画布维度,因此我尝试为两种场景找到解决方法

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'] });
  • 对于检测任何JavaScript canvas.style更改,MutationObserver API非常适合。它不检测特定的样式属性,但 在这种情况下,检查canvas.clientWidth和canvas.clientHeight是否已更改就足够了

  • 如果画布大小是在带有百分比单位的样式标记中声明的,那么我们在使用JavaScript正确解释css选择器(>、*、::before…)时会遇到问题。我认为在这种情况下,最好的方法是设置window.resize处理程序并检查画布客户端大小


  • 我想这已经足够好了。但是,使用
    setInterval()
    来处理一些应该是交互式的东西会让我每次都感到不寒而栗。最好是连接到resize()事件和(re-)每次启动重绘计时器时启动它。只有当重绘计时器用完时,才会绘制图像。这实际有效吗?MDN说仅
    窗口
    启动重绘计时器event@oberhamsi是的,它可以工作,并且不检查resize事件,它在一个间隔上进行大小比较。在循环中执行逻辑“以防万一”发生的事情是黑客代码。我强烈建议不要使用这种方法,因为它总是会对电池寿命产生负面影响,并会大幅增加应用程序的占用空间。此外,300ms是一个任意的数字,这使得它对事件的异步响应可能因此变得不可靠。300ms也会看起来很慢/很慢y给用户。在您的代码中有多少不同的地方您正在调整画布的大小?您不能在更改大小后调用重画函数吗?我不想断言我是唯一一个调整特定画布大小的人。我不知道这是否适用于您,但我正在使用
    requestAnimationFrame()重画每个帧
    -我的速度是60帧/秒,我不必担心在调整大小时重新绘制。问题是检测何时发生大小调整。
    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'] });