Canvas:实现在线画板操作

想象一下,用几行代码就能创造出如此逼真的图像和动画,仿佛将艺术与科技完美融合,前端开发的Canvas技术正是这个数字化时代中最具魔力的一环,它不仅仅是网页的一部分,更是一个无限创意的画布,一个让你的想象力自由驰骋的平台。

目录

基础页面搭建

绘画操作

按钮点击事件

最后总结


基础页面搭建

接下来借助canvas实现一个简易的画版操作,首先这里我们设置一下画布的一些基础布局样式:

<body><canvas id="canvas" width="800" height="600" style="border: 1px solid #ccc;"></canvas><hr><button id="boldBtn" type="button">粗线条</button><button id="thinBtn" type="button">细线条</button><button id="saveBtn" type="button">保持签名</button><input type="color" name="" id="color" value=""><button class="clearBtn">橡皮擦</button><button id="nullBtn">清空画布</button>
</body>

实现的效果如下所示,一个比较简陋的画布,以及一些基础操作的按钮:

绘画操作

接下来我们开始实现绘画操作的功能,通过监听鼠标不同情况的事件来实现画布上书写内容的操作,首先这里我们先绘制画布以及获取对应的dom元素进行操作:

<script>// 获取canvas画布绘制上下文对象以及获取2d画笔对象let canvas = document.getElementById("canvas");      let ctx = canvas.getContext("2d");ctx.lineJoin = 'round'; // 线条连接处为圆角ctx.lineCap = 'round'; // 线条端点为圆角// 获取DOM元素let boldBtn = document.getElementById("boldBtn");let thinBtn = document.getElementById("thinBtn");let saveBtn = document.getElementById("saveBtn");let color = document.getElementById("color");let clearBtn = document.getElementsByClassName("clearBtn")[0];let nullBtn = document.getElementById("nullBtn");
</script>

接下来开始开始监听鼠标的按下、弹起、移动以及离开画布的四种情况的操作,完整代码如下:

<script>// 获取canvas画布绘制上下文对象以及获取2d画笔对象let canvas = document.getElementById("canvas");      let ctx = canvas.getContext("2d");ctx.lineJoin = 'round'; // 线条连接处为圆角ctx.lineCap = 'round'; // 线条端点为圆角// 获取DOM元素let boldBtn = document.getElementById("boldBtn");let thinBtn = document.getElementById("thinBtn");let saveBtn = document.getElementById("saveBtn");let color = document.getElementById("color");let clearBtn = document.getElementsByClassName("clearBtn")[0];let nullBtn = document.getElementById("nullBtn");// 设置是否开始绘画的变量let isDraw = false;// 鼠标按下去函数canvas.onmousedown = function(e) {isDraw = true; // 开始绘画ctx.beginPath(); // 开始路径// 获取鼠标点击的坐标let x = e.pageX - canvas.offsetLeft; let y = e.pageY - canvas.offsetTop; ctx.moveTo(x, y); // 移动到当前点}// 鼠标移动函数canvas.onmousemove = function(e) {if (isDraw) { // 如果开始绘画let x = e.pageX - canvas.offsetLeft; let y = e.pageY - canvas.offsetTop; ctx.lineTo(x, y); // 绘制ctx.stroke()}}// 鼠标弹起函数canvas.onmouseup = function(e) {isDraw = false; // 结束绘画ctx.closePath(); // 结束路径}// 鼠标离开画布函数canvas.onmouseleave = function(e) {isDraw = false; // 结束绘画ctx.closePath(); // 结束路径}
</script>

最终呈现的效果如下所示:

按钮点击事件

接下来给画布下方的按钮设置对应的点击事件,让其能够实现对应的功能,如下:

粗线条:这里设置点击事件函数如下,遮盖策略设置在现有画布上下文之上绘制新图形,点击之后宽度增加到20,并添加对应激活类名active,删除其他按钮可能存在的active类名:

