最近一個小夥遇到一個需求,客戶須要繪製圓點樣式的線條。 大體效果是這樣的:前端
他本身實現了一種思路,而後諮詢我有沒有更好的思路。 先看看他的思路是如何實現的,大體代碼以下:java
// 繪製圓點線,經過計算在線條上進行插值運算,計算出須要繪製圓點的一系列點位
// 而後調用drawDot方法繪製圓點
function DrawDottedLine(x1,y1,x2,y2,dotRadius,dotCount,dotColor){
var dx=x2-x1;
var dy=y2-y1;
var spaceX=dx/(dotCount-1);
var spaceY=dy/(dotCount-1);
var newX=x1;
var newY=y1;
for (var i=0;i<dotCount;i++){
drawDot(newX,newY,dotRadius,dotColor);
newX+=spaceX;
newY+=spaceY;
}
drawDot(x1,y1,3,"red");
drawDot(x2,y2,3,"red");
}
// 繪製圓點
function drawDot(x,y,dotRadius,dotColor){
ctx.beginPath();
ctx.arc(x,y, dotRadius, 0, 2 * Math.PI, false);
ctx.fillStyle = dotColor;
ctx.fill();
}
複製代碼
經過上面的簡單的示意代碼能夠看出,繪製邏輯是經過計算直線之間的點位,而後再相應的點上面繪製圓形。 該方法最終能夠達到效果,但是有以下問題:node
固然此思路在繪製一些更加複雜的效果的時候,可能會有用。好比沿線繪製五角星,其餘任意形狀或者圖片等等。或者要繪製的是圓圈而不是填充的圓形的效果,也須要使用此方法。程序員
可是若是隻是繪製圓點線,咱們可使用更加簡便的方法,主要思路就是使用setLineDash方法+lineCap設置數據庫
CanvasRenderingContext2D.lineCap 是 Canvas 2D API 指定如何繪製每一條線段末端的屬性。有3個可能的值,分別是:butt, round and square。默認值是 butt。canvas
使用時,直接賦值便可:數組
ctx.lineCap = "butt";
ctx.lineCap = "round";
ctx.lineCap = "square";
複製代碼
下面從左到右分別是butt, round ,square的效果:bash
能夠看出 「round」和「square」都是在本來繪製得線段以外擴展了一個半圓和一個矩形,這點在後面會用到。架構
相關知識,能夠參考這篇文章: canvas基礎知識回顧併發
Canvas 2D API的CanvasRenderingContext2D
接口的**setLineDash()
**方法在填充線時使用虛線模式。 它使用一組值來指定描述模式的線和間隙的交替長度。
語法以下:
ctx.setLineDash(segments);
//segments數組。一組描述交替繪製線段和間距(座標空間單位)長
//度的數字。 若是數組元素的數量是奇數, 數組的元素會被複制並重
//復。例如, `[5, 15, 25]` 會變成 `[5, 15, 25, 5, 15, 25]。`</dd>
複製代碼
有了上面兩個知識點,只須要把二者結合起來,就能夠繪製出圓點線,咱們首先使用ctx.setLineDash方法把線段分紅一段一段得虛線。 而後把lineCap設置爲「round」,咱們就會獲得一段一段得端點是半圓得小線段,代碼以下:
ctx.beginPath();
ctx.lineWidth = 5;
ctx.lineCap = "round"
ctx.setLineDash([10, 30]);
ctx.moveTo(0, 50);
ctx.lineTo(300, 50);
ctx.lineTo(300, 200);
ctx.quadraticCurveTo(500,300,400,400);
ctx.stroke();
複製代碼
最終繪製得效果以下圖所示:
到此,又朋友可能有疑問,這個也不是圓點線得效果。 其實只須要把上面得代碼稍微得修改,讓實線線段自己得長度變成0便可,修改代碼:
...
ctx.setLineDash([0, 30]);
...
複製代碼
最終繪製得效果以下圖所示:
結合前面 lineCap 得知識點,相信很容易理解。
若是要繪製方塊得效果,也是很容易得,只須要把lineCap 改爲"square" 便可:
ctx.beginPath();
ctx.lineWidth = 10;
ctx.lineCap = "square"
ctx.setLineDash([0, 30]);
ctx.moveTo(0, 50);
ctx.lineTo(300, 50);
ctx.lineTo(300, 200);
ctx.quadraticCurveTo(500,300,400,400);
ctx.stroke();
複製代碼
效果以下:
此處有人可能會說,lineCap 爲「butt」一樣能夠作出方塊得效果,只須要調整setLineDash得參數便可:
ctx.beginPath();
ctx.lineWidth = 10;
ctx.lineCap = "butt"
ctx.setLineDash([10, 30]);
ctx.moveTo(0, 50);
ctx.lineTo(300, 50);
ctx.lineTo(300, 200);
ctx.quadraticCurveTo(500,300,400,400);
ctx.stroke();
複製代碼
確實如此,可是使用「square」 得狀況下setLineDash函數的參數的一個值始終是0,而「butt」 的狀況下,setLineDash函數的參數的第一個參數值須要隨着lineWidth變化而變化,很不方便,並且「butt」的狀況下,還會出現尾部可能不是一個方塊的效果,以下圖:
若是要繪製以下得線條樣式,應該怎麼作呢:
其實也很簡單,就是把同一條線段用不一樣得lineDash和lineCap繪製兩次便可,代碼以下:
// 繪製圓點
ctx.save();
ctx.beginPath();
ctx.lineCap = "round";
ctx.setLineDash([0, 80]);
ctx.lineWidth = 20;
ctx.moveTo(50, 50);
ctx.lineTo(400, 50);
ctx.lineTo(400, 400);
ctx.quadraticCurveTo(750, 450, 800, 800);
ctx.stroke();
//繪製直線
ctx.lineCap = "butt";
ctx.setLineDash([0, 20, 40, 20]);
ctx.lineWidth = 10;
ctx.moveTo(50, 50);
ctx.lineTo(400, 50);
ctx.lineTo(400, 400);
ctx.quadraticCurveTo(750, 450, 800, 800);
ctx.stroke();
複製代碼
須要注意的是繪製第二段的時候,須要調整好lineDash的segments的值。
歡迎關注公衆號「ITman彪叔」。彪叔,擁有10多年開發經驗,現任公司系統架構師、技術總監、技術培訓師、職業規劃師。熟悉Java、JavaScript、Python語言,熟悉數據庫。熟悉java、nodejs應用系統架構,大數據高併發、高可用、分佈式架構。在計算機圖形學、WebGL、前端可視化方面有深刻研究。對程序員思惟能力訓練和培訓、程序員職業規劃有濃厚興趣。