Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
26
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

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

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

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
26
Help us understand the problem. What are the problem?