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

思路一:计算并使用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();
}

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

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

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

    深入理解贝塞尔曲线

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

但是如果只是绘制圆点线,我们可以使用更加简便的方法,主要思路就是使用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的效果:

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

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

canvas基础知识回顾

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

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

到此,又朋友可能有疑问,这个也不是圆点线得效果。 其实只需要把上面得代码稍微得修改,让实线线段本身得长度变成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、前端可视化方面有深入研究。对程序员思维能力训练和培训、程序员职业规划有浓厚兴趣。

Canvas绘制圆点线段的更多相关文章

  1. canvas学习总结三:绘制路径-线段

    Canvas绘图环境中有些属于立即绘制图形方法,有些绘图方法是基于路径的. 立即绘制图形方法仅有两个strokeRect(),fillRect(),虽然strokezText(),fillText() ...

  2. Canvas学习:封装Canvas绘制基本图形API

    Canvas学习:封装Canvas绘制基本图形API Canvas Canvas学习   从前面的文章中我们了解到,通过Canvas中的CanvasRenderingContext2D对象中的属性和方 ...

  3. 使用Canvas绘制图形的基本教程

    原文地址:http://www.cnblogs.com/picaso/archive/2012/11/26/2789077.html HTML5火的正热,最近有个想法也是要用到HTML的相关功能,所以 ...

  4. HTML5之Canvas绘图——使用Canvas绘制图形的基本教程

    原文转自:http://www.cnblogs.com/picaso/archive/2012/11/26/2789077.html HTML5火的正热,最近有个想法也是要用到HTML的相关功能,所以 ...

  5. canvas总结:线段宽度与像素边界

    在canvas中,我们经常需要绘制线段,主要使用moveTo和lineTo两个方法,moveTo移动至线段起始点,lineTo将线段绘制至终点.同时,绘制线段时可以指定线段的宽度,使用lineWidt ...

  6. canvas 绘制双线技巧

    楔子 最近一个项目,需要绘制双线的效果,双线效果表示的是轨道(类似铁轨之类的),如下图所示: 负责这块功能开发的小伙,姑且称之为L吧,最开始是通过数学计算的方式来实现这种双线,也就是在原来的路径的基础 ...

  7. canvas绘制线和矩形

    ###canvas绘制矩形 HTML中的元素canvas只支持一种原生的图形绘制:矩形.所有其他的图形的绘制都至少需要生成一条路径 1.绘制矩形 canvas提供了三种方法绘制矩形: ----> ...

  8. 怎样用JavaScript和HTML5 Canvas绘制图表

    原文:https://code.tutsplus.com/zh-...原作:John Negoita翻译:Stypstive 在这篇教程中,我将展示用JavaScript和canvas作为手段,在饼状 ...

  9. HTML5学习总结——canvas绘制象棋(canvas绘图)

    一.HTML5学习总结——canvas绘制象棋 1.第一次:canvas绘制象棋(笨方法)示例代码: <!DOCTYPE html> <html> <head> & ...

随机推荐

  1. ruoyi-plus-server(一):引入Mybatis-Plus

    背景:著名开源管理系统ruoyi-vue是基于SpringBoot,Spring Security,JWT,Vue & Element 的前后端分离权限管理系统(https://gitee.c ...

  2. 愉快地使用Open Live Writer写博客

    想要坚持写博客的习惯,却又无法忍受网页编辑器的各种不方便?open live writer是一个不错的选择.对我来说最有诱惑的就是能够快速的黏贴图片.代码.使用过程遇到不少坑,最坑的就是不能使用163 ...

  3. mysql运维入门5:MySQL+kepalived高可用架构

    keepalive 类似3/4/7层交换机制的软件,也就是平时说的第三层.第四层.第七层交换 作用是检测web服务器的状态,如果有一台web服务器.mysql服务器宕机.或工作出现故障,keepali ...

  4. slf4j、log4j、 logback关系详解和相关用法

    slf4j log4j logback关系详解和相关用法 写java也有一段时间了,一直都有用slf4j log4j输出日志的习惯.但是始终都是抱着“拿来主义”的态度,复制粘贴下配置文件就开始编码了, ...

  5. BZOJ1022

    1022: [SHOI2008]小约翰的游戏John Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 2701  Solved: 1721[Submit] ...

  6. BZOJ 1050并查集+贪心

    1050: [HAOI2006]旅行comf Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3333  Solved: 1851[Submit][St ...

  7. Spring注入的对象到底是什么类型

    开篇 之前,在用spring编码调试的时候,有时候发现被自动注入的对象是原始类的对象,有时候是代理类的对象,那什么时候注入的原始类对象呢,有什么时候注入的是代理类的对象呢?心里就留下了这个疑问.后来再 ...

  8. net core获取appsetting.json的另外一种思路(全局,实时变化无需重启项目)

    最近在写net core的项目,在非controller和service里面需要用到appsetting.json文件里面的一些配置,查资料大概有几种思路: 注入,然后config.GetSectio ...

  9. Java中的集合类型体系(一)

    Java中的集合类型体系(一) 提问:为什么需要集合? 通常情况下,程序需要根据运行时才知道创建了多少对象.若非程序运行时,而在开发阶段,我们并不知道创建了多少对象,甚至不知道对象的准确类型,为了满足 ...

  10. 接口(interface)的使用

    类实现接口就具有接口的功能 实现可以多实现,实现多个接口 package cm.aff.abst; /* 接口(interface)是与类并行的一个概念 1. 接口可以看做是一个特殊的抽象类,是常量与 ...