2 770 Codepen

Спирали

Случайно генерируемые градиентные спирали на канвасе


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));

Комментарии

  • Facebook
  • Вконтакте

Похожие статьи