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变得具有交互性,比如用户可以选择、拖动画布上的图形。那么我们必须记录绘制的每一个对象,才能在将来灵活的修改并重绘它们,实现交互。
 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  };

 *Canvas点击事件

 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 = [];

    // 重新绘制画布.

    drawCircles();
    }


  window.onload = function() {
      canvas = document.getElementById("canvas");
      context = canvas.getContext("2d");
      canvas.onmousedown = canvasClick;
      canvas.onmouseup = stopDragging;
      canvas.onmouseout = stopDragging;
      canvas.onmousemove =dragRect;
; };
原文地址:https://www.cnblogs.com/fengchaoran/p/8057338.html