目前的工做在作在線的標註工具,接觸canvas一年了,各類繪製,基本上圖像的交互canvas均可以完成,也寫了幾篇關於canvas的文章,遇到的問題也寫博客上了,對於canvas有問題的朋友能夠去看看。一直想寫一個關於canvas系列的東西,也沒時間。正好最近再搗鼓canvas,有時間就寫一點,一個功能一個功能的寫,爭取寫一個系列。html
之前都是繪製矩形,今天寫一個新鮮的,繪製多邊形可拖動編輯的多邊形。見下圖(截取自工程的一部分):canvas
(太大的GIF圖傳不上來,只能截取一小部分,找個時間把完整的功能錄一個視頻放在網盤上)。數組
鼠標點擊繪製點,而且自動繪製曲線,(當曲線閉合的時候,彈出名稱邊界框--不重要),繪製完畢後,點擊點能夠改變形狀,點擊曲線內部能夠拖動位置。工具
這篇文章就先寫繪製不規則圖像與拖動點吧,移動圖像值得另起寫一篇文章。ui
正文this
寫了這麼多的canvas代碼,個人經驗就是必定要去寫,一邊寫邊看效果,作的過程當中會有新的想法。對於canvas各類繪製的效果,仍是得去動手去修改才能出效果。spa
寫以前整理下思路:code
1.鼠標點擊繪製點-->繪製圓的方法,鼠標點爲中心點。視頻
2.每點擊一次,繪製線段。--Lineto方法。htm
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的一些東東。可繪製、拖拽、編輯、下載座標信息,對於一些數據集的標註工做能夠輔助標記。