// 粗线条函数
boldBtn.onclick = function(e) {ctx.globalCompositeOperation = 'source-over'; ctx.lineWidth = 20boldBtn.classList.add("active");thinBtn.classList.remove("active");clearBtn.classList.remove("active");
}

细线条:这里设置点击事件函数如下,遮盖策略设置在现有画布上下文之上绘制新图形,点击之后宽度减少到2,并添加对应激活类名active,删除其他按钮可能存在的active类名:

// 细线条函数
thinBtn.onclick = function(e) {ctx.globalCompositeOperation = 'source-over'; ctx.lineWidth = 2thinBtn.classList.add("active");boldBtn.classList.remove("active");clearBtn.classList.remove("active");
}

保存签名:获取图片数据并创建一个a标签进行文件下载:

// 保存签名函数
saveBtn.onclick = function(e) {let urlData = canvas.toDataURL(); // 获取图片数据// let img = new Image()// img.src = urlData; // 图片地址// document.body.appendChild(img); // 添加图片到bodylet downloadA = document.createElement("a"); // 创建a标签downloadA.setAttribute("download", "签名"); // 设置下载文件名downloadA.href = urlData; // 设置a标签的地址downloadA.click(); // 点击a标签
}

修改颜色:设置监听函数,动态修改canvas颜色:

// 颜色选择函数
color.onchange = function(e) {ctx.strokeStyle = color.value; // 设置线条颜色
}

橡皮擦:这里设置点击事件函数如下,遮盖策略设置现有内容保持在新图形不重叠的地方,点击之后区域呈现空白,并添加对应激活类名active,删除其他按钮可能存在的active类名:

// 橡皮擦函数
clearBtn.onclick = function(e) {// 清除画布ctx.globalCompositeOperation = 'destination-out';ctx.lineWidth = 30clearBtn.classList.add("active");boldBtn.classList.remove("active");thinBtn.classList.remove("active");
}

清空画布:调用canvas函数直接清除整个画布的内容:

// 清空画布函数
nullBtn.onclick = function(e) {ctx.clearRect(0, 0, 800, 600);
}

最终呈现的效果如下所示:

最后总结

本次代码实现了一个简单的画板功能,让用户可以在网页上绘制、调整线条粗细、选择颜色、保存签名等操作。以下是代码的实现思路:

1)HTML结构部分

在<body>中包含一个 <canvas> 元素,用于绘制图形。

一组按钮和一个颜色选择器,用于控制画笔的粗细、颜色以及清除和保存绘制的功能。

2)CSS部分

定义了一个按钮的样式 .active,用于表示当前选中状态,例如粗线条、细线条、橡皮擦等按钮会根据点击状态变化背景颜色。

3)JavaScript部分

《1》获取元素:

使用 document.getElementById 和 document.getElementsByClassName 获取 <canvas> 和各种控制按钮。

《2》绘图相关事件:

canvas.onmousedown:鼠标按下时开始绘画,记录起始点。
canvas.onmousemove:鼠标移动时,如果正在绘画(isDraw为真),则根据当前鼠标位置绘制线条。
canvas.onmouseup 和 canvas.onmouseleave:鼠标抬起或离开画布时结束绘画路径。

《3》功能按钮事件:

粗线条 (boldBtn) 和 细线条 (thinBtn):设置线条宽度,并通过 classList 控制按钮的选中状态。
保存签名 (saveBtn):使用 canvas.toDataURL() 获取绘制内容的DataURL,创建一个下载链接,允许用户保存签名。
颜色选择 (color):通过 color.onchange 设置绘制线条的颜色。
橡皮擦 (clearBtn):使用 ctx.globalCompositeOperation = 'destination-out' 实现擦除效果,清除画布上的内容。
清空画布 (nullBtn):使用 ctx.clearRect() 清除整个画布的内容。

《4》绘图上下文:

使用 getContext('2d') 获取 Canvas 2D 渲染上下文对象 ctx,设置线条的样式(圆角连接和端点)。

