Есть категория сайтов, которую мы обычно называем «вау-сайты».
Они предназначены не для непосредственного потребления контента, а для того, чтобы произвести впечатление на посетителя.
Эти сайты, как правило, уникальны по своему дизайну, содержат экспериментальные решения для взаимодействия с пользователем, ломают стереотипы и изобилуют различной анимацией.
Особый интерес представляют различные трюки с SVG и анимацией на основе большого количества частиц, о которых и пойдет речь в этой статье.
Вообще идея воссоздания различных объектов в виде набора частиц существует уже давно.
Но в связи с тем, что практическое применение этой идеи весьма ограничено, а каждая конкретная реализация привязана к конкретному содержанию, не существует единой структурированной базы знаний, в которой можно было бы быстро ознакомиться со всеми методиками.
В результате многие разработчики не осознают, что идеи, лежащие в основе всего, очень просты.
Их может реализовать любой, кто более-менее знаком с JS. Мы попробуем разобрать базовый подход к созданию анимации из частиц в 2D и рассмотрим пару практических примеров, не углубляясь в низкоуровневые оптимизации и особенности конкретных библиотек для работы с холстом.
Все дальнейшее обсуждение будет основываться на предположении, что читатель знаком с основами работы с холстом.
Если нет, то лучше остановиться на этом месте и посмотреть.
Примеры кода будут немного упрощены, чтобы передать идеи, а не конкретные рецепты копирования и вставки, поэтому будет полезно иметь контекст. Небольшое отступление: найдутся люди, которые скажут, что все это съедает ресурсы процессора, новый Макбук лагает и вообще на сайте сделать это совершенно невозможно.
С одной стороны, это замечание верно.
Современный JS в браузере — не лучшая основа для сложных вычислений, особенно если речь идет о среднестатистическом веб-сайте.
Но мы ведь говорим не об обычных сайтах, не так ли?
Мысль номер один.
Размер имеет значение
В большинстве случаев частицы не могут быть очень маленькими.
Это проблема производительности.
На среднестатистическом ноутбуке мы не сможем просчитывать весь экран по одному пикселю и при этом иметь хотя бы 30 кадров в секунду, не говоря уже о 60. Необходимо уменьшить количество частиц.
На практике в анимации обычно используются либо мелкие частицы размером 2-3 пикселя, если вы работаете с небольшим изображением, либо крупные, размером в десятки пикселей и рассчитанные на заполнение большой площади экрана.
С другой стороны, частицы не могут быть слишком большими.
Это уже вопрос адаптивности.
Имеет смысл помнить, что на телефоне экран меньше и крупные частицы просто создадут нечитаемый беспорядок.
Хорошим выбором будет привязка размера частиц к размеру холста, с которым мы работаем.
Мысль номер два.
Нам нужна готовая схема расположения частиц.
Нам нужен фундамент. Ни одну сложную анимацию невозможно создать за разумное время без основы.
Здесь есть два варианта.
Либо за основу берем изображение, либо текст. Текстом может быть заголовок, часы, номер ошибки или просто какое-то слово на заборе.
Основу, какой бы она ни была, необходимо перенести на холст. С текстом все просто: написав его стандартным fillText, мы получаем черно-белую схему расположения частиц.
Это именно то, что нам нужно.
ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, width, height); ctx.fillStyle = '#000'; ctx.font = `${fontSize}px Arial`; ctx.textAlign = 'center'; ctx.fillText('Hello', width/2, height/2 + fontSize/4);
Стоит отметить, что предварительная заливка фона белым цветом не будет лишней.
Да, в современных браузерах фон формально будет белым, но не в Safari. Если кто не слышал, это наш новый ослик, который по-своему работает с прозрачностью, как в CSS-градиентах, так и на холсте.
Из-за этого могут появиться те цвета, которые мы ожидаем.
Причем в разных версиях браузера поломки происходят по-разному.
Получив цветовую схему расположения частиц, мы можем простым поиском создать набор этих самых частиц, каждая из которых будет иметь свои координаты.
В будущем мы добавим к ним дополнительные параметры.
Здесь и далее высота и ширина — размеры холста, частицы — массив частиц, шаг — начальное расстояние между частицами.
const data = ctx.getImageData(0, 0, width, height).
data;
const data32 = new Uint32Array(data.buffer);
for (let x = 0; x < width; x += step) {
for (let y = 0; y < height; y += step) {
const color = data32[y * width + x];
if (color != 0xFFFFFFFF) {
particles.push({ x, y });
}
}
}
Мы просто обходим весь холст попиксельно с определенным шагом, определяющим расстояние между частицами, и сохраняем частицы, попавшие на буквы.
Поскольку схема состоит из двух цветов, то не имеет значения, с каким из них сравнивать.
Но при использовании картинки в качестве основы может быть удобно сравнить ее с фоном, особенно если это товар или товарный человек на белом фоне.
В некоторых случаях такой отбор проб вообще не производится и частица сохраняется на каждом этапе цикла.
Никто не мешает вам усложнять частицы, например, вы можете добавить к ним цвет, который будет совпадать с цветом пикселя исходного изображения или вычислить средний цвет по соседним пикселям, хотя это, скорее всего, будет лишним.
Теперь мы можем очистить холст и заполнить его частицами, например, нарисовав на их местах квадраты: particles.forEach((particle) => {
ctx.fillStyle = particle.color;
ctx.fillRect(
particle.x,
particle.y,
step,
step
);
});
Особо интересного эффекта это не даст, просто сделает нашу картинку или текст немного пикселизированной.
Или превратится в набор любых других геометрических фигур, если мы нарисуем что-то кроме квадратов.
Но когда вы добавляете движение, вы начинаете получать интересные результаты:
ХОРОШО.
Какое движение добавить? В целом частицы имеют следующие основные параметры:
- Координаты
- Размер
- Форма
- Цвет
Другими словами, мы пытаемся привязать все, что изменится, ко времени.
Здесь есть интересная особенность — мы можем увеличивать или уменьшать счетчик, тем самым меняя ход времени и возвращая анимацию к истокам.
Одна из самых простых анимаций, но любимая многими, — это случайное движение частиц вокруг их исходных координат. Это хорошо работает с текстами.
Чем хаотичнее движение, тем более резким и рывковым будет результат. Если движение привязано к чему-то более-менее равномерному, например к маленькому кругу (помните про синус и косинус), то эффект будет более плавным, плавным, особенно если немного изменить размер частиц.
В этом примере показано, что произойдет, если вы сохраните частицы большого размера на маленьком экране (сравните с предыдущим примером).
Речь идет о проблеме адаптивности.
Здесь главное внести разнообразие, чтобы частицы меняли свои параметры не совсем синхронно.
Это можно сделать по-разному, но обычно для каждой частицы делается какой-то множитель, позволяющий изменять ее параметры в зависимости от порядкового номера в массиве частиц.
Часто достаточно умножить аргумент того же синуса на порядковый номер частицы.
Такой подход позволяет без особых умственных усилий добиться приемлемого уровня случайности.
С точки зрения математика-криптографа это не будет выглядеть случайной последовательностью, но для анимации этого вполне достаточно — зритель успеет впечатлиться и пойти дальше, прежде чем произойдут заметные синхронизации в движении частиц.
Полезный совет по цвету для новичков: если вам нужно плавно менять цвет частиц с течением времени, забудьте о RGB и перейдите на HSL. Это позволит вам не заморачиваться и плавно менять только один из параметров изменения тембра.
То же самое и с насыщенностью.
И даже если вы выберете черный или белый цвет, вам не придется думать о том, что цветовая гамма немного размыта, как на старом телевизоре.
Пески времени…
Еще одна эффектная вещь – создать некое подобие водопада, а еще лучше – оползня.
Частицы начинают двигаться в одном направлении со случайным ускорением, увеличиваясь в высоту.
Они как будто оставляют за собой след. Подобные приемы хорошо работают с картинками.
Чтобы разместить изображение на холсте, мы используем стандартный метод drawImage. При необходимости вы можете упорядочить изображения, используя поведение, аналогичное свойству object-fit: покрывать или содержать.
В интернете есть готовые решения на этот случай.
Но вернемся к самому эффекту.
Это легко сделать из предыдущего примера.
Нам нужно добавить частицам новые параметры — размер и скорость.
particles.forEach((particle) => {
ctx.fillStyle = particle.color;
ctx.fillRect(
particle.x,
particle.y,
particle.width,
particle.height
);
particle.speed += timeCounter * Math.abs(Math.sin(5 * particle.x + 7));
particle.y += particle.speed;
particle.height += particle.speed;
});
timeCounter++;
Если вы когда-нибудь писали генератор случайных чисел, то наверняка уже думали, что комбинация двух простых чисел (5 и 7) напоминает что-то очень знакомое, только числа эти очень маленькие.
Можно было бы вспомнить теорию, но на практике при создании подобных эффектов числовые коэффициенты обычно подбираются методом проб и ошибок — заранее сложно сказать, каким будет полученный визуальный эффект. И важен именно он.
Такие анимации можно использовать для эффективной замены одной картинки на другую, когда одна течет в одну сторону, а другая — с противоположной.
Чтобы осуществить такую смену картинок, нужно заранее вычислить положение частиц для второй картинки и запустить счетчик времени для нее в обратном направлении.
Удобнее всего это сделать, предварительно выразив все параметры частиц через счетчик времени в явном виде.
Куда идти дальше?
Мы рассмотрели простейшие способы использования частиц в анимации.Это лишь верхушка айсберга.
Лучший способ научиться делать эти вещи — начать их делать.
На CodePen регулярно появляются интересные демо, с которыми будет полезно ознакомиться.
Хотелось бы дать совет начинающим разработчикам: уделяйте больше внимания идеям, заложенным в изучаемых вами примерах, чем конкретным реализациям, и не бойтесь экспериментировать.
Теги: #анимации #вау-эффект #частицы #Разработка сайтов #JavaScript
-
Влияние Мобильных Приложений На Наше Будущее
19 Oct, 24 -
Сравнение Матриц Мониторов - Tn И *Va.
19 Oct, 24