canvas实现折现随机变化的动画效果

本文展示了如何利用HTML5的canvas和javascript实现一个折线随机变化的动画效果。通过集成不同的缓动函数,并对给定点集进行随机移动,实现了在canvas上动态展示的动画。附带了示例代码,包括html和js文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在项目前期预研中(设计阶段)设计师想要一个折现集随机缓动的效果,于是就用canvas尝试做了下。

1、集成了js常见的缓动函数公式,放在Easing对象下;

2、对给定的点集及目标点集做随机前往,过程使用动画方式。

好了,不多说,附件中有net.js(封装了简单的类),及index.html示例代码。


html代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>canvas动画</title>
<style type="text/css">
*{margin: 0;padding: 0;}
body{overflow: hidden;}
</style>
</head>
<body>
<canvas id="target"></canvas>
<script type="text/javascript" src="net.js"></script>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded',function(e){
var s_width = window.innerWidth;
var s_height = window.innerHeight;


var canvas = document.getElementById('target');
canvas.setAttribute('width',s_width);
canvas.setAttribute('height',s_height);


var ctx = canvas.getContext('2d');
//一组以一个顶点发出的射线
var group = [
{
points : [
{
x : 100,
y : s_height
},
{
x : 400,
y : s_height
},
{
x : 800,
y : s_height
}],
t_points : [
{
x : 200,
y : 500
},
{
x : 500,
y : 500
},
{
x : 600,
y : 300
}
],
status : {
//保存该组当前端点和下一个端点的索引
index : 0,
n_index : 0
}
},
{
points : [
{
x : 150,
y : s_height
},
{
x : 450,
y : s_height
},
{
x : 850,
y : s_height
}],
t_points : [
{
x : 250,
y : 500
},
{
x : 550,
y : 500
},
{
x : 650,
y : 300
}
],
status : {
//保存该组当前端点和下一个端点的索引
index : 0,
n_index : 0
}
}
];
var net = new Net({
context : ctx,
group : group,
rect : {
x : 0,
y : 0,
width : s_width,
height : s_height
}
});
net.move();
});
</script>
</body>
</html>


js文件:

/*
*** Author : CLuo ***
*** Date : 2014/10/18 ***
*/
var pow = Math.pow,
BACK_CONST = 1.70158,
Easing = {
  // 匀速运动
  linear: function (t) {
      return t;
  },
  easeIn: function (t) {
      return t * t;
  },
  easeOut: function (t) {
      return (2 - t) * t;
  },
  easeBoth: function (t) {
      return (t *= 2) < 1 ? .5 * t * t : .5 * (1 - (--t) * (t - 2));
  },
  easeInStrong: function (t) {
      return t * t * t * t;
  },
  easeOutStrong: function (t) {
      return 1 - (--t) * t * t * t;
  },
  easeBothStrong: function (t) {
      return (t *= 2) < 1 ? .5 * t * t * t * t : .5 * (2 - (t -= 2) * t * t * t);
  },
  easeOutQuart: function (t) {
      return -(pow((t - 1), 4) - 1)
  },
  easeInOutExpo: function (t) {
      if (t === 0) return 0;
      if (t === 1) return 1;
      if ((t /= 0.5) < 1) return 0.5 * pow(2, 10 * (t - 1));
      return 0.5 * (-pow(2, - 10 * --t) + 2);
  },
  easeOutExpo: function (t) {
      return (t === 1) ? 1 : -pow(2, - 10 * t) + 1;
  },
  swingFrom: function (t) {
      return t * t * ((BACK_CONST + 1) * t - BACK_CONST);
  },
  swingTo: function (t) {
      return (t -= 1) * t * ((BACK_CONST + 1) * t + BACK_CONST) + 1;
  },
  backIn: function (t) {
      if (t === 1) t -= .001;
      return t * t * ((BACK_CONST + 1) * t - BACK_CONST);
  },
  backOut: function (t) {
      return (t -= 1) * t * ((BACK_CONST + 1) * t + BACK_CONST) + 1;
  },
  bounce: function (t) {
      var s = 7.5625,
          r;
      if (t < (1 / 2.75)) {
          r = s * t * t;
      } else if (t < (2 / 2.75)) {
          r = s * (t -= (1.5 / 2.75)) * t + .75;
      } else if (t < (2.5 / 2.75)) {
          r = s * (t -= (2.25 / 2.75)) * t + .9375;
      } else {
          r = s * (t -= (2.625 / 2.75)) * t + .984375;
      }
      return r;
  }
};
function Net(param){
  //动画时间
  this.duration = param.duration || 2000;
  //每一帧总时长
  this.frameTime = param.frameTime || 3000;
  this.context = param.context;
  this.group = param.group;
  //画布的起始位置和宽高
  this.rect = param.rect;
  this._init();
}
Net.prototype = {
  _init : function(){
    this.draw([
          {
            x : this.group[0].t_points[0].x,
            y : this.group[0].t_points[0].y
          },
          {
            x : this.group[1].t_points[0].x,
            y : this.group[1].t_points[0].y
          }
        ]);
  },
  draw : function(t_points){
    var context = this.context,group = this.group;
    context.clearRect(this.rect.x,this.rect.y,this.rect.width,this.rect.height);
    //获取每一个组的内容
    for(var i = 0;i < t_points.length;i++){
      for(var j=0;j<group[i].points.length;j++){
        context.beginPath();
        context.moveTo(t_points[i].x,t_points[i].y);
        context.lineTo(group[i].points[j].x,group[i].points[j].y);
        context.stroke();
        context.closePath();
      }
      //绘制端点
      context.beginPath();
      context.arc(t_points[i].x,t_points[i].y,5,0,Math.PI*2,true);
      context.fill();
      context.closePath();
    }
  },
  animate : function(){
    var _this = this;
    var group = this.group;
    var duration = this.duration;
    var callBack = null;
    var easing = this.easing || Easing.easeOutQuart;
    var startTime = +new Date(),//记录当前时间,+new Date()为new Date().getTime()的简写
              endTime       = startTime+duration,//结束时间
              curTime, //当前时间
              t,       //当前时间,在总时间的比例,范围0.0~1.0
              e,       //动画算子
              timer,   //setTimeout,的定时器
              //一个单位动画执行的函数
              run = function(){
                curTime = +new Date();
                //计算,当前时间,在总时间的比例,范围0.0~1.0
                t = curTime > endTime ? 1 : (curTime - startTime)/duration;
                //动画算子
                e = easing?easing(t):t;
                //计算时间t时的点坐标
                var tmp_tpoints = [];
                for(var i=0;i<group.length;i++){
                  var p = {
                    x : ((group[i].t_points[group[i].status.n_index]).x - (group[i].t_points[group[i].status.index]).x)*e + (group[i].t_points[group[i].status.index]).x,
                    y : ((group[i].t_points[group[i].status.n_index]).y - (group[i].t_points[group[i].status.index]).y)*e + (group[i].t_points[group[i].status.index]).y
                  };
                  tmp_tpoints.push(p);
                }
                //绘制图集
                _this.draw(tmp_tpoints);


                if(t < 1){
                  //t < 1.0表面动画未结束 ,每16毫秒递归一次run函数。
                  timer = setTimeout(function(){run()},16);
                }else{
                  //如果回调函数存在,执行回调函数
                  callBack&&callBack();
                }
              };
              run();
              return function(){
                timer&&clearTimeout(timer);
              };
  },
  move : function(){
    var group = this.group;
    var _this = this;
    var timer = setInterval(function(){
          //对于每一个group随机下一个端点的位置
          for(var i=0;i<group.length;i++){
            //this.group[i].t_points[location[i].n_index].x,this.group[i].t_points[location[i].n_index].y
            var tmp = Math.ceil(Math.random()*(group[i].t_points.length -1)+1);
            group[i].status.n_index = tmp-1;
          }


          //重绘调整后的射线
          _this.animate(2000,null,Easing.easeOutQuart);
          var r_timer = setTimeout(function(){
            for(var j=0;j<group.length;j++){
              group[j].status.index = group[j].status.n_index;
            }
            clearTimeout(r_timer);
          },2000);
        },3000);
  }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值