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

部分程序如下:

  1. var p = this;
  2. p.originParams = originParams;
  3. p.params = params;
  4. p.innerWidth = window.innerWidth;//页面视图区大小
  5. p.innerHeight = window.innerHeight;
  6. p.points = [];
  7. p.pageXY = {pageX:p.innerWidth/2,pageY:p.innerHeight/2};
  8. if(container[0] === '#') {
  9. p.container = container.split('#')[1];
  10. };
  11. //获取canvas元素
  12. p.canvas = document.getElementById(p.container);
  13. //创建context对象
  14. p.ctx = p.canvas.getContext('2d');
  15. //初始化
  16. p.init = function() {
  17. p.canvas.width = p.innerWidth;
  18. p.canvas.height = p.innerHeight;
  19. p.drawBackground();
  20. p.addOverlap();
  21. p.initDrawPoint();
  22. p.animation();
  23. p.mouseEvent();
  24. p.windowResize();
  25. };
  26. p.addOverlap=function(){
  27. p.overlap=document.createElement('div');
  28. p.overlap.style.width=p.innerWidth+'px';
  29. p.overlap.style.height=p.innerHeight+'px';
  30. p.overlap.style.position='absolute';
  31. p.overlap.style.top='0px';
  32. p.overlap.style.left='0px';
  33. p.overlap.style.zIndex='100';
  34. if(p.canvas.nextElementSibling){//??
  35. p.canvas.parentNode.insertBefore(p.overlap,p.canvas.nextElementSibling);//insertBefore接收要插入的节点和作为参考的节点
  36. }else{
  37. p.canvas.parentNode.appendChild(p.overlap);
  38. };
  39. };
  40. //粒子颜色
  41. p.color = function() {
  42. function random() {
  43. return Math.round(Math.random() * 255);
  44. };
  45. this.r = random();
  46. this.g = random();
  47. this.b = random();//分别调用三次取随机值
  48. this.a = random(1, 0.8);
  49. this.rgba = 'rgba(' + this.r + ',' + this.g + ',' + this.b + ',' + this.a + ')';
  50. return this;
  51. };
  52. //获取随机数
  53. p.random = function(max, min) {
  54. var min = arguments[1] || 0;
  55. return Math.floor(Math.random() * (max - min + 1) + min);
  56. };
  57. //绘制背景图
  58. p.drawBackground = function() {
  59. if(!p.canvas) return;
  60. p.ctx.fillStyle = '#000';
  61. p.ctx.fillRect(0, 0, p.innerWidth, p.innerHeight);
  62. };
  63. //粒子
  64. p.point = function() {//每个粒子包括颜色,坐标、半径
  65. this.color = new p.color();
  66. this.x = Math.random() * p.innerWidth;//随机坐标
  67. this.y = Math.random() * p.innerHeight;
  68. this.vx = p.random(10, -10) / 40;//步进,调用p.random
  69. this.vy = p.random(10, -10) / 40;
  70. this.r = p.random(3, 1);//半径,调用p.random,半径最大为3,最小为1,在这个范围内波动
  71. this.scale = 1;//放大倍数
  72. };
  73. //初始化点
  74. p.initDrawPoint = function() {
  75. for(var i = 0; i < p.params.point; i++) {//所有点
  76. var point = new p.point();
  77. p.points.push(point);
  78. p.ctx.beginPath();
  79. p.ctx.fillStyle = point.color.rgba;
  80. p.ctx.arc(point.x, point.y, point.r * point.scale, 0, Math.PI * 2, true);
  81. p.ctx.fill();
  82. };
  83. p.ctx.closePath();
  84. };
  85. //点点连线
  86. p.connect = function() {
  87. function lineColor(p1, p2) {
  88. var linear = p.ctx.createLinearGradient(p1.x, p1.y, p2.x, p2.y);//起点终点坐标
  89. linear.addColorStop(0, p1.color.rgba);//开始的颜色
  90. linear.addColorStop(1, p2.color.rgba);//结束的颜色
  91. return linear;
  92. };
  93. for(var i = 0; i < p.params.point; i++) {
  94. for(var j = 0; j < p.params.point; j++) {
  95. var p1 = p.points[i];
  96. var p2 = p.points[j];
  97. if(Math.abs(p2.x - p1.x) < p.params.minDis && Math.abs(p2.y - p1.y) < p.params.minDis) {//两点之间距离小于一定程度才连线
  98.  
  99. p.ctx.beginPath();
  100. p.ctx.lineWidth = 0.2;
  101. p.ctx.strokeStyle = lineColor(p1, p2);//采用渐变,描边样式
  102. p.ctx.moveTo(p1.x, p1.y);
  103. p.ctx.lineTo(p2.x, p2.y);
  104. p.ctx.stroke();//描边,使用的是strokeStyle
  105. p.ctx.closePath();
  106. };
  107. };
  108. };
  109. };
  110. p.lineto = function() {//和鼠标位置有关
  111. function isInView(point) {
  112. return Math.abs(point.x - p.pageXY.pageX) < p.params.mouseDis && Math.abs(point.y - p.pageXY.pageY) < p.params.mouseDis;
  113. };
  114. (function line() {
  115. function lineColor(p1, p2) {
  116. var linear = p.ctx.createLinearGradient(p1.x, p1.y, p2.x, p2.y);
  117. linear.addColorStop(0, p1.color.rgba);
  118. linear.addColorStop(1, p2.color.rgba);
  119. return linear;
  120. };
  121. for(var i = 0; i < p.params.point; i++) {
  122. for(var j = 0; j < p.params.point; j++) {
  123. if(i != j) {
  124. var p1 = p.points[i];
  125. var p2 = p.points[j];
  126. if(isInView(p1) && isInView(p2)) {
  127. if(Math.abs(p2.x - p1.x) < p.params.minDis && Math.abs(p2.y - p1.y) < p.params.minDis) {
  128. p.ctx.beginPath();
  129. p.ctx.lineWidth = 0.2;
  130. p.ctx.strokeStyle = lineColor(p1, p2);
  131. p.ctx.moveTo(p1.x, p1.y);
  132. p.ctx.lineTo(p2.x, p2.y);
  133. p.ctx.stroke();
  134. p.ctx.closePath();
  135. };
  136. };
  137. };
  138. };
  139. };
  140. })();
  141. };
  142. //无限循环动画
  143. p.animation = function() {
  144. p.ctx.clearRect(0, 0, p.innerWidth, p.innerHeight);
  145. p.drawBackground();
  146. for(var i = 0; i < p.params.point; i++) {
  147. var point = p.points[i];
  148. if(point.x < 0 || point.x > p.innerWidth) {//当小圆球碰到矩形壁以后反弹
  149. point.vx = -point.vx;
  150. };
  151. if(point.y < 0 || point.y > p.innerHeight) {
  152. point.vy = -point.vy;
  153. };
  154. p.ctx.beginPath();
  155. p.ctx.fillStyle = point.color.rgba;
  156. point.x += point.vx; //小圆球不断移动
  157. point.y += point.vy;
  158. p.ctx.arc(point.x, point.y, point.r * point.scale, 0, Math.PI * 2, true);
  159. p.ctx.fill();
  160. };
  161. if(p.params.effect == 'zoom') {
  162. p.connect();//将小球与小球用线连接,鼠标移动事件定义在mouseEvent中
  163. } else if(p.params.effect == 'line') {
  164. p.lineto();//该函数与鼠标位置有关,通过鼠标事件传入鼠标位置,在该位置附近连线
  165. };
  166. requestAnimationFrame(p.animation);
  167. };
  168. //鼠标事件
  169. p.mouseEvent = function() {
  170. p.overlap.addEventListener('mousemove', function(e) {//鼠标指针移动时触发div中的事件
  171. var e = e || window.event;
  172. var pageX = (e.clientX + document.body.scrollLeft || e.pageX) - this.offsetLeft;//offsetLeft指div到边框??
  173. var pageY = (e.clientY + document.body.scrollTop || e.pageY) - this.offsetTop;
  174. if(p.params.effect == 'zoom'){
  175. for(var t = 0; t < p.params.point; t++) {
  176. var point = p.points[t];
  177. if(Math.abs(point.x - p.pageXY.pageX) < p.params.minDis && Math.abs(point.y - p.pageXY.pageY) < p.params.minDis) {//鼠标附近的点
  178. point.scale = 5;
  179. } else {
  180. point.scale = 1;
  181. };
  182. };
  183. };
  184. p.pageXY.pageX = pageX;
  185. p.pageXY.pageY = pageY;
  186. });
  187. p.overlap.addEventListener('mouseout', function(e) {//鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发
  188. if(p.params.effect == 'zoom'){//zoom鼠标移出div都变为原来的比例
  189. for(var i = 0; i < p.params.point; i++) {
  190. var point = p.points[i];
  191. if(point.scale != 1) {
  192. point.scale = 1;
  193. };
  194. };
  195. }else{
  196. p.pageXY.pageX=p.innerWidth/2;//line方式鼠标移出div自动定位到中心
  197. p.pageXY.pageY=p.innerHeight/2;
  198. };
  199. });
  200. };
  201. p.windowResize = function() {
  202. window.addEventListener('resize', p.init);
  203. };
  204. p.init();
  205. return p;
  206. };
  207. //兼容requestAnimFrame
  208. window.requestAnimationFrame = (function() {//requestAnimationFrame??
  209. return window.requestAnimationFrame ||
  210. window.webkitRequestAnimationFrame ||
  211. window.mozRequestAnimationFrame ||
  212. function(callback) {//前面三个都不支持则采用该函数
  213. window.setTimeout(callback, 1000 / 60);
  214. };
  215. })();

