使用 React 和 Konva 实现一个在线画板组件

文章目录

  • 一、前言
  • 二、Konva.js 介绍
  • 三、创建 React 画板项目
    • 3.1 安装依赖
    • 3.2 创建 `CanvasBoard` 组件
  • 四、增加画布控制功能
    • 4.1 清空画布
    • 4.2 撤销 & 重做功能
  • 五、增加颜色和画笔大小选择
    • 5.1 选择颜色
    • 5.2 选择画笔大小
  • 六、最终效果
  • 七、总结

一、前言

在线画板是许多应用(如白板协作工具、手写笔记、绘图软件)中的重要组件。我们可以使用 React + Konva.js 结合 react-konva 来实现一个功能丰富的画板。

本教程将带你实现一个支持 自由绘制、清空画布、撤销/重做 的 React 画板组件。


二、Konva.js 介绍

Konva.js 是一个基于 Canvas API 的 2D 图形库,支持高性能的绘图操作,如路径、形状、文本、图片等。它具有以下优点:

  • 更高性能:相比 DOM 操作,Canvas 渲染更加流畅;
  • 提供丰富的图形 API(直线、多边形、贝塞尔曲线等);
  • 支持事件监听,如 clickdragtouch 等。

react-konva 是 Konva.js 的 React 封装库,使其可以在 React 中更方便地使用。


三、创建 React 画板项目

3.1 安装依赖

在 React 项目中,安装 react-konvakonva

{bash}
npm install react-konva konva
{bash}


3.2 创建 CanvasBoard 组件

新建 CanvasBoard.js,并使用 react-konva 组件创建一个可绘制的 Canvas。

// CanvasBoard.js
import React, { useRef, useState } from "react";
import { Stage, Layer, Line } from "react-konva";const CanvasBoard = () => {const [lines, setLines] = useState([]);const [isDrawing, setIsDrawing] = useState(false);const stageRef = useRef(null);// 开始绘制const handleMouseDown = (event) => {setIsDrawing(true);const { x, y } = event.target.getStage().getPointerPosition();setLines([...lines, { points: [x, y] }]);};// 画线const handleMouseMove = (event) => {if (!isDrawing) return;const { x, y } = event.target.getStage().getPointerPosition();const newLines = [...lines];newLines[newLines.length - 1].points.push(x, y);setLines(newLines);};// 结束绘制const handleMouseUp = () => {setIsDrawing(false);};return (<div><Stagewidth={800}height={500}ref={stageRef}onMouseDown={handleMouseDown}onMousemove={handleMouseMove}onMouseup={handleMouseUp}style={{ border: "1px solid #ccc", background: "#fff" }}><Layer>{lines.map((line, index) => (<Line key={index} points={line.points} stroke="black" strokeWidth={3} tension={0.5} lineCap="round" />))}</Layer></Stage></div>);
};export default CanvasBoard;

四、增加画布控制功能

4.1 清空画布

我们可以添加一个“清空”按钮,点击后清除所有线条。

const handleClearCanvas = () => {setLines([]);
};
{javascript}并在 `CanvasBoard` 组件中添加按钮:{javascript}
<button onClick={handleClearCanvas}>清空画布</button>

4.2 撤销 & 重做功能

为了实现 撤销/重做,我们需要一个状态栈来存储历史操作。

修改 CanvasBoard.js

const [history, setHistory] = useState([]);
const [redoStack, setRedoStack] = useState([]);const handleUndo = () => {if (lines.length > 0) {setRedoStack([...redoStack, lines[lines.length - 1]]);setLines(lines.slice(0, -1));}
};const handleRedo = () => {if (redoStack.length > 0) {setLines([...lines, redoStack[redoStack.length - 1]]);setRedoStack(redoStack.slice(0, -1));}
};

并在 CanvasBoard 组件中添加按钮:

<button onClick={handleUndo}>撤销</button>
<button onClick={handleRedo}>重做</button>

五、增加颜色和画笔大小选择

我们可以添加选择颜色和画笔大小的功能,使画板更丰富。

5.1 选择颜色

CanvasBoard.js 中添加颜色选择器:

const [color, setColor] = useState("black");<input type="color" value={color} onChange={(e) => setColor(e.target.value)} />

并修改 Line 组件,让它支持动态颜色:

<Line key={index} points={line.points} stroke={line.color || "black"} strokeWidth={3} />
{javascript}当鼠标按下时,将颜色存入 `lines`{javascript}
setLines([...lines, { points: [x, y], color }]);

5.2 选择画笔大小

CanvasBoard.js 添加画笔大小选择器:

