这是js实现的粒子动画,有两种模式,分别是zoom和line,它们对应的效果不同,但是原理都相同,具体分析如下:

部分程序如下:

        var p = this;
p.originParams = originParams;
p.params = params;
p.innerWidth = window.innerWidth;//页面视图区大小
p.innerHeight = window.innerHeight;
p.points = [];
p.pageXY = {pageX:p.innerWidth/2,pageY:p.innerHeight/2};
if(container[0] === '#') {
p.container = container.split('#')[1];
};
//获取canvas元素
p.canvas = document.getElementById(p.container);
//创建context对象
p.ctx = p.canvas.getContext('2d');
//初始化
p.init = function() {
p.canvas.width = p.innerWidth;
p.canvas.height = p.innerHeight;
p.drawBackground();
p.addOverlap();
p.initDrawPoint();
p.animation();
p.mouseEvent();
p.windowResize();
};
p.addOverlap=function(){
p.overlap=document.createElement('div');
p.overlap.style.width=p.innerWidth+'px';
p.overlap.style.height=p.innerHeight+'px';
p.overlap.style.position='absolute';
p.overlap.style.top='0px';
p.overlap.style.left='0px';
p.overlap.style.zIndex='100';
if(p.canvas.nextElementSibling){//??
p.canvas.parentNode.insertBefore(p.overlap,p.canvas.nextElementSibling);//insertBefore接收要插入的节点和作为参考的节点
}else{
p.canvas.parentNode.appendChild(p.overlap);
};
};
//粒子颜色
p.color = function() {
function random() {
return Math.round(Math.random() * 255);
};
this.r = random();
this.g = random();
this.b = random();//分别调用三次取随机值
this.a = random(1, 0.8);
this.rgba = 'rgba(' + this.r + ',' + this.g + ',' + this.b + ',' + this.a + ')';
return this;
};
//获取随机数
p.random = function(max, min) {
var min = arguments[1] || 0;
return Math.floor(Math.random() * (max - min + 1) + min);
};
//绘制背景图
p.drawBackground = function() {
if(!p.canvas) return;
p.ctx.fillStyle = '#000';
p.ctx.fillRect(0, 0, p.innerWidth, p.innerHeight);
};
//粒子
p.point = function() {//每个粒子包括颜色,坐标、半径
this.color = new p.color();
this.x = Math.random() * p.innerWidth;//随机坐标
this.y = Math.random() * p.innerHeight;
this.vx = p.random(10, -10) / 40;//步进,调用p.random
this.vy = p.random(10, -10) / 40;
this.r = p.random(3, 1);//半径,调用p.random,半径最大为3,最小为1,在这个范围内波动
this.scale = 1;//放大倍数
};
//初始化点
p.initDrawPoint = function() {
for(var i = 0; i < p.params.point; i++) {//所有点
var point = new p.point();
p.points.push(point);
p.ctx.beginPath();
p.ctx.fillStyle = point.color.rgba;
p.ctx.arc(point.x, point.y, point.r * point.scale, 0, Math.PI * 2, true);
p.ctx.fill();
};
p.ctx.closePath();
};
//点点连线
p.connect = function() {
function lineColor(p1, p2) {
var linear = p.ctx.createLinearGradient(p1.x, p1.y, p2.x, p2.y);//起点终点坐标
linear.addColorStop(0, p1.color.rgba);//开始的颜色
linear.addColorStop(1, p2.color.rgba);//结束的颜色
return linear;
};
for(var i = 0; i < p.params.point; i++) {
for(var j = 0; j < p.params.point; j++) {
var p1 = p.points[i];
var p2 = p.points[j];
if(Math.abs(p2.x - p1.x) < p.params.minDis && Math.abs(p2.y - p1.y) < p.params.minDis) {//两点之间距离小于一定程度才连线 p.ctx.beginPath();
p.ctx.lineWidth = 0.2;
p.ctx.strokeStyle = lineColor(p1, p2);//采用渐变,描边样式
p.ctx.moveTo(p1.x, p1.y);
p.ctx.lineTo(p2.x, p2.y);
p.ctx.stroke();//描边,使用的是strokeStyle
p.ctx.closePath();
};
};
};
};
p.lineto = function() {//和鼠标位置有关
function isInView(point) {
return Math.abs(point.x - p.pageXY.pageX) < p.params.mouseDis && Math.abs(point.y - p.pageXY.pageY) < p.params.mouseDis;
};
(function line() {
function lineColor(p1, p2) {
var linear = p.ctx.createLinearGradient(p1.x, p1.y, p2.x, p2.y);
linear.addColorStop(0, p1.color.rgba);
linear.addColorStop(1, p2.color.rgba);
return linear;
};
for(var i = 0; i < p.params.point; i++) {
for(var j = 0; j < p.params.point; j++) {
if(i != j) {
var p1 = p.points[i];
var p2 = p.points[j];
if(isInView(p1) && isInView(p2)) {
if(Math.abs(p2.x - p1.x) < p.params.minDis && Math.abs(p2.y - p1.y) < p.params.minDis) {
p.ctx.beginPath();
p.ctx.lineWidth = 0.2;
p.ctx.strokeStyle = lineColor(p1, p2);
p.ctx.moveTo(p1.x, p1.y);
p.ctx.lineTo(p2.x, p2.y);
p.ctx.stroke();
p.ctx.closePath();
};
};
};
};
};
})();
};
//无限循环动画
p.animation = function() {
p.ctx.clearRect(0, 0, p.innerWidth, p.innerHeight);
p.drawBackground();
for(var i = 0; i < p.params.point; i++) {
var point = p.points[i];
if(point.x < 0 || point.x > p.innerWidth) {//当小圆球碰到矩形壁以后反弹
point.vx = -point.vx;
};
if(point.y < 0 || point.y > p.innerHeight) {
point.vy = -point.vy;
};
p.ctx.beginPath();
p.ctx.fillStyle = point.color.rgba;
point.x += point.vx; //小圆球不断移动
point.y += point.vy;
p.ctx.arc(point.x, point.y, point.r * point.scale, 0, Math.PI * 2, true);
p.ctx.fill();
};
if(p.params.effect == 'zoom') {
p.connect();//将小球与小球用线连接,鼠标移动事件定义在mouseEvent中
} else if(p.params.effect == 'line') {
p.lineto();//该函数与鼠标位置有关,通过鼠标事件传入鼠标位置,在该位置附近连线
};
requestAnimationFrame(p.animation);
};
//鼠标事件
p.mouseEvent = function() {
p.overlap.addEventListener('mousemove', function(e) {//鼠标指针移动时触发div中的事件
var e = e || window.event;
var pageX = (e.clientX + document.body.scrollLeft || e.pageX) - this.offsetLeft;//offsetLeft指div到边框??
var pageY = (e.clientY + document.body.scrollTop || e.pageY) - this.offsetTop;
if(p.params.effect == 'zoom'){
for(var t = 0; t < p.params.point; t++) {
var point = p.points[t];
if(Math.abs(point.x - p.pageXY.pageX) < p.params.minDis && Math.abs(point.y - p.pageXY.pageY) < p.params.minDis) {//鼠标附近的点
point.scale = 5;
} else {
point.scale = 1;
};
};
};
p.pageXY.pageX = pageX;
p.pageXY.pageY = pageY;
});
p.overlap.addEventListener('mouseout', function(e) {//鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发
if(p.params.effect == 'zoom'){//zoom鼠标移出div都变为原来的比例
for(var i = 0; i < p.params.point; i++) {
var point = p.points[i];
if(point.scale != 1) {
point.scale = 1;
};
};
}else{
p.pageXY.pageX=p.innerWidth/2;//line方式鼠标移出div自动定位到中心
p.pageXY.pageY=p.innerHeight/2;
};
});
};
p.windowResize = function() {
window.addEventListener('resize', p.init);
};
p.init();
return p;
};
//兼容requestAnimFrame
window.requestAnimationFrame = (function() {//requestAnimationFrame??
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function(callback) {//前面三个都不支持则采用该函数
window.setTimeout(callback, 1000 / 60);
};
})();

