zoukankan      html  css  js  c++  java
  • 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;
    ; };
  • 相关阅读:
    centos7 查看启动ntp服务命令
    集群重启某一主机下所有osd down解决办法
    不卸载ceph重新获取一个干净的集群环境
    centos7 中文乱码解决方法
    ceph-deploy mon add 失败
    批量删除osd的shell脚本
    搭建自己的框架WedeNet(二)
    搭建自己的框架WedeNet(一)
    多线程总结
    C#中操作单个cookie和cookie字典
  • 原文地址:https://www.cnblogs.com/fengchaoran/p/8057338.html
Copyright © 2011-2022 走看看