这是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. Java学习--jsp内置对象

    九个内置对象,其中Out,request,response,session,application常用 get与post区别: request对象: response对象: 请求转发与请求重定向的区别 ...

  2. mysql分表,批量生成数据

    一.mysql的分表策略 根据经验,Mysql表数据一般达到百万级别,查询效率会很低,容易造成表锁,甚至堆积很多连接,直接挂掉: 1,水平分割: 水平(横向)拆分:将同一个表的数据进行分块保存到不同的 ...

  3. ios开发 学习积累20161101

    20161101 XML的声明 <?XML version="1.0" encoding="UTF-8" ?> XML文档必须有根元素 XML 对大 ...

  4. springboot+mybatis遇到BUG:自动注入失败

    今天用springboot+mybatis写一个小demo遇到如下错误 Error starting ApplicationContext. To display the conditions rep ...

  5. python(九):迭代器与生成器

    一.Python的迭代协议 迭代器是访问集合内元素的一种方式.它只能依次访问集合内元素.其特点是惰性执行. collection.abc的迭代协议提供了两个概念:可迭代对象和迭代器.可迭代对象:必须具 ...

  6. js-js的语句

    - Java里面的语句: ** if判断 *** =:表示赋值 *** ==:表示判断 ** switch语句 ** 循环 for while do-while - js里面的也是这些语句 ** if ...

  7. web杂记-禁止输入框自动填充文字

    1:背景 公司基于业务需求开发了一套纯JS的时间控件,本来用得好好得.后来发现在部分浏览器下使用该时间控件会出现输入框自动填充的部分与控件的展示产生了冲突: 如图: 2:问题分析 因为部分浏览太人性化 ...

  8. WC前的颓废——带花树

    QAQ现在很不想写题解博客那就来写个算法吧QAQ... 带花树 题目 来看个题... UOJ79. 某机房里有\(n\)个OIer,其中有\(n\)个男生,\(0\)个女生.现在他们要两两配对. 有\ ...

  9. 移动目标在三维GIS中的实现方法

    对于基于ArcGIS Runtime的应用程序,其实现方法比较简单,可以直接更新图形的Geometry属性,即可实现位置的移动: private void AddGraphics() { var gl ...

  10. Portal for ArcGIS 10.2.2更改域名和导入自定义证书

    1.产品版本 Portal for ArcGIS10.2.2(同样适用于ArcGIS10.3) 2.修改说明 )修改Portal中的域名:(2)修改Portal中的证书. 3.修改步骤 3.1.在ho ...