canvas简单快速的实现知乎登录页背景效果


Posted in Javascript onMay 08, 2017

前言

打开知乎的登录页,就可以看到其背景有一个动效,看起来好像蛮不错的样子:

canvas简单快速的实现知乎登录页背景效果

这个效果使用canvas是不难实现的,接下来就一步一步地讲解并实现这个效果。

分析

在动工之前先分析这个效果到底是如何运动的。首先要理解的是虽然看起来好像所有线和圆都在运动,但实际上只有圆才是在运动的,而线只不过是把满足一定条件的任意两个圆连接在一起。那么接下来就分析圆是怎么运动的,从效果看,每个圆都是在做匀速直线运动,而且运动方向不一,通过物理相关知识可以得知,每一个圆在水平方向和垂直方向都有一个速度。最后是当圆运动出画布任一边界的时候,这个圆会从出边界的这条边的对边再次进入画布。把这三个关键点理解清楚了就清晰很多了。

实践

先创建一个canvas画布:

// 这里就简单地设置下背景色
<body style="background:#f7fafc;">
 <canvas id="canvas" style="width: 100%; height: 100%;"></canvas>
</body>

接着先获取canvas的上下文环境并设置一些共用的属性

var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");

canvas.width = document.documentElement.clientWidth;
canvas.height = document.documentElement.clientHeight;

context.fillStyle = "rgba(0, 0, 0, 0.08)";
context.strokeStyle = "rgba(0, 0, 0, 0.05)";
context.lineWidth = 0.5;

接下来绘制圆,那么绘制圆需要圆的圆心坐标,半径,水平方向的速度,垂直方向的速度,并且这些信息要满足一定的条件,通过一个函数来创建:

// 存放所有圆的数组,这里用balls
var balls = [];
function createBall() {
 // x坐标
 var _x = Math.random() * canvas.width;
 // y坐标
 var _y = Math.random() * canvas.height;
 // 半径 [0.01, 15.01]
 var _r = Math.random() * 15 + 0.01;
 // 水平速度 [±0.0, ±0.5]
 var _vx = Math.random() * 0.5 * Math.pow( -1, Math.floor(Math.random() * 2 + 1) );
 // 垂直速度 [±0.0, ±0.5]
 var _vy = Math.random() * 0.5 * Math.pow( -1, Math.floor(Math.random() * 2 + 1) );
 // 把每一个圆的信息存放到数组中
 balls.push({
 x: _x,
 y: _y,
 r: _r,
 vx: _vx,
 vy: _vy
 });
}

然后根据自己的情况选择需要绘制多少个圆,这里我假设有20个,看起来舒服一点:

// 圆的数量
var num = 20;
for(var i = 0; i < num; i++) {
 createBall();
}

现在圆的信息都有了,下一步就是绘制每一帧的圆和线,创建一个render函数,然后在函数内先绘制所有的圆出来:

for(var k = 0; k < num; k++) {
 context.save();
 context.beginPath();
 context.arc( balls[k].x, balls[k].y, balls[k].r, 0, Math.PI*2 );
 context.fill();
 context.restore();
}

接着要遍历每两个圆的圆心之间的距离是否小于某个临界值(比如500),满足则将这两个圆的圆心连接起来:

for(var i = 0; i < num; i++) {
 for(var j = i + 1; j < num; j++) {
 if( distance( balls[i], balls[j] ) < 500 ) {
  context.beginPath();
  context.moveTo( balls[i].x, balls[i].y );
  context.lineTo( balls[j].x, balls[j].y );
  context.stroke();
 }
 }
}

这里的 distance 函数就是计算两点之间的距离:

function distance(point1, point2) {
 return Math.sqrt( Math.pow( (point1.x - point2.x), 2 ) + Math.pow( (point1.y - point2.y), 2 ) );
}

还有一步就是判断圆是否超出了边界值,若满足条件则从对边再次进来:

for(var k = 0; k < num; k++) {
 balls[k].x += balls[k].vx;
 balls[k].y += balls[k].vy;

 if( balls[k].x - balls[k].r > canvas.width ) {
 balls[k].x = 0 - balls[k].r;
 }
 if( balls[k].x + balls[k].r < 0 ) {
 balls[k].x = canvas.width + balls[k].r;
 }
 if( balls[k].y - balls[k].r > canvas.height ) {
 balls[k].y = 0 - balls[k].r;
 }
 if( balls[k].y + balls[k].r < 0 ) {
 balls[k].y = canvas.height + balls[k].r;
 }
}

当然如果想简单点,只要圆超出就移除并重新生成一个圆即可:

