在我们做的可视化大屏项目中,经常会遇到飞线的效果。 在我们的大屏编辑器中,可以通过拖拽+配置参数的方式很快就能够实现。下面是我们使用大屏编辑器实现的一个项目效果:

中间地图就有飞线的效果。

抛开编辑器的快速实现不说,我们大致来说下canvas绘制飞线的大致原理。

贝塞尔曲线

飞线的路径主要是一个贝塞尔曲线,canvas绘制贝塞尔曲线比较容易。canvas支持绘制二次和三次,在本次示例中,主要还是绘制二次贝塞尔曲线为主。canvas中指定二次贝塞尔曲线路径的函数如下:

ctx.quadraticCurveTo(cpx, cpy, x, y);

有关贝塞尔曲线的基础知识,读者可以自行学习,此处不再赘述。

渐变实现

从图中,可以看出飞线的效果是淡入的效果,颜色并不是一致的,起点处颜色很淡,终点处颜色就比较浓厚。

怎么样能够实现这种效果呢? 答案就是渐变,我们知道,canvas支持线性渐变和放射渐变。但是这两种渐变似乎都不太适合曲线的路径。

事实上,我们会考虑使用线性渐变。因为飞线效果中,曲线的弯曲程度都不太大,所以使用线性渐变,曲线造成的差异,人眼是感觉不出来的。

嗯嗯,图形学就是欺骗的艺术。

只要在线的起点和终点创建一个线性渐变,起点的颜色非透明度是0,终点的非透明度是1即可达到目标。

示例代码如下:

  function createGradient(ctx,p0,p1){
var grd = ctx.createLinearGradient(p0.x,p0.y,p1.x,p1.y);
grd.addColorStop(0,'rgba(255,0,255,0)');
grd.addColorStop(1,'rgba(255,0,255,1)');
return grd;
}
ctx.beginPath();
ctx.moveTo(P0.x,P0.y);
ctx.quadraticCurveTo(Q01.x,Q01.y,B1.x,B1.y);
ctx.lineCap = 'round';
ctx.lineWidth =3;
ctx.strokeStyle = createGradient(ctx,P0,P2);
ctx.shadowColor = 'rgba(255,0,255,1)';
ctx.shadowBlur = 5;
ctx.stroke();

流动效果

流动效果就是线条从起点开始,慢慢飞到终点的效果。 技术角度来说,就是绘制二次曲线百分之几的一部分,百分比的数值从0增加到1,然后又回到0,周而复始。

代码如下:

        let percent = 0.0;
function render(){
ctx.save();
//按百分比绘制
ctx.restore();
percent += 0.005;
if(percent > 1){
percent = 0.;
}
requestAnimationFrame(render);
}

问题的关键在于如何绘制贝塞尔曲线的一部分。 一种思路是使用二次贝塞尔曲线的公式,把曲线分成很多片段来进行模拟,然而这种方式的效率并不高。 其实可以使用插值的方式来获取一段贝塞尔曲线。代码如下:

    // 参考https://xiaozhuanlan.com/topic/9506147283#section0t
let P0 = startPoint, P1 = controlPoint,P2 = endPoint;
let Q01 = interpolation(P0,P1,percent),
Q11 = interpolation(P1,P2,percent),
B1 = interpolation(Q01,Q11,percent);
function interpolation(P0,P1,t) {
var Q = {
x: P0.x * (1 - t) + P1.x * (t),
y: P0.y * (1 - t) + P1.y * (t),
};
return Q;
}

有关上面插值的原理,可以参考下面的说明,摘取字文章:

https://xiaozhuanlan.com/topic/9506147283#section-5

二次贝塞尔曲线

我们知道二次贝塞尔曲线有三个点P0、P1、P2。二次贝塞尔曲线的表达方程如下:

B(t) = (1-t)2 * P0 + 2t(1-t) * P1 + t2 * P2

其中: $t \in $[0,1]

借助上面一次贝塞尔曲线的计算方法,可以通过以下步骤来确定二次贝塞尔曲线的B(t)点:

  • 选定 $t \in $[0,1]
  • 通过插值运算法则,在P0和P1所组成的线段上,计算出P0和P1点之间的插值点Q0,其中插值的比例值是t。根据插值规则有:length( P0, Q0 ) = length( P0, P1 ) * t
  • 通过插值运算法则,在P1和P2所组成的线段上,计算出P1和P2点之间的插值点Q1,其中插值的比例是t。
  • 通过插值运算法则,在Q1和Q2所组成的线段上,计算出P1和P2点之间的插值点B,其中插值的比例是t。

    上述过程中计算出来的点B就是在曲线上面点。上述过程如下图所示:

从图中可以得出结论:

  • 直线(Q0,Q1)和曲线相切于B点。

另外还有隐藏的结论:

  • 曲线(P0,B)也是贝塞尔曲线,P0是曲线的起始点,B是曲线的终止点,而Q0是控制点
  • 曲线(B,P2)也是贝塞尔曲线,B是曲线的起始点,P2是曲线的终止点,而Q1是控制点

上面两个结论会很有用,有了这个两个结论,前面“迭代(分片)”绘制部分贝塞尔的方法,可以用更加简单的方法替代,这在稍后详细说明。

如果将t的值从0过渡到1,不断计算点B,这些点的集合就可以组成一条二次贝塞尔曲线。下面图形动画复现了这个效果:

通过上面的方式,就可以绘制流动的飞线效果了,如下图所示:

加上阴影

