1

キャンバスのステータスを関数 draw1() に保存し、別の関数 draw2() で復元したいと考えます。そこで、次のコードを書きました。しかし、うまくいきません。

<canvas id="canvas" style="width:500px; height:500px;" height="500" width="500"></canvas>
ctx = document.querySelector('#canvas').getContext('2d');
function draw1(){
   ctx.save();
   ctx.fillRect(25,25,100,100);
}
function draw2(){
   ctx.restore();
}
draw1();
draw2();

その理由は、ステータスがコールスタックに保存されているためだと思います。そのため、関数が戻った後、保存状態もクリアされます。

私のニーズを実装する他の方法はありますか?

UPD:背景は、ほとんどが静的な単純なアニメーションを実装したいということです。setInterval()を使用して描画関数draw( ) を実行することを期待しています。draw()では、最初にキャンバスを元に戻し、残りの動的部分を描画します。

4

3 に答える 3

5

私の理解が正しければ、いくつかの静的オブジェクトを一度だけ描画してから、各フレームでアニメーション化されたオブジェクトを描画するだけで済みます。

まず第一に、あなたはメソッドとメソッドを完全に誤解してsaveおりrestore、Michael Geary がその理由を示しました。また、markE はtoDataURLいつでもキャンバスのスナップショットを取り、画像オブジェクトに保存する方法を教えてくれます。これは強力な機能ですが、単純なアニメーションに本当に必要なものではありません。

では、静的オブジェクトと動的オブジェクトを使用してアニメーションを作成するにはどうすればよいでしょうか?

静的オブジェクトと動的オブジェクトを使用してアニメーションを作成する方法

主なオプションは 2 つあります。

  1. 1 つのキャンバスを使用して、すべてのオブジェクト (静的および動的) をアニメーションのフレームごとに描画します。これは、ほとんどのオブジェクトが静的であるため、おそらく最適ではありません。
  2. 静的オブジェクト用のキャンバスと動的オブジェクト用の別のキャンバスを用意します。この手法を使用すると、静的オブジェクトを 1 回だけ描画し、そこで忘れる必要があり (キャンバスを「復元」する必要はありません)、別のキャンバスでアニメーション (フレームごとに動的オブジェクトを描画する) を実行します。

オプション 2 が最適だと思います。

複数のキャンバスをレイヤーとして使用する

divCSS を使用して、すべてのキャンバスを親タグ内の (0,0) の絶対位置に設定します。

また、CSS を使用してキャンバスの z-index を設定します。z-index プロパティは、要素のスタック順序を指定します。z-index 値が低いアイテムは、z-index 値が高いアイテムの後ろに表示されます。

キャンバスを適切に定義したので、遊んでみましょう!

デモ

必要なアニメーションを実現する方法を示すために、jsFiddle を作成しました。

フィドルをチェック

そのフィドルで使用されるコード:

HTML:

<div id="canvasesdiv">
    <canvas id="static" width=400 height=400>This text is displayed if your browser does not support HTML5 Canvas</canvas>
    <canvas id="dynamic" width=400 height=400>This text is displayed if your browser does not support HTML5 Canvas</canvas>
</div>

CSS:

#canvasesdiv {
    position:relative;
    width:400px;
    height:300px;
}
#static {
    position: absolute;
    left: 0;
    top: 0;
    z-index: 1;
}
#dynamic {
    position: absolute;
    left: 0;
    top: 0;
    z-index: 2;
}

Javascript:

// static canvas
var static = document.getElementById("static");
var staticCtx = static.getContext("2d");

// dynamic canvas
var dynamic = document.getElementById("dynamic");
var dynamicCtx = dynamic.getContext("2d");

// animation status
var FPS = 30;
var INTERVAL = 1000 / FPS;

// our background
var myStaticObject = {
    x: 0,
    y: 0,
    width: static.width,
    height: static.height,
    draw: function () {
        staticCtx.fillStyle = "rgb(100, 100, 0)";
        staticCtx.fillRect(0, 0, static.width, static.height);
    }
};

// our bouncing rectangle
var myDynamicObject = {
    x: 30,
    y: 30,
    width: 50,
    height: 50,
    gravity: 0.98,
    elasticity: 0.90,
    friction: 0.1,
    velX: 10,
    velY: 0,
    bouncingY: false,
    bouncingX: false,
    draw: function () {   // example of dynamic animation code
        // clear the last draw of this object
        dynamicCtx.clearRect(this.x - 1, this.y - 1, this.width + 2, this.height + 2);            
        // compute gravity
        this.velY += this.gravity;
        // bounce Y
        if (!this.bouncingY && this.y >= dynamic.height - this.height) {
            this.bouncingY = true;
            this.y = dynamic.height - this.height;
            this.velY = -(this.velY * this.elasticity);
        } else {
            this.bouncingY = false;
        }
        // bounce X
        if (!this.bouncingX && (this.x >= dynamic.width - this.width) || this.x <= 0) {
            this.bouncingX = true;
            this.x = (this.x < 0 ? 0 : dynamic.width - this.width);
            this.velX = -(this.velX * this.elasticity);
        } else {
            this.bouncingX = false;
        }
        // compute new position
        this.x += this.velX;
        this.y += this.velY;            
        // render the object
        dynamicCtx.fillStyle = "rgb(150, 100, 170)";
        dynamicCtx.fillRect(this.x, this.y, this.width, this.height);
    }
};

function drawStatic() {
    myStaticObject.draw();
    // you can add more static objects and draw here
}

function drawDynamic() {        
    myDynamicObject.draw();
    // you can add more dynamic objects and draw here
}

function animate() {
    setInterval(function () {
        // only need to redraw dynamic objects
        drawDynamic();
    }, INTERVAL);
}

drawStatic(); // draw the static objects
animate(); // entry point for animated (dynamic) objects
于 2013-05-24T10:36:04.923 に答える
2

canvas.toDataURL() を使用して、キャンバス上のピクセルを保存および再読み込みできます。

保存は次のとおりです。

dataURL=canvas.toDataURL();

リロードは次のとおりです。

var image=new Image();
image.onload=function(){
    ctx.drawImage(image,0,0);
}
image.src=dataURL;

コンテキスト属性 (fillStyle など) を保存する必要がある場合は、それらをオブジェクトに保存し、ピクセルを再読み込みするときにそれらをコンテキストに再読み込みする必要があります。

変換を保存する必要がある場合は、変換行列 (6 つの数値の配列) を作成する必要があります。次に、変換行列を操作して行う各変換を追跡する必要があります。このブログ投稿を参照してください: http://blog.safaribooksonline.com/2012/04/26/html5-canvas-games-tracking-transformation-matrices/

ここにコードとフィドルがあります: http://jsfiddle.net/m1erickson/btmLE/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
</style>

<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");

    ctx.fillRect(25,25,100,100);

    var dataURL;

    $("#save").click(function(){
        dataURL=canvas.toDataURL();
        ctx.clearRect(0,0,canvas.width,canvas.height);
    });

    $("#reload").click(function(){
        var image=new Image();
        image.onload=function(){
            ctx.drawImage(image,0,0);
        }
        image.src=dataURL;
    });

}); // end $(function(){});
</script>

</head>

<body>
    <canvas id="canvas" width=300 height=300></canvas><br>
    <button id="save">Save</button>
    <button id="reload">Reload</button>
</body>
</html>
于 2013-05-24T06:00:45.203 に答える