if( balls[k].x - balls[k].r > canvas.width || 
 balls[k].x + balls[k].r < 0 || 
 balls[k].y - balls[k].r > canvas.height || 
 balls[k].y + balls[k].r < 0) {
 balls.splice(k, 1);
 createBall();
}

这样每一帧绘制的细节就完成了,最后一步就是让圆都运动起来:

(function loop(){
 render();
 requestAnimationFrame(loop);
})();

到此,整个效果就出来了。当然这里面有很多细节可以自己琢磨琢磨,让这个效果变得更加细腻多彩。希望对新手有所帮助。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
JavaScript判断窗口是否最小化的代码(跨浏览器)
Aug 01 Javascript
关于firefox的ElementTraversal 接口 使用说明
Nov 11 Javascript
jquery数组封装使用方法分享(jquery数组遍历)
Mar 25 Javascript
js中confirm实现执行操作前弹出确认框的方法
Nov 01 Javascript
AngularJS基础知识笔记之过滤器
May 10 Javascript
AngularJS constant和value区别详解
Feb 28 Javascript
javascript 中null和undefined区分和比较
Apr 19 Javascript
Angular 5.0 来了! 有这些大变化
Nov 15 Javascript
react-native-video实现视频全屏播放的方法
Mar 19 Javascript
详解各版本React路由的跳转的方法
May 10 Javascript
在Vue项目中使用jsencrypt.js对数据进行加密传输的方法
Apr 17 Javascript
实现vuex与组件data之间的数据同步更新方式
Nov 12 Javascript
详解JavaScript中return的用法
May 08 #Javascript
如何使用angularJs
May 08 #Javascript
关于foreach循环中遇到的问题小结
May 08 #Javascript
js下载文件并修改文件名
May 08 #Javascript
JS将unicode码转中文方法
May 08 #Javascript
js实现点击切换checkbox背景图片的简单实例
May 08 #Javascript
完美解决浏览器跨域的几种方法(汇总)
May 08 #Javascript
You might like
php2html php生成静态页函数
2008/12/08 PHP
php中常用的预定义变量小结
2012/05/09 PHP
php设置session值和cookies的学习示例
2014/03/21 PHP
浅析THINKPHP的addAll支持的最大数据量
2015/02/03 PHP
php无法连接mysql数据库的正确解决方法
2016/07/01 PHP
PHP 5.6.11 访问SQL Server2008R2的几种情况详解
2016/08/08 PHP
功能强大的PHP发邮件类
2016/08/29 PHP
ThinkPHP的SAE开发相关注意事项详解
2016/10/09 PHP
PHP处理bmp格式图片的方法分析
2017/07/04 PHP
如何利用预加载优化Laravel Model查询详解
2017/08/11 PHP
JavaScript 开发中规范性的一点感想
2009/06/23 Javascript
JS判断客服QQ号在线还是离线状态的方法
2015/01/13 Javascript
JavaScript使用cookie实现记住账号密码功能
2015/04/27 Javascript
JavaScript判断IE版本型号
2015/07/27 Javascript
利用JS实现页面删除并重新排序功能
2016/12/09 Javascript
详解javascript获取url信息的常见方法
2016/12/19 Javascript
Bootstrap列表组学习使用
2017/02/09 Javascript
Webpack实现按需打包Lodash的几种方法详解
2017/05/08 Javascript
利用JS判断客户端类型你应该知道的四种方法
2017/12/22 Javascript
ejsExcel模板在Vue.js项目中的实际运用
2018/01/27 Javascript
vue2.0 实现导航守卫(路由守卫)
2018/05/21 Javascript
Vue实现购物车的全选、单选、显示商品价格代码实例
2019/05/06 Javascript
python中的实例方法、静态方法、类方法、类变量和实例变量浅析
2014/04/26 Python
详解如何设置Python环境变量?
2019/05/13 Python
Python Django框架单元测试之文件上传测试示例
2019/05/17 Python
pytorch标签转onehot形式实例
2020/01/02 Python
Python 模拟生成动态产生验证码图片的方法
2020/02/01 Python
Python如何用filter函数筛选数据
2020/03/05 Python
奥地利网上书店:Weltbild
2017/07/14 全球购物
大学生入党思想汇报
2014/01/14 职场文书
公司收款委托书范本
2014/09/20 职场文书
小学教师自我剖析材料
2014/09/29 职场文书
2014年科室工作总结范文
2014/12/19 职场文书
农贸批发市场管理制度
2015/08/07 职场文书
安全教育日主题班会
2015/08/13 职场文书
实例详解Python的进程,线程和协程
2022/03/13 Python