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的一些東東。可繪制、拖拽、編輯、下載坐標信息,對於一些數據集的標注工作可以輔助標記。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM