js 鼠标拖动canvas画布

news/2024/10/22 14:19:07/
htmledit_views">

功能点:

  • 鼠标拖拽canvas画布移动
  • 鼠标检测rect
  • 鼠标检测circle

代码

html" title=javascript>javascript"><!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>鼠标移动画布-事件检测</title><style>html,body {margin: 0;padding: 0;height: 100%;width: 100%;overflow: hidden;}</style></head><body><canvas id="canvas"></canvas><script>const canvas = document.getElementById('canvas');const { clientWidth: width, clientHeight: height } = document.body;canvas.width = width;canvas.height = height;const ctx = canvas.getContext('2d');// 储累积的偏移量let totalOffsetX = 0;let totalOffsetY = 0;// 缩放系数let scale = 1;// 图形数据const shapes = [{type: 'rect',x: 100,y: 100,width: 20,height: 20,strokeStyle: '#000',fillStyle: '#f00',},{type: 'circle',x: 200,y: 200,radius: 10,strokeStyle: '#000',fillStyle: '#0f0',},{type: 'polyline',points: [{ x: 200, y: 100 },{ x: 150, y: 100 },{ x: 200, y: 150 },],strokeStyle: '#000',fillStyle: '#00f',},];function render(offsetX, offsetY) {// 绘制时需要使用beginPath,否则无法使用clearRect清空画布ctx.clearRect(0, 0, width, height);ctx.fillStyle = '#999';ctx.fillRect(0, 0, width, height);ctx.fill();ctx.translate(totalOffsetX, totalOffsetY);ctx.scale(scale, scale);shapes.forEach((shape) => {const { type, x, y, width, height, radius, points } = shape;ctx.fillStyle = shape.fillStyle;ctx.beginPath();if (type === 'rect') {ctx.fillRect(x, y, width, height);} else if (type === 'circle') {ctx.arc(x, y, radius, 0, Math.PI * 2);} else if (type === 'polyline') {ctx.moveTo(points[0].x, points[0].y);points.slice(1).forEach((point) => {ctx.lineTo(point.x, point.y);});ctx.closePath();}ctx.fill();});ctx.resetTransform();}render();canvas.addEventListener('mousedown', onMouseDown);canvas.addEventListener('mousemove', onMouseMove);canvas.addEventListener('mouseup', onMouseUp);canvas.addEventListener('mouseleave', onMouseLeave);canvas.addEventListener('wheel', onWheel);let isMouseDown = false;let startX, startY;function onMouseDown(e) {canvas.style.cursor = 'grab';isMouseDown = true;startX = e.offsetX;startY = e.offsetY;}function onMouseMove(e) {isShapePoint(e);if (isMouseDown) {totalOffsetX += e.offsetX - startX;totalOffsetY += e.offsetY - startY;startX = e.offsetX;startY = e.offsetY;requestAnimationFrame(render);}}function onMouseUp(e) {isMouseDown = false;}function onMouseLeave(e) {isMouseDown = false;}function onWheel(e) {// 缩放,最大5倍,最小0.2倍if (e.deltaY === -100) {if (scale + 0.1 > 5) return;// 放大scale += 0.1;} else {if (scale - 0.1 <= 0.2) return;// 缩小scale -= 0.1;}requestAnimationFrame(render);}// 检测设备function isShapePoint(e) {const { offsetX, offsetY } = e;let check = false;shapes.forEach((shape) => {// 检测rectif (shape.type === 'rect') {const { type, x, y, width, height } = shape;const transformedX = (offsetX - totalOffsetX) / scale;const transformedY = (offsetY - totalOffsetY) / scale;if (transformedX >= x &&transformedX <= x + width &&transformedY >= y &&transformedY <= y + height) {check = true;}} else if (shape.type === 'circle') {// 检测圆形const { x, y, radius } = shape;const transformedX = (offsetX - totalOffsetX) / scale;const transformedY = (offsetY - totalOffsetY) / scale;const circleX = x;const circleY = y;// 计算光标与圆心的距离const distance = Math.sqrt((transformedX - circleX) ** 2 + (transformedY - circleY) ** 2);if (radius >= distance) {check = true;}} else if (shape.type === 'polyline') {const { points: polygon } = shape;let inside = false;const transformedX = (offsetX - totalOffsetX) / scale;const transformedY = (offsetY - totalOffsetY) / scale;for (let i = 0, j = polygon.length - 1;i < polygon.length;j = i++) {const xi = polygon[i].x,yi = polygon[i].y;const xj = polygon[j].x,yj = polygon[j].y;const intersect =yi > transformedY !== yj > transformedY &&transformedX <((xj - xi) * (transformedY - yi)) / (yj - yi) + xi;if (intersect) {inside = !inside;if (inside) {check = true;} else {check = false;}}}}});if (check) {canvas.style.cursor = 'move';} else {canvas.style.cursor = 'grab';}}</script></body>
</html>


