快来看看使用React构建的交互式绘图应用效果
前言
在如今数字化时代,Web
应用程序已成为了人们日常生活的一部分。绘图应用是其中一种常见的应用类型,他可以让用户在Web
浏览器中进行绘图和创作。本文将介绍如何使用React
构建一个简单的绘图应用,通过该应用,用户可以在画布上绘制图形、更改画笔尺寸和颜色,以及清空画布等功能。
背景
本文实现的绘图应用的构建是基于React
框架。众所周知,React
是一个用于构建用户界面的Javascript
库,它提供了组件化的开发方式,使得构建复杂的交互方式应用更加高效和可维护。在本项目中,将使用React
的状态管理和事件处理功能来实现绘图应用的核心功能。
开发
那话不多说,下面就一起来看看该项目的实现过程,请往下瞧→
首先,需要引入React
库,并在组件中引入所需的Hooks
和样式文件。如下:
import React, { useRef, useState } from 'react';
import './index.less';
至于样式文件,这里就把已经写好的代码贴出来算了,后续自行修改相关样式即可。如下:
* {
box-sizing: border-box;
}
canvas {
border: 2px solid #34516a;
}
.toolbox {
display: flex;
width: 904px;
padding: 10px;
background-color: #34516a;
border: 1px solid #34516a;
}
.toolbox > * {
display: flex;
align-items: center;
justify-content: center;
font-size: 28px;
height: 50px;
width: 50px;
margin: 4px;
padding: 4px;
cursor: pointer;
color: #333;
background-color: #fff;
border: none;
}
.toolbox > *:last-child {
margin-left: auto;
}
在函数组件DrawingApp
中,需要定义一些状态变量,用于存储画笔尺寸、颜色、鼠标状态和鼠标位置等信息。然后通过使用React的useState
Hooks,就可以在函数组件中定义和更新这些状态。代码如下:
const DrawingApp = () => {
const canvasRef = useRef(null);
const [size, setSize] = useState(10);
const [color, setColor] = useState('#ff0000');
const [isPressed, setIsPressed] = useState(false);
const [prevX, setPrevX] = useState(null);
const [prevY, setPrevY] = useState(null);
接下来,需要编写处理鼠标事件的函数。当鼠标按下时,记录鼠标的位置,并将isPressed
的状态设置为true
,表示鼠标当前处于按下状态。代码如下:
/**
* 鼠标按下
* @param e
*/
const handleMouseDown = (e) => {
setIsPressed(true);
const canvas = canvasRef.current;
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
setPrevX(x);
setPrevY(y);
};
当鼠标松开时,将isPressed
的状态设置为false
,表示鼠标当前处于未按下状态,并清空之前记录的鼠标位置。代码如下:
/**
* 鼠标松开
*/
const handleMouseUp = () => {
setIsPressed(false);
setPrevX(null);
setPrevY(null);
};
在鼠标移动时,需要判断鼠标是否处于按下状态。如果是,则获取当前鼠标的位置,并调用drawCircle
和drawLine
函数进行绘制操作。绘制圆形和绘制直线的具体代码如下:
/**
* 移动鼠标
* @param e
*/
const handleMouseMove = (e) => {
if (!isPressed) return;
const canvas = canvasRef.current;
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
drawCircle(x, y);
drawLine(prevX, prevY, x, y);
setPrevX(x);
setPrevY(y);
};
/**
* 画圆角
* @param x
* @param y
*/
const drawCircle = (x, y) => {
const canvas = canvasRef.current;
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.arc(x, y, size, 0, Math.PI * 2);
ctx.fillStyle = color;
ctx.fill();
};
/**
* 画线
* @param x1
* @param y1
* @param x2
* @param y2
*/
const drawLine = (x1, y1, x2, y2) => {
const canvas = canvasRef.current;
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.strokeStyle = color;
ctx.lineWidth = size * 2;
ctx.stroke();
};
为了使该应用的体验更好,还提供了一些额外的功能。通过调用increaseSize
和decreaseSize
函数,用户可以增加或减小画笔的尺寸。这里限制了尺寸的取值范围在5~50之间。同时,将尺寸大小实时地显示在界面上。代码如下:
/**
* 更新屏幕尺寸
*/
const updateSizeOnScreen = () => {
const sizeEl = document.getElementById('size');
if (sizeEl) {
sizeEl.innerText = size;
}
};
/**
* 减小画笔尺寸
*/
const increaseSize = () => {
let newSize = size + 5;
if (newSize > 30) {
newSize = 30;
}
setSize(newSize);
updateSizeOnScreen();
};
/**
* 增加画笔尺寸
*/
const decreaseSize = () => {
let newSize = size - 5;
if (newSize < 5) {
newSize = 5;
}
setSize(newSize);
updateSizeOnScreen();
};
此外,还提供了一个颜色选择器,可以让用户自由地选择画笔颜色。通过调用handleColorChange
函数,可以更新当前选择的颜色。代码如下:
/**
* 更改颜色
* @param e
*/
const handleColorChange = (e) => {
setColor(e.target.value);
};
最后,还提供了一个清空画布的功能,通过调用clearCanvas
函数可以清除整个画布的内容。代码如下:
/**
* 清除画布
*/
const clearCanvas = () => {
const canvas = canvasRef.current;
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
};
到这里,该应用的核心代码就介绍完了。下面就是福利时刻,完整的代码如下:
import React, { useRef, useState } from 'react';
import './index.less';
const DrawingApp = () => {
const canvasRef = useRef(null);
const [size, setSize] = useState(10);
const [color, setColor] = useState('#ff0000');
const [isPressed, setIsPressed] = useState(false);
const [prevX, setPrevX] = useState(null);
const [prevY, setPrevY] = useState(null);
/**
* 鼠标按下
* @param e
*/
const handleMouseDown = (e) => {
setIsPressed(true);
const canvas = canvasRef.current;
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
setPrevX(x);
setPrevY(y);
};
/**
* 鼠标松开
*/
const handleMouseUp = () => {
setIsPressed(false);
setPrevX(null);
setPrevY(null);
};
/**
* 移动鼠标
* @param e
*/
const handleMouseMove = (e) => {
if (!isPressed) return;
const canvas = canvasRef.current;
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
drawCircle(x, y);
drawLine(prevX, prevY, x, y);
setPrevX(x);
setPrevY(y);
};
/**
* 画圆角
* @param x
* @param y
*/
const drawCircle = (x, y) => {
const canvas = canvasRef.current;
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.arc(x, y, size, 0, Math.PI * 2);
ctx.fillStyle = color;
ctx.fill();
};
/**
* 画线
* @param x1
* @param y1
* @param x2
* @param y2
*/
const drawLine = (x1, y1, x2, y2) => {
const canvas = canvasRef.current;
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.strokeStyle = color;
ctx.lineWidth = size * 2;
ctx.stroke();
};
/**
* 更新屏幕尺寸
*/
const updateSizeOnScreen = () => {
const sizeEl = document.getElementById('size');
if (sizeEl) {
sizeEl.innerText = size;
}
};
/**
* 减小画笔尺寸
*/
const increaseSize = () => {
let newSize = size + 5;
if (newSize > 30) {
newSize = 30;
}
setSize(newSize);
updateSizeOnScreen();
};
/**
* 增加画笔尺寸
*/
const decreaseSize = () => {
let newSize = size - 5;
if (newSize < 5) {
newSize = 5;
}
setSize(newSize);
updateSizeOnScreen();
};
/**
* 更改颜色
* @param e
*/
const handleColorChange = (e) => {
setColor(e.target.value);
};
/**
* 清除画布
*/
const clearCanvas = () => {
const canvas = canvasRef.current;
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
};
return (
<div>
<div className="toolbox">
<button onClick={decreaseSize}>-</button>
<span id="size">{size}</span>
<button onClick={increaseSize}>+</button>
<input type="color" id="color" onChange={handleColorChange} value={color} />
<button onClick={clearCanvas}>X</button>
</div>
<canvas
ref={canvasRef}
width="900"
height="600"
onMouseDown={handleMouseDown}
onMouseUp={handleMouseUp}
onMouseMove={handleMouseMove}
></canvas>
</div>
);
}
export default DrawingApp;
将上述代码复制到React
项目中并运行,你可以得到如下效果:
总结一下,本文介绍了如何使用React
构建绘图应用,并详细解释了应用中的核心代码。使用了useRef
来引用canvas
元素,useState
来管理状态变量,包括画笔尺寸、颜色、鼠标状态和位置等。通过鼠标事件处理函数,实现了绘制圆形和直线的功能,并在鼠标移动时不断更新画布。此外,还提供了调整画笔尺寸、选择画笔颜色和清空画布等额外功能,以提升用户体验。
通过本文的介绍,你可以根据提供的代码和思路,进一步扩展和定制绘图应用,以满足实际开发中的更多需求。
后语
小伙伴们,如果觉得本文对你有些许帮助,点个👍或者➕个关注再走吧^_^ 。另外如果本文章有问题或有不理解的部分,欢迎大家在评论区评论指出,我们一起讨论共勉。
转载自:https://juejin.cn/post/7242203662415216698