Подтвердить что ты не робот

Создание падающего снега с использованием HTML 5 и JS

Я посетил Stack Exchange Winter Bash сайт, и мне нравится падающий снег! Мой вопрос в том, как я могу воссоздать аналогичный эффект, который выглядит так же хорошо. Я попытался перепроектировать код, чтобы узнать, могу ли я это понять, но, к сожалению, нам не повезло. JS над моей головой. Я сделал несколько поисковых запросов и наткнулся на некоторые примеры, но они были не такими элегантными, как сайт SE, или выглядели не очень хорошо.

Может ли кто-нибудь предоставить некоторые инструкции о том, как реплицировать сайт SE Winter Bash или место, где я мог бы узнать, как это сделать?

Изменить: я хотел бы воспроизвести эффект как можно ближе, IE: падать снег со снежинками, а также перемещать мышь и заставлять снег двигаться или вихрем с моментом мыши.

4b9b3361

Ответ 1

Отличный вопрос, я на самом деле недавно написал плагин для снега, который постоянно обновляю видеть его в действии. Также ссылка на источник чистого js

Я заметил, что вы отметили вопрос html5 и canvas, однако вы можете сделать это, не используя ни того, ни просто стандартные элементы с изображениями или разными цветами фона.

Вот два действительно простых, которые я собрал сейчас, чтобы вы могли возиться. Ключ, на мой взгляд, использует грех, чтобы получить хороший волнистый эффект, когда хлопья падают. Первый использует элемент холста, второй использует обычные элементы dom.

Так как я абсолютно зависим от холста, здесь есть версия холста, которая выглядит очень красиво, на мой взгляд.

Версия холста

Полный экран

(function() {
    var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame ||
    function(callback) {
        window.setTimeout(callback, 1000 / 60);
    };
    window.requestAnimationFrame = requestAnimationFrame;
})();


var flakes = [],
    canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    flakeCount = 200,
    mX = -100,
    mY = -100

    canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

function snow() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    for (var i = 0; i < flakeCount; i++) {
        var flake = flakes[i],
            x = mX,
            y = mY,
            minDist = 150,
            x2 = flake.x,
            y2 = flake.y;

        var dist = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)),
            dx = x2 - x,
            dy = y2 - y;

        if (dist < minDist) {
            var force = minDist / (dist * dist),
                xcomp = (x - x2) / dist,
                ycomp = (y - y2) / dist,
                deltaV = force / 2;

            flake.velX -= deltaV * xcomp;
            flake.velY -= deltaV * ycomp;

        } else {
            flake.velX *= .98;
            if (flake.velY <= flake.speed) {
                flake.velY = flake.speed
            }
            flake.velX += Math.cos(flake.step += .05) * flake.stepSize;
        }

        ctx.fillStyle = "rgba(255,255,255," + flake.opacity + ")";
        flake.y += flake.velY;
        flake.x += flake.velX;

        if (flake.y >= canvas.height || flake.y <= 0) {
            reset(flake);
        }


        if (flake.x >= canvas.width || flake.x <= 0) {
            reset(flake);
        }

        ctx.beginPath();
        ctx.arc(flake.x, flake.y, flake.size, 0, Math.PI * 2);
        ctx.fill();
    }
    requestAnimationFrame(snow);
};

function reset(flake) {
    flake.x = Math.floor(Math.random() * canvas.width);
    flake.y = 0;
    flake.size = (Math.random() * 3) + 2;
    flake.speed = (Math.random() * 1) + 0.5;
    flake.velY = flake.speed;
    flake.velX = 0;
    flake.opacity = (Math.random() * 0.5) + 0.3;
}

