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 动态生成方法的例子
Jul 22 Javascript
jquery ready()的几种实现方法小结
Jun 18 Javascript
js 有框架页面跳转(target)三种情况下的应用
Apr 09 Javascript
JavaScript中创建字典对象(dictionary)实例
Mar 31 Javascript
js滑动提示效果代码分享
Mar 10 Javascript
jQuery处理XML文件的几种方法
Jun 14 Javascript
JS生成不重复的随机数组的简单实例
Jul 10 Javascript
JS继承之借用构造函数继承和组合继承
Sep 07 Javascript
JavaScript编写一个简易购物车功能
Sep 17 Javascript
浅谈jquery中next与siblings的区别
Oct 27 Javascript
基于jQuery封装的分页组件
Jun 26 jQuery
谈谈为什么你的 JavaScript 代码如此冗长
Jan 30 Javascript
JavaScript原始值与包装对象的详细介绍
May 11 #Javascript
vue组件的路由高亮问题解决方法
原生Js 实现的简单无缝滚动轮播图的示例代码
May 10 #Javascript
Angular性能优化之第三方组件和懒加载技术
Vue通过懒加载提升页面响应速度
如何开发一个渐进式Web应用程序PWA
Html5生成验证码的示例代码
May 10 #Javascript
You might like
将兴奋、喜悦和坎加斯带到戴安娜:亚马逊公主
2020/03/03 欧美动漫
php缩放图片(根据宽高的等比例缩放)实例介绍
2013/06/09 PHP
php解析字符串里所有URL地址的方法
2015/04/03 PHP
基于jQueryUI和Corethink实现百度的搜索提示功能
2016/11/09 PHP
PHP实现读取文件夹及批量重命名文件操作示例
2019/04/15 PHP
js操作ajax返回的json的注意问题!
2010/02/23 Javascript
js获取图片大小的函数代码
2011/09/20 Javascript
异步JS框架的作用以及实现方法
2015/10/29 Javascript
前端jquery部分很精彩
2016/05/03 Javascript
分享JavaScript监听全部Ajax请求事件的方法
2016/08/28 Javascript
几句话带你理解JS中的this、闭包、原型链
2016/09/26 Javascript
详解百度百科目录导航树小插件
2017/01/08 Javascript
微信小程序的动画效果详解
2017/01/18 Javascript
Angular 4依赖注入学习教程之InjectToken的使用(八)
2017/06/04 Javascript
在Vue中使用echarts的实例代码(3种图)
2017/07/10 Javascript
微信小程序 swiper组件构建轮播图的实例
2017/09/20 Javascript
bootstrap可编辑下拉框jquery.editable-select
2017/10/12 jQuery
微信小程序页面上下滚动效果
2020/11/18 Javascript
vue element upload实现图片本地预览
2019/08/20 Javascript
jQuery实现的移动端图片缩放功能组件示例
2020/05/01 jQuery
vue 项目软键盘回车触发搜索事件
2020/09/09 Javascript
python实现删除文件与目录的方法
2014/11/10 Python
Python下载网络小说实例代码
2018/02/03 Python
python实现寻找最长回文子序列的方法
2018/06/02 Python
python使用tornado实现简单爬虫
2018/07/28 Python
使用Python实现将list中的每一项的首字母大写
2019/06/11 Python
Pycharm生成可执行文件.exe的实现方法
2020/06/02 Python
JAVA代码查错题
2014/10/10 面试题
毕业生求职信的经典写法
2014/01/31 职场文书
阳光体育活动方案
2014/02/16 职场文书
空乘英文求职信
2014/04/13 职场文书
培训科主任岗位职责
2014/08/08 职场文书
婚礼迎宾词大全
2015/08/10 职场文书
2016暑期政治学习心得体会
2016/01/23 职场文书
日本读研:怎样写好一篇日本研究计划书?
2019/07/15 职场文书
关于python pygame游戏进行声音添加的技巧
2021/10/24 Python