canvas绘制折线路径动画实现


Posted in Javascript onMay 12, 2021

最近有读者加我微信咨询这个问题:

canvas绘制折线路径动画实现

其中的效果是一个折线路径动画效果,如下图所示:

canvas绘制折线路径动画实现

要实现以上路径动画,一般可以使用svg的动画功能。或者使用canvas绘制,结合路径数学计算来实现。
如果用canvas来绘制,其中的难点在于:

  • 需要计算子路径,这块计算比较复杂。(当然是可以实现的)
  • 渐变的计算, 从图中可以看出,动画的子路径是有渐变效果的,如果要分段计算渐变也很复杂。

本文介绍一种思路,使用clip方法,动态移动clip的区域,来达到近似的效果。具体怎么做。

绘制灰色路径

绘制路径的代码比较简单,此处就不详细说明,下面代码就模拟了了一个折线路径的绘制:

ctx.beginPath();    
 ctx.moveTo(100,100);
 ctx.lineTo(200,100);
 ctx.lineTo(230,200);
 ctx.lineTo(250,50);
 ctx.lineTo(270,180);
 ctx.lineTo(300,60);
 ctx.lineTo(330,160);
 ctx.lineTo(350,60);
 ctx.lineTo(380,100);
 ctx.lineTo(480,100);
 ctx.strokeStyle = "gray";
 ctx.lineJoin = "round";
 ctx.stroke();

效果如下:

canvas绘制折线路径动画实现

绘制亮色路径

绘制亮色路径的代码和绘制灰色路径的代码一样,只是样式是一个亮的颜色:

ctx.save();
            ctx.beginPath();    
            ctx.moveTo(100,100);
            ctx.lineTo(200,100);
            ctx.lineTo(230,200);
            ctx.lineTo(250,50);
            ctx.lineTo(270,180);
            ctx.lineTo(300,60);
            ctx.lineTo(330,160);
            ctx.lineTo(350,60);
            ctx.lineTo(380,100);
            ctx.lineTo(480,100);
            ctx.strokeStyle = "gray";
            ctx.lineJoin = "round";
            ctx.stroke();

效果如下:

canvas绘制折线路径动画实现

clip控制亮色路径的绘制区域

canvas的clip方法可以控制绘制的区域,通过该方法,可以控制智绘制路径的一部分:

ctx.beginPath();
        ctx.rect(offset,0,100,500); // offset 等于0
        ctx.clip();
           ...
        ctx.stroke();

clip之后,亮色路径就只会绘制一部分,如下图:

canvas绘制折线路径动画实现

动画效果

通过不断变化offset的值,就可以大道亮色路径移动的效果,代码如下:

offset += 2;
 if(offset > 600){
       offset = 100;
 }
requestAnimationFrame(animate);

最终效果如下:

canvas绘制折线路径动画实现

渐变

我们知道渐变没法沿着任意路径,如果计算折线,分段计算渐变又很麻烦。 其实在本案例中,虽然是折线,但是整体的运动方向总是从左往右的,所以可以用从左往右的渐变来近似模拟既可以:

function createGradient(ctx,x0,y0,x1,y1){
          var grd = ctx.createLinearGradient(x0,y0,x1,y1);
           grd.addColorStop(0,'#129ab3');
           grd.addColorStop(1,"#19b5fe");
           return grd;
}

ctx.strokeStyle = createGradient(ctx,offset,0,offset + 100,0);

最终效果如下所示:

canvas绘制折线路径动画实现

全部代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>line animate</title>
    <style>
        canvas {
            border: 1px solid #000;
        }
    </style>
</head>
<body>
    <canvas id="canvas" width="600" height="400"></canvas>
    <script>
        var ctx = document.getElementById( 'canvas' ).getContext( '2d' );
        var w = canvas.width,
                h = canvas.height;

        var x = w / 2,y = h / 2;

        function setupCanvas(canvas) {
            let width = canvas.width,
            height = canvas.height,
            dpr = window.devicePixelRatio || 1.0;
            if (dpr != 1.0 ) {
            canvas.style.width = width + "px";
            canvas.style.height = height + "px";
            canvas.height = height * dpr;
            canvas.width = width * dpr;
            ctx.scale(dpr, dpr);
            }
        }
        setupCanvas(canvas);
        var offset = 100;
        function createGradient(ctx,x0,y0,x1,y1){
           var grd = ctx.createLinearGradient(x0,y0,x1,y1);
           grd.addColorStop(0,'#9a12b3');
           grd.addColorStop(1,"#19b5fe");
           return grd;
        }

        function animate(){
            ctx.fillStyle = "black";
            ctx.fillRect(0,0,canvas.width,canvas.height);
            ctx.lineWidth = 3;
            ctx.save();
            ctx.beginPath();    
            ctx.moveTo(100,100);
            ctx.lineTo(200,100);
            ctx.lineTo(230,200);
            ctx.lineTo(250,50);
            ctx.lineTo(270,180);
            ctx.lineTo(300,60);
            ctx.lineTo(330,160);
            ctx.lineTo(350,60);
            ctx.lineTo(380,100);
            ctx.lineTo(480,100);
            ctx.strokeStyle = "gray";
            ctx.lineJoin = "round";
            ctx.stroke(); 

            ctx.beginPath();
            ctx.rect(offset,0,150,500);
            ctx.clip();
            ctx.beginPath();
            ctx.moveTo(100,100);
            ctx.lineTo(200,100);
            ctx.lineTo(230,200);
            ctx.lineTo(250,50);
            ctx.lineTo(270,180);
            ctx.lineTo(300,60);
            ctx.lineTo(330,160);
            ctx.lineTo(350,60);
            ctx.lineTo(380,100);
            ctx.lineTo(480,100);
            ctx.lineWidth = 4;
            ctx.strokeStyle = createGradient(ctx,offset,0,offset + 150,0);
            ctx.lineCap = "round";
            // ctx.globalCompositeOperation = 'lighter';
            ctx.lineJoin = "round";
            ctx.stroke(); 

            ctx.restore();

            offset += 2;
            if(offset > 600){
                offset = 100;
            }

            requestAnimationFrame(animate);
        }

        animate();
    </script>
