使用canvas做了一个最简单的网页版画板,5分钟学会

news2025/1/10 17:03:27

画板实现的效果:可以切换画笔的粗细,颜色,还可以使用橡皮擦,还可以清除画布,然后将画的内容保存下载成一张图片:

具体用到的canvas功能有:画笔的粗细调整lineWidth,开始一个新的画笔路径beginPath,结束一个画笔路径closePath,这个可以保证不影响之前画的效果,重新开始一个画笔路径。 还有橡皮擦使用的ctx.globalCompositeOperation = 'destination-out'属性,清空画布使用的:ctx.clearRect(0, 0, canvas.width, canvas.height),保存图片使用的是let url = canvas.toDataURL('image/png')。

完整的代码如下:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>像素操作</title>
        <style>
            .active {
                background-color: #f2a1a1;
            }
        </style>
    </head>
    <body>
        <div>创建一个画布,可以使用画笔随意画画</div>
        <div style="width: 800px; margin-top: 6px">
            <button class="bold">粗线条</button>
            <button class="thin">细线条</button>
            <input id="color" type="color" />
            <button class="del">橡皮擦</button>
            <button class="clear">清空画布</button>
            <button class="save">保存图片</button>
            <hr />
            <canvas id="myCanvas" width="800" height="600"></canvas>
        </div>
        <script>
            // 获取画布
            const canvas = document.getElementById('myCanvas')
            // 获取画笔
            const ctx = canvas.getContext('2d')
            // 让画笔的拐弯处更加圆润,没有锯齿感
            ctx.lineCap = 'round'
            ctx.lineJoin = 'round'
            // 获取控制按钮
            const bold = document.querySelector('.bold')
            const thin = document.querySelector('.thin')
            const color = document.querySelector('#color')
            const del = document.querySelector('.del')
            const clear = document.querySelector('.clear')
            const save = document.querySelector('.save')
            // 添加点击事件
            bold.onclick = function () {
                ctx.lineWidth = 20
                bold.classList.add('active')
                thin.classList.remove('active')
                del.classList.remove('active')
                clear.classList.remove('active')
                save.classList.remove('active')
            }
            thin.onclick = function () {
                ctx.lineWidth = 5
                thin.classList.add('active')
                bold.classList.remove('active')
                del.classList.remove('active')
                clear.classList.remove('active')
                save.classList.remove('active')
            }
            color.onchange = function (e) {
                console.log('颜色改变了:', e.target.value)
                ctx.strokeStyle = e.target.value
            }
            del.onclick = function () {
                console.log('橡皮擦')
                ctx.globalCompositeOperation = 'destination-out'
                ctx.lineWidth = 30
                del.classList.add('active')
                bold.classList.remove('active')
                thin.classList.remove('active')
                clear.classList.remove('active')
                save.classList.remove('active')
            }

            clear.onclick = function () {
                console.log('清空画布')
                ctx.clearRect(0, 0, canvas.width, canvas.height)
            }
            // 保存图片
            save.onclick = function () {
                console.log('保存图片')
                let url = canvas.toDataURL('image/png')
                let a = document.createElement('a')
                a.href = url
                a.download = 'canvas.png'
                a.click()
            }

            // 监听画布画画事件
            let mouseDown = false

            // 鼠标按下将变量设置为true
            canvas.onmousedown = function (e) {
                ctx.beginPath()
                mouseDown = true
                ctx.moveTo(e.offsetX, e.offsetY)
            }

            // 鼠标抬起将变量设置为false
            canvas.onmouseup = function () {
                mouseDown = false
                ctx.closePath()
                ctx.globalCompositeOperation = 'source-over'
            }

            canvas.onmouseleave = function () {
                mouseDown = false
                ctx.closePath()
            }

            // 鼠标移动
            canvas.onmousemove = function (e) {
                if (mouseDown) {
                    console.log('鼠标移动')
                    ctx.lineTo(e.offsetX, e.offsetY)
                    ctx.stroke()
                }
            }
        </script>
    </body>
