JavaScript+Canvasの操作について
- 元に戻す Undo(アンドゥ)
- やり直し Redo(リドゥ)
この2つは自力での実装が大変です。
ただ便利なライブラリを見つけました。
その名も Undo-Canvas というライブラリ
そこでその紹介と記録も兼ね、
JSでCanvasのUndo・Redoの実装について
このページの目次
Undo-Canvasの使い方と実装コード例
実装方法は次の通り
1.ライブラリ本体の読み込み
このライブラリは単独で動きます。
▼ 次のGitHubページからダウンロード
▼ ヘッダーなどで読み込みする
1 2 |
<!-- ライブラリ読み込み --> <script src="./undo-canvas.js"></script> |
jQueryなど他依存ライブラリも必要なし
本当にそれ単体で動かせます。
2.Undo・Redo機能をContext2Dに対して適用
そしたら実際のHTML・JSを作成していきます。
簡単に次のようなコードを書いてみました。
1.Canvas要素と履歴操作ボタン作成
1 2 3 |
<canvas id="appCanvas"></canvas> <button id="btnUndo" >元に戻す</button> <button id="btnRedo" >やり直し</button> |
Canvas要素は普通に作成。
それから元に戻す(Undo)するために #btnUndo というボタン要素を、やり直し(Redo)するために #btnRedo というボタン要素も作りました。名前については好きなようにつけてください。
2.UndoCanvasの初期化&Cnavasに図形などを描く
次にUndoCanvasライブラリの初期化。
そのあとにCanvasに円をランダムに描画します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
const canvas = document.getElementById('appCanvas'); const ctx = canvas.getContext('2d'); /// UndoCanvasを初期化 UndoCanvas.enableUndo(ctx); /// ランダムに円を10描く for(var i = 0; i < 10; i++){ var x = Math.random()*330; var y = Math.random()*300; var radius = (Math.random()*(50-25))+25; ctx.beginPath(); ctx.arc(x, y, radius, 0, Math.PI*2, 1); ctx.fillStyle = "#" + ((1<<24)*Math.random() | 0).toString(16); ctx.fill(); } |
どういう結果になるかはお楽しみ
3.ボタン要素押下時にUndo・Redoを実行
最後にボタン押下時の処理追加
▼ jQueryを使ったコード
1 2 3 4 5 6 |
$('#btnUndo').click(function(){ ctx.undo(); }); $('#btnRedo').click(function(){ ctx.redo(); }); |
単純に UndoCanvas.enableUndo(ctx); を呼び出したコンテキストに対し、元に戻すときは ctx.undo(); を実行、やり直すときは ctx.redo(); とするだけです。
使い方が簡単なのがこのライブラリの利点
UndoCanvasの実際に機能させてみた様子
上のコードを書いた結果・・・
次のような感じでしっかり機能しました。
▼ Undo・Redoしている様子(Gif動画)
実装自体はシンプルなのに、やりたいことはしっかり実現できてます。こういったライブラリは本当にありがたい。
グループ化してundo・redoもできる
このライブラリは応用的な機能もついてます。
それがグループ化したundo・redo
例えば画像編集ソフトだと「図形・オブジェクトに対する一連の操作」をグループ化していることが多いです。そうすればやり直しボタンを連打しなくてすむ
その機能がUndo-Canvasにも備わってます。
▼ 例えばコード例は以下の通り
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
for(var i = 0; i < 10; i++){ if(i % 2 === 0){ ctx.putTag(); } var x = Math.random()*330; var y = Math.random()*300; var radius = (Math.random()*(50-35))+35; ctx.beginPath(); ctx.arc(x, y, radius, 0, Math.PI*2, 1); ctx.fillStyle = "#" + ((1<<24)*Math.random() | 0).toString(16); ctx.fill(); } ctx.putTag(); $('#btnUndo').click(function(){ ctx.undoTag(); }); $('#btnRedo').click(function(){ ctx.redoTag(); }); |
この例でもランダムに円を描いてるんですが、2回に1回ごとに ctx.putTag() を呼び出してます。これを使うことで次にputTag()が呼ばれるまでの範囲をグループ化できるわけです。
あとはアンドゥするときは ctx.undoTag() 、リドゥするときは ctx.redoTag() のように呼び出しすればOK。
▼ 実際の動作はこのようになる
グループ化したundo・redoの方が使う場面は多そうです。
ちなみに汎用的なundo/redoの実装について
この記事と直接の関係はないものの・・・
JavaScriptでのUndo/Redoの実装アイデアについて
今紹介したライブラリ的なのがあれば楽ですが、開発アプリによっては全てゼロから実装しないといけない場面もあります。(というかそっちの場合の方が多い)
そこで上記事でJSにおけるUndo/Redoの実装アイデアをまとめました。もし独自のUndoシステムがどういう実装になるか知りたいならご覧ください。
以上、JSでのCanvasへのundo・redo機能実装でした。
ではまた バイバイ(@^^)/~~~