项目的一个新需求,动态生成矩形框,鼠标点击拖动改变矩形框的位置,并能够调整大小。html
以前作过一个小demo,需求相似,可是在canvas内只有一个矩形框,拖动移动,当时记得是用isPointInPath()直接判断鼠标是否点在了矩形框之内。新需求的矩形框个数为n,通过测试,isPointinPath实现过程当中有bug,并不能精准定位到具体点击到canvas的某一个矩形框。通过一系列的头脑风暴,才想出了解决办法,才发现原来是最简单的方法,可是在思考的当初就被pass了,见代码:canvas
<body> <canvas id="canvas" width="400" height="300"> </canvas> </body>
小demo,不作其余修饰,直接写逻辑吧。数组
第一步,建立一个容器,以保存Canvas内绘制的元素点。Canvas是一种非保留性的绘图界面,即不会记录过去执行的绘图操做,而是保持最终结果(构成图像的彩色像素)。dom
1 // canvas 矩形框集合 2 var rects=[]; 3 function rectar(x,y,width,height){ 4 this.x = x; 5 this.y = y; 6 this.width = width; 7 this.height = height; 8 this.isSelected = false; 9 };
1 function drawRect() { 2 // 清除画布,准备绘制 3 context.clearRect(0, 0, canvas.width, canvas.height); 4 5 // 遍历全部矩形框 6 for(var i=0; i<rects.length; i++) { 7 var rect = rects[i]; 8 9 // 绘制矩形 10 context.strokeStyle="#FF0000"; 11 context.strokeRect(rect.x,rect.y,rect.width,rect.height,rect.color); 12 13 if (rect.isSelected) { 14 context.lineWidth = 50; 15 } 16 else { 17 context.lineWidth = 10; 18 } 19 } 20 }
这是一个绘制函数,由于在Canvas的全部操做,所有都是从新绘制的(先清除,在绘制),每次程序刷新画布时,会先使用 clearRect() 方法清除画布上的全部内容。但不用小心这样会形成画布闪烁,即画布上的圆圈一会儿所有消失,而后一会儿又从新出现。由于Canvas针对这个问题进行了优化,会在全部绘图逻辑执行完毕后才清除或绘制全部内容,保证最终结果的流畅。而后遍历矩形数组 其中的x,y,width,height来画矩形。函数
*这里个人项目是根据病变位置动态生成的矩形框,每一次生成矩形框,都要把它的位置信息添加到数组中,这里就直接建立矩形框了,能够根据本身需求改造测试
1 function addRandomRect() { 2 var x=10; 3 var y=10; 4 var width=100; 5 var height=100; 6 // 建立一个新的矩形对象 7 var rect=new rectar(x,y,width,height); 8 9 // 把它保存在数组中 10 rects.push(rect); 11 // 从新绘制画布 12 drawRect(); 13 };
1 var SelectedRect; 2 var x1; 3 var y1; 4 var right=false; 5 var widthstart,widthend; 6 var heightstart,heightend; 7 8 function canvasClick(e) { 9 // 取得画布上被单击的点 10 var clickX = e.pageX - canvas.offsetLeft; 11 var clickY = e.pageY - canvas.offsetTop; 12 13 // 查找被单击的矩形框 14 for(var i=rects.length-1; i>=0; i--) { 15 var rect = rects[i]; 16 17 widthstart=rect.x; 18 widthend=rect.x+rect.width; 19 20 heightstart=rect.y; 21 heightend=rect.y+rect.height; 22 23 // 判断这个点是否在矩形框中 24 if ((clickX>=widthstart&&clickX<(widthend-20))&&(clickY>=heightstart)&&(clickY<(heightend-20))) { 25 console.log(clickX); 26 // 清除以前选择的矩形框 27 if (SelectedRect != null) SelectedRect.isSelected = false; 28 SelectedRect = rect; 29 x1=clickX-SelectedRect.x; 30 y1=clickY-SelectedRect.y; 31 //选择新圆圈 32 rect.isSelected = true; 33 34 // 使圆圈容许拖拽 35 isDragging = true; 36 37 //更新显示 38 drawRect(); 39 //中止搜索 40 return; 41 }; 42 /* 43 设置拉伸的界限。 44 */ 45 // if ((clickX>=(widthend-20))&&(clickY>=(heightend-20))) 46 // { 47 // SelectedRect = rect; 48 // right=true; 49 // }
//18-02-01改
if ((clickX>=(widthend-20)&&((clickX<=(widthend+20)))&&(clickY>=(heightend-20))&&(clickY>=(heightend+20)))
{
SelectedRect = rect;
right=true;
}
50 }
51 }
代码中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 = [];this
// 从新绘制画布.spa
drawCircles();
}
window.onload = function() { canvas = document.getElementById("canvas"); context = canvas.getContext("2d"); canvas.onmousedown = canvasClick; canvas.onmouseup = stopDragging; canvas.onmouseout = stopDragging; canvas.onmousemove =dragRect;
; };