LoginSignup
24
27

More than 5 years have passed since last update.

Canvasで元に戻す(Undo),やり直し(Redo)を実装する方法

Last updated at Posted at 2018-01-20

これを作った時の知見を忘れないうちにメモ

getImageDataとputImageData

canvasのcontext.getImageData()を用いることで、描画されているラスタのデータを範囲指定してピクセルの配列(ImageData)として取得することができます。
また、取得したImageDataはputImageData()で描画を行うことができます。

ImageDataをスタックとして変数に保持しておけば元に戻す・やり直すという動作を実現させることができます。
それぞれの配列の挙動はFIFOになるように実装します。

サンプルコード

let $canvas = $('#myCanvas');
// contextを取得
let ctx = $canvas[0].getContext('2d');
// スタックしておく最大回数。キャンバスの大きさの都合などに合わせて調整したら良いです。
const STACK_MAX_SIZE = 5;
// スタックデータ保存用の配列
let undoDataStack = [];
let redoDataStack = [];

// canvasへの描画処理を行う前に行う処理
function beforeDraw() {
    // やり直し用スタックの中身を削除
    redoDataStack = [];
    // 元に戻す用の配列が最大保持数より大きくなっているかどうか
    if (undoDataStack.length >= STACK_MAX_SIZE) {
        // 条件に該当する場合末尾の要素を削除
        undoDataStack.pop();
    }
    // 元に戻す配列の先頭にcontextのImageDataを保持する
    undoDataStack.unshift(ctx.getImageData(0, 0, $canvas[0].width(), $canvas[0].height()));
}

function undo () {
     // 戻す配列にスタックしているデータがなければ処理を終了する
    if (undoDataStack.length <= 0) return;
    // やり直し用の配列に元に戻す操作をする前のCanvasの状態をスタックしておく
    redoDataStack.unshift(ctx.getImageData(0, 0, $canvas[0].width(), $canvas[0].height()));
    // 元に戻す配列の先頭からイメージデータを取得して
    var imageData = undoDataStack.shift();
    // 描画する
    ctx.putImageData(imageData, 0, 0);
}

function redo () {
    // やり直し用配列にスタックしているデータがなければ処理を終了する
    if (redoDataStack.length <= 0) return;
    // 元に戻す用の配列にやり直し操作をする前のCanvasの状態をスタックしておく
    undoDataStack.unshift(ctx.getImageData(0, 0, $canvas[0].width(), $canvas[0].height()));
    // やり直す配列の先頭からイメージデータを取得して
    var imageData = redoDataStack.shift();
    // 描画する
    ctx.putImageData(imageData, 0, 0);
}

関連リファレンス

https://developer.mozilla.org/ja/docs/Web/API/CanvasRenderingContext2D/getImageData
https://developer.mozilla.org/ja/docs/Web/API/CanvasRenderingContext2D/putImageData
https://developer.mozilla.org/ja/docs/Web/API/ImageData

24
27
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
27