Canvasに「戻る」や「進む」の機能を搭載してみた

2017年12月5日

はじめに

前々からCanvasにペイントツールのような「戻る」や「進む」の機能が欲しいなと思っていました。

という訳で作ってみました!

 

 

作ってみる

 

■HTML

<canvas id="canvassample" width="500" height="300"></canvas>
<div>
 <button type="button" onclick="prevCanvas()">戻る</button>
 <button type="button" onclick="nextCanvas()">進む</button>
</div>

 

■CSS

canvas {
  position: relative;
  border:3px solid #000;
}

div#img-box{
  border:3px solid #000;
  width:500px;
}

div#btn-box{
  position: fixed;
  bottom :0px;
}

 

■JavaScript

var canvas = document.getElementById('canvassample'),
    ctx = canvas.getContext('2d'),
    moveflg = 0,
    Xpoint,
    Ypoint,
    temp = [];
 
//初期値(サイズ、色、アルファ値)の決定
var defSize = 7,
    defColor = "#555";
 

// ストレージの初期化
var myStorage = localStorage;
window.onload = initLocalStorage();
 
 
// PC対応
canvas.addEventListener('mousedown', startPoint, false);
canvas.addEventListener('mousemove', movePoint, false);
canvas.addEventListener('mouseup', endPoint, false);
// スマホ対応
canvas.addEventListener('touchstart', startPoint, false);
canvas.addEventListener('touchmove', movePoint, false);
canvas.addEventListener('touchend', endPoint, false);
 
function startPoint(e){
  e.preventDefault();
  ctx.beginPath();
  console.log(e.clientX);
 
   
  // 矢印の先っぽから始まるように調整
  Xpoint = e.clientX-8;
  Ypoint = e.clientY-8;
   
  ctx.moveTo(Xpoint, Ypoint);
}
 
function movePoint(e){
  if(e.buttons === 1 || e.witch === 1 || e.type == 'touchmove')
  {
    Xpoint = e.pageX-8;
   Ypoint = e.pageY-8;
    moveflg = 1;
     
    ctx.lineTo(Xpoint, Ypoint);
    ctx.lineCap = "round";
    ctx.lineWidth = defSize * 2;
    ctx.strokeStyle = defColor;
    ctx.stroke();
     
  }
}
 
function endPoint(e)
{
    if(moveflg === 0)
    {
       ctx.lineTo(Xpoint-1, Ypoint-1);
       ctx.lineCap = "round";
       ctx.lineWidth = defSize * 2;
       ctx.strokeStyle = defColor;
       ctx.stroke();
        
    }
    moveflg = 0;
    
    setLocalStoreage();
}

function resetCanvas() {
    ctx.clearRect(0, 0, ctx.canvas.clientWidth, ctx.canvas.clientHeight);
}



function initLocalStorage(){
    myStorage.setItem("__log", JSON.stringify([]));
}
function setLocalStoreage(){
    var png = canvas.toDataURL();
    var logs = JSON.parse(myStorage.getItem("__log"));

    setTimeout(function(){
        logs.unshift({png:png});

        myStorage.setItem("__log", JSON.stringify(logs));

        temp = [];

    }, 0);
}

function prevCanvas(){
    var logs = JSON.parse(myStorage.getItem("__log"));

    if(logs.length > 0)
    {
        temp.unshift(logs.shift());

        setTimeout(function(){
            myStorage.setItem("__log", JSON.stringify(logs));
            resetCanvas();

            draw(logs[0]['png']);

        }, 0);
    }
}

function nextCanvas(){
    var logs = JSON.parse(myStorage.getItem("__log"));

    if(temp.length > 0)
    {
        logs.unshift(temp.shift());

        setTimeout(function(){
            myStorage.setItem("__log", JSON.stringify(logs));
            resetCanvas();

            draw(logs[0]['png']);

        }, 0);
    }
}

function draw(src) {
    var img = new Image();
    img.src = src;

    img.onload = function() {
        ctx.drawImage(img, 0, 0);
    }
}

 

 

■デモ

See the Pen Canvas to go back and forward by カバの樹 (@kabanoki) on CodePen.0

 

解説

動作の流れをざっくり説明すると、以下になります。

  1. Canvasに文字を書く
  2. Canvasを画像化する
  3. 画像を配列に格納してローカルストレージに保存
  4. ローカルストレージの配列から画像を取得
  5. Canvasに反映する

 

Canvasに文字を書く

過去のこの記事を参考

参考Canvasを使って手書きの署名機能を実装する

ルート営業を行うクライアントから、タブレットの契約書に手書きで署名できる機能が欲しいと言われました。
アプリで作ろうか悩みましたが、試しにHTML5で実装したものを提案してみました。

続きを見る

 

Canvasを画像化する

過去のこの記事を参考

参考Canvasで書いたものを画像に変換する

Canvasで署名したものを画像に変換します。そして、書いたものを消せるように消しゴム機能も実装しました。

続きを見る

 

画像を配列に格納してローカルストレージに保存

まず下記設定でローカルストレージを呼び出しつつ、初期化します。


// ストレージの呼び出し
var myStorage = localStorage;

// ストレージの初期化
window.onload = initLocalStorage();

function initLocalStorage(){
  myStorage.setItem("__log", JSON.stringify([]));
}

 

次に、画像を配列に格納して、ローカルストレージに保存します。


function setLocalStoreage() {
   // 履歴データ保存用の変数
   // これは履歴を戻った時に、戻る前の画像データを一時確保しておく為のもの
  var temp = []
   // 画像化する
  var png = canvas.toDataURL();
  // ローカルストレージから配列を取得
  var logs = JSON.parse(myStorage.getItem("__log"));

  setTimeout(function(){
    // 配列に画像を格納
    logs.unshift({png});
    // ローカルストレージに配列を保存
    myStorage.setItem("__log", JSON.stringify(logs));

    // 履歴を初期化
    temp = [];

  }, 0);
}

 

 

ローカルストレージの配列から画像を取得

ローカルストレージに保存されている配列を利用して、Canvasを戻したり進めたりする機能を実装する。

// Canvasを戻す
function prevCanvas(){
  var logs = JSON.parse(myStorage.getItem("__log"));

  if(logs.length > 0)
  {
    temp.unshift(logs.shift());

    setTimeout(function(){
       myStorage.setItem("__log", JSON.stringify(logs));
      //Canvasを初期化する
      resetCanvas(); 
      //画像を描写する
      draw(logs[0]['png']);

    }, 0);
  }
}

// Canvasを進める
function nextCanvas(){
  var logs = JSON.parse(myStorage.getItem("__log"));

  if(temp.length > 0)
  {
    logs.unshift(temp.shift());

    setTimeout(function(){
      myStorage.setItem("__log", JSON.stringify(logs));
      //Canvasを初期化する
      resetCanvas();
      //画像を描写する
      draw(logs[0]['png']);

    }, 0);
  }
}

 

 

Canvasに反映

Canvasに画像を描写します。


function draw(src) {
  var img = new Image();
  img.src = src;
  img.onload = function() {
    ctx.drawImage(img, 0, 0);
  }
}

 

いかがでしょうか?

今日はこの辺でー

 

  • この記事を書いた人

カバノキ

印刷会社のWEB部隊に所属してます。 WEB制作に携わってから、もう時期10年になります。 普段の業務では、PHPをメインにサーバーサイドの言語を扱っています。 最近のお気に入りはJavascriptです。 Vue.jsを狂喜乱舞しながら、社内に布教中です。

-JavaScript
-, , , , ,