这段代码整合了 HTML、CSS 和 JavaScript,提供了一个简单而功能丰富的在线绘图工具,用户可以通过点击不同的按钮和操作来绘制、擦除、保存签名等。完整代码如下:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>button.active {color: #fff;background-color: orange;}</style>
</head><body><canvas id="canvas" width="800" height="600" style="border: 1px solid #ccc;"></canvas><hr><button id="boldBtn" type="button">粗线条</button><button id="thinBtn" type="button">细线条</button><button id="saveBtn" type="button">保存签名</button><input type="color" name="" id="color" value=""><button class="clearBtn">橡皮擦</button><button id="nullBtn">清空画布</button>
<script>// 获取canvas画布绘制上下文对象以及获取2d画笔对象let canvas = document.getElementById("canvas");      let ctx = canvas.getContext("2d");ctx.lineJoin = 'round'; // 线条连接处为圆角ctx.lineCap = 'round'; // 线条端点为圆角// 获取DOM元素let boldBtn = document.getElementById("boldBtn");let thinBtn = document.getElementById("thinBtn");let saveBtn = document.getElementById("saveBtn");let color = document.getElementById("color");let clearBtn = document.getElementsByClassName("clearBtn")[0];let nullBtn = document.getElementById("nullBtn");// 设置是否开始绘画的变量let isDraw = false;// 鼠标按下去函数canvas.onmousedown = function(e) {isDraw = true; // 开始绘画ctx.beginPath(); // 开始路径// 获取鼠标点击的坐标let x = e.pageX - canvas.offsetLeft; let y = e.pageY - canvas.offsetTop; ctx.moveTo(x, y); // 移动到当前点}// 鼠标移动函数canvas.onmousemove = function(e) {if (isDraw) { // 如果开始绘画let x = e.pageX - canvas.offsetLeft; let y = e.pageY - canvas.offsetTop; ctx.lineTo(x, y); // 绘制ctx.stroke()}}// 鼠标弹起函数canvas.onmouseup = function(e) {isDraw = false; // 结束绘画ctx.closePath(); // 结束路径}// 鼠标离开画布函数canvas.onmouseleave = function(e) {isDraw = false; // 结束绘画ctx.closePath(); // 结束路径}// 粗线条函数boldBtn.onclick = function(e) {ctx.globalCompositeOperation = 'source-over'; ctx.lineWidth = 20boldBtn.classList.add("active");thinBtn.classList.remove("active");clearBtn.classList.remove("active");}// 细线条函数thinBtn.onclick = function(e) {ctx.globalCompositeOperation = 'source-over'; ctx.lineWidth = 2thinBtn.classList.add("active");boldBtn.classList.remove("active");clearBtn.classList.remove("active");}// 保存签名函数saveBtn.onclick = function(e) {let urlData = canvas.toDataURL(); // 获取图片数据// let img = new Image()// img.src = urlData; // 图片地址// document.body.appendChild(img); // 添加图片到bodylet downloadA = document.createElement("a"); // 创建a标签downloadA.setAttribute("download", "签名"); // 设置下载文件名downloadA.href = urlData; // 设置a标签的地址downloadA.click(); // 点击a标签}// 颜色选择函数color.onchange = function(e) {ctx.strokeStyle = color.value; // 设置线条颜色}// 橡皮擦函数clearBtn.onclick = function(e) {// 清除画布ctx.globalCompositeOperation = 'destination-out';ctx.lineWidth = 30clearBtn.classList.add("active");boldBtn.classList.remove("active");thinBtn.classList.remove("active");}// 清空画布函数nullBtn.onclick = function(e) {ctx.clearRect(0, 0, 800, 600);}
</script>
</body>
</html>

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

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

相关文章

python网络爬虫之Urllib

概述 urllib的request模块提供了最基本的构造HTTP请求的方法&#xff0c;使用它可以方便地实现请求的发送并得到响应&#xff0c;同时它还带有处理授权验证&#xff08;authentication&#xff09;、重定向&#xff08;redirection&#xff09;、浏览器Cookies以及其他内容。 …

DELTA: DEGRADATION-FREE FULLY TEST-TIME ADAPTATION--论文笔记

论文笔记 资料 1.代码地址 2.论文地址 https://arxiv.org/abs/2301.13018 3.数据集地址 https://github.com/bwbwzhao/DELTA 论文摘要的翻译 完全测试时间自适应旨在使预训练模型在实时推理过程中适应测试数据流&#xff0c;当测试数据分布与训练数据分布不同时&#x…

算法中的基础知识点,你知道多少呢!

递归 场景&#xff1a; ​ 1&#xff09;斐波那契数列 递推 场景&#xff1a; ​ 1&#xff09;斐波那契数列 ​ 2&#xff09;递归 回溯 栈 先进后出 场景&#xff1a; ​ 1&#xff09;path.resolve /a/b/…/c/d —> /a/c/d ​ 2&#xff09;JSX ​ 3&#xff09;加减乘…

VBA实现Excel的数据透视表

前言 本节会介绍通过VBA的PivotCaches.Create方法实现Excel创建新的数据透视表、修改原有的数据透视表的数据源以及刷新数据透视表内容。 本节测试内容以下表信息为例 1、创建数据透视表 语法&#xff1a;PivotCaches.Create(SourceType, [SourceData], [Version]) 说明&am…

打卡第8天-----字符串

进入字符串章节了,我真的特别希望把leetcode上的题快点全部都给刷完,我是社招准备跳槽才选择这个训练营的,面试总是挂算法题和编程题,希望通过这个训练营我的算法和编程的水平能有所提升,抓住机会,成功上岸。我现在的这份工作,真的是一天都不想干了,但是下家工作单位还…

Spring——配置说明

1. 别名 别名&#xff1a;如果添加了别名&#xff0c;也可以使用别名获取这个对象 <alias name"user" alias"user2"/> 2. Bean的配置 id&#xff1a;bean 的唯一标识符&#xff0c;也就是相当于我们学的对象名class&#xff1a;bean 对象所对应的…

无法解析主机:mirrorlist.centos.org Centos 7

从 2024 年 7 月 1 日起&#xff0c;在 CentOS 7 上&#xff0c;请切换到 Vault 存档存储库&#xff1a; vi /etc/yum.repos.d/CentOS-Base.repo 复制/粘贴以下内容并注意您的操作系统版本。如果需要&#xff0c;请更改。此配置中的版本为 7.9.2009&#xff1a; [base] name…

Mac虚拟机跑Windows流畅吗 Mac虚拟机连不上网络怎么解决 mac虚拟机网速慢怎么解决

随着技术的发展&#xff0c;很多用户希望能在Mac电脑上运行Windows系统&#xff0c;从而能够使用那些仅支持Windows系统的软件。使用虚拟机软件可以轻松满足这一需求。但是&#xff0c;很多人可能会有疑问&#xff1a;“Mac虚拟机跑Windows流畅吗&#xff1f;”&#xff0c;而且…

【AI前沿】深度学习基础:训练神经网络

文章目录 &#x1f4d1;前言一、前向传播与反向传播1.1 前向传播&#xff08;Forward Propagation&#xff09;1.2 反向传播&#xff08;Backpropagation&#xff09; 二、损失函数和优化算法2.1 损失函数&#xff08;Loss Function&#xff09;2.2 优化算法&#xff08;Optimi…

极狐Gitlab使用

目录 续接上篇&#xff1a;极狐Gitlab安装部署-CSDN博客 1. 关闭注册功能 2. 创建群组 3. 创建用户 5. 邀请成员到群组 6. 设置导入导出项目源 7. 通过gitee导入库 8. 通过仓库URL导入 9. 自创建项目 10. 默认分支main的权限 11. 使用普通用户进入自建库 12. 创建用…

python的isinstance和type

class A:passclass B(A)passbB()#isinstance可以进行继承关系的判断 print(isinstance(b,B))#Trueprint(isinstance(b,A))#Trueprint(type(b) is B)#Trueprint(type(b) is A)#Falseprint(type(b),A,B,b)#<class __main__.B> <class __main__.A> <class __main__…

B. Corner Twist(cf956)

题意&#xff1a;给你两个网格&#xff0c;a和b&#xff0c;都是n行和 m 列。网格中的所有数值都是 0 &#xff0c; 1 或 2 。 您可以多次对 a&#x1d44e; 执行以下操作&#xff1a; 选取网格中任意一个长宽的子矩形。您可以选择整个网格作为子矩形。子矩形有四个角。取所选…

【Linux 线程】线程的基本概念、LWP的理解

文章目录 一、ps -L 指令&#x1f34e;二、线程控制 一、ps -L 指令&#x1f34e; &#x1f427; 使用 ps -L 命令查看轻量级进程信息&#xff1b;&#x1f427; pthread_self() 用于获取用户态线程的 tid&#xff0c;而并非轻量级进程ID&#xff1b;&#x1f427; getpid() 用…

生成日志系统和监控

背景&#xff1a;已知某后台服务将日志存放在本地硬盘的日志文件中&#xff0c;该服务也支持代码热更新&#xff0c;并在完成热更新后输出一条日志。我们需要对服务日志进行监控&#xff0c;以确保文件热更新后的错误能被第一时间发现。 我们提供 Python 程序模拟&#xff08;…

matlab仿真 模拟调制(上)

&#xff08;内容源自详解MATLAB&#xff0f;SIMULINK 通信系统建模与仿真 刘学勇编著第五章内容&#xff0c;有兴趣的读者请阅读原书&#xff09; 1.幅度调制 clear all ts0.0025; %信号抽样时间间隔 t0:ts:10-ts;%时间矢量 fs1/ts;%抽样频率 dffs/length(t); %fft的频率分…

国内从事人机交互的团队——浙江工业大学

一、背景 当我们选择一个新的课题后&#xff0c;需要清楚的了解从事该方向的团队都有哪些&#xff0c;这样可以及时跟踪和学习大牛团队的最新进展&#xff0c;以免自己认为的good idea&#xff0c;其实早就已经研究过了。 随着人形机器人的发展&#xff0c;机器人不仅需要在无…

人类远未触及自然规律的本质

我想知道上帝是如何创造这个世界的&#xff0c;对于这样或那样的现象我不感兴趣&#xff0c;我想知道的是他的思想&#xff0c;其余的都是细枝末节。——爱因斯坦 人类对自然规律的研究已经取得了不少进展&#xff0c;但是看起来研究清楚了原理&#xff0c;其实只是发现了更深…

【Windows】实现窗口子类化(基于远程线程注入)

目录 前言 原理解释 完整项目 相关文献 文章出处链接&#xff1a;[https://blog.csdn.net/qq_59075481/article/details/140334106] 前言 众所周知&#xff0c;DLL 注入有多种用途&#xff0c;如热修补、日志记录、子类化等。本文重点介绍使用 DLL 注入对窗口进行子类化。…

mysql中count的区别

count(1)和count(*) 从执行计划来看&#xff0c;count(1)和count(*)的效果是一样的当表的数据量大些时&#xff0c;对表分析之后&#xff0c;使用count(1)还要比使用count(*)用时多当数据量在1W以内时&#xff0c;count(1)会比count(*)的用时少&#xff0c;不过也差不多如果cou…

GOLLIE : ANNOTATION GUIDELINES IMPROVE ZERO-SHOT INFORMATION-EXTRACTION

文章目录 题目摘要引言方法实验消融 题目 Gollie&#xff1a;注释指南改进零样本信息提取 论文地址&#xff1a;https://arxiv.org/abs/2310.03668 摘要 大型语言模型 (LLM) 与指令调优相结合&#xff0c;在泛化到未见过的任务时取得了重大进展。然而&#xff0c;它们在信息提…