http://www.ppmy.cn/news/1541074.html

相关文章

Rust编程语言变量的所有权(ownership)

文章目录 什么是所有权所有权规则转让所有权变量与数据交互的方式(一):移动变量与数据交互的方式(二):克隆只在栈上的数据:拷贝所有权与函数返回值与作用域引用和借用可变引用悬垂引用(Dangling References)引用的规则什么是所有权 所有权(ownership)是Rust 的核心功能之一…

ARAIM在航空领域的重要性及其面临的主要挑战

笔者这篇博客主要目的是总结目前ARAIM技术面临的主要问题&#xff0c;为做高级接收机自主完好性的小伙伴提供论文创新点思路。对于研究方向迷茫的小伙伴可以参考ARAIM目前存在的主要问题&#xff0c;展开相关研究&#xff0c;希望该博客对读者有所帮助。 1.全球卫星导航系统发…

Axure使用教程,产品经理如何用Axure制作一份高质量高保真的OA办公管理系统原型?附源文件下载

OA办公管理系统&#xff08;Office Automation Management System&#xff09;是通过现代计算机和通信技术&#xff0c;将办公过程中的信息、数据和流程进行自动化处理&#xff0c;以提高工作效率、降低成本的一套系统。构建OA办公管理系统涉及多个步骤&#xff0c;以下是一个概…

手写模拟Spring的基本功能

文章目录 1. Spring的基本功能2. 容器启动 容器启动&#xff0c;即创建容器对象并赋予配置对象3. BeanDefinition扫描4. Bean的生命周期5. 单例Bean与多例Bean6. 依赖注入7. AOP8. Aware 回调9. 初始化10. BeanPostProcessor附录&#xff1a; 1. Spring的基本功能 2. 容器启动 …

Ajax:跨域、防抖和节流、HTTP协议

在善意的“双向奔赴”中&#xff0c;每个普通人都如星辰&#xff0c;微小但释放着自己的光芒&#xff0c;交织成灿烂的星河 文章目录 跨域防抖和节流HTTP协议HTP状态码以及代表意义错误代码的影响移动的小天使 跨域 同源策略 概念&#xff1a;协议&#xff0c;域名&#xff0c…

大数据-178 Elasticsearch Query - Java API 索引操作 文档操作

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

uniapp 获取签名证书 SHA1 自有证书签名打包

1.登录你的Dcloud 账户 2.找到我的应用菜单 3.点开某个应用 4.查看证书详情&#xff0c;里面有SHA1 和别名&#xff0c;密码&#xff0c;下载证书用于云打包&#xff0c;可以选择自有证书&#xff0c;输入别名&#xff0c;密码打包

Linux网络编程(六)-TCP协议服务端及代码实现

1.概述 在讲述了那么多以后我们终于来到了代码阶段的讲解了&#xff0c;先放一张流程图便于大家理解。接着会为大家讲述具体的实现过程。 通过上图我们可以看到一个完整的Socket网络通信&#xff0c;是有客户端和服务端两部分代码组成的&#xff0c;即两个程序&#xff08;你发…