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 相关文章推荐
网页常用特效代码整理
Jun 23 Javascript
javascript 图片上传预览-兼容标准
Jun 01 Javascript
Javascript学习笔记9 prototype封装继承
Jan 11 Javascript
jQuery实现图片信息的浮动显示实例代码
Aug 28 Javascript
jquery实现当滑动到一定位置时固定效果
Jun 17 Javascript
JavaScript弹出新窗口后向父窗口输出内容的方法
Apr 06 Javascript
js简单实现竖向tab选项卡的方法
May 04 Javascript
JavaScript字符串对象(string)基本用法示例
Jan 18 Javascript
详解Require.js与Sea.js的区别
Aug 05 Javascript
Javascript数组方法reduce的妙用之处分享
Jun 10 Javascript
javascript使用正则表达式实现注册登入校验
Sep 23 Javascript
TypeScript魔法堂之枚举的超实用手册
Oct 29 Javascript
JavaScript原始值与包装对象的详细介绍
May 11 #Javascript
vue组件的路由高亮问题解决方法
原生Js 实现的简单无缝滚动轮播图的示例代码
May 10 #Javascript
Angular性能优化之第三方组件和懒加载技术
Vue通过懒加载提升页面响应速度
如何开发一个渐进式Web应用程序PWA
Html5生成验证码的示例代码
May 10 #Javascript
You might like
PHP静态类
2006/11/25 PHP
PHP 数组教程 定义数组
2009/10/23 PHP
3个PHP多维数组转为一维数组的方法实例
2014/03/13 PHP
WIN8.1下搭建PHP5.6环境
2015/04/29 PHP
[原创]smarty简单模板变量输出方法
2016/07/09 PHP
微信公众平台开发-微信服务器IP接口实例(含源码)
2017/03/05 PHP
php curl简单采集图片生成base64编码(并附curl函数参数说明)
2019/02/15 PHP
Aster vs Newbee BO3 第三场2.18
2021/03/10 DOTA
script标签的 charset 属性使用说明
2010/12/04 Javascript
document.createElement()用法及注意事项(ff下不兼容)
2013/03/13 Javascript
jQuery渐变发光导航菜单的实例代码
2013/03/27 Javascript
json+jQuery实现的无限级树形菜单效果代码
2015/08/27 Javascript
JS中Eval解析JSON字符串的一个小问题
2016/02/21 Javascript
jQuery.Uploadify插件实现带进度条的批量上传功能
2016/06/08 Javascript
微信小程序 教程之列表渲染
2016/10/18 Javascript
node 利用进程通信实现Cluster共享内存
2017/10/27 Javascript
vue计算属性时v-for处理数组时遇到的一个bug问题
2018/01/21 Javascript
AngularJS使用$http配置对象方式与服务端交互方法
2018/08/13 Javascript
vue中Element-ui 输入银行账号每四位加一个空格的实现代码
2018/09/14 Javascript
Vue.js中对css的操作(修改)具体方式详解
2018/10/30 Javascript
微信小程序实现上拉加载功能
2019/11/20 Javascript
JavaScript运行机制实例分析
2020/04/11 Javascript
在vue-cli3中使用axios获取本地json操作
2020/07/30 Javascript
[01:10]DOTA2次级职业联赛 - Fly战队宣传片
2014/12/01 DOTA
Python中replace方法实例分析
2014/08/20 Python
Python实现处理逆波兰表达式示例
2018/07/30 Python
Python3.5面向对象编程图文与实例详解
2019/04/24 Python
Python判断字符串是否xx开始或结尾的示例
2019/08/08 Python
Django User 模块之 AbstractUser 扩展详解
2020/03/11 Python
Python collections.defaultdict模块用法详解
2020/06/18 Python
使用Python制作一盏 3D 花灯喜迎元宵佳节
2021/02/26 Python
英国最大的电脑零售连锁店集团:PC World
2016/10/10 全球购物
简历自荐信
2013/12/02 职场文书
高中微机老师自我鉴定
2014/02/16 职场文书
入党自荐书范文
2015/03/05 职场文书
教师节作文之小学四年级
2019/09/03 职场文书