jekyll-theme-satellite 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/_config.yml +82 -0
  4. data/_includes/loading.html +6 -0
  5. data/_includes/navigation.html +84 -0
  6. data/_includes/pagination.html +71 -0
  7. data/_includes/post.html +65 -0
  8. data/_includes/search.html +21 -0
  9. data/_includes/sidebar.html +83 -0
  10. data/_layouts/default.html +113 -0
  11. data/_sass/darkmode.scss +211 -0
  12. data/_sass/layout.scss +57 -0
  13. data/_sass/navigation.scss +178 -0
  14. data/_sass/pagination.scss +253 -0
  15. data/_sass/post.scss +640 -0
  16. data/_sass/search.scss +248 -0
  17. data/_sass/sidebar.scss +309 -0
  18. data/_sass/toc.scss +52 -0
  19. data/_sass/vars.scss +15 -0
  20. data/assets/css/highlight-dark.min.css +1 -0
  21. data/assets/css/highlight-default.min.css +1 -0
  22. data/assets/css/style.scss +89 -0
  23. data/assets/fonts/Lato-Regular.ttf +0 -0
  24. data/assets/fonts/NunitoSans-Regular.ttf +0 -0
  25. data/assets/fonts/Righteous-Regular.ttf +0 -0
  26. data/assets/img/La-Mancha.jpg +0 -0
  27. data/assets/img/example.jpg +0 -0
  28. data/assets/img/favicon.webp +0 -0
  29. data/assets/img/icon/book-solid.svg +1 -0
  30. data/assets/img/icon/calendar-days-regular.svg +1 -0
  31. data/assets/img/icon/clipboard-regular.svg +1 -0
  32. data/assets/img/icon/folder-open-regular.svg +1 -0
  33. data/assets/img/icon/tags-solid.svg +1 -0
  34. data/assets/img/loading.webp +0 -0
  35. data/assets/img/profile.jpg +0 -0
  36. data/assets/img/sorry.png +0 -0
  37. data/assets/img/thumbnail/book.jpg +0 -0
  38. data/assets/img/thumbnail/bricks.webp +0 -0
  39. data/assets/img/thumbnail/empty.jpg +0 -0
  40. data/assets/img/thumbnail/nightgardenflower.jpg +0 -0
  41. data/assets/img/thumbnail/sample.png +0 -0
  42. data/assets/img/tile.png +0 -0
  43. data/assets/js/404.js +22 -0
  44. data/assets/js/highlight.min.js +1213 -0
  45. data/assets/js/main.js +709 -0
  46. data/assets/js/stars.js +700 -0
  47. data/assets/js/sweet-scroll.min.js +2 -0
  48. data/assets/js/tocbot.min.js +1 -0
  49. metadata +104 -0
