14558
現在、canvasで書けるお絵描きアプリを作っています。  
jqueryで書いていますが、1こ前の状態に戻すundo機能をつけたいと思っています。

mouseupするごとに配列に入れて、[0][1][2][3]みたいに動作をそれぞれの箱に入れたいのですが、どう記述すればよいでしょうか？

```

    $(can).on("mousemove", function(e){
        if(canvas_mouse_event == true){
            var px = e.offsetX - $(this).offset().left - txy;
            var py = e.offsetY - $(this).offset().left - txy;
            context.strokeStyle = color ;
            context.lineWidth = lineWidth;
            context.beginPath();
            context.lineCap = "round";
            context.moveTo(oldX, oldY);
            context.lineTo(px, py);
            context.stroke();
            context.closePath();
            oldX = px;
            oldY = py;
        }
    });
    
     $(can).on("mouseup", function(e){
            canvas_mouse_event = false;
        });
    
```
CC BY-SA 3.0
2015-08-17T11:32:56.250
14529
2015-08-18T03:06:50.607
8415
question
javascript jquery
絵をかくようなアプリ(canvas)でundo機能を作りたい
context.save()ってーのとcontext.restore()って便利なもんがあるだろ。  
mouseupしたときにsaveしてundoボタンなり押したときにrestoreすればいいんじゃないか
CC BY-SA 3.0
2015-08-17T19:04:30.797
14547
2015-08-17T19:04:30.797
10964
14529
answer
効率はさておき、Undoを実現する一番簡単なものとしては、その時点でのアプリケーション全体の状態、ここではキャンバスのピクセルデータをそのまま保持しておき、それを上書きするような関数を配列`undoList`に積んでおく方法があります。Undoボタンを押されたら`undoList`からひとつ関数を取り出して呼び出すだけです。

```

    var undoList = [];
    var canvas = document.getElementById("canvas");
    var context = canvas.getContext("2d");
    
    canvas.addEventListener("mousedown", function(e) {
      var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
      undoList.push(function() {
        context.putImageData(imageData, 0, 0);
      });
    
      context.fillRect(e.offsetX, e.offsetY, 10, 10);
    });
    
    document.getElementById("undo").addEventListener("click", function() {
      if (undoList.length > 0) {
        undoList.pop()();
      }
    });
```

```

    <canvas id="canvas" style="border: solid 1px black;"></canvas>
    <button id="undo">Undo</button>
```

ただしこの方法はメモリを大きく圧迫していきます。効率を改善するには必要な差分のみを保持しておくなどの最適化が必要ですが、
**そのような最適化は個々のアプリケーションの振る舞いとデータ構造に強く依存するものであり、最適化については自分でそのアプリケーションの振る舞いを検討して自分で方法を考案してもらうしかありません。**

なお、質問文で完全なコードスニペットを示してくれれば、「回答にスニペットをコピー」で複製して必要な部分だけ書き足せばいいので回答も楽なのですが、質問文ではコードが中途半端に抜粋されていて実際に実行できない不完全なコードしか示されていないので、回答に実際に実行できるスニペットを作るのに無用な手間がかかっています。せっかく言語もブラウザ上で動くJavaScriptなんですから、中途半端な抜粋などせず、実行できる完全なコードスニペットを示してもらうとお互い助かります。
CC BY-SA 3.0
2015-08-18T02:48:59.763
14558
2015-08-18T03:06:50.607
2015-08-18T03:06:50.607
10330
10330
14529
answer