防止调整窗口大小时清除画布

38

我正在尝试创建一个简单的应用程序,在Canvas标签中绘制矩形。我已经将Canvas调整为全屏,但每当我调整视口大小时,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;
      }

    };
  })();

看一下这个:https://dev59.com/RHDYa4cB1Zd3GeqPC6pc#23128583 - karaxuna
6个回答

25

设置canvas的width属性会清空画布
如果你调整样式的宽度(例如canvas.style.visibility),它会缩放(通常不太好看)
如果你想让画布变大但保持其中的元素不变,我建议将canvas存储为图像--例如使用toDataURL方法获取图像,然后用drawImage()将其绘制到调整大小的canvas上。


canvas.style.width = "320px"; - user202448
2
令人难以置信的是,我不知道改变画布的高度或宽度属性会清除画布! - sidonaldson
2
为什么要费心使用 toDataURL,当你可以简单地使用 getImageData()/putImageData()呢? - Will

11

这是我如何使用 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 的尺寸。


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

一个解决方案是:

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

唯一的问题是,在缩小画布后,您会失去在画布之外的数据。

4
使用样式(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和变量名称以加快速度,因此可能会出现一些小错误,例如“canvas.ctx”或dom调用。

1
这对我不起作用。当我在Chrome中使用CSS设置画布大小时,它会绘制变形!https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_usage#The_<canvas>_element - dano
运行得很好。干杯! - user4938328
1
正如Evildonald所提到的,如果你想在画布上进行任何绘制,这种方法并不推荐。这里有一个演示,展示了通过CSS调整尺寸会产生不良绘图行为的fiddle:https://jsfiddle.net/kuLLe2wo/ - Bower

1

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


是的,我确实这么做了。 window.onresize = this.windowResized 我已经添加了部分代码。 - alvincrespo
3
我发现你正在调整画布的大小,但是在画布大小调整后没有进行任何绘制操作。添加一个函数来进行绘制,并在更改高度和宽度属性后调用该函数。 - Justin Pearce

-2
我遇到了与我的画布相同的问题,但我已经解决了这个问题。请参考下面的代码。希望您能通过此解决该问题。
注意:在参数中设置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>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接