最近一个小伙遇到一个需求,客户须要绘制圆点样式的线条。 大体效果是这样的:前端
他本身实现了一种思路,而后咨询我有没有更好的思路。 先看看他的思路是如何实现的,大体代码以下: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、前端可视化方面有深刻研究。对程序员思惟能力训练和培训、程序员职业规划有浓厚兴趣。