</html>

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

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

相关文章

postman接收后端返回的文件流并自动下载

不要点send&#xff0c;点send and download&#xff0c;postman接受完文件流会弹出文件保存框让你选择保存路径

Unity Spine 指定导入新Spine动画的默认材质

指定导入新Spine动画的默认材质 找到Spine的Editor导入配置如何修改方法一: 你可以通过脚本 去修改Assets/Editor/SpineSettings.asset文件方法二&#xff1a;通过面板手动设置 找到Spine的Editor导入配置 通常在 Assets/Editor/SpineSettings.asset 配置文件对应着 Edit/Prefe…

从“特种兵游”到Citywalk,年轻人的下一个旅游热点会在哪?

2023年&#xff0c;国内游在逐步放开&#xff0c;境外旅游目的地名单也逐步“扩容”&#xff0c;生活的轨迹在回正&#xff0c;越来越多人重启旅行&#xff0c;感受生活。于此同时&#xff0c;在短短几个月内&#xff0c;寺庙游、citywalk、淄博烧烤、特种兵旅行各种与旅游相关…

docker部署前后端分离springboot+vue项目

前置知识 虚拟网桥 docker容器需要在同一个网段才能通信&#xff0c;当启动一个容器时会自动连接一个docker中默认网桥段但此默认网桥段非本容器固定&#xff0c;当下次容器启动分配的ip会变&#xff0c;并且不可用名称直接访问。 自定义网段将需要互通的容器放入&#xff0c…

Python容器和可迭代对象

在刚开始学Python的时候&#xff0c;是不是经常会听到大佬们在讲容器、可迭代对象、迭代器、生成器、列表/集合/字典推导式等等众多概念&#xff0c;其实这不是大佬们没事就搁那扯专业术语来装B&#xff0c;而是这些东西都得要明白的&#xff0c;光知道字符串、列表等基础还是不…

业务出海、高效传输、动态加速,尽在云栖大会「CDN与边缘计算」专场

2023杭州云栖大会&#xff0c;即将热力来袭。 一场云计算盛会&#xff0c;500前沿话题&#xff0c;3000科技展品&#xff0c;与阿里云一起&#xff0c;共赴72小时的Tech沉浸之旅。 今日&#xff0c;「CDN与边缘计算」Tech专场&#xff0c;重磅议题抢先知晓&#xff01; 01 「…

【ccc3.8】虚拟列表

一个简单的虚拟列表&#xff0c;没有任何其他东西。 原理就是向上滚动时&#xff0c;将下面离开屏幕的那一个item塞到上侧来&#xff1a; 主代码仅有两个&#xff1a;ScrollList对应的滚动容器&#xff0c;ScrollListItem对应单项的预制体 当前支持两种&#xff1a;竖向滚动、…

C# out参数out多个参数

文章目录 C# out参数out多个参数背景说明作用方法定义调用方法测试结果注意 C# out参数out多个参数 背景说明 一个方法返回多个相同数据类型的变量&#xff0c;可以采用数据的方式&#xff1b; 我需要返回多个不同数据类型的方法&#xff0c;在这里采用out多个参数的方式。 …

js中循环判断找到满足条件的单项后结束循环

当选择的所有项中&#xff0c;如果有一项不满足条件则返回false&#xff0c;让业务逻辑停止&#xff0c;一般都是使用forEach循环&#xff0c;但是forEach循环有个弊端就是return不能跳出循环&#xff0c;所以这时候就需要使用for循环中的break来跳出循环。 下面是代码示例&am…

【Maven】VSCode Java+Maven 环境配置

0x00 前言 没写过 Java&#xff0c;得配个带 Maven 的编码环境&#xff0c;不太明白&#xff0c;试试看顺便记录一下 0x01 配置过程 安装 jdk1.8 后&#xff0c;找到安装位置&#xff1a; (base) dianCD-Ali doraemon % /usr/libexec/java_home -V Matching Java Virtual Ma…

数据结构:选择题+编程题(每日一练)

