Современные решения ИТ задач и программной инженерии

Придаем сайту новогоднее настроение, снег на сайте!

Придаем сайту новогоднее настроение, снег на сайте!
Приближается новый год. Как же можно приукрасить свой сайт? Многие обновляют на сайте дизайн под новогодний стиль, что вполне затратно во времени. А иногда просто изменяют некоторые элементы. Так же можно найти на просторах интернета всякие варианты решения на JavaScript и при помощи дополнительных картинок. Для того что бы добавить например снежинки на сайт, или сделать снег на сайте. Падающие снежинки или падающий снег.

Но все что существует, оно или очень нагружает сайт или очень криво сделано. Например те же падающие снежинки. Помимо того что нужно написать скрипт, добавить стили, так еще и загрузить картинку снежинки, плюс один лишний запрос при обращении к страницам сайта. Конечно же, картинка закешируется при первом обращении и будет браться из кеша. Но это только для того пользователя который вернется на сайт и до того времени когда в кеша не выйдет срок годности.

Другое дело, падающий снег. Его можно изобразить без дополнительных изображений. Даже можно создать один HTML элемент, застилить его при помощи CSS и потом через JavaScript его дублировать и делать имитацию падения. Но это тоже очень проблемно и накладно, лишние элементы могут ломать верстку сайта или перекрывать другие элементы.

Предлагаем вашему вниманию еще один очень простой и элегантный способ. И кстати это довольно таки карасиво получилось и совсем не нагружает страницу сайта. Суть в чем. Создаем всего один HTML элемент - canvas и на нем при помощи JavaScript рисуем анимацию падающего снега. Итак приступим.

Для начала создадим сразу после тега body canvas элемент:

...
<body>
  <canvas id="snow"></canvas>
  ...
</body>

Желательно canvas элемент разместить сразу после открывающегося тега body. Добавили "полотно для рисования" но его теперь нужно привести в нормальный вид. Задать высоту, ширину и позицию. Что бы оно было всегда сверху. Добавим следующие CSS стили:

<style type="text/css">
  #snow {
    width: 100%;
    height: 100%;
    position: fixed;
    top: 0px;
    left: 0px;
    z-index: 999999;
    pointer-events: none;
    -moz-pointer-events: none;
    -webkit-pointer-events: none;
    -o-pointer-events: none;
  }
</style>

При помощи CSS мы задаем ширину и высоту элемента, делаем его позицию фиксированную, задаем ему относительную позицию, ставим максимальный z-index, что бы снег был поверх всех остальных элементов сайта и так же следует отключить все события мыши - "pointer-events". Для различных браузеров пропишем с приставками "-moz-" для FireFox, "-webkit-" для браузеров на движке webkit и "-o-" для браузера Opera. Это нужно для того, что бы пользователи имели возможность переходить по ссылкам на странице и элемент canvas пропускал все события как будто его нет но визуально он отображался. Перейдем к последний части на JavaScript.

<script type="text/javascript">
  function StartSnow() {
    var canvas = document.getElementById("snow");
    var ctx = canvas.getContext("2d");
    var W = window.innerWidth;
    var H = window.innerHeight;
    canvas.width = W;
    canvas.height = H;
    var mp = 50;
    var particles = [];
    for(var i=0; i<mp; i++) {
      particles.push({
        x: Math.random() * W,
        y: Math.random() * H,
        r: Math.random() * 4 + 1,
        d: Math.random() * mp
      });
    }
    function drawSnow() {
      ctx.clearRect(0, 0, W, H);
      ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
      ctx.beginPath();
      for(var i=0; i<mp; i++) {
        var p = particles[i];
        ctx.moveTo(p.x, p.y);
        ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2, true);
      }
      ctx.fill();
      updateSnow();
    }
    var angle = 0;
    function updateSnow() {
      angle += 0.01;
      for(var i=0; i<mp; i++) {
        var p = particles[i];
        p.y += Math.cos(angle + p.d) + 1 + p.r / 2;
        p.x += Math.sin(angle) * 2;
        if(p.x > W + 5 || p.x < -5 || p.y > H) {
          if(i % 3 > 0) {
            particles[i] = {x: Math.random() * W, y: -10, r: p.r, d: p.d};
          } else {
            if(Math.sin(angle) > 0) {
              particles[i] = {x: -5, y: Math.random() * H, r: p.r, d: p.d};
            } else {
              particles[i] = {x: W + 5, y: Math.random() * H, r: p.r, d: p.d};
            }
          }
        }
      }
    }
    setInterval(drawSnow, 30);
  };
  if(window.addEventListener) {
    window.addEventListener('load', StartSnow, false);
  } else if(window.attachEvent) {
    window.attachEvent('onload', StartSnow);
  }
</script>

Рассмотрим скрипт подробно. При помощи события "onload" вешаем нашу функцию "StartSnow" в которой выполняется полностью все рисование. Дополнительно добавим две функции для рисовании одной "снежки" и ее обновлении, точнее анимации: "drawSnow" и "updateSnow".

В самом начале функции "StartSnow" мы получаем наш объект canvas по его id, получаем 2D контекст для рисования, задаем канвасу высоту и ширину, задаем максимальное количество частей, в данном случае - 50 и генерируем изначальный массив частей. В массиве идет рандомное установление положения каждой снежки, скорость падения а так же размер.

Далее запускаем функцию "setInterval", которая будет выполнять нашу функцию "drawSnow" с интервалом каждые 30 милисекунд. В функции "drawSnow" мы сначала очищаем полностью канвас, затем задаем цвет и прозрачность кисти в формате RGBA, A - Alpha канал, прозрачность. Рисуем каждую снежку на канвасе, пробегая по всему нашему ранее заданном массиве. Далее вызываем функцию "updateSnow".

Функция "updateSnow" отвечает за физику, поведение снежки, то есть каждые 30 милисекунд мы очищаем полностью все видимое пространство, рисуем каждую частицу "снежку" и обновляем ее параметры (передвигаем ее координаты). Таким образом создается эффект движения, анимация падения.

Таким образом мы избавляемся от зависимости HTML элементов, CSS и внешних изображений. Кстати физику, цвет и прозрачность можно поправить по своему вкусу. Демо версию работы можно посмотреть на текущем сайте в новогодние праздники) Немного позднее сюда будет добавлена всесезонная ссылка на демо работы. С наступающим!