Canvas实现贝赛尔曲线轨迹动画

栏目: Html5 · 发布时间: 5年前

内容简介:最近实现的下图的效果,跟大家分享一下假如我们要画下图曲线的动画

最近实现的下图的效果,跟大家分享一下

Canvas实现贝赛尔曲线轨迹动画

假如我们要画下图曲线的动画

Canvas实现贝赛尔曲线轨迹动画

如果每次都画一条短线连接起来,如下图被分成五段

Canvas实现贝赛尔曲线轨迹动画

再看十段

Canvas实现贝赛尔曲线轨迹动画

要是被分的段数足够多时每次画一段就很像曲线轨迹了

二次贝赛尔曲线

/**
 * 二次贝塞尔曲线动画
 * @param  {Array<number>} start 起点坐标
 * @param  {Array<number>} 曲度点坐标(也就是转弯的点,不是准确的坐标,只是大致的方向)
 * @param  {Array<number>} end 终点坐标
 * @param  {number} percent 绘制百分比(0-100)
 */
 
  function drawCurvePath(start, point, end, percent){
            ctx.beginPath();    //开始画线
            ctx.moveTo(start[0], start[1]);   //画笔移动到起点
            for (var t = 0; t <= percent / 100; t += 0.005) {
                //获取每个时间点的坐标
                var x = quadraticBezier(start[0], point[0], end[0], t);   
                var y = quadraticBezier(start[1], point[1], end[1], t);
                ctx.lineTo(x, y);   //画出上个时间点到当前时间点的直线
            }
             ctx.stroke();   //描边
        }
        
        
/**
 * 二次贝塞尔曲线方程
 * @param  {Array<number>} start 起点
 * @param  {Array<number>} 曲度点
 * @param  {Array<number>} end 终点
 * @param  {number} 绘制进度(0-1)
 */
     function quadraticBezier(p0, p1, p2, t) {
            var k = 1 - t;
            return k * k * p0 + 2 * (1 - t) * t * p1 + t * t * p2; 
        }

更加详细的贝塞尔曲线内容请参考 这篇博客

放入完整的代码中

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>二次贝塞尔曲线动画</title>
    <style>
         body {
            background: #0f1632;
        }

        #canvas {
            border: 1px solid #ccc;
        }
         #img {
            display: none; 
            <!--img直接隐藏就行,后面会直接引用-->
        }
        
    </style>
</head>

<body>
    <canvas id="canvas" width="1500" height="750"></canvas>
    <img id="img" src="https://s3.imgsha.com/2019/04/22/light.png">
    
    <script>
        var ctx = document.getElementById('canvas').getContext('2d');
        var img = document.getElementById('img');
        var percent = 0;
        var data = {
                start: [400, 200],
                point: [300, 100],
                end: [100, 400],
                department: '数据1',
                value: 4321
            }
            
        function init(){
            percent = 0;  //每次重置进程
            draw();
        }
        function draw(){
            ctx.clearRect(0, 0, 1500, 750);  //每次清除画布
            ctx.strokeStyle = '#ffffff';    //设置线条样式
            
            drawCurvePath(data.start, data.point, data.end, percent);
           
            percent += 0.8; //进程增加,这个控制动画速度
            
             if (percent <= 100) { //没有画完接着调用,画完的话重置进度
                requestAnimationFrame(draw);
            }else{
                init()
            }
        }
        function drawCurvePath(start, point, end, percent)
            //...
        }
        function quadraticBezier(p0, p1, p2, t) {
            //...
        }
    </script>
</body>

</html>

动画就出来了

Canvas实现贝赛尔曲线轨迹动画

之前说了 drawCurvePath(start, point, end, percent) 函数中 point 这个参数不是具体曲度的点,只是一个大致的方向

Canvas实现贝赛尔曲线轨迹动画

再开看一下 point 改为 [200,200] 的情况

Canvas实现贝赛尔曲线轨迹动画

添加渐变

如果想实现坠落的效果,由高到低由远及近需要给线条加一个渐变的效果

Canvas实现贝赛尔曲线轨迹动画

/**
 * 创建线性渐变
 * @param  {Array<number>} start 起点
 * @param  {Array<number>} 曲度点
 * @param  {Array<number>} end 终点
 * @param  {number} 绘制进度(0-1)
 */
