preface
It was interesting to see the drawing tool in the system before, so I used React and Canvas to implement a simple drawing tool without React. I mainly used React because I wrote it in the original project.
Here is the online address: Paint
The source code is in the project Library: source code
implementation
Brush function
<canvas
id="canvas"
onMouseDown={mouseEvent}
onMouseMove={mouseEvent}
onMouseUp={mouseEvent}
>
</canvas>
Copy the code
First, add mousedown, Mousemove and Mouseup to canvas.
Turn the isDraw switch on when the mouse is down and turn it off when the mouse is up to control the Mousemove, otherwise the Mousemove event will be triggered as soon as you enter the Canvas area.
The mouseEvent event is listened for for brevity, and different logic is fired within the event based on event.type.
Here’s a brush idea:
-
Click the mouse, isDraw switch open;
-
Drag the mouse to trigger the Mousemove event
-
I’m going to record the position of the mouse click, and I’m going to use a two-dimensional array here, and I’m going to record the X axis and the Y axis
-
Initialize the color and thickness of the brush and its shape
-
Start drawing a line, get the position of the mouse in the array, stroke between each point, so that the dots connect to form a line
-
Mouse up, turn isDraw off, disable mousemove trigger
That’s the general idea. Here’s the code:
const mouseEvent = (e) = > {
let ctx = canvas2D.getContext('2d')
e.persist()
if (e.type === 'mousedown') {
switch (active) {
case 'spray':
return canvas2D.style.backgroundColor = color
default:
isDraw = true
arr = []
return}}if (e.type === 'mousemove' && isDraw) {
arr.push([e.pageX - canvas2D.offsetLeft, e.pageY - document.querySelector('.admin-box').offsetTop - 40])
switch (active) {
case 'pen':
ctx.strokeStyle = color
ctx.lineJoin = "round";
ctx.lineWidth = 5;
ctx.beginPath();
arr.length > 1 && ctx.moveTo(arr[arr.length - 2] [0], arr[arr.length - 2] [1]);
ctx.lineTo(arr[arr.length - 1] [0], arr[arr.length - 1] [1]);
ctx.closePath();
ctx.stroke(); / / stroke
return
default:
return}}if (e.type === 'mouseup') {
setCanvasUrl(url= > {
url.push(canvas2D.toDataURL())
return url
})
isDraw = false}}Copy the code
The eraser
The eraser is a bit tricky here, overlaying the brush color with the background color so that it looks like erasure. The idea is the same as the brush, but change the color to the background color
case 'eraser':
ctx.strokeStyle = canvas2D.style.backgroundColor || '#ccc'
ctx.lineJoin = "round";
ctx.lineWidth = 50;
ctx.beginPath();
arr.length > 1 && ctx.moveTo(arr[arr.length - 2] [0], arr[arr.length - 2] [1]);
ctx.lineTo(arr[arr.length - 1] [0], arr[arr.length - 1] [1]);
ctx.closePath();
ctx.stroke(); / / stroke
return
Copy the code
The paint bucket
This is the easiest one, get the color in the color palette and replace the background color
Draw a rectangular
To draw a rectangle, two methods, clearRect and strokeRect, take four parameters: the starting coordinates X and Y, and the length and width of the rectangle.
Ideas:
Each time mousemove is triggered it will actually draw a rectangle, but we can clear the area before drawing a rectangle.
ClearRect is to clear the traces in the rectangle
So it looks like we’ve drawn a rectangle
case 'rectangle':
let left = arr[0] [0]
let top = arr[0] [1]
let prewidth = arr.length > 1 && arr[arr.length - 2] [0] - left
let preheight = arr.length > 1 && arr[arr.length - 2] [1] - top
let width = arr[arr.length - 1] [0] - left
let height = arr[arr.length - 1] [1] - top
ctx.beginPath();
ctx.lineWidth = "6";
ctx.strokeStyle = "red";
ctx.clearRect(left, top, prewidth, preheight)
ctx.strokeRect(left, top, width, height);
return
Copy the code
Undo the previous function
This will use the canvas drawImage and toDataURL methods.
Ideas:
-
After each operation, convert the Canvas to IMG via the toDataURL method and store it in the array
-
When you click Recall, the canvas image from the previous operation is loaded using the drawImage method.
-
Remove the last data in the array to facilitate the next recall operation.
-
Check if the array is empty. If it is empty, no more operations are allowed
The code is as follows:
const recallClick = (e) = > {
let ctx = canvas2D.getContext('2d')
let step = canvasUrl.length - 1
if (step >= 0) {
step--;
ctx.clearRect(0.0.1000.1000);
let canvasPic = new Image();
canvasPic.src = canvasUrl[step];
canvasPic.addEventListener('load', () => {
ctx.drawImage(canvasPic, 0.0);
});
setCanvasUrl(canvasUrl= > {
canvasUrl.pop()
return canvasUrl
})
} else {
console.log('I can't undo it anymore.'); }}Copy the code
Download function
Get the graph of the current canvas via the toDataURL. Create an A tag, assign the address to it, and perform a click event download. This implementation is a bit crude, but this is the general idea. You can also pop up the window according to the scene and modify the relevant information downloaded.
The code is as follows:
const downloadImg = (a)= > {
var url = canvas2D.toDataURL('image/png');
var a = document.createElement('a');
document.body.appendChild(a);
a.href = url;
a.download = 'My Drawing';
a.target = '_blank';
a.click();
}
Copy the code
Color picker
The react-color plugin is used here.
The end of the
Here, the idea of simple sketchpad is clear, and you can develop more functions on this basis.
fighting~