繁体   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