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 29 Javascript
(function($){...})(jQuery)的意思
Jul 22 Javascript
改变隐藏的input中value值的方法
Mar 19 Javascript
Node.js环境下JavaScript实现单链表与双链表结构
Jun 12 Javascript
JavaScript每天必学之基础知识
Sep 17 Javascript
JS声明式函数与赋值式函数实例分析
Dec 13 Javascript
javascript 注释代码的几种方法总结
Jan 04 Javascript
vue.js todolist实现代码
Oct 29 Javascript
微信小程序使用slider设置数据值及switch开关组件功能【附源码下载】
Dec 09 Javascript
JavaScript实现元素滚动条到达一定位置循环追加内容
Dec 28 Javascript
vue 虚拟dom的patch源码分析
Mar 01 Javascript
vue组件三大核心概念图文详解
May 30 Javascript
JavaScript原始值与包装对象的详细介绍
May 11 #Javascript
vue组件的路由高亮问题解决方法
原生Js 实现的简单无缝滚动轮播图的示例代码
May 10 #Javascript
Angular性能优化之第三方组件和懒加载技术
Vue通过懒加载提升页面响应速度
如何开发一个渐进式Web应用程序PWA
Html5生成验证码的示例代码
May 10 #Javascript
You might like
php页面防重复提交方法总结
2013/11/25 PHP
使用symfony命令创建项目的方法
2016/03/17 PHP
php监测数据是否成功插入到Mysql数据库的方法
2016/11/25 PHP
PHP addslashes()函数讲解
2019/02/03 PHP
用javascript获取地址栏参数
2006/12/22 Javascript
javascript 在网页中的运用(asp.net)
2009/11/23 Javascript
导航跟随滚动条置顶移动示例代码
2013/09/11 Javascript
一款由jquery实现的整屏切换特效
2014/09/15 Javascript
JavaScript中数据结构与算法(五):经典KMP算法
2015/06/19 Javascript
javascript实现给定半径求出圆的面积
2015/06/26 Javascript
一个极为简单的requirejs实现方法
2016/10/20 Javascript
在vue-cli脚手架中配置一个vue-router前端路由
2017/07/03 Javascript
浅谈node中的exports与module.exports的关系
2017/08/01 Javascript
10分钟上手vue-cli 3.0 入门介绍
2018/04/04 Javascript
vue实现一个炫酷的日历组件
2018/10/08 Javascript
javaScript实现游戏倒计时功能
2018/11/17 Javascript
vue中axios实现数据交互与跨域问题
2019/05/12 Javascript
浅谈vue使用axios的回调函数中this不指向vue实例,为undefined
2020/09/21 Javascript
使用jQuery实现购物车
2020/10/29 jQuery
Python标准库sched模块使用指南
2017/07/06 Python
Python cookbook(数据结构与算法)在字典中将键映射到多个值上的方法
2018/02/18 Python
Python实现注册、登录小程序功能
2018/09/21 Python
tensorflow dataset.shuffle、dataset.batch、dataset.repeat顺序区别详解
2020/06/03 Python
Python threading模块condition原理及运行流程详解
2020/10/05 Python
css3media响应式布局实例
2016/07/08 HTML / CSS
国际化的太阳镜及太阳镜配件零售商:Sunglass Hut
2016/07/26 全球购物
德国最新街头服饰网上商店:BODYCHECK
2019/09/15 全球购物
如何配置、使用和清除Smarty缓存
2015/12/23 面试题
高中毕业生自我鉴定例文
2013/12/29 职场文书
给老婆的搞笑检讨书
2014/01/12 职场文书
校本课程教学计划
2015/01/19 职场文书
辛德勒的名单观后感
2015/06/03 职场文书
鉴史问廉观后感
2015/06/10 职场文书
小学教师教育随笔
2015/08/14 职场文书
2016个人廉洁自律承诺书
2016/03/25 职场文书
js基础语法与maven项目配置教程案例
2021/07/15 Javascript