В этой статье представлен код реализации эффекта частиц текста на холсте, и я надеюсь, что он будет полезен всем. Подробности следующие:
Рисование текста с помощью частиц кажется интересным, а согласование движения частиц сделает эффект еще круче. В этой статье рассказывается, как рисовать текст с помощью частиц на холсте.
Принцип реализацииВообще говоря, сделать эффект превращения текста в отображение частиц очень просто. Принцип реализации заключается в использовании двух холстов. Один — это холст A, который не видит пользователь, который используется для рисования текста. тот, который может видеть пользователь. Полученный холст B используется для генерации частиц на основе текстовых данных A. Визуальное представление такое, как показано на рисунке:
Создайте холст за кадромHTML необходимо разместить только на основном холсте:
<!-- Структура HTML--><html><head> ...</head><body> <canvas id=stage></canvas></body></html>
Затем создайте закадровый холст и нарисуйте текст:
const WIDTH = window.innerWidth; const HEIGHT = window.innerHeight; const offscreenCanvas = document.createElement('canvas'); const offscreenCtx = offscreenCanvas.getContext('2d'); offscreenCanvas.width = WIDTH; offscreenCtx.font = '100px PingFang SC';offscreenCtx.textAlign = 'center';offscreenCtx.baseline = 'middle';offscreenCtx.fillText('Hello', WIDTH / 2, HEIGHT / 2);В это время на странице ничего не происходит, но вы можете представить это на закадровом холсте. Должно быть так, как показано на рисунке:
Основной метод getImageData С помощью метода getImageData холста можно получить объект ImageData , который используется для описания данных пикселей в указанной области холста. Другими словами, мы можем получить положение и цвет каждого пикселя текста Hello и сгенерировать частицы в указанном месте. Конечный эффект заключается в том, что частицы объединяются в текст.
Для получения информации о пикселях необходимо использовать атрибут data объекта ImageData , который распределяет значения rgba всех пикселей в массив. Каждый пиксель имеет четыре значения rgba. Число этого массива равно 像素点数量* 4 .
Предположим, я выбираю область 3 * 4 , тогда всего 12 пикселей, каждый пиксель имеет четыре значения rgba, поэтому массив данных будет иметь 12 * 4 = 48 элементов.
Если вы распечатаете данные, вы увидите RGBA этих пикселей, расположенных слева направо и сверху вниз.
Конечно, область, которую мы хотим получить, должна содержать текст, поэтому мы должны получить всю внеэкранную область холста:
const imgData = offscreenCtx.getImageData(0, 0, WIDTH, HEIGHT).data;Генерировать частицы
После получения ImageData, просматривая массив данных, вы можете определить, какие точки на закадровом холсте окрашены (в середине текста), а какие бесцветны (не в тексте), и поместить эти цветные пиксели. вниз по позиции, затем сгенерируйте частицы на основном холсте, и все готово.
Сначала создайте класс частиц:
класс Particle { конструктор (options = {}) { const { x = 0, y = 0, color = '#fff', radius = 5} = options; this.x = this.y; = y; this.color = color; } draw (ctx) { ctx.beginPath(); this.x, this.y, this.radius, 0, 2 * Math.PI, false); ctx.fillStyle = this.color; ctx.closePath();Просматривая данные, мы можем определить, находится ли пиксель в тексте на основе прозрачности, то есть не равен ли четвертый элемент в rgba 0.
const частицы = [];const пропустить = 4;for (var y = 0; y <HEIGHT; y += пропустить) { for (var x = 0; x < WIDTH; x += пропустить) { var opacityIndex = (x + y * WIDTH) * 4 + 3; if (imgData[opacityIndex] > 0) {articles.push(new Particle({ x, y, radius: 1, цвет: '#2EA9DF' })); Мы используем массив particles для хранения всех частиц. Функция skip здесь — это размер шага обхода. Если мы сканируем попиксельно, частицы, которые в конечном итоге объединят текст, будут очень плотными. Увеличьте это значение и окончательный результат. частицы будут генерироваться реже.
Наконец, создайте основной холст и нарисуйте его:
const Canvas = document.querySelector('#stage');canvas.width = WIDTH;canvas.height = HEIGHT;const ctx = Canvas.getContext('2d');for (const частица частиц) {article.draw(ctx) );}Эффект следующий:
Полный код см. в разделе 01-basic-text-to-particles.
Добавить эффектыПосле понимания принципа реализации осталось добавить к частицам некоторые анимационные эффекты. Во-первых, вы можете придать частицам случайное смещение, чтобы они не выглядели слишком аккуратно.
const частицы = [];const пропустить = 4;for (var y = 0; y <HEIGHT; y += пропустить) { for (var x = 0; x < WIDTH; x += пропустить) { var opacityIndex = (x + y * WIDTH) * 4 + 3; if (imgData[opacityIndex] > 0) { // Добавляем случайное смещение при создании частиц частиц.push(new Particle({ x: x + Math.random() * 6 - 3, y: y + Math.random() * 6 - 3, радиус: 1, цвет: '#2EA9DF' }));Эффект следующий:
Если вы хотите добиться большего эффекта, например:
Как это реализовать? Во-первых, вам нужно случайным образом сгенерировать размер частиц. Для этого требуется только рандомизировать радиус при создании частиц. Кроме того, если вы хотите, чтобы радиус частицы менялся динамически, вам необходимо различать радиус рендеринга частицы и начальный радиус и использовать requestAnimationFrame для рендеринга анимации:
class Particle { конструктор (options = {}) { const { x = 0, y = 0, color = '#fff', radius = 5} = options; this.radius = radius; // ... this.dynamicRadius = радиус; // Добавляем свойство DynamicRadius} draw (ctx) { // ... ctx.arc(this.x, this.y, this.dynamicRadius, 0, 2 * Math.PI, false); Заменить на DynamicRadius // ... } update () { // TODO }}requestAnimationFrame(function Loop() { requestAnimationFrame(loop); ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, WIDTH, HEIGHT) ); for (const частица частиц) {article.update(); Тогда ключ заключается в том, как реализовать метод update частиц. Предположим, мы хотим, чтобы радиус частицы менялся плавно и циклически от 1 до 5. Легко придумать тригонометрические функции, такие как:
Горизонтальная ось должна быть связана со временем. Вы можете сохранить переменную и добавлять ее каждый раз, когда вызываете обновление. Вы также можете использовать метку времени для простого расчета. Пример метода update выглядит следующим образом:
update () { this.dynamicRadius = 3 + 2 * Math.sin(new Date() / 1000 % 1000 * this.radius);}Полный код см. в разделе «02-текст-в-частицы-с-изменением размера».
Выше приведено все содержание этой статьи. Я надеюсь, что она будет полезна для изучения всеми. Я также надеюсь, что все поддержат сеть VeVb Wulin.