【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. flask中的数据操作

    flask中数据访问: pip install flask-sqlalemy 创建数据: 创建app的工厂 from flask import Flask from flask_sqlalchemy ...

  2. centos 网络很慢且无法远程登陆的解决办法

    安装了centOS,但是发现网速实在是卡得几乎不能上网,连百度都打不开 后来想到偶然记得有一次看过一段话,说到关闭ipv6,测试来一下,果然有效,关闭来ipv6打开网速飞快. 关闭方法,在/etc/m ...

  3. 1.Java设计模式-工厂模式

    1.简单工厂模式(Factory Method) 常用的工厂模式是静态工厂模式,利用static修饰方法,作为一种类似于常见的工具类Utils等辅助效果,一般情况下工厂类不需要实例化. //1.定义一 ...

  4. 【SSH网上商城项目实战07】Struts2和Json的整合

    转自:https://blog.csdn.net/eson_15/article/details/51332758 上一节我们完成了DataGrid显示jason数据,但是没有和后台联系在一起,只是单 ...

  5. Django中用Jquery实现不刷新页面进行身份验证和计算器功能

    1.下载jquery http://www.jq22.com/jquery-info122 下载解压之后加入工程中的static文件夹中 2.路由分发. """Djang ...

  6. 浅谈arguments与arguments的妙用

    1.每个函数都有一个arguments属性,表示函数的实参集合,这里的实参是重点,就是执行函数时实际传入的参数的集合. 2.arguments不是数组而是一个对象,但它和数组很相似,所以通常称为类数组 ...

  7. JavaScript中的__proto__

    实例中的__proto__ 箭头函数的__proto__ 需要注意的是箭头函数的__proto__并没有指向Function构造函数的的原型对象 MDN上的资料显示,箭头函数不绑定Arguments ...

  8. java中的==、equals()、hashCode()源码分析(转载)

    在java编程或者面试中经常会遇到 == .equals()的比较.自己看了看源码,结合实际的编程总结一下. 1. ==  java中的==是比较两个对象在JVM中的地址.比较好理解.看下面的代码: ...

  9. 【javascript】javasrcipt设计模式之策略模式

    策略模式支持在运行时由使用者选择合适的算法,对于使用者而言不用关心背后的具体事项,而使用者自动根据当前程序执行的上下文和配置,从已有的算法列表中选择出合适的算法来处理当前任务. 1.要解决的问题 2. ...

  10. 状态开关(ToggleButton)

    状态开关(ToggleButton): 常用属性:isChecked(是否被选中,如true) 监听:1.监听方法:setOnCheckedChangeListener 2.监听器:CompoundB ...