canvas实现鼠标拖拽矩形移动改变大小
项目的一个新需求,动态生成矩形框,鼠标点击拖动改变矩形框的位置,并可以调整大小。
之前做过一个小demo,需求类似,但是在canvas内只有一个矩形框,拖动移动,当时记得是用isPointInPath()直接判断鼠标是否点在了矩形框以内。新需求的矩形框个数为n,经过测试,isPointinPath实现过程中有bug,并不能精准定位到具体点击到canvas的某一个矩形框。经过一系列的头脑风暴,才想出了解决办法,才发现原来是最简单的方法,但是在思考的当初就被pass了,见代码:
html:
<body>
<canvas id="canvas" width="400" height="300">
</canvas>
</body>
小demo,不做其他修饰,直接写逻辑吧。
js:
第一步,创建一个容器,以保存Canvas内绘制的元素点。Canvas是一种非保留性的绘图界面,即不会记录过去执行的绘图操作,而是保持最终结果(构成图像的彩色像素)。
// canvas 矩形框集合
var rects=[];
function rectar(x,y,width,height){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.isSelected = false;
};
绘制矩形框:
function drawRect() {
// 清除画布,准备绘制
context.clearRect(0, 0, canvas.width, canvas.height);
// 遍历所有矩形框
for(var i=0; i<rects.length; i++) {
var rect = rects[i];
// 绘制矩形
context.strokeStyle="#FF0000";
context.strokeRect(rect.x,rect.y,rect.width,rect.height,rect.color);
if (rect.isSelected) {
context.lineWidth = 50;
}
else {
context.lineWidth = 10;
}
}
}
这是一个绘制函数,因为在Canvas的所有操作,全部都是重新绘制的(先清除,在绘制),每次程序刷新画布时,会先使用 clearRect() 方法清除画布上的所有内容。但不用当心这样会造成画布闪烁,即画布上的圆圈一下子全部消失,然后一下子又重新出现。因为Canvas针对这个问题进行了优化,会在所有绘图逻辑执行完毕后才清除或绘制所有内容,保证最终结果的流畅。然后遍历矩形数组 其中的x,y,width,height来画矩形。
*这里我的项目是根据病变位置动态生成的矩形框,每一次生成矩形框,都要把它的位置信息添加到数组中,这里就直接创建矩形框了,可以根据自己需求改造
function addRandomRect() {
var x=10;
var y=10;
var width=100;
var height=100;
// 创建一个新的矩形对象
var rect=new rectar(x,y,width,height);
// 把它保存在数组中
rects.push(rect);
// 重新绘制画布
drawRect();
13 };
*Canvas点击事件
var SelectedRect;
var x1;
var y1;
var right=false;
var widthstart,widthend;
var heightstart,heightend; function canvasClick(e) {
// 取得画布上被单击的点
var clickX = e.pageX - canvas.offsetLeft;
var clickY = e.pageY - canvas.offsetTop; // 查找被单击的矩形框
for(var i=rects.length-1; i>=0; i--) {
var rect = rects[i]; widthstart=rect.x;
widthend=rect.x+rect.width; heightstart=rect.y;
heightend=rect.y+rect.height; // 判断这个点是否在矩形框中
if ((clickX>=widthstart&&clickX<(widthend-20))&&(clickY>=heightstart)&&(clickY<(heightend-20))) {
console.log(clickX);
// 清除之前选择的矩形框
if (SelectedRect != null) SelectedRect.isSelected = false;
SelectedRect = rect;
x1=clickX-SelectedRect.x;
y1=clickY-SelectedRect.y;
//选择新圆圈
rect.isSelected = true; // 使圆圈允许拖拽
isDragging = true; //更新显示
drawRect();
//停止搜索
return;
};
/*
设置拉伸的界限。
*/
// if ((clickX>=(widthend-20))&&(clickY>=(heightend-20)))
// {
// SelectedRect = rect;
// right=true;
// }
//18-02-01改
if ((clickX>=(widthend-20)&&((clickX<=(widthend+20)))&&(clickY>=(heightend-20))&&(clickY>=(heightend+20)))
{
SelectedRect = rect;
right=true;
}
} }
代码中23行为判断具体点击哪个元素的语句,其实很简单,当初绕了很久,很简单直接判断鼠标点击点是否在矩形框之内即可,无论是哪个矩形框,只要在矩形框之内,就把当前矩形框设置为点击的矩形框。29行判断鼠标点击点相对于矩形框的位置。42-49行,是鼠标拉伸改变大小的判断,可以设置矩形四个角拉伸,但我认为太复杂了,只保留了右下角拉伸的点击判断,操作更简单一些。
响应事件:
function dragRect(e) {
// 判断矩形是否开始拖拽
if (isDragging == true) {
// 判断拖拽对象是否存在
if (SelectedRect != null) {
// 取得鼠标位置
var x = e.pageX - canvas.offsetLeft;
var y = e.pageY - canvas.offsetTop;
// 将圆圈移动到鼠标位置
SelectedRect.x= x-x1;
SelectedRect.y= y-y1;
// 更新画布
drawRect();
}
}
//判断是否开始拉伸
if (right) {
//设置拉伸最小的边界
if ((e.pageX - canvas.offsetLeft-SelectedRect.x)>50) {
SelectedRect.width=e.pageX - canvas.offsetLeft-SelectedRect.x;
}
else {
SelectedRect.width=50;
}
console.log(SelectedRect.width);
if((e.pageY - canvas.offsetTop-SelectedRect.y)>50){
SelectedRect.height=e.pageY - canvas.offsetTop-SelectedRect.y;
}
else {
SelectedRect.height=50;
}
drawRect();
}
};
以上就完成了对矩形框的基本操作,然后添加onmouseup的函数和调用函数:
var isDragging = false;
function stopDragging() {
isDragging = false;
right=false;
};
function clearCanvas() {
// 去除所有矩形
rects = [];
// 重新绘制画布.
drawCircles();
}
window.onload = function() {
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
canvas.onmousedown = canvasClick;
canvas.onmouseup = stopDragging;
canvas.onmouseout = stopDragging;
canvas.onmousemove =dragRect;
; };
canvas实现鼠标拖拽矩形移动改变大小的更多相关文章
- JS实现漂亮的窗口拖拽效果(可改变大小、最大化、最小化、关闭)
转自<JS实现漂亮的窗口拖拽效果(可改变大小.最大化.最小化.关闭)>:http://www.jb51.net/article/73157.htm 这篇文章主要介绍了JS实现漂亮的窗口 ...
- WPF 在image控件用鼠标拖拽出矩形
原文:WPF 在image控件用鼠标拖拽出矩形 版权声明:博客已迁移到 http://lindexi.gitee.io 欢迎访问.如果当前博客图片看不到,请到 http://lindexi.gitee ...
- 2018-11-19-WPF-在image控件用鼠标拖拽出矩形
title author date CreateTime categories WPF 在image控件用鼠标拖拽出矩形 lindexi 2018-11-19 15:35:13 +0800 2018- ...
- Java3D读取3DMax模型并实现鼠标拖拽、旋转、滚轮缩放等功能
/**-------------------------------------------------代码区--------------------------------------------- ...
- CSharpGL(20)用unProject和Project实现鼠标拖拽图元
CSharpGL(20)用unProject和Project实现鼠标拖拽图元 效果图 例如,你可以把Big Dipper这个模型拽成下面这个样子. 配合旋转,还可以继续拖拽成这样. 当然,能拖拽的不只 ...
- 拼图 canvas分割 dom拖拽 pc 移动端
参考:Canvas drag 实现拖拽拼图小游戏 参考的案例,不支持手机端.总结下实现过程中遇到的小坑. gitHub:https://github.com/WppFrontEnd/puzzle 大概 ...
- JavaScript鼠标拖拽特效及相关问题总结
#div1{width:200px;height:200px;background:red;position:absolute;} #div2{width:200px;height:200px;bac ...
- 一款基于jQuery的支持鼠标拖拽滑动焦点图
记得之前我们分享过一款jQuery全屏广告图片焦点图,图片切换效果还不错.今天我们要分享另外一款jQuery焦点图插件,它的特点是支持鼠标拖拽滑动,所以在移动设备上使用更加方便,你只要用手指滑动屏幕即 ...
- 【狼】unity 鼠标拖拽物体实现任意角度自旋转
主要涉及函数 Input.GetAxis(“Mouse x”) 可取得鼠标横向(x轴)移动增量 Input.GetAxis(“Mouse y”) 可取得鼠标竖向(y轴)移动增量 通过勾股定理获取拖拽长 ...
随机推荐
- 两台Linux系统之间传输文件
用CRT分别连上两台需要传输文件的linux系统服务器,并检查防火墙是否关闭. 查看防火墙状态: /etc/init.d/iptables status 若防火墙启用,暂时关闭防火墙: /etc/in ...
- Jmeter(三)断言和关联
Jmeter断言 断言是什么呢,它是用来检查返回结果对不对的.用来验证结果是否正确,如果正确的话,就代表这个请求的返回是正确的,如果没有的话就代表这个请求的结果和我们预期的不一致,这样我们就可以通过断 ...
- Spark如何写入HBase/Redis/MySQL/Kafka
一些概念 一个partition 对应一个task,一个task 必定存在于一个Executor,一个Executor 对应一个JVM. Partition 是一个可迭代数据集合 Task 本质是作用 ...
- 转 Merkle Tree(默克尔树)算法解析
Merkle Tree概念 Merkle Tree,通常也被称作Hash Tree,顾名思义,就是存储hash值的一棵树.Merkle树的叶子是数据块(例如,文件或者文件的集合)的hash值.非叶节 ...
- MySQL,sqlalchemy
Mariadb 数据库是一堆表的集合 主键 外键 索引 安装: Centos7 [root@host]# mysqladmin -u root password "new_password& ...
- iOS 关于BTC 一些知识点
1.BTC 用这个网 可以校验 自己的库生成的助记词 地址 是否是合法正常的 https://iancoleman.io/bip39/ 2.知晓 BTC 钱包是否有钱 和交易记录 https://te ...
- apache服务器设置
服务器目录 目录说明 bin: apache常用的一些命令 cgi-bin:存放一些脚本语言命令 conf:apache配置文件 error:错误记录 htodcs存放站点文件 logs:记录日志 m ...
- Apple 的命令行交付工具“Transporter”
Apple 的命令行交付工具“Transporter” 占坑... https://help.apple.com/itc/transporteruserguide/#/apdATD1E1026-D1E ...
- Python Date 1–Hello world print
对比学习Python与C str1 = 'hello python 2'# 字符串i = 3.1415926535 print(str1)print("hello python\n" ...
- 手写一款符合Promise/A+规范的Promise
手写一款符合Promise/A+规范的Promise 长篇预警!有点长,可以选择性观看.如果对Promise源码不是很清楚,还是推荐从头看,相信你认真从头看到尾,并且去实际操作了,肯定会有收获的.主要 ...