【JavaScript】particle的更多相关文章

  1. 【javascript】html5中使用canvas编写头像上传截取功能

    [javascript]html5中使用canvas编写头像上传截取功能 本人对canvas很是喜欢,于是想仿照新浪微博头像上传功能(前端使用canvas) 本程序目前在谷歌浏览器和火狐浏览器测试可用 ...

  2. 【JavaScript】出现即使设置了ID也获取不到的可能原因与window.onload

    有时候.在JavaScript中.即使设置了ID也有可能出现document.getElementById()获取不到的情况,然后你就開始想document是否写错之类的.事实上根本就不是你的代码的大 ...

  3. 【JavaScript】我的JavaScript技术总结第一篇——编程细节

    遍历数组 for (var i=0, l=arr.length; i<l; i++) 这样写的一个好处就是让每次循环少一步获取数组对象长度的操作,数组长度越长,价值越明显. 判断变量的真假 if ...

  4. 【JavaScript】下大雪

    引用[JavaScript]满天星的代码,稍作修改的结果: function drawStars() { for (i = 1; i < 100; ++i) { ctx.fillText(&qu ...

  5. 【JavaScript】JavaScript中的replaceAll

    JavaScript中是没有replaceAll的.仅仅有replace,replace仅仅能替换字符中的第一个字符.并且这个replace里面不支持正則表達式,以达到replaceAll的目的. 只 ...

  6. 【JavaScript】Leetcode每日一题-在D天内送包裹的能力

    [JavaScript]Leetcode每日一题-在D天内送包裹的能力 [题目描述] 传送带上的包裹必须在 D 天内从一个港口运送到另一个港口. 传送带上的第 i 个包裹的重量为 weights[i] ...

  7. 【JavaScript】Leetcode每日一题-青蛙过河

    [JavaScript]Leetcode每日一题-青蛙过河 [题目描述] 一只青蛙想要过河. 假定河流被等分为若干个单元格,并且在每一个单元格内都有可能放有一块石子(也有可能没有). 青蛙可以跳上石子 ...

  8. 【JavaScript】Leetcode每日一题-平方数之和

    [JavaScript]Leetcode每日一题-平方数之和 [题目描述] 给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a2 + b2 = c . 示例1: 输入:c = 5 ...

  9. 【JavaScript】Leetcode每日一题-二叉搜索树的范围和

    [JavaScript]Leetcode每日一题-二叉搜索树的范围和 [题目描述] 给定二叉搜索树的根结点 root,返回值位于范围 [low, high] 之间的所有结点的值的和. 示例1: 输入: ...

随机推荐

  1. android FrameLayout

    FrameLayout:帧布局,可以显示图片的动画效果 前景图像: 永远处于帧布局最顶的,直接面对用户的图像,,就是不会被覆盖的图片 常用属性: android:foreground:设置该帧布局容器 ...

  2. [javaSE] GUI(Action事件)

    对自己定义的类规范化一下,事件和图形化组件分离出来 定义一个类FrameDemo 定义成员属性Frame frame 定义成员属性Botton 定义构造方法FrameDemo() 定义初始化方法ini ...

  3. Spring 中的Enum HttpStatus 及HTTP状态码

    官方API https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/http/HttpStatus.htm ...

  4. redux、immutablejs和mobx性能对比(三)

    四.我的结论 通过第三部分的数据数据分析,我觉得我们可以得到以下结论: 无论是在开发环境还是测试环下页面的首次加载速度结果都是:redux>immutablejs>mobx,但是他们之间的 ...

  5. Nuget Tips

    Install-Package时老是提示找不到Available Source,研究了下Nuget Package Manager的配置.发现有两个地方可以改: 1.Visual Studio中Too ...

  6. unzipping/Users/xq/.gradle/wrapper /dists/gradle-3.3-all/55gk2rcmfc6p2dg9u9ohc3hw9/gradle-3.3-all.zi

    unzipping/Users/xq/.gradle/wrapper /dists/gradle-3.3-all/55gk2rcmfc6p2dg9u9ohc3hw9/gradle-3.3-all.zi ...

  7. MySQL允许root远程访问

    1. mysql -u root -p;     // 登录mysql, 并输入密码 2. use mysql;             // 打开 mysql 数据库 3. update user ...

  8. 算法之水仙花数(Java语言)

    概述 在数论中,水仙花数(Narcissistic number),也被称为超完全数字不变数(pluperfect digital invariant, PPDI).自恋数.自幂数.阿姆斯壮数或阿姆斯 ...

  9. 图书管理系统 基于form组件

    models: from django.db import models # Create your models here. class Book(models.Model): name = mod ...

  10. SCOM中的通配符

    通配符模式匹配按从左到右的方式完成,一次匹配一个字符或基本通配符模式.模式和传入字符串必须完全匹配,因此,举例来说,模式“abc”与字符串“abcd”不匹配.复合模式包含由 (&) 号或波形符 ...