DEV Community

Cover image for How to create a drawing app with React
Posandu
Posandu

Posted on • Originally published at tronic247.com

How to create a drawing app with React

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
Enter fullscreen mode Exit fullscreen mode

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

cd drawing-app
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

First, we will create the canvas.

<canvas></canvas>
Enter fullscreen mode Exit fullscreen mode

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

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

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
Enter fullscreen mode Exit fullscreen mode

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
    });
};
Enter fullscreen mode Exit fullscreen mode

Now we add event listeners to our canvas.

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

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
Enter fullscreen mode Exit fullscreen mode

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!
};
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

Connect

Email - posandumapa@gmail.com
https://bio.link/posandu

Top comments (1)

Collapse
 
posandu profile image
Posandu • Edited

Thanks for reading! If this helped you, make sure to leave a β™₯ and a πŸ¦„!