【问题标题】:Preventing Canvas Clear when Resizing Window调整窗口大小时防止画布清除
【发布时间】:2011-04-01 19:11:39
【问题描述】:

我正在尝试创建一个在 Canvas 标记内绘制矩形的简单应用程序。我已经将画布大小调整为全屏,但每当我调整视口大小时,画布就会清除。我试图阻止它被清除并只保留其中的内容。有什么想法吗?

http://mediajux.com/experiments/canvas/drawing/

谢谢!

      /*
      * This is the primary class used for the application
      * @author Alvin Crespo
      */
      var app = (function(){

        var domBod          = document.body;
        var canvas          = null;
        var canvasWidth     = null;
        var canvasHeight     = null;

        return {

          //Runs after the DOM has achieved an onreadystatechange of "complete"
          initApplication: function()
          {
            //setup envrionment variables
            canvas = document.getElementById('canvas') || null;

            //we need to resize the canvas at the start of the app to be the full window
            this.windowResized();

            //only set the canvas height and width if it is not false/null
            if(canvas)
            {
              canvasWidth = canvas.offsetWidth;
              canvasHeight = canvas.offsetHeight;        
            }

            //add window events
            window.onresize = this.windowResized;   

            circles.canvas = canvas;
            circles.canvasWidth = canvasWidth;
            circles.canvasHeight = canvasHeight;
            circles.generateCircles(10);  

            setInterval(function(){
                circles.animateCircles();
            }, 50);   
          },

          /**
          * Executes Resizing procedures on the canvas element
          */
          windowResized: function()
          {
            (this.domBod === null) ? 'true' : 'false';
            try{
              console.log(canvas);
              canvas.setAttribute('width', document.body.clientWidth);
              canvas.setAttribute('height', document.body.clientHeight);        
            }catch(e) {
              console.log(e.name + " :: " + e.message);
            }
          },

          /**
          * Returns the canvas element 
          * @returns canvas
          */
          getCanvas: function()
          {
            return canvas;
          }

        };
      })();

【问题讨论】:

标签: html canvas redraw


【解决方案1】:

设置画布宽度属性将清除画布。如果您调整样式宽度的大小(例如 canvas.style.visibility),它将缩放(通常不是以这种漂亮的方式)。如果您想使画布更大但保留其中的元素,我建议将画布存储为图像 - 例如调用 toDataURL 方法获取图像,然后使用 drawImage() 将其绘制到调整大小的画布上。

【讨论】:

  • 例如canvas.style.width = "320px";
  • 难以置信,我不知道更改高度或宽度属性会清除画布!
  • 既然可以simply use getImageData()/putImageData(),为什么还要麻烦toDataURL
【解决方案2】:

这是我使用JS3 解决此问题的方法。

在内部,我将主画布和上下文分别存储为 _canvas 和 _context。

function resize(w, h){
// create a temporary canvas obj to cache the pixel data //
    var temp_cnvs = document.createElement('canvas');
    var temp_cntx = temp_cnvs.getContext('2d');
// set it to the new width & height and draw the current canvas data into it // 
    temp_cnvs.width = w; 
    temp_cnvs.height = h;
    temp_cntx.fillStyle = _background;  // the original canvas's background color
    temp_cntx.fillRect(0, 0, w, h);
    temp_cntx.drawImage(_canvas, 0, 0);
// resize & clear the original canvas and copy back in the cached pixel data //
    _canvas.width = w; 
    _canvas.height = h;
    _context.drawImage(temp_cnvs, 0, 0);
}

JS3 还提供了一个 autoSize 标志,它会自动将您的画布调整为浏览器窗口或其父 div 的尺寸。

