particles.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. /* -----------------------------------------------
  2. /* Author : Vincent Garreau - vincentgarreau.com
  3. /* MIT license: http://opensource.org/licenses/MIT
  4. /* GitHub : https://github.com/VincentGarreau/particles.js
  5. /* How to use? : Check the GitHub README
  6. /* v1.0.3
  7. /* ----------------------------------------------- */
  8. /** **/
  9. function launchParticlesJS(tag_id, params){
  10. var canvas_el = document.querySelector('#'+tag_id+' > canvas');
  11. /* particles.js variables with default values */
  12. pJS = {
  13. canvas: {
  14. el: canvas_el,
  15. w: canvas_el.offsetWidth,
  16. h: canvas_el.offsetHeight
  17. },
  18. particles: {
  19. color: '#fff',
  20. shape: 'circle',
  21. opacity: 1,
  22. size: 2.5,
  23. size_random: true,
  24. nb: 200,
  25. line_linked: {
  26. enable_auto: true,
  27. distance: 100,
  28. color: '#fff',
  29. opacity: 1,
  30. width: 1,
  31. condensed_mode: {
  32. enable: true,
  33. rotateX: 65000,
  34. rotateY: 65000
  35. }
  36. },
  37. anim: {
  38. enable: true,
  39. speed: 1
  40. },
  41. array: []
  42. },
  43. interactivity: {
  44. enable: true,
  45. mouse: {
  46. distance: 100
  47. },
  48. detect_on: 'canvas',
  49. mode: 'grab',
  50. line_linked: {
  51. opacity: 1
  52. },
  53. events: {
  54. onclick: {
  55. enable: true,
  56. mode: 'push',
  57. nb: 4
  58. }
  59. }
  60. },
  61. retina_detect: false,
  62. fn: {
  63. vendors:{
  64. interactivity: {}
  65. }
  66. }
  67. };
  68. /* params settings */
  69. if(params){
  70. if(params.particles){
  71. var paramsForParticles = params.particles;
  72. if(paramsForParticles.color) pJS.particles.color = paramsForParticles.color;
  73. if(paramsForParticles.shape) pJS.particles.shape = paramsForParticles.shape;
  74. if(paramsForParticles.opacity) pJS.particles.opacity = paramsForParticles.opacity;
  75. if(paramsForParticles.size) pJS.particles.size = paramsForParticles.size;
  76. if(paramsForParticles.size_random == false) pJS.particles.size_random = paramsForParticles.size_random;
  77. if(paramsForParticles.nb) pJS.particles.nb = paramsForParticles.nb;
  78. if(paramsForParticles.line_linked){
  79. var paramsForLineLinked = paramsForParticles.line_linked;
  80. if(paramsForLineLinked.enable_auto == false) pJS.particles.line_linked.enable_auto = paramsForLineLinked.enable_auto;
  81. if(paramsForLineLinked.distance) pJS.particles.line_linked.distance = paramsForLineLinked.distance;
  82. if(paramsForLineLinked.color) pJS.particles.line_linked.color = paramsForLineLinked.color;
  83. if(paramsForLineLinked.opacity) pJS.particles.line_linked.opacity = paramsForLineLinked.opacity;
  84. if(paramsForLineLinked.width) pJS.particles.line_linked.width = paramsForLineLinked.width;
  85. if(paramsForLineLinked.condensed_mode){
  86. var paramsForCondensedMode = paramsForLineLinked.condensed_mode;
  87. if(paramsForCondensedMode.enable == false) pJS.particles.line_linked.condensed_mode.enable = paramsForCondensedMode.enable;
  88. if(paramsForCondensedMode.rotateX) pJS.particles.line_linked.condensed_mode.rotateX = paramsForCondensedMode.rotateX;
  89. if(paramsForCondensedMode.rotateY) pJS.particles.line_linked.condensed_mode.rotateY = paramsForCondensedMode.rotateY;
  90. }
  91. }
  92. if(paramsForParticles.anim){
  93. var paramsForAnim = paramsForParticles.anim;
  94. if(paramsForAnim.enable == false) pJS.particles.anim.enable = paramsForAnim.enable;
  95. if(paramsForAnim.speed) pJS.particles.anim.speed = paramsForAnim.speed;
  96. }
  97. }
  98. if(params.interactivity){
  99. var paramsForInteractivity = params.interactivity;
  100. if(paramsForInteractivity.enable == false) pJS.interactivity.enable = paramsForInteractivity.enable;
  101. if(paramsForInteractivity.mouse){
  102. if(paramsForInteractivity.mouse.distance) pJS.interactivity.mouse.distance = paramsForInteractivity.mouse.distance;
  103. }
  104. if(paramsForInteractivity.detect_on) pJS.interactivity.detect_on = paramsForInteractivity.detect_on;
  105. if(paramsForInteractivity.mode) pJS.interactivity.mode = paramsForInteractivity.mode;
  106. if(paramsForInteractivity.line_linked){
  107. if(paramsForInteractivity.line_linked.opacity) pJS.interactivity.line_linked.opacity = paramsForInteractivity.line_linked.opacity;
  108. }
  109. if(paramsForInteractivity.events){
  110. var paramsForEvents = paramsForInteractivity.events;
  111. if(paramsForEvents.onclick){
  112. var paramsForOnclick = paramsForEvents.onclick;
  113. if(paramsForOnclick.enable == false) pJS.interactivity.events.onclick.enable = false;
  114. if(paramsForOnclick.mode != 'push') pJS.interactivity.events.onclick.mode = paramsForOnclick.mode;
  115. if(paramsForOnclick.nb) pJS.interactivity.events.onclick.nb = paramsForOnclick.nb;
  116. }
  117. }
  118. }
  119. pJS.retina_detect = params.retina_detect;
  120. }
  121. /* convert hex colors to rgb */
  122. pJS.particles.color_rgb = hexToRgb(pJS.particles.color);
  123. pJS.particles.line_linked.color_rgb_line = hexToRgb(pJS.particles.line_linked.color);
  124. /* detect retina */
  125. if(pJS.retina_detect && window.devicePixelRatio > 1){
  126. pJS.retina = true;
  127. pJS.canvas.pxratio = window.devicePixelRatio
  128. pJS.canvas.w = pJS.canvas.el.offsetWidth * pJS.canvas.pxratio;
  129. pJS.canvas.h = pJS.canvas.el.offsetHeight * pJS.canvas.pxratio;
  130. pJS.particles.anim.speed = pJS.particles.anim.speed * pJS.canvas.pxratio;
  131. pJS.particles.line_linked.distance = pJS.particles.line_linked.distance * pJS.canvas.pxratio;
  132. pJS.particles.line_linked.width = pJS.particles.line_linked.width * pJS.canvas.pxratio;
  133. pJS.interactivity.mouse.distance = pJS.interactivity.mouse.distance * pJS.canvas.pxratio;
  134. }
  135. /* ---------- CANVAS functions ------------ */
  136. pJS.fn.canvasInit = function(){
  137. pJS.canvas.ctx = pJS.canvas.el.getContext('2d');
  138. };
  139. pJS.fn.canvasSize = function(){
  140. pJS.canvas.el.width = pJS.canvas.w;
  141. pJS.canvas.el.height = pJS.canvas.h;
  142. window.onresize = function(){
  143. if(pJS){
  144. pJS.canvas.w = pJS.canvas.el.offsetWidth;
  145. pJS.canvas.h = pJS.canvas.el.offsetHeight;
  146. /* resize canvas */
  147. if(pJS.retina){
  148. pJS.canvas.w *= pJS.canvas.pxratio;
  149. pJS.canvas.h *= pJS.canvas.pxratio;
  150. }
  151. pJS.canvas.el.width = pJS.canvas.w;
  152. pJS.canvas.el.height = pJS.canvas.h;
  153. /* repaint canvas */
  154. pJS.fn.canvasPaint();
  155. if(!pJS.particles.anim.enable){
  156. pJS.fn.particlesRemove();
  157. pJS.fn.canvasRemove();
  158. launchParticles();
  159. }
  160. }
  161. }
  162. };
  163. pJS.fn.canvasPaint = function(){
  164. pJS.canvas.ctx.fillRect(0, 0, pJS.canvas.w, pJS.canvas.h);
  165. };
  166. pJS.fn.canvasRemove = function(){
  167. pJS.canvas.ctx.clearRect(0, 0, pJS.canvas.w, pJS.canvas.h);
  168. }
  169. /* --------- PARTICLES functions ----------- */
  170. pJS.fn.particle = function(color, opacity, position){
  171. /* position */
  172. this.x = position ? position.x : Math.random() * pJS.canvas.w;
  173. this.y = position ? position.y : Math.random() * pJS.canvas.h;
  174. /* size */
  175. this.radius = (pJS.particles.size_random ? Math.random() : 1) * pJS.particles.size;
  176. if (pJS.retina) this.radius *= pJS.canvas.pxratio;
  177. /* color */
  178. this.color = color;
  179. /* opacity */
  180. this.opacity = opacity;
  181. /* animation - velocity for speed */
  182. this.vx = -.5 + Math.random();
  183. this.vy = -.5 + Math.random();
  184. /* draw function */
  185. this.draw = function(){
  186. pJS.canvas.ctx.fillStyle = 'rgba('+this.color.r+','+this.color.g+','+this.color.b+','+this.opacity+')';
  187. pJS.canvas.ctx.beginPath();
  188. switch(pJS.particles.shape){
  189. case 'circle':
  190. pJS.canvas.ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
  191. break;
  192. case 'edge':
  193. pJS.canvas.ctx.rect(this.x, this.y, this.radius*2, this.radius*2);
  194. break;
  195. case 'triangle':
  196. pJS.canvas.ctx.moveTo(this.x,this.y-this.radius);
  197. pJS.canvas.ctx.lineTo(this.x+this.radius,this.y+this.radius);
  198. pJS.canvas.ctx.lineTo(this.x-this.radius,this.y+this.radius);
  199. pJS.canvas.ctx.closePath();
  200. break;
  201. }
  202. pJS.canvas.ctx.fill();
  203. }
  204. };
  205. pJS.fn.particlesCreate = function(){
  206. for(var i = 0; i < pJS.particles.nb; i++) {
  207. pJS.particles.array.push(new pJS.fn.particle(pJS.particles.color_rgb, pJS.particles.opacity));
  208. }
  209. };
  210. pJS.fn.particlesAnimate = function(){
  211. for(var i = 0; i < pJS.particles.array.length; i++){
  212. /* the particle */
  213. var p = pJS.particles.array[i];
  214. /* move the particle */
  215. p.x += p.vx * (pJS.particles.anim.speed/2);
  216. p.y += p.vy * (pJS.particles.anim.speed/2);
  217. /* change particle position if it is out of canvas */
  218. if(p.x - p.radius > pJS.canvas.w) p.x = p.radius;
  219. else if(p.x + p.radius < 0) p.x = pJS.canvas.w + p.radius;
  220. if(p.y - p.radius > pJS.canvas.h) p.y = p.radius;
  221. else if(p.y + p.radius < 0) p.y = pJS.canvas.h + p.radius;
  222. /* Check distance between each particle and mouse position */
  223. for(var j = i + 1; j < pJS.particles.array.length; j++){
  224. var p2 = pJS.particles.array[j];
  225. /* link particles if enable */
  226. if(pJS.particles.line_linked.enable_auto){
  227. pJS.fn.vendors.distanceParticles(p,p2);
  228. }
  229. /* set interactivity if enable */
  230. if(pJS.interactivity.enable){
  231. /* interactivity mode */
  232. switch(pJS.interactivity.mode){
  233. case 'grab':
  234. pJS.fn.vendors.interactivity.grabParticles(p,p2);
  235. break;
  236. }
  237. }
  238. }
  239. }
  240. };
  241. pJS.fn.particlesDraw = function(){
  242. /* clear canvas */
  243. pJS.canvas.ctx.clearRect(0, 0, pJS.canvas.w, pJS.canvas.h);
  244. /* move particles */
  245. pJS.fn.particlesAnimate();
  246. /* draw each particle */
  247. for(var i = 0; i < pJS.particles.array.length; i++){
  248. var p = pJS.particles.array[i];
  249. p.draw('rgba('+p.color.r+','+p.color.g+','+p.color.b+','+p.opacity+')');
  250. }
  251. };
  252. pJS.fn.particlesRemove = function(){
  253. pJS.particles.array = [];
  254. };
  255. /* ---------- VENDORS functions ------------ */
  256. pJS.fn.vendors.distanceParticles = function(p1, p2){
  257. var dx = p1.x - p2.x,
  258. dy = p1.y - p2.y,
  259. dist = Math.sqrt(dx*dx + dy*dy);
  260. /* Check distance between particle and mouse mos */
  261. if(dist <= pJS.particles.line_linked.distance) {
  262. /* draw the line */
  263. var color_line = pJS.particles.line_linked.color_rgb_line;
  264. pJS.canvas.ctx.beginPath();
  265. pJS.canvas.ctx.strokeStyle = 'rgba('+color_line.r+','+color_line.g+','+color_line.b+','+ (pJS.particles.line_linked.opacity-dist/pJS.particles.line_linked.distance) +')';
  266. pJS.canvas.ctx.moveTo(p1.x, p1.y);
  267. pJS.canvas.ctx.lineTo(p2.x, p2.y);
  268. pJS.canvas.ctx.lineWidth = pJS.particles.line_linked.width;
  269. pJS.canvas.ctx.stroke();
  270. pJS.canvas.ctx.closePath();
  271. /* condensed particles */
  272. if(pJS.particles.line_linked.condensed_mode.enable){
  273. var dx = p1.x - p2.x,
  274. dy = p1.y - p2.y,
  275. ax = dx/(pJS.particles.line_linked.condensed_mode.rotateX*1000),
  276. ay = dy/(pJS.particles.line_linked.condensed_mode.rotateY*1000);
  277. p2.vx += ax;
  278. p2.vy += ay;
  279. }
  280. }
  281. };
  282. pJS.fn.vendors.interactivity.listeners = function(){
  283. /* init el */
  284. if(pJS.interactivity.detect_on == 'window'){
  285. var detect_el = window;
  286. }else{
  287. var detect_el = pJS.canvas.el;
  288. }
  289. /* el on mousemove */
  290. detect_el.onmousemove = function(e){
  291. if(detect_el == window){
  292. var pos_x = e.clientX,
  293. pos_y = e.clientY;
  294. }
  295. else{
  296. var pos_x = e.offsetX||e.clientX,
  297. pos_y = e.offsetY||e.clientY;
  298. }
  299. if(pJS){
  300. pJS.interactivity.mouse.pos_x = pos_x;
  301. pJS.interactivity.mouse.pos_y = pos_y;
  302. if(pJS.retina){
  303. pJS.interactivity.mouse.pos_x *= pJS.canvas.pxratio;
  304. pJS.interactivity.mouse.pos_y *= pJS.canvas.pxratio;
  305. }
  306. pJS.interactivity.status = 'mousemove';
  307. }
  308. };
  309. /* el on onmouseleave */
  310. detect_el.onmouseleave = function(e){
  311. if(pJS){
  312. pJS.interactivity.mouse.pos_x = 0;
  313. pJS.interactivity.mouse.pos_y = 0;
  314. pJS.interactivity.status = 'mouseleave';
  315. }
  316. };
  317. /* el on onclick */
  318. if(pJS.interactivity.events.onclick.enable){
  319. switch(pJS.interactivity.events.onclick.mode){
  320. case 'push':
  321. detect_el.onclick = function(e){
  322. if(pJS){
  323. for(var i = 0; i < pJS.interactivity.events.onclick.nb; i++){
  324. pJS.particles.array.push(
  325. new pJS.fn.particle(
  326. pJS.particles.color_rgb,
  327. pJS.particles.opacity,
  328. {
  329. 'x': pJS.interactivity.mouse.pos_x,
  330. 'y': pJS.interactivity.mouse.pos_y
  331. }
  332. )
  333. )
  334. }
  335. }
  336. }
  337. break;
  338. case 'remove':
  339. detect_el.onclick = function(e){
  340. pJS.particles.array.splice(0, pJS.interactivity.events.onclick.nb);
  341. }
  342. break;
  343. }
  344. }
  345. };
  346. pJS.fn.vendors.interactivity.grabParticles = function(p1, p2){
  347. var dx = p1.x - p2.x,
  348. dy = p1.y - p2.y,
  349. dist = Math.sqrt(dx*dx + dy*dy);
  350. var dx_mouse = p1.x - pJS.interactivity.mouse.pos_x,
  351. dy_mouse = p1.y - pJS.interactivity.mouse.pos_y,
  352. dist_mouse = Math.sqrt(dx_mouse*dx_mouse + dy_mouse*dy_mouse);
  353. /* Check distance between 2 particles + Check distance between 1 particle and mouse position */
  354. if(dist <= pJS.particles.line_linked.distance && dist_mouse <= pJS.interactivity.mouse.distance && pJS.interactivity.status == 'mousemove'){
  355. /* Draw the line */
  356. var color_line = pJS.particles.line_linked.color_rgb_line;
  357. pJS.canvas.ctx.beginPath();
  358. pJS.canvas.ctx.strokeStyle = 'rgba('+color_line.r+','+color_line.g+','+color_line.b+','+ (pJS.interactivity.line_linked.opacity-dist_mouse/pJS.interactivity.mouse.distance) +')';
  359. pJS.canvas.ctx.moveTo(p1.x, p1.y);
  360. pJS.canvas.ctx.lineTo(pJS.interactivity.mouse.pos_x, pJS.interactivity.mouse.pos_y);
  361. pJS.canvas.ctx.lineWidth = pJS.particles.line_linked.width;
  362. pJS.canvas.ctx.stroke();
  363. pJS.canvas.ctx.closePath();
  364. }
  365. };
  366. pJS.fn.vendors.destroy = function(){
  367. cancelAnimationFrame(pJS.fn.requestAnimFrame);
  368. canvas_el.remove();
  369. delete pJS;
  370. };
  371. /* --------- LAUNCH ----------- */
  372. function launchParticles(){
  373. pJS.fn.canvasInit();
  374. pJS.fn.canvasSize();
  375. pJS.fn.canvasPaint();
  376. pJS.fn.particlesCreate();
  377. pJS.fn.particlesDraw();
  378. };
  379. function launchAnimation(){
  380. pJS.fn.particlesDraw();
  381. pJS.fn.requestAnimFrame = requestAnimFrame(launchAnimation);
  382. };
  383. launchParticles();
  384. if(pJS.particles.anim.enable){
  385. launchAnimation();
  386. }
  387. if(pJS.interactivity.enable){
  388. pJS.fn.vendors.interactivity.listeners();
  389. }
  390. };
  391. /* --- VENDORS --- */
  392. window.requestAnimFrame = (function(){
  393. return window.requestAnimationFrame ||
  394. window.webkitRequestAnimationFrame ||
  395. window.mozRequestAnimationFrame ||
  396. window.oRequestAnimationFrame ||
  397. window.msRequestAnimationFrame ||
  398. function(callback){
  399. window.setTimeout(callback, 1000 / 60);
  400. };
  401. })();
  402. window.cancelRequestAnimFrame = ( function() {
  403. return window.cancelAnimationFrame ||
  404. window.webkitCancelRequestAnimationFrame ||
  405. window.mozCancelRequestAnimationFrame ||
  406. window.oCancelRequestAnimationFrame ||
  407. window.msCancelRequestAnimationFrame ||
  408. clearTimeout
  409. } )();
  410. function hexToRgb(hex){
  411. // By Tim Down - http://stackoverflow.com/a/5624139/3493650
  412. // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
  413. var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
  414. hex = hex.replace(shorthandRegex, function(m, r, g, b) {
  415. return r + r + g + g + b + b;
  416. });
  417. var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  418. return result ? {
  419. r: parseInt(result[1], 16),
  420. g: parseInt(result[2], 16),
  421. b: parseInt(result[3], 16)
  422. } : null;
  423. };
  424. /* --- LAUNCH --- */
  425. window.particlesJS = function(tag_id, params){
  426. /* no string id? so it's object params, and set the id with default id */
  427. if(typeof(tag_id) != 'string'){
  428. params = tag_id;
  429. tag_id = 'particles-js';
  430. }
  431. /* no id? set the id to default id */
  432. if(!tag_id){
  433. tag_id = 'particles-js';
  434. }
  435. /* create canvas element */
  436. var canvas_el = document.createElement('canvas');
  437. /* set size canvas */
  438. canvas_el.style.width = "100%";
  439. canvas_el.style.height = "20vw";
  440. /* append canvas */
  441. var canvas = document.getElementById(tag_id).appendChild(canvas_el);
  442. /* launch particle.js */
  443. if(canvas != null){
  444. launchParticlesJS(tag_id, params);
  445. }
  446. };