canvas跟随鼠标画有透明度的矩形边框

提示:canvas跟随鼠标画有透明度的矩形边框

文章目录

  • 前言
  • 一、跟随鼠标画有透明度的矩形边框
  • 总结


前言

一、跟随鼠标画有透明度的矩形边框

test.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>canvas跟随鼠标移动画透明线</title><style>div,canvas,img{user-select: none;}.my_canvas,.bg_img{position: absolute;top: 50%;left: 50%;transform: translate(-50%,-50%);}.cf{content: '';display: block;overflow: hidden;clear: both;}.fl{float: left;}.fr{float: right;}.bg_img{width: 674px;height: 495px;background: #ddd;}.img_tools{position: absolute;top: 20px;left: 50%;transform: translateX(-50%);border: 1px solid #eee;border-radius: 64px;height: 64px;line-height: 64px;box-sizing: border-box;padding: 15px 20px 0;}.img_tool{height: 32px;line-height: 32px;color: #000;font-size: 14px;text-align: center;width: 80px;border: 1px solid #ddd;border-radius: 32px;margin-right: 10px;cursor: pointer;}.img_tool_active{color: #409EFF;border: 1px solid #409EFF;}</style>
</head>
<body><div class="bg_img"></div><canvas id="myCanvasBot" class="my_canvas" width="674" height="495"></canvas><canvas id="myCanvasTop" class="my_canvas" width="674" height="495"></canvas><div class="img_tools cf"><div class="img_tool img_tool_active fl" onclick="changeType('curve',this)">涂鸦</div><div class="img_tool fl" onclick="changeType('line',this)">直线</div><div class="img_tool fl" onclick="changeType('rect',this)">矩形</div><div class="img_tool fl" onclick="changeType('eraser',this)">橡皮擦</div></div><script>const canvasWidth = 674;const canvasHeight = 495;//底层canvasconst botCan = document.getElementById('myCanvasBot');//顶层canvasconst topCan = document.getElementById('myCanvasTop');//底层画布const botCtx = botCan.getContext('2d');//顶层画布const topCtx = topCan.getContext('2d');topCtx.lineCap = 'round';topCtx.lineJoin = 'round';//鼠标是否按下  是否移动let isDown = false,isMove = false;//鼠标是否在canvas上抬起let isCanUp = false;//需要画图的轨迹let drawPoints = [];//起始点x,ylet startPoint = {x:0,y:0};//图片历史let imgHistory = [];//icon历史// let partHistory = [];//操作类型let drawType = 'curve';//画线宽度const lineWidth = 10;//鼠标按下const mousedown = (e)=>{isDown = true;let x = (e||window.event).offsetX;let y = (e||window.event).offsetY;startPoint = {x,y};drawPoints.push([{x,y}]);topCtx.strokeStyle = 'rgba(255,0,0,0.2)';topCtx.lineWidth = lineWidth;topCtx.beginPath();topCtx.moveTo(x,y);}//鼠标移动const mousemove = (e)=>{let x = (e||window.event).offsetX;let y = (e||window.event).offsetY;if(isDown){isMove = true;switch(drawType){case 'curve':drawCurve(x,y);break;case 'line':drawLine(x,y);break;case 'eraser':drawEraser(x,y);break;case 'rect':drawRect(x,y);break;}}}//鼠标抬起const mouseup = (e)=>{isCanUp = true;if(isDown){// topCan内容画到botCan上topToBot();}}//topCan内容画到botCan上const topToBot = ()=>{//把topCan画布生成图片let img = new Image();img.src = topCan.toDataURL('image/png');img.onload = ()=>{// partHistory.push(img);//添加到botCtx画布botCtx.drawImage(img,0,0);let historyImg = new Image();historyImg = botCan.toDataURL('image/png');historyImg.onload = ()=>{//添加到历史记录imgHistory.push(historyImg);}//清除topCtx画布topCtx.clearRect(0,0,canvasWidth,canvasHeight);//botCan画完之后,重置canvas的mouseup isCanUpif(isCanUp)isCanUp=false;}drawPoints = [];isDown = false;isMove = false;}//画矩形const drawRect = (x,y)=>{//清除topCtx画布topCtx.clearRect(0,0,canvasWidth,canvasHeight);topCtx.beginPath();// 矩形topCtx.rect(startPoint.x, startPoint.y, x-startPoint.x, y - startPoint.y);topCtx.stroke();}//橡皮擦const drawEraser = (x,y)=>{//橡皮擦圆形半径const radius = lineWidth/2;botCtx.beginPath(); for(let i=0;i<radius*2;i++){//勾股定理高hlet h = Math.abs( radius - i); //i>radius h = i-radius; i<radius  h = radius - i//勾股定理llet l = Math.sqrt(radius*radius -h*h); //矩形高度let rectHeight = 1;//矩形宽度let rectWidth = 2*l;//矩形Xlet rectX = x-l;//矩形Ylet rectY = y-radius + i;botCtx.clearRect(rectX, rectY, rectWidth, rectHeight);}}//画透明度直线const drawLine = (x,y)=>{if(!isDown)return;//清空当前画布内容topCtx.clearRect(0,0,canvasWidth,canvasHeight);//必须每次都beginPath  不然会卡topCtx.beginPath();topCtx.moveTo(startPoint.x,startPoint.y);topCtx.lineTo(x,y);topCtx.stroke();}//画带透明度涂鸦const drawCurve = (x,y)=>{drawPoints.push({x,y});//清空当前画布内容topCtx.clearRect(0,0,canvasWidth,canvasHeight);//必须每次都beginPath  不然会卡topCtx.beginPath();topCtx.moveTo(drawPoints[0].x,drawPoints[0].y);for(let i=1;i<drawPoints.length;i++){topCtx.lineTo(drawPoints[i].x,drawPoints[i].y);}topCtx.stroke();}//切换操作const changeType = (type,that)=>{if(drawType == type) return;let tools = document.getElementsByClassName('img_tool');for(let i=0;i<tools.length;i++){let ele = tools[i];if(ele.classList.contains('img_tool_active'))ele.classList.remove('img_tool_active'); //ele.removeClassName('img_tool_active');}that.classList.add('img_tool_active');drawType = type;}//canvas添加鼠标事件topCan.addEventListener('mousedown',mousedown);topCan.addEventListener('mousemove',mousemove);topCan.addEventListener('mouseup',mouseup);//全局添加鼠标抬起事件document.addEventListener('mouseup',(e)=>{let x = (e||window.event).offsetX;let y = (e||window.event).offsetY;if(!isCanUp){if(drawType == 'line'){let clientX = topCan.getBoundingClientRect().x;let clientY = topCan.getBoundingClientRect().y;drawLine(x-clientX,y-clientY);}// topCan内容画到botCan上topToBot();}});//全局添加鼠标移动事件document.addEventListener('mousemove',(e)=>{if(isMove)return isMove = false;let x = (e||window.event).offsetX;let y = (e||window.event).offsetY;if(drawType == 'line'){let clientX = topCan.getBoundingClientRect().x;let clientY = topCan.getBoundingClientRect().y;drawLine(x-clientX,y-clientY);}});</script>
</body>
</html>

在这里插入图片描述

总结

踩坑路漫漫长@~@

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

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

相关文章

【笔记】OpenHarmony设备开发:搭建开发环境(Ubuntu 20.04,VirtualBox 7.0.14)

参考&#xff1a;搭建开发环境&#xff08;HarmonyOS Device&#xff09; Note&#xff1a;Windows系统虚拟机中Ubuntu系统安装完成后&#xff0c;根据指导完成Ubuntu20.04基础环境配置&#xff08;HarmonyOS Connect 开发工具系列课&#xff09; 系统要求 Windows系统要求&…

Python包管理工具 pip 及其常用命令和参数用法

目录 PIP 主要功能 安装包 升级包 卸载包 列出包 检查依赖 pip的配置和环境 主要用法 1&#xff1a;版本 2&#xff1a;安装 Python 库 3&#xff1a;升级库 4&#xff1a;卸载库 5&#xff1a;搜索库 6&#xff1a;查看已安装库详细信息 7&#xff1a;只下载库…

MT6762_联发科MTK6762安卓核心板规格参数

MTK6762核心板是一款集成了蓝牙、fm、wlan和gps模块的高度集成基带平台&#xff0c;为LTE/LTE-A和C2K智能手机应用程序提供支持。该安卓核心板集成了ARM Cortex-A53处理器&#xff0c;工作频率可达2.0GHz&#xff0c;并且还集成了功能强大的多标准视频编解码器。除此之外&#…

OriginBot智能机器人开源套件

详情可参见&#xff1a;OriginBot智能机器人开源套件——支持ROS2/TogetherROS&#xff0c;算力强劲&#xff0c;配套古月居定制课程 (guyuehome.com) OriginBot智能机器人开源套件 最新消息&#xff1a;OriginBot V2.1.0版本正式发布&#xff0c;新增车牌识别&#xff0c;点击…

【Java程序设计】【C00376】基于(JavaWeb)Springboot的社区帮扶对象管理系统(有论文)

【C00376】基于&#xff08;JavaWeb&#xff09;Springboot的社区帮扶对象管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;已经做了六年的毕业设计程序开发&am…

jupyter notebook导出含中文的pdf(LaTex安装和Pandoc、MiKTex安装)

用jupyter notebook导出pdf时&#xff0c;因为报错信息&#xff0c;需要用到Tex nbconvert failed: xelatex not found on PATH, if you have not installed xelatex you may need to do so. Find further instructions at https://nbconvert.readthedocs.io/en/latest/install…

基于SpringBoot和Leaflet的行政区划地图掩膜效果实战

目录 前言 一、掩膜小知识 1、GIS掩膜的实现原理 2、图层掩膜流程 二、使用插件 1、leaflet-mask介绍 2、核心代码解释 三、完整实例实现 1、后台逻辑实现 2、省级行政区划查询实现 3、行政区划定位及掩膜实现 4、成果展示 总结 前言 在之前的博客提过按空间矢量…

Ansys Speos | Light Expert Group探测器组使用技巧

附件下载 联系工作人员获取附件 概述 相机挡板的设计需要在光路的不同位置同步多个照度图&#xff0c;以尽量减少杂散光。2023R2 Speos提供了一种新的探测器&#xff0c;用于高阶杂散光分析&#xff0c;可以同时对多个探测器进行光线追迹。Light Expert工具可以即时过滤3D视…

SQLite数据库成为内存中数据库(三)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLite使用的临时文件&#xff08;二&#xff09; 下一篇&#xff1a;SQLite中的原子提交&#xff08;四) ​​ SQLite数据库通常存储在单个普通磁盘中文件。但是&#xff0c;在某些情况下&#xff0c;数据库可能…

业务服务:xss攻击

文章目录 前言一、使用注解预防1. 添加依赖2. 自定义注解3. 自定义校验逻辑4. 使用 二、使用过滤器1. 添加配置2. 创建配置类3. 创建过滤器4. 创建过滤器类5. 使用 前言 xss攻击时安全领域中非常常见的一种方法&#xff0c;保证我们的系统安全是非常重要的 xss攻击简单来说就…

代码随想录 图论-并查集

代码随想录 (programmercarl.com) 寻找图中是否存在路径这道题中的类可看做并查集的标准类 目录 1971.寻找图中是否存在路径 684.冗余连接 685.冗余连接II 1971.寻找图中是否存在路径 1971. 寻找图中是否存在路径 已解答 简单 相关标签 相关企业 有一个具有 n 个顶…

使用ai智能写作场景之gpt整理资料,如何ai智能写作整理资料

Ai智能写作助手&#xff1a;Ai智能整理资料小助手 Ai智能整理资料小助手可试用3天&#xff01; 通俗的解释一下怎么用ChatGPT来进行资料整理&#xff1a; 搜寻并获取指定数量的特定领域文章&#xff1a; 想像你在和我说话一样&#xff0c;告诉我你想要多少篇关于某个话题的文…

Flask python :logging日志功能使用

logging日志的使用 一、了解flask日志1.1、Loggers记录器1.2、Handlers 处理器1.3、Formatters 格式化器 二、使用日志2.1、官网上的一个简单的示例2.2、基本配置2.3、具体使用示例2.4、运行 三、写在最后 一、了解flask日志 日志是一种非常重要的工具&#xff0c;可以帮助开发…

【双指针】Leetcode 查找总价格为目标值的两个商品

题目解析 LCR 179. 查找总价格为目标值的两个商品 本题很友好&#xff0c;只需要返回任意一个 算法讲解 这道题很显然就是使用对撞双指针&#xff0c;一个从左边&#xff0c;一个从右边&#xff0c;两边进行和target比较来移动 代码编写 class Solution { public:vector<…

谷粒商城——缓存——SpringCache

1. 配置使用 首先需要导入相关的依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency> 随后在配置文件中进行配置&#xff1a; spring:cache:t…

C语言文件操作(详细)

⽬录 一. 为什么使⽤⽂件&#xff1f; 二. 什么是⽂件&#xff1f; 三. ⼆进制⽂件和⽂本⽂件&#xff1f; 四. ⽂件的打开和关闭 五. ⽂件的顺序读写 六. ⽂件的随机读写 七. ⽂件读取结束的判定 八. ⽂件缓冲区 一. 为什么使⽤⽂件&#xff1f; 如果没有⽂件&#…

STM32技术打造:智能考勤打卡系统 | 刷卡式上下班签到自动化解决方案

文章目录 一、简易刷卡式打卡考勤系统&#xff08;一&#xff09;功能简介原理图设计程序设计 哔哩哔哩&#xff1a; https://www.bilibili.com/video/BV1NZ421Y79W/?spm_id_from333.999.0.0&vd_sourcee5082ef80535e952b2a4301746491be0 一、简易刷卡式打卡考勤系统 &…

docker拉取镜像

docker 拉取镜像 命令格式 docker pull 仓库名称[:标签] 从下载过程可以看出&#xff1a; &#xff08;1&#xff09;镜像文件是由若干层组成&#xff0c;即&#xff1a;AUFS联合文件系统。这是实现增量保存与更新的基础 &#xff08;2&#xff09;下载过程会输出各层镜像的信…

界面控件DevExpress WinForms/WPF v23.2 - 电子表格支持表单控件

DevExpress WinForm拥有180组件和UI库&#xff0c;能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForm能完美构建流畅、美观且易于使用的应用程序&#xff0c;无论是Office风格的界面&#xff0c;还是分析处理大批量的业务数据&#xff0c;它都能轻松胜任…

String类(三)

文章目录 string类&#xff08;三&#xff09;string类的模拟实现&#xff1a;1.默认成员变量和函数2.string的长度和下表引用3.字符串拷贝构造4. 赋值拷贝5.字符串比较6.字符串的增添操作7.insert插入操作8.遍历字符 string类&#xff08;三&#xff09; string类的模拟实现&…