jekyll-theme-satellite 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/_config.yml +82 -0
- data/_includes/loading.html +6 -0
- data/_includes/navigation.html +84 -0
- data/_includes/pagination.html +71 -0
- data/_includes/post.html +65 -0
- data/_includes/search.html +21 -0
- data/_includes/sidebar.html +83 -0
- data/_layouts/default.html +113 -0
- data/_sass/darkmode.scss +211 -0
- data/_sass/layout.scss +57 -0
- data/_sass/navigation.scss +178 -0
- data/_sass/pagination.scss +253 -0
- data/_sass/post.scss +640 -0
- data/_sass/search.scss +248 -0
- data/_sass/sidebar.scss +309 -0
- data/_sass/toc.scss +52 -0
- data/_sass/vars.scss +15 -0
- data/assets/css/highlight-dark.min.css +1 -0
- data/assets/css/highlight-default.min.css +1 -0
- data/assets/css/style.scss +89 -0
- data/assets/fonts/Lato-Regular.ttf +0 -0
- data/assets/fonts/NunitoSans-Regular.ttf +0 -0
- data/assets/fonts/Righteous-Regular.ttf +0 -0
- data/assets/img/La-Mancha.jpg +0 -0
- data/assets/img/example.jpg +0 -0
- data/assets/img/favicon.webp +0 -0
- data/assets/img/icon/book-solid.svg +1 -0
- data/assets/img/icon/calendar-days-regular.svg +1 -0
- data/assets/img/icon/clipboard-regular.svg +1 -0
- data/assets/img/icon/folder-open-regular.svg +1 -0
- data/assets/img/icon/tags-solid.svg +1 -0
- data/assets/img/loading.webp +0 -0
- data/assets/img/profile.jpg +0 -0
- data/assets/img/sorry.png +0 -0
- data/assets/img/thumbnail/book.jpg +0 -0
- data/assets/img/thumbnail/bricks.webp +0 -0
- data/assets/img/thumbnail/empty.jpg +0 -0
- data/assets/img/thumbnail/nightgardenflower.jpg +0 -0
- data/assets/img/thumbnail/sample.png +0 -0
- data/assets/img/tile.png +0 -0
- data/assets/js/404.js +22 -0
- data/assets/js/highlight.min.js +1213 -0
- data/assets/js/main.js +709 -0
- data/assets/js/stars.js +700 -0
- data/assets/js/sweet-scroll.min.js +2 -0
- data/assets/js/tocbot.min.js +1 -0
- metadata +104 -0
data/assets/js/stars.js
ADDED
@@ -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();
|