const [strokeWidth, setStrokeWidth] = useState(3);<input type="range" min="1" max="10" value={strokeWidth} onChange={(e) => setStrokeWidth(e.target.value)} />
{javascript}修改 `Line` 组件,让它支持动态画笔大小:{javascript}
<Line key={index} points={line.points} stroke={line.color || "black"} strokeWidth={line.strokeWidth || 3} />

当鼠标按下时,将 strokeWidth 存入 lines

setLines([...lines, { points: [x, y], color, strokeWidth }]);

六、最终效果

最终,我们的在线画板具备以下功能:
✅ 支持自由绘制
✅ 支持清空画布
✅ 支持撤销/重做
✅ 支持颜色选择
✅ 支持画笔大小调整

你可以将 CanvasBoard 组件导入 App.js 进行测试:

// App.js
import React from "react";
import CanvasBoard from "./CanvasBoard";function App() {return (<div className="App"><h1>React 画板</h1><CanvasBoard /></div>);
}export default App;

七、总结

本篇文章介绍了如何使用 React + Konva 实现一个 在线画板组件,并添加了 撤销/重做、颜色选择、画笔大小调整 等功能。Konva 提供了高效的 Canvas API,使得 React 处理复杂的绘图操作变得更加轻松。

你可以在此基础上继续扩展,比如:

  • 添加橡皮擦功能
  • 支持图像导入与导出
  • 多人协作(结合 WebSocket)

到这里,这篇文章就和大家说再见啦!我的主页里还藏着很多 篇 前端 实战干货,感兴趣的话可以点击头像看看,说不定能找到你需要的解决方案~
创作这篇内容花了很多的功夫。如果它帮你解决了问题,或者带来了启发,欢迎:
点个赞❤️ 让更多人看到优质内容
关注「前端极客探险家」🚀 每周解锁新技巧
收藏文章⭐️ 方便随时查阅
📢 特别提醒:
转载请注明原文链接,商业合作请私信联系
感谢你的阅读!我们下篇文章再见~ 💕

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/900542.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

服务器配置虚拟IP

服务器配置虚拟IP的核心步骤取决于具体场景&#xff0c;主要包括本地单机多IP配置和高可用集群下的虚拟IP管理两种模式。‌ 一、本地虚拟IP配置&#xff08;单服务器多IP&#xff09; ‌基于Linux系统‌&#xff1a; ‌确认网络接口‌&#xff1a;使用 ip addr 或 ifconfig 查…

C++ —— 文件操作(流式操作)

C —— 文件操作&#xff08;流式操作&#xff09; ofstream文件创建文件写入 ofstream 文件打开模式std::ios::out 写入模式std::ios::app 追加模式std::ios::trunc 截断std::ios::binary 二进制std::ios::ate at the end模式 ifstreamstd::ios::in 读取模式&#xff08;默认&…

【Cursor】打开Vscode设置

在这里打开设置界面 打开设置json

智能指针和STL库学习思维导图和练习

思维导图&#xff1a; #include <iostream> #include <vector> #include <string> using namespace std;// 用户结构体 struct User {string username;string password; };vector<User> users; // 存储所有注册用户// 使用迭代器查找用户名是否存在 ve…

前端工具方法整理

文章目录 1.在数组中找到匹配项&#xff0c;然后创建新对象2.对象转JSON字符串3.JSON字符串转JSON对象4.有个响应式对象&#xff0c;然后想清空所有属性5.判断参数不为空6.格式化字符串7.解析数组内容用逗号拼接8.刷新整个页面 1.在数组中找到匹配项&#xff0c;然后创建新对象…

状态空间建模与极点配置 —— 理论、案例与交互式 GUI 实现

目录 状态空间建模与极点配置 —— 理论、案例与交互式 GUI 实现一、引言二、状态空间建模的基本理论2.1 状态空间模型的优势2.2 状态空间模型的物理意义三、极点配置的理论与方法3.1 闭环系统的状态反馈3.2 极点配置条件与方法3.3 设计流程四、状态空间建模与极点配置的优缺点…

仿modou库one thread one loop式并发服务器

源码&#xff1a;田某super/moduo 目录 SERVER模块&#xff1a; Buffer模块&#xff1a; Socket模块&#xff1a; Channel模块&#xff1a; Connection模块&#xff1a; Acceptor模块&#xff1a; TimerQueue模块&#xff1a; Poller模块&#xff1a; EventLoop模块&a…

Oracle中的UNION原理

Oracle中的UNION操作用于合并多个SELECT语句的结果集&#xff0c;并自动去除重复行。其核心原理可分为以下几个步骤&#xff1a; 1. 执行各个子查询 每个SELECT语句独立执行&#xff0c;生成各自的结果集。 如果子查询包含过滤条件&#xff08;如WHERE&#xff09;、排序&…

