【问题标题】:JavaScript event for canvas resize画布调整大小的 JavaScript 事件
【发布时间】:2011-08-15 02:09:48
【问题描述】:

似乎改变画布的尺寸会清除该画布上已经完成的所有绘图。

是否有在画布调整大小时触发的事件,所以我可以挂钩它并在它发生时重绘?

【问题讨论】:

  • 您在代码中有多少个不同的地方重新调整了画布的大小?难道你不能在改变大小后调用你的重绘函数吗?
  • 我不想断言我是唯一一个调整特定画布大小的人。
  • 我不知道它是否适合你,但我正在使用 requestAnimationFrame() 重绘每一帧 - 我得到了 60fps,我不必担心在调整大小时重绘

标签: javascript html canvas


【解决方案1】:

您通常不想严格检查调整大小事件,因为当您进行动态调整大小时它们会触发很多,例如 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!"); } );

【讨论】:

  • 足够好了,我想。将setInterval() 用于应该是交互式的东西让我每次都感到不寒而栗。
  • 最好实际连接到 resize() 事件并在每次触发时(重新)启动重绘计时器。只有当重绘计时器用完时,才会绘制图像。
  • 这真的有效吗? MDN 说只有 window 触发调整大小事件
  • @oberhamsi 是的,它可以工作并且它不检查调整大小事件,它会在间隔上进行大小比较。
  • 在循环中执行逻辑“以防万一”是hacky代码。我强烈建议不要使用这种方法,因为它总是会对电池寿命产生不利影响并大量增加应用程序的占用空间。此外,300ms 是一个可以选择的任意数字,这使其成为对可能使其不可靠的事件的异步响应。 300 毫秒对用户来说也会显得很慢/很卡。
【解决方案2】:

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

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

调整大小后

ctx.putImageData(imgDat,0,0)

【讨论】:

  • 问题是检测何时发生调整大小。
【解决方案3】:

2020 年更新

Jemenake 的答案看起来不错,但总的来说,我建议加载到提供 debounce 功能的库中,因为这就是所谓的。

例如使用 lodash ,您可以使用window.addEventListner('resize', _.debounce(onResize, 500)。请注意,还有第三个参数,您可以在其中指定您想要的行为(例如window.addEventListner('resize', _.debounce(onResize, 500, {leading: true, trailing true})),尽管默认值应该很好。


Kit Sunde 的回答会在未调整浏览器窗口大小的情况下做很多不必要的工作。最好检查事件是否为响应浏览器事件而调整大小,然后在给定的时间内忽略调整大小事件,然后再次进行检查(这将导致快速连续进行两次检查,代码可能是进行了改进以防止这种情况发生,但您可能明白了)。

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

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

【讨论】:

    【解决方案4】:

    David Mulder 的回答是一个改进,但看起来它会在 first resize 事件后等待 timeout 毫秒后触发。换句话说,如果在超时之前发生了更多的调整大小,它不会重置计时器。我在寻找相反的东西;我想要的东西会等待一点时间让调整大小事件停止,然后在 last 事件之后的一定时间后触发。下面的代码就是这样做的。

    任何当前正在运行的计时器的 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);
    

    【讨论】:

      【解决方案5】:

      我没有找到任何内置事件来检测新的画布尺寸,因此我尝试为两种情况找到解决方法。

      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. 如果画布大小在带有百分比单位的样式标签中声明,我们将无法使用 JavaScript 正确解释 css 选择器(>、*、::before、...)。我认为在这种情况下,最好的方法是设置一个 window.resize 处理程序并检查画布客户端大小。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-23
        • 1970-01-01
        相关资源
        最近更新 更多