function createLinearGradient(start,end,startColor,endColor){
  var lineGradient = ctx.createLinearGradient(...start, ...end);
                lineGradient.addColorStop(0, startColor);
                // lineGradient.addColorStop(0.3, '#fff');
                lineGradient.addColorStop(1, endColor);
  return lineGradient
}
//draw函数需要做些调整
function draw(){
    //ctx.strokeStyle = '#ffffff';
      ctx.strokeStyle = createLinearGradient(data.start,
                                             data.end,
                                             'rgba(255,255,255,.2)',
                                             '#fff'
                                             );
     //...
}

canvas渐变详情请参考 MDN

头部光晕

添加头部光晕需要画一个圆,并设置径向渐变,利用 drawCurvePath 函数获取x,y并重置圆的位置

Canvas实现贝赛尔曲线轨迹动画

function createHeadLight(x,y){
  ctx.beginPath();
  //创建径向渐变
  var radialGradient = ctx.createRadialGradient(x, y, 0, x, y, 20);
        radialGradient.addColorStop(0, "rgba(255,255,255,1)");
        radialGradient.addColorStop(.2, "rgba(255,255,255,.8)");
        radialGradient.addColorStop(1, "transparent");
        
        ctx.fillStyle = radialGradient;
        //画圆
        ctx.arc(x, y, 20, 0, 2 * Math.PI, false);
        ctx.fill();
}

//drawCurvePath函数需要做些调整
function drawCurvePath(start, point, end, percent){
        //...
         ctx.stroke();   //描边
         createHeadLight(x,y) //和画线频率一样画圆
    }

绘制圆 arc 参数详情参考 MDN

添加文本

添加文本和添加头部光晕很相似,都是利用 drawCurvePath 函数获取x,y并重置文本块的位置

Canvas实现贝赛尔曲线轨迹动画

/**
 * 创建文本
 * @param  {String} 部门数据
 * @param  {Number} 数据
 * @param  {Number} x轴坐标
 * @param  {Number} y轴坐标
 */
function drawText(department, value, x, y) {
            ctx.fillStyle = '#fff'
            ctx.font = "22px 微软雅黑";
            ctx.fillText(department, x + 30, y + 20);  //为了使文本在光晕右下角x,y轴需要偏移一些距离
            var width = ctx.measureText(value).width;   //获取文本的宽度
            ctx.fillStyle = createLinearGradient([x + 30, 0],   //文本渐变x轴的渲染范围是[x+30,x+30+文本的宽度], 
                                                 [x + 30 + width, 0],       //这里y取0,是因为没找到获取文本高的api,写0也是可以的
                                                 '#fffd00',
                                                 '#ff6d00'
                                                 );
            ctx.fillText(value.toLocaleString(), x + 30, y + 50);
    
        }
    
//drawCurvePath函数需要做些调整
 function drawCurvePath(start, point, end, percent, department, value) {
           //...
           createHeadLight(x,y)
           drawText(department, value, x, y)
        }

动画完成后结束位置添加文本和图片

动画完成后添加文本和图片需要注意下,曲线动画完成后需要立即清理画布,然后添加文本和图片

Canvas实现贝赛尔曲线轨迹动画

/**
 * 创建图片
 * @param  {Number} x轴坐标
 * @param  {Number} y轴坐标
 */
function drawImg(x, y) {
        ctx.drawImage(img, x - img.width / 2, y - img.height);
    }

//draw 函数需要做些调整
draw(){
    //...
    
     if (percent <= 100) {
                requestAnimationFrame(draw);
            }else{
            ctx.clearRect(0, 0, 1500, 750);   //曲线动画完立即清除画布
                drawText(data.department,   //渲染文本
                         data.value, 
                         data.end[0], 
                         data.end[1])
                drawImg(data.end[0], data.end[1])   //渲染图片
                  setTimeout(function(){    //2000ms后重绘
                     init()
                  },2000)
            }
    
}

结束

本篇示例完整代码

文章首图示例完整代码

参考文章: 用canvas绘制一个曲线动画——深入理解贝塞尔曲线

本篇如能对您有所帮助,实在是感到荣幸。如有不合理之处也请大家多多指点


以上所述就是小编给大家介绍的《Canvas实现贝赛尔曲线轨迹动画》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Building Web Reputation Systems

Building Web Reputation Systems

Randy Farmer、Bryce Glass / Yahoo Press / 2010 / GBP 31.99

What do Amazon's product reviews, eBay's feedback score system, Slashdot's Karma System, and Xbox Live's Achievements have in common? They're all examples of successful reputation systems that enable ......一起来看看 《Building Web Reputation Systems》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具