0
0

React(TypeScript)でcanvas要素を扱う

Posted at

背景

React(TypeScript)でcanvas要素を扱いたいと思ったところ、
Reactの場合だとどんなふうにコードを書けばいいか分からず、
色々と苦戦したので備忘録として残します。

ゴール

canvas上で図形をドラックして動かせるようなサンプルを作ります。
can.png

結論

このように書くと、canvas上で赤い四角形をドラックして動かせるサンプルができます。

import React, { useEffect, useRef, FC, useState } from "react";


export const Canvas:FC = () =>{

    const canvasRef = useRef<HTMLCanvasElement>(null);//canvas要素取得
    const [x,setX] = useState<number>(0);//X座砲
    const [y,setY] = useState<number>(0);//Y座標
    const [drug,SetDrug] = useState(false);//マウスドラック状態の管理



    useEffect(() => {
        if (!canvasRef.current) {
            throw new Error("canvas要素の取得に失敗しました");
        }
        const canvas = canvasRef.current;
        const ctx = canvas.getContext("2d");
        if (!ctx) {
            throw new Error("context取得失敗");
        }

        //描画前に既に描画済みのものを消してリセット
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

        //赤色の四角形を描画
        ctx.fillStyle = "red";
        ctx.fillRect(x, y, 10, 10);

    }, [x,y,drug]);



    const StartMove =()=>{
        SetDrug(true);
    }

    const EndMove = () => {
        SetDrug(false);
    };

    const Move = (e:any) => {
        //変数drugがtrueの場合座標を更新する
        if(drug){
            const canvas:any= canvasRef.current;
            const rect = canvas.getBoundingClientRect();//キャンバスの位置取得
            setX(e.clientX - rect.left);//マウスのX座標をセット
            setY(e.clientY - rect.top);//マウスのY座標をセット
        }
    };


    return(
        <>
            <div className="my-10" >
                <div className="border border-slate-700 p-3">
                    <h1 className="text-center text-3xl">キャンバス</h1>
                    <h2>座標</h2>
                    <p>x軸:{x}</p>
                    <p>y軸:{y}</p>
                    <canvas ref={canvasRef} 
                        width={400} 
                        height={450} 
                        onMouseDown={StartMove} 
                        onMouseUp={EndMove}
                        onMouseMove={Move}
                        className="border border-blue-700" 
                    />
                </div>
            </div>
        </>
    );
}

ポイント

まずキャンバスを取得するには"useRef"で取得するのがいいようです。
canvasタグにidをつけてdeiElementByIdで取得もできますが、
状態管理する上ではこのやり方がいいみたいです。

const canvasRef = useRef<HTMLCanvasElement>(null);//canvas要素取得

また、キャンバスに描画する際はuseEffect内で実行するのがいいようです。
今回のサンプルでは、座標(x,y)や描画可能か判定する変数drugが更新される度にuseEffectでanvasの描画を再実行することで四角形の描画位置を変更しています。

    useEffect(() => {
        if (!canvasRef.current) {
            throw new Error("canvas要素の取得に失敗しました");
        }
        const canvas = canvasRef.current;
        const ctx = canvas.getContext("2d");
        if (!ctx) {
            throw new Error("context取得失敗");
        }

        //描画前に既に描画済みのものを消してリセット
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

        //赤色の四角形を描画
        ctx.fillStyle = "red";
        ctx.fillRect(x, y, 10, 10);

    }, [x,y,drug]);
0
0
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
0
0