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 相关文章推荐
javascript String 对象
Apr 25 Javascript
JQuery AJAX提交中文乱码的解决方案
Jul 02 Javascript
jquery trigger伪造a标签的click事件取代window.open方法
Jun 23 Javascript
Javascript进制转换实例分析
May 14 Javascript
jquery京东商城双11焦点图多图广告特效代码分享
Sep 06 Javascript
js从外部获取图片的实现方法
Aug 05 Javascript
轻松掌握JavaScript单例模式
Aug 25 Javascript
浅谈webpack打包生成的bundle.js文件过大的问题
Feb 22 Javascript
玩转vue的slot内容分发
Sep 22 Javascript
详解关于webpack多入口热加载很慢的原因
Apr 24 Javascript
vue 使用localstorage实现面包屑的操作
Nov 16 Javascript
详解vue 组件注册
Nov 20 Vue.js
JavaScript原始值与包装对象的详细介绍
May 11 #Javascript
vue组件的路由高亮问题解决方法
原生Js 实现的简单无缝滚动轮播图的示例代码
May 10 #Javascript
Angular性能优化之第三方组件和懒加载技术
Vue通过懒加载提升页面响应速度
如何开发一个渐进式Web应用程序PWA
Html5生成验证码的示例代码
May 10 #Javascript
You might like
ThinkPHP CURD方法之table方法详解
2014/06/18 PHP
php导入大量数据到mysql性能优化技巧
2014/12/29 PHP
PHP搭建大文件切割分块上传功能示例
2017/01/04 PHP
ZendFramework2连接数据库操作实例
2017/04/18 PHP
ThinkPHP5框架缓存查询操作分析
2018/05/30 PHP
4种Windows系统下Laravel框架的开发环境安装及部署方法详解
2020/04/06 PHP
JavaScript Base64编码和解码,实现URL参数传递。
2006/09/18 Javascript
JavaScript 拖拉缩放效果
2008/12/10 Javascript
JQuery 表格操作(交替显示、拖动表格行、选择行等)
2009/07/29 Javascript
Jquery实现简单的动画效果代码
2012/03/18 Javascript
Javascript Request获取请求参数如何实现
2012/11/28 Javascript
javascript 实现字符串反转的三种方法
2013/11/23 Javascript
js判断页面中是否有指定控件的简单实例
2014/03/04 Javascript
基于NodeJS的前后端分离的思考与实践(六)Nginx + Node.js + Java 的软件栈部署实践
2014/09/26 NodeJs
Javascript基础_简单比较undefined和null 值
2016/06/14 Javascript
遍历js中对象的属性和值的实例
2016/11/21 Javascript
基于Require.js使用方法(总结)
2017/10/26 Javascript
vue刷新和tab切换实例
2018/02/11 Javascript
利用adb shell和node.js实现抖音自动抢红包功能(推荐)
2018/02/22 Javascript
js使用cookie实现记住用户名功能示例
2019/06/13 Javascript
三步搞定:Vue.js调用Android原生操作
2020/09/07 Javascript
[02:20]DOTA2亚洲邀请赛 IG战队出场宣传片
2015/02/07 DOTA
python实现apahce网站日志分析示例
2014/04/02 Python
python实现txt文件格式转换为arff格式
2018/05/31 Python
详解Python 多线程 Timer定时器/延迟执行、Event事件
2019/06/27 Python
redis数据库及与python交互用法简单示例
2019/11/01 Python
浅谈pandas.cut与pandas.qcut的使用方法及区别
2020/03/03 Python
Python字符串hashlib加密模块使用案例
2020/03/10 Python
曼城官方网上商店:Manchester City
2019/09/10 全球购物
大专生毕业的自我评价
2014/02/06 职场文书
车间安全生产标语
2014/06/06 职场文书
喝酒驾驶检讨书
2014/10/01 职场文书
2014年电话客服工作总结
2014/12/09 职场文书
农村环境卫生倡议书
2015/04/29 职场文书
《亲亲我的妈妈》观后感(3篇)
2019/09/26 职场文书
利用Python脚本写端口扫描器socket,python-nmap
2022/07/23 Python