面试算法高频04-分治与回溯

分治与回溯 分治和回溯算法&#xff0c;包括其概念、特性、代码模板&#xff0c;并结合具体题目进行讲解&#xff0c;旨在帮助学员理解和掌握这两种算法的应用。 分治与回溯的概念 分治&#xff08;Divide & Conquer&#xff09;&#xff1a;本质上基于递归&#xff0c;先…

线性方程组的解法

文章目录 线性方程组的解法认识一些基本的矩阵函数MATLAB 实现机电工程学院教学函数构造1.高斯消元法2.列主元消去法3. L U LU LU分解法 线性方程组的解法 看到以下线性方程组的一般形式&#xff1a;设有以下的 n n n阶线性方程组&#xff1a; A x b \mathbf{Ax}\mathbf{b} A…

Java的Selenium的特殊元素操作与定位之模态框

Modal Dialogue Box&#xff0c;又叫做模式对话框&#xff0c;是指在用户想要对对话框以外的应用程序进行操作时&#xff0c;必须首先对该对话框进行响应。如单击【确定】或【取消】按钮等将该对话框关闭。 alert&#xff08;警告&#xff09; //访问本地的HTML文件 chromeDr…

2022年全国职业院校技能大赛 高职组 “大数据技术与应用” 赛项赛卷(1卷)任务书

2022年全国职业院校技能大赛 高职组 “大数据技术与应用” 赛项赛卷&#xff08;1卷&#xff09;任务书 背景描述&#xff1a;模块A&#xff1a;大数据平台搭建&#xff08;容器环境&#xff09;&#xff08;15分&#xff09;任务一&#xff1a;Hadoop 完全分布式安装配置任务二…

题目练习之set的奇妙使用

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…

Java虚拟机——JVM(Java Virtual Machine)解析一

1.JVM是什么&#xff1f; 1.1 JVM概念 Java Virtual Machine (JVM) 是JDK的核心组件之一&#xff0c;它使得 Java 程序能够在任何支持 JVM 的设备或操作系统上运行&#xff0c;而无需修改源代码 JDK是什么&#xff0c;JDK和JVM是什么关系&#xff1f;1.Java IDE(Integrated …

初识 Three.js:开启你的 Web 3D 世界 ✨

3D 技术已经不再是游戏引擎的专属&#xff0c;随着浏览器技术的发展&#xff0c;我们完全可以在网页上实现令人惊艳的 3D 效果。而 Three.js&#xff0c;作为 WebGL 的封装库&#xff0c;让 Web 3D 的大门向更多开发者敞开了。 这是我开启这个 Three.js 专栏的第一篇文章&…

OpenGL ES -> SurfaceView + EGL实现立方体纹理贴图+透视效果

XML文件 <?xml version"1.0" encoding"utf-8"?> <com.example.myapplication.MySurfaceView xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"…

pikachu靶场搭建教程,csfr实操

靶场安装 靶场下载地址 百度网盘下载地址和密码 百度网盘 请输入提取码 0278 github靶场下载地址 https://gitcode.com/Resource-Bundle-Collection/c7cc1 安装前提 这两个文件夹的配置文件都要进行更改修改数据库密码 D:\phpstudy_pro\WWW\pikachu\inc D:\phpstudy_pro…

浙江大学DeepSeek系列专题线上公开课第二季第四期即将上线!端云协同:让AI更懂你的小心思! - 张圣宇 研究员

今晚8点10分左右&#xff0c;端云协同&#xff1a;让AI更懂你的小心思&#xff01;浙大学者张圣宇研究员将揭秘人机交互新玩法。浙江大学DeepSeek系列专题线上公开课第二季第四期即将上线&#xff01; 讲座 主题&#xff1a; 大小模型端云协同赋能人机交互 主讲人&#xff1a…

Vue3实战三、Axios封装结合mock数据、Vite跨域及环境变量配置

目录 Axios封装、调用mock接口、Vite跨域及环境变量配置封装Axios对象调用mock接口数据第一步、安装axios&#xff0c;处理一部请求第二步、创建request.ts文件第三步、本地模拟mock数据接口第四步、测试axiosmock接口是否可以调用第五步、自行扩展 axios 返回的数据类型 axios…

Linux如何删除文件名包含无效编码字符文件

在Linux中&#xff0c;文件名包含无效编码字符或特殊不可见字符时&#xff0c;可能导致此文件无法通过常规方式选中或删除&#xff0c;可以通过下面方法处理 1、确认文件名问题 检查终端编码环境 echo $LANG # 默认应为 UTF-8&#xff08;如 en_US.UTF-8&#xff09; 查看…