</body>
</html>

总结

其实整体思路是用了近似,而不是严格的控制路径长度和渐变效果,这样可以更方便实现以上功能。  其实人眼有时候是分辨不出来一些细节,可视化,有的时候只有能够达到让人“觉得”是那么回事,其实目的也就达到了。
以上方案只能适用于,折线路径的整体方向是一致的。如果整体方向是先水平向右,然后在垂直向下,或者甚至出现往回拐的情况,就不适合了。

到此这篇关于canvas绘制折线路径动画实现的文章就介绍到这了,更多相关canvas折线路径动画内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章,希望大家以后多多支持三水点靠木!

 
Javascript 相关文章推荐
一个小型js框架myJSFrame附API使用帮助
Jun 28 Javascript
jQuery Study Notes学习笔记 (二)
Aug 04 Javascript
js实现选中复选框文字变色的方法
Aug 14 Javascript
关于json字符串与实体之间的严格验证代码
Nov 10 Javascript
JavaScript常见的五种数组去重的方式
Dec 15 Javascript
Angular2中select用法之设置默认值与事件详解
May 07 Javascript
Vue单文件组件的如何使用方式介绍
Jul 28 Javascript
静态页面实现 include 引入公用代码的示例
Sep 25 Javascript
js中apply()和call()的区别与用法实例分析
Aug 14 Javascript
详解js 创建对象的几种方法
Mar 08 Javascript
turn.js异步加载实现翻书效果
Jul 25 Javascript
vue2.0实现列表数据增加和删除
Jun 17 Javascript
JavaScript原始值与包装对象的详细介绍
May 11 #Javascript
vue组件的路由高亮问题解决方法
原生Js 实现的简单无缝滚动轮播图的示例代码
May 10 #Javascript
Angular性能优化之第三方组件和懒加载技术
Vue通过懒加载提升页面响应速度
如何开发一个渐进式Web应用程序PWA
Html5生成验证码的示例代码
May 10 #Javascript
You might like
PHP URL地址获取函数代码(端口等) 推荐
2010/05/15 PHP
php中通过Ajax如何实现异步文件上传的代码实例
2011/05/07 PHP
php+js实现图片的上传、裁剪、预览、提交示例
2013/08/27 PHP
浅析php数据类型转换
2014/01/09 PHP
php抛出异常与捕捉特定类型的异常详解
2016/10/26 PHP
PHP使用curl函数发送Post请求的注意事项
2016/11/26 PHP
php抽象方法和抽象类实例分析
2016/12/07 PHP
php使用ftp实现文件上传与下载功能
2017/07/21 PHP
PHP pthreads v3下worker和pool的使用方法示例
2020/02/21 PHP
JavaScript 异步调用框架 (Part 6 - 实例 &amp; 模式)
2009/08/04 Javascript
使用upstart把nodejs应用封装为系统服务实例
2014/06/01 NodeJs
探讨AngularJs中ui.route的简单应用
2016/11/16 Javascript
使用JS正则表达式 替换括号,尖括号等
2016/11/29 Javascript
jquery实现图片轮播器
2017/05/23 jQuery
JavaScript时间与时间戳的转换操作实例分析
2018/12/07 Javascript
今天,小程序正式支持 SVG
2019/04/20 Javascript
ES6 Iterator接口和for...of循环用法分析
2019/07/31 Javascript
JavaScript Canvas编写炫彩的网页时钟
2019/10/16 Javascript
[02:53]DOTA2英雄基础教程 山岭巨人小小
2013/12/09 DOTA
Pandas 对Dataframe结构排序的实现方法
2018/04/10 Python
Python 3.7新功能之dataclass装饰器详解
2018/04/21 Python
python输入整条数据分割存入数组的方法
2018/11/13 Python
详解django2中关于时间处理策略
2019/03/06 Python
Python函数的默认参数设计示例详解
2019/12/01 Python
python可视化text()函数使用详解
2020/02/11 Python
简单了解如何封装自己的Python包
2020/07/08 Python
移动端适配 使px自动转换rem
2019/08/26 HTML / CSS
北大研究生linux应用求职信
2013/10/29 职场文书
一名女生的自荐信
2013/12/08 职场文书
监察建议书格式
2014/05/19 职场文书
教师暑期培训感言
2014/08/15 职场文书
孝敬父母的活动方案
2014/08/28 职场文书
银行贷款委托书范本
2014/10/11 职场文书
关于工作经历的证明书
2014/10/11 职场文书
酒店财务总监岗位职责
2015/04/03 职场文书
python之np.argmax()及对axis=0或者1的理解
2021/06/02 Python