Спирали
Случайно генерируемые градиентные спирали на канвасе
SCSS
html, body {
background: black;
overflow: hidden;
cursor: pointer;
}
canvas {
transition: transform 0.8s;
&:hover {
transform: scale(1.05);
}
}
ul {
display: flex;
position: absolute;
bottom: 0;
left: 0;
z-index: 1;
padding: 16px;
a {
display: block;
padding: 8px;
color: white;
font-family: sans-serif;
text-decoration: none;
&:hover {
cursor: crosshair;
}
}
}
JS
"use strict";
const particleCount = 3000;
const particleProps = [
"x",
"y",
"w",
"r",
"t",
"s",
"e",
"h",
"ic"
];
const backgroundColor = "hsla(0,0%,0%,0.35)";
let canvas;
let ctx;
let center;
let tick;
let particleArray;
function setup() {
tick = 0;
createCanvas();
resize();
createSpiral();
draw();
}
function createSpiral() {
particleArray = new ParticleArray(particleCount, particleProps);
const ns = round(particleCount / ceil(rand(3)) + 3);
let i = 0;
let d, rc, sc, tc, bh, hc;
for (; i < particleArray.length; i += particleProps.length) {
if (!(i % ns)) {
d = rand(20);
rc = (round(rand(70)) + 70) * 0.125;
sc = (1 + round(rand(1))) * 0.0035;
tc = round(rand(1)) ? 2 : -2;
bh = round(rand(360));
hc = (1 + rand(2)) * 0.0125;
}
initParticle(i, d, rc, sc, tc, bh, hc);
}
}
function initParticle(i, d, rc, sc, tc, bh, hc) {
const irtc = i / rc * tc;
const ditsc = d + (i * tc) * sc;
let x, y, r, w, t, s, e, h, ic;
t = (i / particleCount * rc) * (tc * TAU);
x = center[0] + ditsc * cos(t);
y = center[1] + ditsc * sin(t);
r = i / (0.5 * particleCount) + 2;
w = norm(i, 0, particleArray.length) + 0.1;
s = irtc + t + HALF_PI;
e = irtc + t + PI;
h = bh + i * hc;
ic = i * 0.0000125;
particleArray.set([x, y, r, w, t, s, e, h, ic], i);
}
function drawParticle(i) {
let [x, y, r, w, t, s, e, h, ic] = particleArray.get(i);
ctx.a.beginPath();
ctx.a.lineWidth = w;
ctx.a.strokeStyle = `hsla(${h},30%,50%,0.5)`;
ctx.a.arc(x, y, r, t + s, t + e);
ctx.a.stroke();
ctx.a.closePath();
t += sin(tick * 0.0015) * ic;
particleArray.set([x, y, r, w, t, s, e, h, ic], i);
}
function createCanvas() {
canvas = {
a: document.createElement("canvas"),
b: document.createElement("canvas")
};
canvas.b.style = `
position: absolute;
top: 0;
left: 0;
width: 100%;
`;
document.body.appendChild(canvas.b);
ctx = {
a: canvas.a.getContext("2d"),
b: canvas.b.getContext("2d")
};
center = [canvas.a.width, canvas.a.height];
canvas.b.addEventListener("click", createSpiral);
}
function resize() {
const { innerWidth, innerHeight } = window;
canvas.a.width = innerWidth;
canvas.a.height = innerHeight;
ctx.a.drawImage(canvas.b, 0, 0);
canvas.b.width = innerWidth;
canvas.b.height = innerHeight;
ctx.b.drawImage(canvas.a, 0, 0);
center[0] = 0.5 * innerWidth;
center[1] = 0.5 * innerHeight;
}
function renderGlow() {
ctx.b.save();
ctx.b.filter = "blur(8px) brightness(200%)";
ctx.b.globalCompositeOperation = "lighter";
ctx.b.drawImage(canvas.a, 0, 0);
ctx.b.restore();
}
function renderToScreen() {
ctx.b.save();
ctx.b.globalCompositeOperation = "lighter";
ctx.b.drawImage(canvas.a, 0, 0);
ctx.b.restore();
}
function drawBackground() {
ctx.a.clearRect(0, 0, canvas.a.width, canvas.a.height);
ctx.b.fillStyle = backgroundColor;
ctx.b.fillRect(0, 0, canvas.a.width, canvas.a.height);
}
function drawSpiral() {
let i = 0;
for (; i < particleArray.length; i += particleProps.length) {
drawParticle(i);
}
}
function draw() {
tick++;
drawBackground();
drawSpiral();
renderGlow();
renderToScreen();
window.requestAnimationFrame(draw);
}
window.addEventListener("load", setup);
window.addEventListener("resize", _.debounce(() => {
resize();
createSpiral();
}, 100));