默认线条的样式并不是很好看,如果加上阴影,可以让效果更加丰满。 加上阴影也很简单,代码如下:

 ctx.shadowColor = 'rgba(255,0,255,1)';
ctx.shadowBlur = 5;

最终的飞线效果参考下图:

结语

如果对可视化感兴趣,可以和我交流,微信541002349. 如果你对我们的大屏编辑器产品或者3d组态编辑器感兴趣,可以加我微信交流,或者发邮件也可以,terry.tan@servasoft.com。 另外关注公众号“ITMan彪叔” 可以及时收到更多有价值的文章。

canvas绘制飞线效果的更多相关文章

  1. canvas绘制图像轮廓效果

    在2d图形可视化开发中,经常要绘制对象的选中效果. 一般来说,表达对象选中可以使用边框,轮廓或者发光的效果.  发光的效果,可以使用canvas的阴影功能,比较容易实现,此处不在赘述. 绘制边框 绘制 ...

  2. 数字雨(Javascript使用canvas绘制Matrix,效果很赞哦)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  3. HTML5 Canvas绘制的下雪效果

    在HTML页面的HEAD区域直接引入snow.js即可,如下:<script type="text/javascript" src="js/snow.js" ...

  4. 神奇的canvas——点与线绘制的绚丽动画效果

    代码地址如下:http://www.demodashi.com/demo/11636.html 前言 之前在某网站上看到了一个canvas绘制的动画效果,虽然组成的元素很简单,只有点和线,但是视觉效果 ...

  5. shader飞线改进版

    项目github地址:https://github.com/ecojust/flyline 前面写过一个飞线(基于THREE.Line进行的颜色变化),只是简单地将可视区片元颜色的alpha通道值设为 ...

  6. 使用canvas绘制渐变色矩形和使用按键控制人物移动

    使用canvas绘制渐变色矩形和使用按键控制人物移动 1.使用canvas绘制渐变色矩形 效果演示 相关代码: <!DOCTYPE html> <html lang="en ...

  7. 测试canvas绘制旋转文字的性能

    canvas 绘制各种动画效果时,我们经常会使用画布旋转,使绘制上去的元素有旋转的效果. 最近在项目中碰到了很严重的性能问题,经常排查发现是因为绘制批量文字时使用了画布旋转,且每行文字的旋转角度是不一 ...

  8. canvas绘制经典星空连线效果

    来自:https://segmentfault.com/a/1190000009675230 下面开始coding:先写个canvas标签 <canvas height="620&qu ...

  9. 【带着canvas去流浪(5)】绘制K线图

    目录 一. 任务说明 二. 重点提示 三. 示例代码 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:<大史住在大前端>原创博文 ...

  10. 带着canvas去流浪系列之五 绘制K线图

    [摘要] 用canvas原生API实现百度Echarts 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...

随机推荐

  1. 29.4K star! 仅需几行代码快速构建机器学习 Web 应用项目,无需前端技能!

    大家好,我是狂师! 今天给大家推荐一款开源的Python库:Gradio! Gradio是一个开源的Python库,用于创建机器学习和数据科学的交互式应用和演示. 项目地址: https://gith ...

  2. 5款超好用的AI换脸软件,一键视频直播换脸(附下载链接)

    随着AIGC的火爆,AI换脸技术也被广泛应用于娱乐.广告.电影制作等领域,本期文章系统介绍了市面上超火的5款AI软件 换脸整合包收录了全部5款AI工具,请按照需要选择下载: 百度网盘:https:// ...

  3. dubbo~javax.validation和jakarta.validation的介绍与排雷

    javax.validation和jakarta.validation都是用于Java中进行数据验证(validation)的相关API,它们提供了一套标准的验证框架,用于验证Java对象的属性是否符 ...

  4. Opencv笔记(12)傅里叶变换

    在之前了解的OpenCV为我们实现的图像变换,这些本质上是从图像到输出图像的映射,即输入仍是一幅图像.本章的傅里叶变换,输出数组的值在含义上和原图像的强度值大不相同,是输入图像的频域表示. cv::d ...

  5. JavaSE print printf println 区别

    *print与println,printf区别 System.out.print();括号内必须含有参数 System.out.println();括号内可以不含参数,此时代表newline即换行; ...

  6. web游览器的标签页仿 ios mac 苹果的墓碑机制 (js代码)

    背景: 本来项目开发系统防挂机功能,在其余游览器中均可以使用.但是呢在苹果的safair游览器中会出现几率失效,最后经过排查发现是苹果的墓碑机制导致.即:此标签页活跃,其他标签页假死.然后就导致防挂机 ...

  7. 填IP那个就算是接口式开发,这回随便填

    ///////////////////////////////////////////////////////////using namespace std; #include<stdlib.h ...

  8. 前端使用 Konva 实现可视化设计器(14)- 折线 - 最优路径应用【代码篇】

    话接上回<前端使用 Konva 实现可视化设计器(13)- 折线 - 最优路径应用[思路篇]>,这一章继续说说相关的代码如何构思的,如何一步步构建数据模型可供 AStar 算法进行路径规划 ...

  9. 网络世界的脊柱——OSI七层模型

    简介 OSI代表开放系统互联(Open Systems Interconnection),这是国际标准化组织(ISO)提出的一个概念模型,用于描述网络通信的功能划分.简单来说,OSI模型把复杂的网络通 ...

  10. Postman使用记录,通过表格动态赋值循环调用接口 - Using CSV and JSON data files in the Postman Collection Runner

    1.GET请求,通过导入csv文件来处理 GET http://localhost:8080/web/addstudent?sno={{sno}}&name={{name}}&sex= ...