How to create a drawing app with React

How to create a drawing app with React

Posandu Mapa
ยทMar 3, 2022ยท

Subscribe to my newsletter and never miss my upcoming articles

Table of contents

  • Creating the react app
  • Starting the app

Today, we will be making this drawing app with React.

So let's get started!

Creating the react app

First, we need to create a new react app, so I will run this in the terminal.

npx create-react-app drawing-app

Now this will create a new folder called drawing-app. Now we change our directory.

cd drawing-app

If we run the ls command you should see this.

image.png

We're ready to go ๐ŸŽŠ

Starting the app

Now we have our app ready, we will start the app.

npm run start

Now open localhost:3000 in your browser. You should see something like this.

image.png

Now we open our editor and remove all the code in App.js and put this code.

// Import dependencies
import { useEffect, useRef, useState } from "react";

// Our code
export default function App() {
  return (
    <div>

    </div>
  );
}

First, we will create the canvas.

<canvas></canvas>

Then, we will use the useRef hook to select the canvas element.

const canvasRef = useRef(null);
.....
<canvas
   ref={canvasRef}
></canvas>

Now we have our canvas, now we will add the functionality to draw it. To do this we will create 2 functions one for setting the mouse position and one for drawing. Before we do that, we need to set our states.

const [mouseData, setMouseData] = useState({ x: 0, y: 0 });
const [canvasCTX, setCanvasCTX] = useState(null);

// Set the canvas ctx as the state
useEffect(() => {
    const canvas = canvasRef.current; // Select the canvas element
    const ctx = canvas.getContext("2d"); // The canvas context
    canvas.width = window.innerWidth; // Set width of the canvas to the width of the screen
    canvas.height = window.innerHeight;// Set height of the canvas to the height of the screen
    setCanvasCTX(ctx); // Finally, set the state
}, [canvasRef]); // Do this everytime the canvas element is changed

The function to save the position

const SetPos = (e) => {
    // The e variable is the event
    setMouseData({
        x: e.clientX, // Mouse X position
        y: e.clientY, // Mouse Y position
    });
};

Now we add event listeners to our canvas.

<canvas
   ref={canvasRef}
   onMouseEnter={(e) => SetPos(e)}
   onMouseMove={(e) => SetPos(e)}
   onMouseDown={(e) => SetPos(e)}
</canvas>

Now every time we move the mouse, the state gets updated.

Function to draw

Now before we create the Draw function, we need to save 2 states.

  1. Color of the pen
  2. Size of the pen

We can use the hook useState again.

const [color, setColor] = useState("#000000"); // Default color is black
const [size, setSize] = useState(10); // Default size is 10

Now we have our states. Let's create the function now.

const Draw = (e) => {
    if (e.buttons !== 1) return; // The left mouse button should be pressed
    const ctx = canvasCTX; // Our saved context
    ctx.beginPath(); // Start the line
    ctx.moveTo(mouseData.x, mouseData.y); // Move the line to the saved mouse location
    setMouseData({
        x: e.clientX, // Update the mouse location
        y: e.clientY, // ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    });
    ctx.lineTo(e.clientX, e.clientY); // Again draw a line to the mouse postion
    ctx.strokeStyle = color; // Set the color as the saved state
    ctx.lineWidth = size; // Set the size to the saved state
    // Set the line cap to round
    ctx.lineCap = "round";
    ctx.stroke(); // Draw it!
};

Now we add our event listener to the canvas.

<canvas
   ref={canvasRef}
   onMouseEnter={(e) => SetPos(e)}
   onMouseMove={(e) => {SetPos(e);Draw(e)}}
   onMouseDown={(e) => SetPos(e)}
></canvas>

Now save the file and open localhost:3000. Now you can draw some stuff. But wait, we need to add the controls.

<div
  className="controlpanel"
  style={{
    position: "absolute",
    top: "0",
    left: "0",
    width: "100%",
  }}
>
  <input
    type="range"
    value={size}
    max={40}
    onChange={(e) => {
      setSize(e.target.value);
    }}
  />
  <input
    type="color"
    value={color}
    onChange={(e) => {
      setColor(e.target.value);
    }}
  />
  <button
    onClick={() => {
      const ctx = canvasCTX;
      ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
    }}
  >
    Clear
  </button>
</div>

Now we have made our drawing app! ๐Ÿ˜ŽThat's all for now. See you next time. ๐Ÿ˜‰

image.png

And if you need to copy-paste the full code here it is.

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

function App() {
    const [mouseData, setMouseData] = useState({ x: 0, y: 0 });
    const canvasRef = useRef(null);
    const [canvasCTX, setCanvasCTX] = useState(null);
    const [color, setColor] = useState("#000000");
    const [size, setSize] = useState(10);

    useEffect(() => {
        const canvas = canvasRef.current;
        const ctx = canvas.getContext("2d");
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        setCanvasCTX(ctx);
    }, [canvasRef]);

    const SetPos = (e) => {
        setMouseData({
            x: e.clientX,
            y: e.clientY,
        });
    };

    const Draw = (e) => {
        if (e.buttons !== 1) return;
        const ctx = canvasCTX;
        ctx.beginPath();
        ctx.moveTo(mouseData.x, mouseData.y);
        setMouseData({
            x: e.clientX,
            y: e.clientY,
        });
        ctx.lineTo(e.clientX, e.clientY);
        ctx.strokeStyle = color;
        ctx.lineWidth = size;
        // Set the line cap to round
        ctx.lineCap = "round";
        ctx.stroke();
    };

    return (
        <div>
            <canvas
                ref={canvasRef}
                onMouseEnter={(e) => SetPos(e)}
                onMouseMove={(e) => SetPos(e)}
                onMouseDown={(e) => SetPos(e)}
                onMouseMove={(e) => Draw(e)}
            ></canvas>

            <div
                className="controlpanel"
                style={{
                    position: "absolute",
                    top: "0",
                    left: "0",
                    width: "100%",
                }}
            >
                <input
                    type="range"
                    value={size}
                    max={40}
                    onChange={(e) => {
                        setSize(e.target.value);
                    }}
                />
                <input
                    type="color"
                    value={color}
                    onChange={(e) => {
                        setColor(e.target.value);
                    }}
                />
                <button
                    onClick={() => {
                        const ctx = canvasCTX;
                        ctx.clearRect(
                            0,
                            0,
                            canvasRef.current.width,
                            canvasRef.current.height
                        );
                    }}
                >
                    Clear
                </button>
            </div>
        </div>
    );
}

export default App;

Connect

Email - https://bio.link/posandu

ย 
Share this