目录 选择题&#xff1a; 题一&#xff1a; 题二&#xff1a; 题三&#xff1a; 题四&#xff1a; 题五&#xff1a; 编程题&#xff1a; 题一&#xff1a;单值二叉树 思路一&#xff1a; 题二&#xff1a;二叉树的最大深度 思路一&#xff1a; 本人实力有限可能对…

缺少win32spl.dll文件? 教你快速修复win32spl.dll

缺少win32spl.dll文件&#xff1f;不要怕&#xff0c;其实这个问题还是比较好解决的&#xff0c;我们今天会给大家介绍多种的解决方法&#xff0c;让你花式去解决缺少win32spl.dll的问题&#xff0c;好了&#xff0c;废话不多少&#xff0c;我们一起进入正题吧。 一.介绍win32s…

在docker环境下从头搭建openvslam/orb_slam3的流程记录以及问题总结

文章目录 0. 前言1. MobaXterm软件2. docker操作2.1. 拉一个ubuntu镜像2.2. 修改名字&#xff08;可选&#xff09;2.3. 删除之前的docker镜像&#xff08;可选&#xff09; 3. openvslam搭建流程3.1. 起容器3.2. 前置包的安装3.3. 安装Eigen3.4. 安装opencv3.5. 安装DBoW23.6.…

uCOSIII实时操作系统 十一 消息传递

目录 消息队列&#xff1a; 消息列队相关的API函数 创建消息队列&#xff1a; 等待消息列队&#xff1a; 向消息列队发送消息&#xff1a; 消息队列实验 任务内嵌消息队列&#xff1a; 任务内建消息队列的API函数 等待任务内建消息&#xff1a; 发送任务内建消息&…

Python-pptx教程之一从零开始生成PPT文件

简介 python-pptx是一个用于创建、读取和更新PowerPoint&#xff08;.pptx&#xff09;文件的python库。 典型的用途是根据动态内容&#xff08;如数据库查询、分析数据等&#xff09;&#xff0c;将这些内容自动化生成PowerPoint演示文稿&#xff0c;将数据可视化&#xff0c…

ES6初步了解生成器

生成器函数是ES6提供的一种异步编程解决方案&#xff0c;语法行为与传统函数完全不同 语法&#xff1a; function * fun(){ } function * gen(){console.log("hello generator");}let iterator gen()console.log(iterator)打印&#xff1a; 我们发现没有打印”hello…

计算机组成原理(一目了然的顶级总纲)(持续更新!)

文章目录 886冯诺依曼计算机计算机的五大部件&#xff08;又称五大字系统&#xff09;细化的计算机组成框图存储器 886 计算机系统由“硬件”和“软件”两大部分组成。 计算机的软件通常又可以分为两大类&#xff1a;系统软件和应用软件。 冯诺依曼计算机 数学家冯诺依曼&am…

MySQL数据库增删改查

删除表 drop table 表名&#xff1b; drop table if exists 表名&#xff1b;修改表 修改表名 alter table 表名 rename to 新表名&#xff1b;添加列 alter table 表名 add 列名 数据类型&#xff1b;删除列 alter table 表名 drop 列名&#xff1b;修改数据类型 alter …

WorkPlus专注私有化部署,为企业安全打造超级沟通协作APP

在如今全球化竞争和高速发展的商业环境中&#xff0c;企业内部的沟通和协作至关重要。面对众多的通讯和协作平台&#xff0c;WorkPlus独辟蹊径&#xff0c;专注私有化部署&#xff0c;致力于为企业打造安全专属、自主可控的超级沟通协作APP。正是这一专注与创新&#xff0c;让W…

发表《Nature》!哈佛大学团队成功研发自纠错量子计算机

&#xff08;图片来源&#xff1a;网络&#xff09; 量子计算机能达到当今最快的超级计算机也无法达到的速度和效率。然而&#xff0c;该技术尚未大规模推广和商业化&#xff0c;很大程度上是因为它无法自我纠错。与经典计算机不同&#xff0c;量子计算机无法通过一遍又一遍地…