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 相关文章推荐
Jquery Uploadify上传带进度条的简单实例
Feb 12 Javascript
利用jQuery实现可以编辑的表格
May 26 Javascript
《JavaScript DOM 编程艺术》读书笔记之JavaScript 简史
Jan 09 Javascript
深入学习JavaScript中的Rest参数和参数默认值
Jul 28 Javascript
vuejs父子组件通信的问题
Jan 11 Javascript
js鼠标经过tab选项卡时实现切换延迟
Mar 24 Javascript
使用百度地图实现地图网格的示例
Feb 06 Javascript
NestJs 静态目录配置详解
Mar 12 Javascript
微信小程序单选radio及多选checkbox按钮用法示例
Apr 30 Javascript
用node.js写一个jenkins发版脚本
May 21 Javascript
解决VUE双向绑定失效的问题
Oct 29 Javascript
微信小程序添加插屏广告并设置显示频率(一天一次)
Dec 06 Javascript
JavaScript原始值与包装对象的详细介绍
May 11 #Javascript
vue组件的路由高亮问题解决方法
原生Js 实现的简单无缝滚动轮播图的示例代码
May 10 #Javascript
Angular性能优化之第三方组件和懒加载技术
Vue通过懒加载提升页面响应速度
如何开发一个渐进式Web应用程序PWA
Html5生成验证码的示例代码
May 10 #Javascript
You might like
类的另类用法--数据的封装
2006/10/09 PHP
简单的php数据库操作类代码(增,删,改,查)
2013/04/08 PHP
php生成txt文件标题及内容的方法
2014/01/16 PHP
php实例分享之html转为rtf格式
2014/06/02 PHP
Yii2中多表关联查询hasOne hasMany的方法
2017/02/15 PHP
php中使用array_filter()函数过滤数组实例讲解
2021/03/03 PHP
javascript 数据类型转换(parseInt,parseFloat)
2010/07/20 Javascript
JS获取键盘上任意按键的值(实例代码)
2013/11/12 Javascript
JavaScript中获取高度和宽度函数总结
2014/10/08 Javascript
js时间日期格式化封装函数
2014/12/02 Javascript
使用js复制链接中的部分文字的方法
2015/07/30 Javascript
使用CamanJS在Web页面上处理图像的技巧
2015/08/18 Javascript
js实现随屏幕滚动的带缓冲效果的右下角广告代码
2015/09/04 Javascript
封装属于自己的JS组件
2016/01/27 Javascript
jQuery插件实现文字无缝向上滚动效果代码
2016/02/25 Javascript
JavaScript中的Object对象学习教程
2016/05/20 Javascript
iscroll实现下拉刷新功能
2017/07/18 Javascript
一篇文章让你彻底弄懂JS的事件冒泡和事件捕获
2017/08/14 Javascript
Electron中实现大文件上传和断点续传功能
2018/10/28 Javascript
浅谈redux, koa, express 中间件实现对比解析
2019/05/23 Javascript
使用axios请求时,发送formData请求的示例
2019/10/29 Javascript
vue开发中遇到的问题总结
2020/04/07 Javascript
python抓取某汽车网数据解析html存入excel示例
2013/12/04 Python
python3 与python2 异常处理的区别与联系
2016/06/19 Python
Python实现随机生成有效手机号码及身份证功能示例
2017/06/05 Python
解析Python的缩进规则的使用
2019/01/16 Python
Python pygame绘制文字制作滚动文字过程解析
2019/12/12 Python
html5使用canvas实现弹幕功能示例
2017/09/11 HTML / CSS
Chinti & Parker官网:奢华羊绒女装和创新针织设计
2021/01/01 全球购物
机械专业应届生求职信
2013/09/21 职场文书
劳动之星获奖感言
2014/02/01 职场文书
群众路线教育实践活动心得体会
2014/03/07 职场文书
公安交警个人对照检查材料思想汇报
2014/10/01 职场文书
2014年爱国卫生工作总结
2014/11/22 职场文书
六一亲子活动感想
2015/08/07 职场文书
PHP中多字节字符串操作实例详解
2021/08/23 PHP