function init() {
    for (var i = 0; i < flakeCount; i++) {
        var x = Math.floor(Math.random() * canvas.width),
            y = Math.floor(Math.random() * canvas.height),
            size = (Math.random() * 3) + 2,
            speed = (Math.random() * 1) + 0.5,
            opacity = (Math.random() * 0.5) + 0.3;

        flakes.push({
            speed: speed,
            velY: speed,
            velX: 0,
            x: x,
            y: y,
            size: size,
            stepSize: (Math.random()) / 30,
            step: 0,
            angle: 180,
            opacity: opacity
        });
    }

    snow();
};

canvas.addEventListener("mousemove", function(e) {
    mX = e.clientX,
    mY = e.clientY
});

init();​

Стандартная версия элемента

var flakes = [],
    bodyHeight = getDocHeight(),
    bodyWidth = document.body.offsetWidth;


function snow() {
    for (var i = 0; i < 50; i++) {
        var flake = flakes[i];

        flake.y += flake.velY;

        if (flake.y > bodyHeight - (flake.size + 6)) {
            flake.y = 0;
        }

        flake.el.style.top = flake.y + 'px';
        flake.el.style.left = ~~flake.x + 'px';

        flake.step += flake.stepSize;
        flake.velX = Math.cos(flake.step);

        flake.x += flake.velX;

        if (flake.x > bodyWidth - 40 || flake.x < 30) {
            flake.y = 0;
        }
    }
    setTimeout(snow, 10);
};


function init() {
    var docFrag = document.createDocumentFragment();
    for (var i = 0; i < 50; i++) {
        var flake = document.createElement("div"),
            x = Math.floor(Math.random() * bodyWidth),
            y = Math.floor(Math.random() * bodyHeight),
            size = (Math.random() * 5) + 2,
            speed = (Math.random() * 1) + 0.5;

        flake.style.width = size + 'px';
        flake.style.height = size + 'px';
        flake.style.background = "#fff";

        flake.style.left = x + 'px';
        flake.style.top = y;
        flake.classList.add("flake");

        flakes.push({
            el: flake,
            speed: speed,
            velY: speed,
            velX: 0,
            x: x,
            y: y,
            size: 2,
            stepSize: (Math.random() * 5) / 100,
            step: 0
        });
        docFrag.appendChild(flake);
    }

    document.body.appendChild(docFrag);
    snow();
};

document.addEventListener("mousemove", function(e) {
    var x = e.clientX,
        y = e.clientY,
        minDist = 150;

    for (var i = 0; i < flakes.length; i++) {
        var x2 = flakes[i].x,
            y2 = flakes[i].y;

        var dist = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y));

        if (dist < minDist) {
            rad = Math.atan2(y2, x2), angle = rad / Math.PI * 180;

            flakes[i].velX = (x2 / dist) * 0.2;
            flakes[i].velY = (y2 / dist) * 0.2;

            flakes[i].x += flakes[i].velX;
            flakes[i].y += flakes[i].velY;
        } else {
            flakes[i].velY *= 0.9;
            flakes[i].velX
            if (flakes[i].velY <= flakes[i].speed) {
                flakes[i].velY = flakes[i].speed;
            }
        }
    }
});

init();

function getDocHeight() {
    return Math.max(
    Math.max(document.body.scrollHeight, document.documentElement.scrollHeight), Math.max(document.body.offsetHeight, document.documentElement.offsetHeight), Math.max(document.body.clientHeight, document.documentElement.clientHeight));
}​

Ответ 2

Падающий снег прост: создайте холст, создайте кучу снежинок, нарисуйте их.

Вы можете создать класс снежинки следующим образом:

function Snowflake() {
    this.x = Math.random()*canvas.width;
    this.y = -16;
    this.speed = Math.random()*3+1;
    this.direction = Math.random()*360;
    this.maxSpeed = 4;
}

Или что-то в этом роде. Затем у вас есть таймер, который на каждом шаге настраивает каждое направление снежинки на небольшое количество, а затем вычисляет свои новые значения X и Y путем факторизации скорости и направления.

Трудно объяснить, но на самом деле довольно простой.