LoginSignup
6
4

More than 5 years have passed since last update.

VueでKonva.jsとcanvasを使ってお絵描き(その4)

Last updated at Posted at 2019-05-01

その3はこちら

戻る および やり直しの処理を実装(undo, redo)

キャンバスの状態を1つ前の状態に戻したり(undo)、やり直したり(redo)してみます。
ここを参考にしました。

描画時:描画する前に、描画前のキャンバスの状態を配列に保存しておく
戻す時:戻す前のキャンバスの状態をやり直し配列に保存し、戻す配列からキャンバスイメージを取り出して反映
やり直す時:やり直し前のキャンバスの状態を戻す配列に保存し、やり直し配列からキャンバスイメージを取り出して反映

※配列への保存と取り出しはFIFO方式で。
※キャンバスの状態はcontext.getImageDataメソッドで取得できるので、それを利用する
※context.putImageDataで、取り出したキャンバスの状態を反映する

親側(CallCanvas.vue)
メソッドを用意して、子の戻す、やり直すメソッドを読んでいるだけです。

CallCanvas.vue
<template>
    <div>
        <div class="md-layout md-gutter" style="margin-left: 340px">
          <div class="md-layout-item">
            ...
            ..
            .

            <md-field style="float: left; margin-top: -8px">
              <md-button
                class="md-dense md-raised md-primary"
                @click="onUndo" <!-- この行を追加 -->
              >
                戻る
              </md-button>
            </md-field>

            <md-field style="float: left; margin-top: -8px">
              <md-button
                class="md-dense md-raised md-primary"
                @click="onRedo" <!-- この行を追加 -->
              >
                進む
              </md-button>
            </md-field>

            ...
            ..
            .
          </div>
        </div>
        ...
        ..
        .
    </div>
</template>

<script>
import FreeDrawing from './FreeDrawing.vue'

export default {
  ...
  ..
  .
  methods: {
    ...
    ..
    .
    // 元に戻す
    onUndo: function () {
      this.$refs.freeDrawing.undo()
    },
    // やり直す
    onRedo: function () {
      this.$refs.freeDrawing.redo()
    }
  },
  ...
  ..
  .
}
</script>
...
..
.

次は子です(FreeDrawing.vue)
undoメソッドとredoメソッドの新規追加に伴い、
dataプロパティに2つ追加 および mousedownメソッドとonClearCanvasメソッドに1行ずつ追加しています。

FreeDrawing.vue
...
..
.

<script>
import Konva from 'konva'

export default {
  ...
  ..
  .
  data: () => ({
    ...
    ..
    .
    /** 追加 */
    undoDataStack: [], // 元に戻す配列
    redoDataStack: [] // やり直し配列
  }),
  ...
  ..
  .
  methods: {
    mousedown: function () {
      ...
      ..
      .
      // 戻す配列に描画前のキャンバスの状態を保存
      this.undoDataStack.push(this.context.getImageData(0, 0, this.canvas.width, this.canvas.height))
    },
    ...
    ..
    .
    onClearCanvas: function () {
      // キャンバスをクリアする前の状態を戻す配列に保存しておく
      this.undoDataStack.push(this.context.getImageData(0, 0, this.canvas.width, this.canvas.height))

      ...
      ..
      .
    },
    ...
    ..
    .
    /** 元に戻す */
    undo: function () {
      // 戻す配列が空の場合は何もしない
      if (this.undoDataStack.length <= 0) {
        return
      }

      // 戻す前の状態をやり直し配列に保存
      this.redoDataStack.push(this.context.getImageData(0, 0, this.canvas.width, this.canvas.height))

      // 元に戻す(戻す配列からキャンバスの状態を取り出して反映)
      this.context.putImageData(this.undoDataStack.pop(), 0, 0)
      this.drawingLayer.draw()
    },
    /** やり直す */
    redo: function () {
      // やり直し配列が空の場合は何もしない
      if (this.redoDataStack.length <= 0) {
        return
      }

      // やり直す前の状態を戻す配列に保存
      this.undoDataStack.push(this.context.getImageData(0, 0, this.canvas.width, this.canvas.height))

      // やり直す(やり直し配列からキャンバスの状態を取り出して反映)
      this.context.putImageData(this.redoDataStack.pop(), 0, 0)
      this.drawingLayer.draw()
    }
  },
  ...
  ..
  .
}
</script>

いざ、戻してみます。
image.png

戻る1回目
image.png

戻る2回目
image.png

戻る3回目
※少しわかりづらいですが、「1」の下の棒?が消えてくれました
image.png

今度はやり直しを実行してみます(「進む」ボタンのこと)。
やり直し1回目
image.png

やり直し2回目
image.png

やり直し3回目
image.png

リセットして戻してみます。
リセット
image.png

戻る
image.png

無事、戻る処理とやり直す処理を実装できました。
モードの「直線」が未実装なので、次は直線を引いてみようと思います。
(多分最後。)

備考

リセットを連打すると、初期の令和だけ表示されてるキャンバス状態が配列にスタックされまくるので、
そこはよしなに処理を追加していただければと思います。

その5 直線を引けるようにしてみた

6
4
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
6
4