フリーランス 技術調査ブログ

フリーランス/エンジニア Ruby Python Nodejs Vuejs React Dockerなどの調査技術調査の備忘録

React/Canvasとreact-colorを利用して書いた絵を保存する

はじめに

  • 前回、Canvasに絵を書くコンポーネントを作成したので、その延長でカラーパレットで線の色を変えてお絵描きできるコンポーネントを作成する
  • お絵描きした絵はJpegでダウンロードできるようにする

インストール

npm install react-color --save

casesandberg.github.io

サンプルコード

import React,{useState,useEffect} from 'react'
import { SketchPicker } from 'react-color';

const Canvas = () =>{
  const [color,setColor] = useState('black')
  let canvas, 
      ctx, 
      drawFlag = false,
      prevX = 0,
      currX = 0,
      prevY = 0,
      currY = 0,
      dotFlag = false;

  // 線の描画イベント
  const draw = () => {
    if (dotFlag) {
      ctx.beginPath();
      ctx.fillStyle = color;
      ctx.fillRect(currX, currY, 2, 2);
      ctx.closePath();
      dotFlag = false;
    }else{    
      ctx.beginPath();
      // 新しいサブパスの開始点を座標指定する
      ctx.moveTo(prevX, prevY);
      //直前の座標と指定座標を結ぶ直線を引く
      ctx.lineTo(currX, currY);
      //  線・輪郭の色やスタイルを指定する
      ctx.strokeStyle = color;
      // 線の幅を指定する
      ctx.lineWidth = 2;
      // 現在の線スタイルでサブパスを輪郭表示する
      ctx.stroke();
      ctx.closePath();
    }
  }

  // マウスイベントの座標を取得及びイベント毎による処理を振り分ける
  const getCoordinate = (event) => {
    console.log(canvas.offsetLeft);
    console.log(canvas.offsetTop);
    console.log(event.clientX);
    console.log(event.clientY);
    if ((event.type == 'mousedown') || (event.type == 'mousemove')) {
      
      prevX = currX;
      prevY = currY;
      currX = event.clientX - canvas.offsetLeft - 20;
      currY = event.clientY - canvas.offsetTop -60;

    }

    if (event.type == 'mousedown') {
      drawFlag = true;
      dotFlag = true;
      if (dotFlag) {
        draw();
      }
    }

    if (event.type == 'mouseup' || event.type == "mouseout") {
      drawFlag = false;
    }

    if ((event.type == 'mousemove') && (drawFlag)) {
      draw();
    }
  }

  useEffect(() => {
    canvas = document.getElementById('canvas');
    ctx = canvas.getContext("2d");
    // 線を引くイベント(mouse move)
    canvas.addEventListener("mousemove", event => getCoordinate(event));
    // 線を引くイベント(mouse down)
    canvas.addEventListener("mousedown", event => getCoordinate(event));
    // 線を引かないイベント(mouse up)
    canvas.addEventListener("mouseup", event => getCoordinate(event));
    // 線を引かないイベント(mouse out)
    canvas.addEventListener("mouseout", event => getCoordinate(event));
  })

  const style = {
    minWidth: 64,
    lineHeight: "32px",
    borderRadius: 4,
    border: "2px solid #000000",
    padding: "0 16px",
    color: "#fff",
    background: "#ffffff"
  };

  const clear = () => {
    if (confirm("クリアしても宜しいでしょうか")) {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        document.getElementById("canvasimg").style.display = "none";
    }
  }

  const save = () => {
    document.getElementById("canvasimg").style.border = "2px solid";
    let dataURL = canvas.toDataURL();
    document.getElementById("canvasimg").src = dataURL;
    document.getElementById("canvasimg").style.display = "inline";
    var a = document.createElement('a');
    //canvasをJPEG変換し、そのBase64文字列をhrefへセット
    a.href = dataURL;
    //canvas.toDataURL('image/jpeg', 0.85);
    //ダウンロード時のファイル名を指定
    a.download = 'download.jpg';
    //クリックイベントを発生させる
    a.click();    
  }

  const handleChange = (selectColor) => {
    setColor(selectColor.hex);
  };
  
  return(
    <>
      <table>
        <tr>
          <td>
            <canvas id="canvas" width="400" height="400"  style={style}></canvas>
          </td>
          <td>
            <SketchPicker
              color={ color }
              onChangeComplete={ handleChange }
            />
          </td>
          <td>
            <img id="canvasimg" />
          </td>
        </tr>
        <tr>
          <td colspan="3" valign="top">
            <input type="button" value="保存" onClick={save}/>
            <input type="button" value="クリア"   onClick={clear}/>

          </td>
        </tr>
      </table>
    </>
  )
}

export default Canvas

画面イメージ

f:id:PX-WING:20200718010714p:plain