zoukankan      html  css  js  c++  java
  • Canvas绘制不规则图形,实现可拖动,编辑--V1.0第一篇

           目前的工作在做在线的标注工具,接触canvas一年了,各种绘制,基本上图像的交互canvas都可以完成,也写了几篇关于canvas的文章,遇到的问题也写博客上了,对于canvas有问题的朋友可以去看看。一直想写一个关于canvas系列的东西,也没时间。正好最近再捣鼓canvas,有时间就写一点,一个功能一个功能的写,争取写一个系列。

           以前都是绘制矩形,今天写一个新鲜的,绘制多边形可拖动编辑的多边形。见下图(截取自工程的一部分):

                                                           

       (太大的GIF图传不上来,只能截取一小部分,找个时间把完整的功能录一个视频放在网盘上)。

       鼠标点击绘制点,并且自动绘制曲线,(当曲线闭合的时候,弹出名称边界框--不重要),绘制完毕后,点击点可以改变形状,点击曲线内部可以拖动位置。

       这篇文章就先写绘制不规则图像与拖动点吧,移动图像值得另起写一篇文章。

       

       正文

       写了这么多的canvas代码,我的经验就是一定要去写,一边写边看效果,做的过程中会有新的想法。对于canvas各种绘制的效果,还是得去动手去修改才能出效果。

        写之前整理下思路:

           1.鼠标点击绘制点-->绘制圆的方法,鼠标点为中心点。

           2.每点击一次,绘制线段。--Lineto方法。

           3.判断是否闭合。

           4.判断是否点击了绘制过的点上--拖动改变形状。

           5.重绘。

     

         画布上每一次的更改都是要重新绘制画布的,所以要把绘制的点保存起来。这个思路和画矩形的思路大体相近,可以看下我的绘制矩形的文章

         

     1 //线段的点的集合
     2 var points=[];
     3 //可拖动圆圈的点的集合
     4 var circles=[];
     5 //每一个点的对象
     6 function Point(x, y) {
     7     this.x = x;
     8     this.y = y;
     9   }
    10 //圆圈对象
    11 function Circle(x, y) {
    12      this.x = x;
    13      this.y = y;
    14      this.radius = 10;
    15      this.color = "blue";
    16      //拖拽点的标记
    17      this.isSelected = false;
    18   }
    19 /*每一次的点都看作一个对象,然后把点放在数组里保存起来
    20 这样circles和points就会是这种形式
    21 points=[{(x0,y0},{x1,y1},{x2,y2}..]
    22 circles=[{x0,y0,10,blue,false}...]*/

    上边的points和circles数组其实xy坐标是一样的,为啥创建两个呢?

    如果项目小,就实现一个拖拽的图像就行了,那可以随便设置数组个数,随着标注工具增加,各种重绘,还是各干各的比较好,不要高耦合。

    绘制:

       canvas.onmousedown=function(e){
         var clickX = e.pageX - canvas.offsetLeft;
         var clickY = e.pageY - canvas.offsetTop;
         //判断当前点击点是否在已经绘制的圆圈上,如果是执行相关操作,并return,不进入画线的代码
         for(var i=1; i<circles.length; i++) {
            var circle = circles[i];
            //使用勾股定理计算这个点与圆心之间的距离
            var distanceFromCenter = Math.sqrt(Math.pow(circle.x - clickX, 2)
                + Math.pow(circle.y - clickY, 2));
    
            // 如果是其他的点,则设置可以拖动
            if (distanceFromCenter <= circle.radius) {
              // 清除之前选择的圆圈
              index=i;
              isDragging=true;
              //停止搜索
              return;
            }
          }
        //如果点击新的位置,则进入下面的代码,绘制点
        context.clearRect(0,0,canvas.width,canvas.height);
        //遍历数组画圆
         var circle=new Circle(clickX,clickY);
         circles.push(circle);
         circles[0].color="green";
         for(var i=0; i<circles.length; i++) {
            var circle = circles[i];
            // 绘制圆圈
            context.globalAlpha = 0.85;
            context.beginPath();
            context.arc(circle.x, circle.y, circle.radius, 0, Math.PI*2);
            context.fillStyle = circle.color;
            context.strokeStyle = "black";
            context.fill();
            context.stroke();
          }
          // 画线
         var point=new Point(clickX,clickY);
         points.push(point);
         context.beginPath();
         context.lineWidth = 4;
         //从起始点开始绘制
         context.moveTo(points[0].x,points[0].y);
         for (var i = 0; i < points.length; i++) {
           context.lineTo(points[i].x, points[i].y);
         }
         context.fillStyle="rgb(2,100,30)";
         context.fill();
         context.strokeStyle="#9d4dca";
         context.stroke();
       };

        每一次点击都要判断一下,如果点在曾经绘制的点上,那么就设置变量isDragging=true可以拖拽,return。如果没有,说明创建的是新的点,那么开始绘制并且加入数组。(代码部分的声明就不写了,直接出关键的思路代码,具体的还要自己动手去写)

    拖拽点移动:

    canvas.onmousemove=function(e){
       // 判断圆圈是否开始拖拽
       if (isDragging == true) {
         // 判断拖拽对象是否存在
           // 取得鼠标位置
           var x1 = e.pageX - canvas.offsetLeft;
           var y1 = e.pageY - canvas.offsetTop;
           context.clearRect(0,0,canvas.width,canvas.height);
           //根据上文得到的index设置index点位置随鼠标改变
           circles[index].x=x1;
           circles[index].y=y1;
           points[index].x=x1;
           points[index].y=y1;
           for(var i=0; i<circles.length; i++) {
              var circle = circles[i];
              // 绘制圆圈
              context.globalAlpha = 0.85;
              context.beginPath();
              context.arc(circle.x, circle.y, circle.radius, 0, Math.PI*2);
              context.fillStyle = circle.color;
              context.strokeStyle = "black";
              context.fill();
              context.stroke();
            }
           context.beginPath();
           context.moveTo(points[0].x,points[0].y);
           for (var i = 0; i < points.length; i++) {
             context.lineTo(points[i].x, points[i].y);
           }
           context.lineTo(points[0].x,points[0].y);
           // context.fillStyle="#831f68";
           context.fillStyle="rgb(2,100,30)";
           context.fill();
           context.strokeStyle="#9d4dca";
           context.stroke();
         }
       };
    
       canvas.onmouseup=function(){
         isDragging=false;
       };
    
       canvas.onmouseout=function(){
         isDragging=false;
       };

    其实实现拖拽并不难, 有一个地方就是如何判断鼠标点在了已经绘制的点上。循环所有点,只要鼠标点到圆心的距离小于半径,那么一定点在了这个点上。

    这样一个简单的拖拽就实现了,后面的文章我还会继续增加新的功能,慢慢丰富代码。欢迎关注。

     更新:一个V1.0工程的视频,百度网盘:链接: https://pan.baidu.com/s/1qFF3yF4T9oE9quiUx7hfoA 密码: md6g

     1.0版本,后续版本慢慢更新,包括canvas的绘制和Vue的一些东东。可绘制、拖拽、编辑、下载坐标信息,对于一些数据集的标注工作可以辅助标记。

  • 相关阅读:
    多层次子查询的sql执行顺序的问题
    RestTemplate不落地中转文件
    Gitbook从安装到使用【转】
    Linux离线安装依赖包技巧
    CentOS7 配置环境变量断开ssh后失效
    分页查询排序问题
    地图坐标的转换
    FeatureLayer图层的属性查询方式(query的使用方法)
    使用LayerView.effect进行点的高亮显示
    DQL + 排序
  • 原文地址:https://www.cnblogs.com/fengchaoran/p/8652638.html
Copyright © 2011-2022 走看看