I am creating an White-board application and I am tying to draw with my mouse using different color pen. I was trying to use ctx.strokeStyle to change the color of pen but for some reason it is not working. I try changing other properties of pen and they are also not changing like thickness
import React, { useEffect, useRef, useState } from "react";
const WhiteBoard = () => {
const canvasRef = useRef(null);
const [isDrawing, setIsDrawing] = useState(false);
const [context, setContext] = useState(null);
const [prevX, setPrevX] = useState(0);
const [prevY, setPrevY] = useState(0);
const divRef = useRef(null);
useEffect(() => {
const canvas = canvasRef.current;
const ctx = canvas.getContext("2d");
setContext(ctx);
ctx.strokeStyle = "red";
console.log(ctx.strokeStyle,'here I am ');
console.log("Stroke style set to:", );
ctx.lineWidth = 2;
const canvasdiv = divRef.current;
// const canvasheight=canvasdiv.offsetHeight;
// const canvaswidth=canvasdiv.offsetWidth;
//Will get the height and width including border and margin
//Excludes border and margin
const canvasheight = canvasdiv.clientHeight;
const canvaswidth = canvasdiv.clientWidth;
canvas.width = canvaswidth;
canvas.height = canvasheight;
}, []);
const startDrawing = (e) => {
setIsDrawing(true);
setPrevX(e.nativeEvent.offsetX);
setPrevY(e.nativeEvent.offsetY);
};
const draw = (e) => {
if (!isDrawing) return;
context.beginPath();
context.moveTo(prevX, prevY);
context.lineTo(e.nativeEvent.offsetX, e.nativeEvent.offsetY);
context.stroke();
setPrevX(e.nativeEvent.offsetX);
setPrevY(e.nativeEvent.offsetY);
};
const stopDrawing = () => {
setIsDrawing(false);
};
return (
<div ref={divRef} className="w-100">
<canvas
ref={canvasRef}
className="w-100"
onMouseDown={startDrawing}
onMouseMove={draw}
onMouseUp={stopDrawing}
onMouseOut={stopDrawing}
style={{ border: "1px solid black" }}
></canvas>
</div>
);
};
export default WhiteBoard;
The output of the console.log is #ff0000 so altest it has the value.
Setting the canvas height and width destroys the style you've previously set on the context. Try setting the width/height first, then applying the style:
const {useEffect, useRef, useState} = React;
const WhiteBoard = () => {
const canvasRef = useRef(null);
const [isDrawing, setIsDrawing] = useState(false);
const [context, setContext] = useState(null);
const [prevX, setPrevX] = useState(0);
const [prevY, setPrevY] = useState(0);
const divRef = useRef(null);
useEffect(() => {
const canvas = canvasRef.current;
const canvasdiv = divRef.current;
const canvasheight = canvasdiv.clientHeight;
const canvaswidth = canvasdiv.clientWidth;
canvas.width = canvaswidth;
canvas.height = canvasheight;
const ctx = canvas.getContext("2d");
ctx.strokeStyle = "red";
setContext(ctx);
}, []);
const startDrawing = (e) => {
setIsDrawing(true);
setPrevX(e.nativeEvent.offsetX);
setPrevY(e.nativeEvent.offsetY);
};
const draw = (e) => {
if (!isDrawing) return;
context.beginPath();
context.moveTo(prevX, prevY);
context.lineTo(e.nativeEvent.offsetX, e.nativeEvent.offsetY);
context.stroke();
setPrevX(e.nativeEvent.offsetX);
setPrevY(e.nativeEvent.offsetY);
};
const stopDrawing = () => {
setIsDrawing(false);
};
return (
<div ref={divRef} className="w-100">
<canvas
ref={canvasRef}
className="w-100"
onMouseDown={startDrawing}
onMouseMove={draw}
onMouseUp={stopDrawing}
onMouseOut={stopDrawing}
style={{ border: "1px solid black" }}
></canvas>
</div>
);
};
ReactDOM.createRoot(document.querySelector("#app"))
.render(<WhiteBoard />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>
Note that where you call setContext(ctx)
doesn't really matter, although it seems best style to do that at the end of the function to communicate that that's the state for the next render.
Here's a minimal example, which shows that the problem is unrelated to React:
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const draw = resize => {
ctx.reset();
ctx.strokeStyle = "red";
ctx.lineWidth = 4;
if (resize) {
// destroys styles set above
canvas.width = 300;
}
ctx.moveTo(0, 0);
ctx.lineTo(150, 100);
ctx.stroke();
};
canvas {
border: 1px solid black;
}
<div>
<button onclick="draw(true)">Draw with resize</button>
<button onclick="draw()">Draw without resize</button>
</div>
<canvas height="150" width="300"></canvas>