【讨论】:

    【解决方案3】:

    使用样式(css)设置画布大小,不要更改属性。

    调整为全屏后

    画布将被调整大小而不是清除,但会被缩放,而不是防止缩放 - 你需要在调整大小后重新缩放,这里是数学:

    var oldWidth    =  $("canvas").css("width").replace("px", "");
    var oldHeight   = $("canvas").css("height").replace("px", "");  
    
    $("canvas").css({ 
                "width" : window.innerWidth, 
                "height": window.innerHeight
            }); 
    
    
    
    var ratio1 =  oldWidth/window.innerWidth;
    var ratio2 =  oldHeight/window.innerHeight;
    
    
    
    canvas.ctx.scale(ratio1, ratio2);
    

    请注意,我从我的代码中复制粘贴并使用 id 和 vars 名称进行了一些快速更改,因此可能会有一些小错误,例如“canvas.ctx”或 dom 调用。

    【讨论】:

    【解决方案4】:

    我解决这个问题的一种方法是:

    const canvas = document.getElementById('ctx')
    const ctx = canvas.getContext('2d')
    var W = canvas.width, H = canvas.height
    function resize() {
        let temp = ctx.getImageData(0,0,W,H)
        ctx.canvas.width = window.innerWidth - 99;
        ctx.canvas.height = window.innerHeight - 99;
        W = canvas.width, H = canvas.height
        ctx.putImageData(temp,0,0)
    }
    

    唯一的问题是缩小后会丢失画布外的数据

    【讨论】:

      【解决方案5】:

      我相信您已经实现了一个监听器,用于调整屏幕大小并在该监听器触发时重绘画布内容。

      【讨论】:

      • 是的,我确实做到了。 window.onresize = this.windowResized 我在上面添加了一些代码。
      • 我看到您正在调整画布大小,但在调整画布大小后您没有执行任何绘制操作。添加一个绘制函数并在调用后调用它以更改高度和宽度属性。
      【解决方案6】:

      我的画布也遇到了同样的问题,我已经解决了这个问题。请参考以下代码。我希望你能用这个解决这个问题。

      注意:在参数中设置alwaysDraw: true

      HTML

      <div id="top-wraper">
              <div id="canvas"></div>
          </div>
      
          <!-- div used to create our plane -->
          <div class="plane" data-vs-id="plane-vs" data-fs-id="plane-fs">
              <!-- image that will be used as a texture by our plane -->
              <img src="texture-img.png" alt="Leo Music - Music from the heart of a Lion"/>
          </div>
      

      JS

      <script>
      
          function loadAnimation() {
              // set up our WebGL context and append the canvas to our wrapper
              var webGLCurtain = new Curtains("canvas");
              webGLCurtain.width = 50;
              // if there's any error during init, we're going to catch it here
              webGLCurtain.onError(function () {
                  // we will add a class to the document body to display original images
                  document.body.classList.add("no-curtains");
              });
              // get our plane element
              var planeElement = document.getElementsByClassName("plane")[0];
              // set our initial parameters (basic uniforms)
              var params = {
                  vertexShaderID: "plane-vs", // our vertex shader ID
                  fragmentShaderID: "plane-fs", // our framgent shader ID
                  alwaysDraw: true,
                  //crossOrigin: "", // codepen specific
                  uniforms: {
                      time: {
                          name: "uTime", // uniform name that will be passed to our shaders
                          type: "1f", // this means our uniform is a float
                          value: 0,
                      },
                  }
              }
      
              // create our plane mesh
              var plane = webGLCurtain.addPlane(planeElement, params);
              // if our plane has been successfully created
              // we use the onRender method of our plane fired at each requestAnimationFrame call
              plane && plane.onRender(function () {
                  plane.uniforms.time.value++; // update our time uniform value
              });
          }
      
          window.onload = function () {
              loadAnimation();
          }
      
      
      </script>
      
      <script id="plane-vs" type="x-shader/x-vertex">
          #ifdef GL_ES
          precision mediump float;
          #endif
      
          // those are the mandatory attributes that the lib sets
          attribute vec3 aVertexPosition;
          attribute vec2 aTextureCoord;
      
          // those are mandatory uniforms that the lib sets and that contain our model view and projection matrix
          uniform mat4 uMVMatrix;
          uniform mat4 uPMatrix;     
          // our texture matrix uniform (this is the lib default name, but it could be changed)
          uniform mat4 uTextureMatrix0;
      
          // if you want to pass your vertex and texture coords to the fragment shader
          varying vec3 vVertexPosition;
          varying vec2 vTextureCoord;
      
          void main() {
          vec3 vertexPosition = aVertexPosition;
      
          gl_Position = uPMatrix * uMVMatrix * vec4(vertexPosition, 1.0);
      
          // set the varyings
          // thanks to the texture matrix we will be able to calculate accurate texture coords
          // so that our texture will always fit our plane without being distorted
          vTextureCoord = (uTextureMatrix0 * vec4(aTextureCoord, 0.0, 1.0)).xy;
          vVertexPosition = vertexPosition;
          }
      </script>
      
      <script id="plane-fs" type="x-shader/x-fragment">
          #ifdef GL_ES
          precision mediump float;
          #endif
      
          // get our varyings
          varying vec3 vVertexPosition;
          varying vec2 vTextureCoord;
          // the uniform we declared inside our javascript
          uniform float uTime;
          // our texture sampler (default name, to use a different name please refer to the documentation)
          uniform sampler2D uSampler0;
          void main() {
          // get our texture coords
          vec2 textureCoord = vTextureCoord;
          // displace our pixels along both axis based on our time uniform and texture UVs
          // this will create a kind of water surface effect
          // try to comment a line or change the constants to see how it changes the effect
          // reminder : textures coords are ranging from 0.0 to 1.0 on both axis
          //    const float PI = 3.141592;
          const float PI = 2.0;
          textureCoord.x += (
          sin(textureCoord.x * 10.0 + ((uTime * (PI / 3.0)) * 0.031))
          + sin(textureCoord.y * 10.0 + ((uTime * (PI / 2.489)) * 0.017))
          ) * 0.0075;
          textureCoord.y += (
          sin(textureCoord.y * 20.0 + ((uTime * (PI / 2.023)) * 0.00))
          + sin(textureCoord.x * 20.0 + ((uTime * (PI / 3.1254)) * 0.0))
          ) * 0.0125;
          gl_FragColor = texture2D(uSampler0, textureCoord);
          }
      </script>
      
      <script src="https://www.curtainsjs.com/build/curtains.min.js" ></script>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-04-06
        • 1970-01-01
        • 2013-04-14
        • 1970-01-01
        • 2018-03-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多