145 lines
3.6 KiB
JavaScript
145 lines
3.6 KiB
JavaScript
console.clear();
|
|
|
|
const canvas = document.querySelector('canvas');
|
|
const svg = document.querySelector('svg');
|
|
const ctx = canvas.getContext('2d');
|
|
let width = svg.clientWidth;
|
|
let height = svg.clientHeight;
|
|
|
|
canvas.width = width;
|
|
canvas.height = height;
|
|
|
|
const gradients = [
|
|
[
|
|
[0, [118, 179, 236]],
|
|
[10, [41, 102, 193]],
|
|
[20, [129, 77, 185]],
|
|
[30, [129, 77, 185]],
|
|
[50, [250, 148, 170]],
|
|
[60, [237, 70, 54]],
|
|
[70, [253, 134, 100]],
|
|
[80, [254, 156, 33]],
|
|
[90, [250, 213, 0]],
|
|
[100, [171, 211, 96]]
|
|
],
|
|
[
|
|
[0, [1, 123, 147]],
|
|
[100, [131, 201, 167]]
|
|
]
|
|
];
|
|
|
|
const dots = [];
|
|
class Dot {
|
|
constructor (x, y, color, delay) {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.r = 0;
|
|
this.color = color;
|
|
this.delay = (delay * 0.9);
|
|
this.tween = gsap.fromTo(this, {
|
|
r: 0,
|
|
x: x - 0.05,
|
|
y: y - 0.05
|
|
}, {
|
|
x: x,
|
|
y: y,
|
|
r: () => width * 0.03 + (Math.abs(Math.sin(this.delay * 3.4 - 1.5)) * width * 0.02),
|
|
duration: 1.8,
|
|
ease: 'elastic.out(1, 0.5)',
|
|
delay: this.delay
|
|
});
|
|
}
|
|
draw () {
|
|
ctx.fillStyle = this.color;
|
|
ctx.beginPath();
|
|
ctx.arc(this.x * width, this.y * height, this.r, 0, 2 * Math.PI);
|
|
ctx.fill();
|
|
}
|
|
}
|
|
|
|
function init () {
|
|
const paths = svg.querySelectorAll('path');
|
|
const totalLength = [...paths].reduce((p) => p.getTotalLength());
|
|
let sum_length = 0;
|
|
paths.forEach((path, pathIndex) => {
|
|
const length = path.getTotalLength();
|
|
for (let i = 0; i < length; i+=2) {
|
|
const point = path.getPointAtLength(i);
|
|
const x = point.x / 400;
|
|
const y = point.y / 488;
|
|
const RGB_color = getColor(pathIndex, length, i / length);
|
|
const color = `rgb(${RGB_color[0]}, ${RGB_color[1]}, ${RGB_color[2]})`;
|
|
|
|
const dot = new Dot(x, y, color, (1.5 - (sum_length / totalLength)));
|
|
dots.push(dot);
|
|
sum_length += 2;
|
|
}
|
|
});
|
|
}
|
|
|
|
/* Code copied from https://stackoverflow.com/a/30144587 */
|
|
function pickHex(color1, color2, weight) {
|
|
var p = weight;
|
|
var w = p * 2 - 1;
|
|
var w1 = (w/1+1) / 2;
|
|
var w2 = 1 - w1;
|
|
var rgb = [Math.round(color1[0] * w1 + color2[0] * w2),
|
|
Math.round(color1[1] * w1 + color2[1] * w2),
|
|
Math.round(color1[2] * w1 + color2[2] * w2)];
|
|
return rgb;
|
|
}
|
|
function getColor(pathIndex, pathLength, colorIndex) {
|
|
var colorRange = [];
|
|
let stop = false;
|
|
const gradient = gradients[pathIndex];
|
|
gradient.forEach((step, index) => {
|
|
if (!stop && (colorIndex * 100) <= step[0]) {
|
|
if (index === 0) {
|
|
index = 1;
|
|
}
|
|
colorRange = [index - 1, index];
|
|
stop = true;
|
|
}
|
|
});
|
|
|
|
//Get the two closest colors
|
|
var firstcolor = gradient[colorRange[0]][1];
|
|
var secondcolor = gradient[colorRange[1]][1];
|
|
//Calculate ratio between the two closest colors
|
|
var firstcolor_x = pathLength * (gradient[colorRange[0]][0]/100);
|
|
var secondcolor_x = pathLength * (gradient[colorRange[1]][0]/100)-firstcolor_x;
|
|
var slider_x = pathLength * colorIndex - firstcolor_x;
|
|
var ratio = slider_x / secondcolor_x;
|
|
|
|
//Get the color with pickHex(thx, less.js's mix function!)
|
|
return pickHex(secondcolor, firstcolor, ratio);
|
|
}
|
|
|
|
|
|
function render () {
|
|
requestAnimationFrame(render);
|
|
ctx.clearRect(0, 0, width, height);
|
|
dots.forEach(dot => {
|
|
dot.draw();
|
|
});
|
|
}
|
|
|
|
window.addEventListener('click', () => {
|
|
dots.forEach(dot => {
|
|
dot.tween.restart(true);
|
|
});
|
|
});
|
|
|
|
window.addEventListener('resize', () => {
|
|
width = svg.clientWidth;
|
|
height = svg.clientHeight;
|
|
|
|
canvas.width = width;
|
|
canvas.height = height;
|
|
dots.forEach(dot => {
|
|
dot.tween.invalidate().restart(true);
|
|
});
|
|
});
|
|
|
|
init();
|
|
requestAnimationFrame(render); |