Canvas绘制圆点线段

简介: Canvas绘制圆点线段

最近一个小伙遇到一个需求,客户需要绘制圆点样式的线条。大致效果是这样的:

微信图片_20220424123403.png

圆点线


思路一:计算并使用arc填充


他自己实现了一种思路,然后咨询我有没有更好的思路。先看看他的思路是如何实现的,大致代码如下:


// 绘制圆点线,通过计算在线条上进行插值运算,计算出需要绘制圆点的一系列点位
// 然后调用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();              
    }


通过上面的简单的示意代码可以看出,绘制逻辑是通过计算直线之间的点位,然后再相应的点上面绘制圆形。


该方法最终可以达到效果,可是有如下问题:

  • 存在性能问题
  • 如果是贝塞尔曲线曲线,可能会涉及到复杂的运行。贝塞尔曲线的相关知识,可以参考下文进行了解:
    深入理解贝塞尔曲线  https://xiaozhuanlan.com/topic/9506147283


当然此思路在绘制一些更加复杂的效果的时候,可能会有用。比如沿线绘制五角星,其他任意形状或者图片等等。或者要绘制的是圆圈而不是填充的圆形的效果,也需要使用此方法。


但是如果只是绘制圆点线,我们可以使用更加简便的方法,主要思路就是使用setLineDash方法+lineCap设置


思路二 setLineDash方法+lineCap设置


lineCap介绍


CanvasRenderingContext2D.lineCap 是 Canvas 2D API 指定如何绘制每一条线段末端的属性。有3个可能的值,分别是:butt, round and square。默认值是 butt。

使用时,直接赋值即可:


ctx.lineCap = "butt";
ctx.lineCap = "round";
ctx.lineCap = "square";


下面从左到右分别是butt, round ,square的效果:


微信图片_20220424123412.png

lineCap


可以看出 “round”和“square”都是在原本绘制得线段之外扩展了一个半圆和一个矩形,这点在后面会用到。

相关知识,可以参考这篇文章:

canvas基础知识回顾 https://xiaozhuanlan.com/topic/5473801692


setLineDash介绍


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();


最终绘制得效果如下图所示:


微信图片_20220424123424.png

image.png


到此,又朋友可能有疑问,这个也不是圆点线得效果。其实只需要把上面得代码稍微得修改,让实线线段本身得长度变成0即可,修改代码:


...
ctx.setLineDash([0, 30]);
...


最终绘制得效果如下图所示:


微信图片_20220424123432.png

image.png


结合前面 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();


效果如下:


微信图片_20220424123437.png

image.png


此处有人可能会说,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”的情况下,还会出现尾部可能不是一个方块的效果,如下图:


微信图片_20220424123441.png

image.png


扩展


如果要绘制如下得线条样式,应该怎么做呢:


微信图片_20220424123445.png

image.png


其实也很简单,就是把同一条线段用不同得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的值。

相关文章
|
6月前
|
前端开发
canvas绘制圆环
canvas绘制圆环
|
6月前
|
Python
绘制矩形
【5月更文挑战第11天】绘制矩形。
44 1
|
4月前
|
前端开发
Canvas如何画一个线条,画布效果最好添加字体和线条回溯
Canvas如何画一个线条,画布效果最好添加字体和线条回溯
|
4月前
|
前端开发 JavaScript
canvas系列教程01——直线、三角形、多边形、矩形、调色板
canvas系列教程01——直线、三角形、多边形、矩形、调色板
93 0
|
4月前
|
前端开发
canvas系列教程02——圆、弧线、圆角矩形、曲线(气泡、心形、N叶草)、扇形
canvas系列教程02——圆、弧线、圆角矩形、曲线(气泡、心形、N叶草)、扇形
39 0
|
机器学习/深度学习 存储 人工智能
391. 完美矩形
391. 完美矩形
66 0
|
前端开发
canvas绘制五角星
canvas绘制五角星
177 0
|
C# 图形学
C#之深入理解GDI+绘制圆弧及圆角矩形等比缩放的绘制
GDI+中对于圆弧的绘制,是以给定的长方形(Rectangle`结构)为边界绘制的椭圆的一部分形成的圆弧。绘制的圆弧的中心为长方形内切椭圆的圆心(如果是正方形,则正方形的...
603 0
C#之深入理解GDI+绘制圆弧及圆角矩形等比缩放的绘制
|
前端开发 JavaScript 数据可视化
用Canvas实现简单画图(线、三角形、矩形、圆)
👋因为在B站看到一个小demo是基于canvas写的,非常喜欢,然后上掘金大数据又给我推了 《Canvas 从入门到劝朋友放弃(图解版)》,就像上手一下canvas,本来不想写笔记的,因为《Canvas 从入门到劝朋友放弃(图解版)》自己看了一下挺全的,但本着输入要有输出,所以就有了这篇文章
244 0
C#编程-132:DrawRectangle绘制矩形
C#编程-132:DrawRectangle绘制矩形
187 0
C#编程-132:DrawRectangle绘制矩形