@@ -0,0 +1,700 @@
1
+ /**
2
+ * Stars
3
+ * Inspired by Steve Courtney's poster art for Celsius GS's Drifter - http://celsiusgs.com/drifter/posters.php
4
+ * by Cory Hughart - http://coryhughart.com
5
+ */
6
+
7
+ // Settings
8
+ var particleCount = 40,
9
+ flareCount = 16,
10
+ motion = 0.05,
11
+ tilt = 0.05,
12
+ color = '#44b5fd',
13
+ colorPalette = ["#c13c3c", "#c13cc1", "#3c3cc1", "#3cc1c1", "#3cc13c", "#c1c13c"],
14
+ particleSizeBase = 2,
15
+ particleSizeMultiplier = 0.5,
16
+ flareSizeBase = 100,
17
+ flareSizeMultiplier = 100,
18
+ lineWidth = 1,
19
+ linkChance = 75, // chance per frame of link, higher = smaller chance
20
+ linkLengthMin = 5, // min linked vertices
21
+ linkLengthMax = 7, // max linked vertices
22
+ linkOpacity = 0.375; // number between 0 & 1
23
+ linkFade = 90, // link fade-out frames
24
+ linkSpeed = 1, // distance a link travels in 1 frame
25
+ glareAngle = -60,
26
+ glareOpacityMultiplier = 0.05,
27
+ renderParticles = true,
28
+ renderParticleGlare = true,
29
+ renderFlares = true,
30
+ renderLinks = true,
31
+ renderMesh = false,
32
+ flicker = true,
33
+ flickerSmoothing = 15, // higher = smoother flicker
34
+ blurSize = 0,
35
+ orbitTilt = true,
36
+ randomMotion = true,
37
+ noiseLength = 1000,
38
+ noiseStrength = 1;
39
+
40
+ var canvas = document.getElementById('stars'),
41
+ context = canvas.getContext('2d'),
42
+ mouse = { x: 0, y: 0 },
43
+ m = {},
44
+ r = 0,
45
+ c = 1000, // multiplier for delaunay points, since floats too small can mess up the algorithm
46
+ n = 0,
47
+ nAngle = (Math.PI * 2) / noiseLength,
48
+ nRad = 100,
49
+ nScale = 0.5,
50
+ nPos = {x: 0, y: 0},
51
+ points = [],
52
+ vertices = [],
53
+ triangles = [],
54
+ links = [],
55
+ particles = [],
56
+ flares = [];
57
+
58
+ // Delaunay Triangulation
59
+ var EPSILON = 1.0 / 1048576.0;
60
+
61
+ function randomColor(colors){
62
+ return colors[Math.floor(Math.random() * colors.length)];
63
+ }
64
+
65
+ function supertriangle(vertices) {
66
+ var xmin = Number.POSITIVE_INFINITY,
67
+ ymin = Number.POSITIVE_INFINITY,
68
+ xmax = Number.NEGATIVE_INFINITY,
69
+ ymax = Number.NEGATIVE_INFINITY,
70
+ i, dx, dy, dmax, xmid, ymid;
71
+
72
+ for(i = vertices.length; i--; ) {
73
+ if(vertices[i][0] < xmin) xmin = vertices[i][0];
74
+ if(vertices[i][0] > xmax) xmax = vertices[i][0];
75
+ if(vertices[i][1] < ymin) ymin = vertices[i][1];
76
+ if(vertices[i][1] > ymax) ymax = vertices[i][1];
77
+ }
78
+
79
+ dx = xmax - xmin;
80
+ dy = ymax - ymin;
81
+ dmax = Math.max(dx, dy);
82
+ xmid = xmin + dx * 0.5;
83
+ ymid = ymin + dy * 0.5;
84
+
85
+ return [
86
+ [xmid - 20 * dmax, ymid - dmax],
87
+ [xmid , ymid + 20 * dmax],
88
+ [xmid + 20 * dmax, ymid - dmax]
89
+ ];
90
+ }
91
+
92
+ function circumcircle(vertices, i, j, k) {
93
+ var x1 = vertices[i][0],
94
+ y1 = vertices[i][1],
95
+ x2 = vertices[j][0],
96
+ y2 = vertices[j][1],
97
+ x3 = vertices[k][0],
98
+ y3 = vertices[k][1],
99
+ fabsy1y2 = Math.abs(y1 - y2),
100
+ fabsy2y3 = Math.abs(y2 - y3),
101
+ xc, yc, m1, m2, mx1, mx2, my1, my2, dx, dy;
102
+
103
+ /* Check for coincident points */
104
+ if(fabsy1y2 < EPSILON && fabsy2y3 < EPSILON)
105
+ throw new Error("Eek! Coincident points!");
106
+
107
+ if(fabsy1y2 < EPSILON) {
108
+ m2 = -((x3 - x2) / (y3 - y2));
109
+ mx2 = (x2 + x3) / 2.0;
110
+ my2 = (y2 + y3) / 2.0;
111
+ xc = (x2 + x1) / 2.0;
112
+ yc = m2 * (xc - mx2) + my2;
113
+ }
114
+ else if(fabsy2y3 < EPSILON) {
115
+ m1 = -((x2 - x1) / (y2 - y1));
116
+ mx1 = (x1 + x2) / 2.0;
117
+ my1 = (y1 + y2) / 2.0;
118
+ xc = (x3 + x2) / 2.0;
119
+ yc = m1 * (xc - mx1) + my1;
120
+ }
121
+ else {
122
+ m1 = -((x2 - x1) / (y2 - y1));
123
+ m2 = -((x3 - x2) / (y3 - y2));
124
+ mx1 = (x1 + x2) / 2.0;
125
+ mx2 = (x2 + x3) / 2.0;
126
+ my1 = (y1 + y2) / 2.0;
127
+ my2 = (y2 + y3) / 2.0;
128
+ xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
129
+ yc = (fabsy1y2 > fabsy2y3) ?
130
+ m1 * (xc - mx1) + my1 :
131
+ m2 * (xc - mx2) + my2;
132
+ }
133
+
134
+ dx = x2 - xc;
135
+ dy = y2 - yc;
136
+ return {i: i, j: j, k: k, x: xc, y: yc, r: dx * dx + dy * dy};
137
+ }
138
+
139
+ function dedup(edges) {
140
+ var i, j, a, b, m, n;
141
+
142
+ for(j = edges.length; j; ) {
143
+ b = edges[--j];
144
+ a = edges[--j];
145
+
146
+ for(i = j; i; ) {
147
+ n = edges[--i];
148
+ m = edges[--i];
149
+
150
+ if((a === m && b === n) || (a === n && b === m)) {
151
+ edges.splice(j, 2);
152
+ edges.splice(i, 2);
153
+ break;
154
+ }
155
+ }
156
+ }
157
+ }
158
+
159
+ function Delaunay(vertices, key) {
160
+ var n = vertices.length,
161
+ i, j, indices, st, open, closed, edges, dx, dy, a, b, c;
162
+
163
+ /* Bail if there aren't enough vertices to form any triangles. */
164
+ if(n < 3)
165
+ return [];
166
+
167
+ /* Slice out the actual vertices from the passed objects. (Duplicate the
168
+ * array even if we don't, though, since we need to make a supertriangle
169
+ * later on!) */
170
+ vertices = vertices.slice(0);
171
+
172
+ if(key)
173
+ for(i = n; i--; )
174
+ vertices[i] = vertices[i][key];
175
+
176
+ /* Make an array of indices into the vertex array, sorted by the
177
+ * vertices' x-position. */
178
+ indices = new Array(n);
179
+
180
+ for(i = n; i--; )
181
+ indices[i] = i;
182
+
183
+ indices.sort(function(i, j) {
184
+ return vertices[j][0] - vertices[i][0];
185
+ });
186
+
187
+ /* Next, find the vertices of the supertriangle (which contains all other
188
+ * triangles), and append them onto the end of a (copy of) the vertex
189
+ * array. */
190
+ st = supertriangle(vertices);
191
+ vertices.push(st[0], st[1], st[2]);
192
+
193
+ /* Initialize the open list (containing the supertriangle and nothing
194
+ * else) and the closed list (which is empty since we havn't processed
195
+ * any triangles yet). */
196
+ open = [circumcircle(vertices, n + 0, n + 1, n + 2)];
197
+ closed = [];
198
+ edges = [];
199
+
200
+ /* Incrementally add each vertex to the mesh. */
201
+ for(i = indices.length; i--; edges.length = 0) {
202
+ c = indices[i];
203
+
204
+ /* For each open triangle, check to see if the current point is
205
+ * inside it's circumcircle. If it is, remove the triangle and add
206
+ * it's edges to an edge list. */
207
+ for(j = open.length; j--; ) {
208
+ /* If this point is to the right of this triangle's circumcircle,
209
+ * then this triangle should never get checked again. Remove it
210
+ * from the open list, add it to the closed list, and skip. */
211
+ dx = vertices[c][0] - open[j].x;
212
+
213
+ if(dx > 0.0 && dx * dx > open[j].r) {
214
+ closed.push(open[j]);
215
+ open.splice(j, 1);
216
+ continue;
217
+ }
218
+
219
+ /* If we're outside the circumcircle, skip this triangle. */
220
+ dy = vertices[c][1] - open[j].y;
221
+
222
+ if(dx * dx + dy * dy - open[j].r > EPSILON)
223
+ continue;
224
+
225
+ /* Remove the triangle and add it's edges to the edge list. */
226
+ edges.push(
227
+ open[j].i, open[j].j,
228
+ open[j].j, open[j].k,
229
+ open[j].k, open[j].i
230
+ );
231
+
232
+ open.splice(j, 1);
233
+ }
234
+
235
+ /* Remove any doubled edges. */
236
+ dedup(edges);
237
+
238
+ /* Add a new triangle for each edge. */
239
+ for(j = edges.length; j; ) {
240
+ b = edges[--j];
241
+ a = edges[--j];
242
+ open.push(circumcircle(vertices, a, b, c));
243
+ }
244
+ }
245
+
246
+ /* Copy any remaining open triangles to the closed list, and then
247
+ * remove any triangles that share a vertex with the supertriangle,
248
+ * building a list of triplets that represent triangles. */
249
+ for(i = open.length; i--; )
250
+ closed.push(open[i]);
251
+
252
+ open.length = 0;
253
+
254
+ for(i = closed.length; i--; )
255
+ if(closed[i].i < n && closed[i].j < n && closed[i].k < n)
256
+ open.push(closed[i].i, closed[i].j, closed[i].k);
257
+
258
+ /* Yay, we're done! */
259
+ return open;
260
+ }
261
+
262
+ function init() {
263
+ var i, j, k;
264
+
265
+ // requestAnimFrame polyfill
266
+ window.requestAnimFrame = (function(){
267
+ return window.requestAnimationFrame ||
268
+ window.webkitRequestAnimationFrame ||
269
+ window.mozRequestAnimationFrame ||
270
+ function( callback ){
271
+ window.setTimeout(callback, 1000 / 60);
272
+ };
273
+ })();
274
+
275
+ // Size canvas
276
+ resize();
277
+
278
+ mouse.x = canvas.clientWidth / 2;
279
+ mouse.y = canvas.clientHeight / 2;
280
+
281
+ // Create particle positions
282
+ for (i = 0; i < particleCount; i++) {
283
+ var p = new Particle();
284
+ particles.push(p);
285
+ points.push([p.x*c, p.y*c]);
286
+ }
287
+
288
+ vertices = Delaunay(points);
289
+ // Create an array of "triangles" (groups of 3 indices)
290
+ var tri = [];
291
+
292
+ for (i = 0; i < vertices.length; i++) {
293
+ if (tri.length == 3) {
294
+ triangles.push(tri);
295
+ tri = [];
296
+ }
297
+
298
+ tri.push(vertices[i]);
299
+ }
300
+
301
+ // Tell all the particles who their neighbors are
302
+ for (i = 0; i < particles.length; i++) {
303
+ // Loop through all tirangles
304
+ for (j = 0; j < triangles.length; j++) {
305
+ // Check if this particle's index is in this triangle
306
+ k = triangles[j].indexOf(i);
307
+ // If it is, add its neighbors to the particles contacts list
308
+ if (k !== -1) {
309
+ triangles[j].forEach(function(value, index, array) {
310
+ if (value !== i && particles[i].neighbors.indexOf(value) == -1) {
311
+ particles[i].neighbors.push(value);
312
+ }
313
+ });
314
+ }
315
+ }
316
+ }
317
+
318
+ if (renderFlares) {
319
+ // Create flare positions
320
+ for (i = 0; i < flareCount; i++) {
321
+ flares.push(new Flare());
322
+ }
323
+ }
324
+
325
+ // Motion mode
326
+ if ('ontouchstart' in document.documentElement && window.DeviceOrientationEvent) {
327
+ console.log('Using device orientation');
328
+ window.addEventListener('deviceorientation', function(e) {
329
+ mouse.x = (canvas.clientWidth / 2) - ((e.gamma / 90) * (canvas.clientWidth / 2) * 2);
330
+ mouse.y = (canvas.clientHeight / 2) - ((e.beta / 90) * (canvas.clientHeight / 2) * 2);
331
+ }, true);
332
+ }
333
+ else {
334
+ // Mouse move listener
335
+ console.log('Using mouse movement');
336
+ document.body.addEventListener('mousemove', function(e) {
337
+ mouse.x = e.clientX;
338
+ mouse.y = e.clientY;
339
+ });
340
+ }
341
+
342
+ // Animation loop
343
+ (function animloop(){
344
+ requestAnimFrame(animloop);
345
+ resize();
346
+ render();
347
+ })();
348
+ }
349
+
350
+ function render() {
351
+ if (randomMotion) {
352
+ n++;
353
+
354
+ if (n >= noiseLength) {
355
+ n = 0;
356
+ }
357
+
358
+ nPos = noisePoint(n);
359
+ }
360
+
361
+ // Clear
362
+ context.clearRect(0, 0, canvas.width, canvas.height);
363
+
364
+ if (blurSize > 0) {
365
+ context.shadowBlur = blurSize;
366
+ context.shadowColor = randomColor(colorPalette);
367
+ }
368
+
369
+ if (renderParticles) {
370
+ // Render particles
371
+ for (var i = 0; i < particleCount; i++) {
372
+ particles[i].render();
373
+ }
374
+ }
375
+
376
+ if (renderMesh) {
377
+ // Render all lines
378
+ context.beginPath();
379
+
380
+ for (var v = 0; v < vertices.length-1; v++) {
381
+ // Splits the array into triplets
382
+ if ((v + 1) % 3 === 0) { continue; }
383
+
384
+ var p1 = particles[vertices[v]],
385
+ p2 = particles[vertices[v+1]];
386
+
387
+ var pos1 = position(p1.x, p1.y, p1.z),
388
+ pos2 = position(p2.x, p2.y, p2.z);
389
+
390
+ context.moveTo(pos1.x, pos1.y);
391
+ context.lineTo(pos2.x, pos2.y);
392
+ }
393
+
394
+ context.strokeStyle = randomColor(colorPalette);
395
+ context.lineWidth = lineWidth;
396
+ context.stroke();
397
+ context.closePath();
398
+ }
399
+
400
+ if (renderLinks) {
401
+ // Possibly start a new link
402
+ if (random(0, linkChance) == linkChance) {
403
+ var length = random(linkLengthMin, linkLengthMax);
404
+ var start = random(0, particles.length-1);
405
+ startLink(start, length);
406
+ }
407
+
408
+ // Render existing links
409
+ // Iterate in reverse so that removing items doesn't affect the loop
410
+ for (var l = links.length-1; l >= 0; l--) {
411
+ if (links[l] && !links[l].finished) {
412
+ links[l].render();
413
+ }
414
+ else {
415
+ delete links[l];
416
+ }
417
+ }
418
+ }
419
+
420
+ if (renderFlares) {
421
+ // Render flares
422
+ for (var j = 0; j < flareCount; j++) {
423
+ flares[j].render();
424
+ }
425
+ }
426
+ }
427
+
428
+ function resize() {
429
+ canvas.width = window.innerWidth * (window.devicePixelRatio || 1);
430
+ canvas.height = canvas.width * (canvas.clientHeight / canvas.clientWidth);
431
+ }
432
+
433
+ function startLink(vertex, length) {
434
+ links.push(new Link(vertex, length));
435
+ }
436
+
437
+ // Particle class
438
+ var Particle = function() {
439
+ this.x = random(-0.1, 1.1, true);
440
+ this.y = random(-0.1, 1.1, true);
441
+ this.z = random(0,4);
442
+ this.color = randomColor(colorPalette);
443
+ this.opacity = random(0.1,1,true);
444
+ this.flicker = 0;
445
+ this.neighbors = []; // placeholder for neighbors
446
+ };
447
+
448
+ Particle.prototype.render = function() {
449
+ var pos = position(this.x, this.y, this.z),
450
+ r = ((this.z * particleSizeMultiplier) + particleSizeBase) * (sizeRatio() / 1000),
451
+ o = this.opacity;
452
+
453
+ if (flicker) {
454
+ var newVal = random(-0.5, 0.5, true);
455
+ this.flicker += (newVal - this.flicker) / flickerSmoothing;
456
+
457
+ if (this.flicker > 0.5) this.flicker = 0.5;
458
+ if (this.flicker < -0.5) this.flicker = -0.5;
459
+
460
+ o += this.flicker;
461
+
462
+ if (o > 1) o = 1;
463
+ if (o < 0) o = 0;
464
+ }
465
+
466
+ context.fillStyle = this.color;
467
+ context.globalAlpha = o;
468
+ context.beginPath();
469
+ context.arc(pos.x, pos.y, r, 0, 2 * Math.PI, false);
470
+ context.fill();
471
+ context.closePath();
472
+
473
+ if (renderParticleGlare) {
474
+ context.globalAlpha = o * glareOpacityMultiplier;
475
+ context.ellipse(pos.x, pos.y, r * 100, r, (glareAngle - ((nPos.x - 0.5) * noiseStrength * motion)) * (Math.PI / 180), 0, 2 * Math.PI, false);
476
+ context.fill();
477
+ context.closePath();
478
+ }
479
+
480
+ context.globalAlpha = 1;
481
+ };
482
+
483
+ // Flare class
484
+ var Flare = function() {
485
+ this.x = random(-0.25, 1.25, true);
486
+ this.y = random(-0.25, 1.25, true);
487
+ this.z = random(0,2);
488
+ this.color = randomColor(colorPalette);
489
+ this.opacity = random(0.001, 0.01, true);
490
+ };
491
+
492
+ Flare.prototype.render = function() {
493
+ var pos = position(this.x, this.y, this.z),
494
+ r = ((this.z * flareSizeMultiplier) + flareSizeBase) * (sizeRatio() / 1000);
495
+
496
+ // Feathered circles
497
+ context.beginPath();
498
+ context.globalAlpha = this.opacity;
499
+ context.arc(pos.x, pos.y, r, 0, 2 * Math.PI, false);
500
+ context.fillStyle = this.color;
501
+ context.fill();
502
+ context.closePath();
503
+ context.globalAlpha = 1;
504
+ };
505
+
506
+ // Link class
507
+ var Link = function(startVertex, numPoints) {
508
+ this.length = numPoints;
509
+ this.verts = [startVertex];
510
+ this.stage = 0;
511
+ this.linked = [startVertex];
512
+ this.distances = [];
513
+ this.traveled = 0;
514
+ this.fade = 0;
515
+ this.finished = false;
516
+ };
517
+
518
+ Link.prototype.render = function() {
519
+ // Stages:
520
+ // 0. Vertex collection
521
+ // 1. Render line reaching from vertex to vertex
522
+ // 2. Fade out
523
+ // 3. Finished (delete me)
524
+
525
+ var i, p, pos, points;
526
+
527
+ switch (this.stage) {
528
+ // VERTEX COLLECTION STAGE
529
+ case 0:
530
+ // Grab the last member of the link
531
+ var last = particles[this.verts[this.verts.length-1]];
532
+ if (last && last.neighbors && last.neighbors.length > 0) {
533
+ // Grab a random neighbor
534
+ var neighbor = last.neighbors[random(0, last.neighbors.length-1)];
535
+ // If we haven't seen that particle before, add it to the link
536
+ if (this.verts.indexOf(neighbor) == -1) {
537
+ this.verts.push(neighbor);
538
+ }
539
+ // If we have seen that particle before, we'll just wait for the next frame
540
+ }
541
+ else {
542
+ this.stage = 3;
543
+ this.finished = true;
544
+ }
545
+
546
+ if (this.verts.length >= this.length) {
547
+ // Calculate all distances at once
548
+ for (i = 0; i < this.verts.length-1; i++) {
549
+ var p1 = particles[this.verts[i]],
550
+ p2 = particles[this.verts[i+1]],
551
+ dx = p1.x - p2.x,
552
+ dy = p1.y - p2.y,
553
+ dist = Math.sqrt(dx*dx + dy*dy);
554
+
555
+ this.distances.push(dist);
556
+ }
557
+ this.stage = 1;
558
+ }
559
+ break;
560
+
561
+ // RENDER LINE ANIMATION STAGE
562
+ case 1:
563
+ if (this.distances.length > 0) {
564
+
565
+ points = [];
566
+
567
+ // Gather all points already linked
568
+ for (i = 0; i < this.linked.length; i++) {
569
+ p = particles[this.linked[i]];
570
+ pos = position(p.x, p.y, p.z);
571
+ points.push([pos.x, pos.y]);
572
+ }
573
+
574
+ var linkSpeedRel = linkSpeed * 0.00001 * canvas.width;
575
+ this.traveled += linkSpeedRel;
576
+ var d = this.distances[this.linked.length-1];
577
+ // Calculate last point based on linkSpeed and distance travelled to next point
578
+ if (this.traveled >= d) {
579
+ this.traveled = 0;
580
+ // We've reached the next point, add coordinates to array
581
+ this.linked.push(this.verts[this.linked.length]);
582
+ p = particles[this.linked[this.linked.length-1]];
583
+ pos = position(p.x, p.y, p.z);
584
+ points.push([pos.x, pos.y]);
585
+
586
+ if (this.linked.length >= this.verts.length) {
587
+ this.stage = 2;
588
+ }
589
+ }
590
+ else {
591
+ // We're still travelling to the next point, get coordinates at travel distance
592
+ // http://math.stackexchange.com/a/85582
593
+ var a = particles[this.linked[this.linked.length-1]],
594
+ b = particles[this.verts[this.linked.length]],
595
+ t = d - this.traveled,
596
+ x = ((this.traveled * b.x) + (t * a.x)) / d,
597
+ y = ((this.traveled * b.y) + (t * a.y)) / d,
598
+ z = ((this.traveled * b.z) + (t * a.z)) / d;
599
+
600
+ pos = position(x, y, z);
601
+ points.push([pos.x, pos.y]);
602
+ }
603
+
604
+ this.drawLine(points);
605
+ }
606
+ else {
607
+ this.stage = 3;
608
+ this.finished = true;
609
+ }
610
+ break;
611
+
612
+ // FADE OUT STAGE
613
+ case 2:
614
+ if (this.verts.length > 1) {
615
+ if (this.fade < linkFade) {
616
+ this.fade++;
617
+
618
+ // Render full link between all vertices and fade over time
619
+ points = [];
620
+ var alpha = (1 - (this.fade / linkFade)) * linkOpacity;
621
+
622
+ for (i = 0; i < this.verts.length; i++) {
623
+ p = particles[this.verts[i]];
624
+ pos = position(p.x, p.y, p.z);
625
+ points.push([pos.x, pos.y]);
626
+ }
627
+
628
+ this.drawLine(points, alpha);
629
+ }
630
+ else {
631
+ this.stage = 3;
632
+ this.finished = true;
633
+ }
634
+ }
635
+ else {
636
+ this.stage = 3;
637
+ this.finished = true;
638
+ }
639
+
640
+ break;
641
+ // FINISHED STAGE
642
+ case 3:
643
+ default:
644
+ this.finished = true;
645
+ break;
646
+ }
647
+ };
648
+
649
+ Link.prototype.drawLine = function(points, alpha) {
650
+ if (typeof alpha !== 'number') alpha = linkOpacity;
651
+
652
+ if (points.length > 1 && alpha > 0) {
653
+ context.globalAlpha = alpha;
654
+ context.beginPath();
655
+
656
+ for (var i = 0; i < points.length-1; i++) {
657
+ context.moveTo(points[i][0], points[i][1]);
658
+ context.lineTo(points[i+1][0], points[i+1][1]);
659
+ }
660
+
661
+ context.strokeStyle = '#888';
662
+ context.lineWidth = lineWidth;
663
+ context.stroke();
664
+ context.closePath();
665
+ context.globalAlpha = 1;
666
+ }
667
+ };
668
+
669
+ // Utils
670
+ function noisePoint(i) {
671
+ var a = nAngle * i,
672
+ cosA = Math.cos(a),
673
+ sinA = Math.sin(a),
674
+ rad = nRad;
675
+
676
+ return {
677
+ x: rad * cosA,
678
+ y: rad * sinA
679
+ };
680
+ }
681
+
682
+ function position(x, y, z) {
683
+ return {
684
+ x: (x * canvas.width) + ((((canvas.width / 2) - mouse.x + ((nPos.x - 0.5) * noiseStrength)) * z) * motion),
685
+ y: (y * canvas.height) + ((((canvas.height / 2) - mouse.y + ((nPos.y - 0.5) * noiseStrength)) * z) * motion)
686
+ };
687
+ }
688
+
689
+ function sizeRatio() {
690
+ return canvas.width >= canvas.height ? canvas.width : canvas.height;
691
+ }
692
+
693
+ function random(min, max, float) {
694
+ return float ?
695
+ Math.random() * (max - min) + min :
696
+ Math.floor(Math.random() * (max - min + 1)) + min;
697
+ }
698
+
699
+ // init
700
+ if (canvas) init();