Маленькие шедевры JavaScript — Эпизод 4
Добро пожаловать на четвертую встречу из серии «Маленькие шедевры JavaScript». Как вы, возможно, уже знаете, я беру пример с некоторых замечательных работ, проделанных программистами со всего мира (которые можно найти в основном на codepen.io), чтобы представить их на всеобщее обозрение и воспользоваться возможностью, чтобы проанализировать их и изучить новый JavaScript и CSS. методы.
На этот раз я имею дело с некоторыми творческими визуальными манипуляциями с текстами, которые могут добавить немного волшебства и вдохновения любому из ваших веб-сайтов. Я выбрал шесть из них, которые, на мой взгляд, являются одними из самых интересных.
Преобразование текста
Первое предложение исходит от Джеми Браун и учит нас, как растворять один текст в другом всего несколькими умелыми штрихами.
Используемая техника на самом деле будет новой для большинства из нас. Он включает в себя применение «порогового» SVG-фильтра к двум текстовым строкам, которые анимируются с постепенным изменением размытия и непрозрачности. Но давайте послушаем самого автора, который любезно предоставил обширные комментарии к своему коду.
/* This pen cleverly utilizes SVG filters to create a "Morphing Text" effect. Essentially, it layers 2 text elements on top of each other, and blurs them depending on which text element should be more visible. Once the blurring is applied, both texts are fed through a threshold filter together, which produces the "gooey" effect. Check the CSS - Comment the #container rule's filter out to see how the blurring works! */ const elts = { text1: document.getElementById("text1"), text2: document.getElementById("text2") }; ... [omitted] // A lot of the magic happens here, this is what applies the blur filter to // the text. function setMorph(fraction) { // fraction = Math.cos(fraction * Math.PI) / -2 + .5; elts.text2.style.filter = `blur(${Math.min(8 / fraction - 8, 100)}px)`; elts.text2.style.opacity = `${Math.pow(fraction, 0.4) * 100}%`; fraction = 1 - fraction; elts.text1.style.filter = `blur(${Math.min(8 / fraction - 8, 100)}px)`; elts.text1.style.opacity = `${Math.pow(fraction, 0.4) * 100}%`; elts.text1.textContent = texts[textIndex % texts.length]; elts.text2.textContent = texts[(textIndex + 1) % texts.length]; } ... [omitted]
Вот часть CSS, на которую он ссылается:
#container { ... [omitted] /* this filter is a lot of the magic */ filter: url(#threshold) blur(0.6px); }
… и «пороговый» фильтр SVG:
<!-- The SVG filter used to create the Merging effect --> <svg id="filters"> <defs> <filter id="threshold"> <!-- Basically just a threshold effect - pixels with a high enough opacity are set to full opacity, and all other pixels are set to completely transparents. --> <feColorMatrix in="SourceGraphic" type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 225 -140" /> </filter> </defs> </svg>
Очистка лука
Второе предложение исходит от Джона Хили и использует пути SVG для анимации преобразования одного персонажа в другого.
Четыре буквы, видимые на изображении, определены как пути SVG:
var paths = [ 'M27.7,13.1v13.6c-0.7,0.5-1.4,1-2.3,1.4c-0.9,0.5-1.8,0.9-2.9,1.2s-2.2,0.6-3.4,0.9c-1.2,0.2-2.5,0.3-3.9,0.3c-2.5,0-4.6-0.3-6.5-1c-1.8-0.7-3.4-1.7-4.6-3c-1.2-1.3-2.1-2.9-2.7-4.7c-0.6-1.8-0.9-3.9-0.9-6.1c0-2.3,0.3-4.5,0.9-6.3S3,5.8,4.2,4.5c1.2-1.3,2.7-2.3,4.5-3c1.8-0.7,3.8-1,6.1-1c2,0,3.8,0.3,5.3,0.8c1.5,0.5,2.8,1.2,3.8,2.1c1,0.9,1.8,1.9,2.4,3.1c0.6,1.2,1,2.4,1.2,3.7l-9.1,0.8c-0.2-1-0.6-1.8-1.2-2.2c-0.6-0.4-1.4-0.6-2.4-0.6c-1.7,0-3,0.6-3.8,1.7c-0.8,1.1-1.2,3-1.2,5.6c0,2.7,0.4,4.6,1.3,5.8c0.9,1.2,2.4,1.8,4.5,1.8c1.4,0,2.6-0.2,3.6-0.6V20h-3.8v-6.9H27.7z', 'M0.5,8.3V0.5h25v7.8h-8v20.8H8.5V8.3H0.5z', 'M20.2,0v7.2H8.9v4.7h10.7V19H8.9v9.6H0V0H20.2z', 'M8.1,29c-1.8-0.7-3.3-1.7-4.5-2.9c-1.2-1.3-2.1-2.8-2.7-4.7C0.3,19.5,0,17.4,0,15.1s0.3-4.4,0.9-6.3s1.5-3.4,2.8-4.8c1.2-1.3,2.7-2.3,4.6-3S12.1,0,14.5,0c2.3,0,4.4,0.3,6.1,1c1.8,0.7,3.3,1.7,4.5,2.9c1.2,1.3,2.1,2.8,2.7,4.7s0.9,3.9,0.9,6.2s-0.3,4.4-0.9,6.3s-1.5,3.5-2.8,4.8c-1.2,1.3-2.7,2.3-4.5,3S16.7,30,14.3,30C12,30,9.9,29.7,8.1,29z M19.4,15c0-4.8-1.7-7.2-5-7.2c-3.3,0-5,2.4-5,7.2c0,4.8,1.7,7.2,5,7.2C17.7,22.2,19.4,19.8,19.4,15z' ]
Замечательный графический эффект достигается благодаря функциям анимационной библиотеки GSAP TweenMax. Для подробного объяснения на этот раз я полагаюсь на моего нового учителя кода, ChatGPT:
Магический текст (частицы)
Мой третий выбор — это визуальный эффект, созданный Сарой Картрайт, который составляет текст путем агрегирования, а затем распада большого набора частиц.
Анимация начинается с создания текста на холсте и превращения его в изображение, из которого захватываются все пиксели:
function init() { ... [omitted] var fontSize = Math.min(height, width) / 2.5; ctx.font = fontSize + 'px Arial'; ctx.textAlign = 'center'; ctx.fillText(text, width / 2, height / 2 + fontSize / 4); imageData = ctx.getImageData(0, 0, width, height); pixels8 = imageData.data; pixels32 = new Uint32Array(pixels8.buffer); for (var x = 0; x < width; x += gatherStep) { for (var y = 0; y < height; y += gatherStep) { var color = pixels32[y * width + x]; if (color != 0) { var color = (255 << 24) | (~~(Math.random() * 50) << 16) | ((~~(Math.random() * 200) + 54) << 8) | ~~(Math.random() * 50); particles.push({ x: x, y: y , color: color}); } } } }
После этого запускает стандартный цикл анимации: на каждой итерации все частицы по спирали перемещаются от периферии к центру и наоборот:
function animation() { // Increment time frame by 0.01 at each iteration frame += .01; // Calculate scale based on the current time frame scale = (Math.cos(frame * 1) + 1) * Math.max(width, height) / 1.8; // Clear all pixels on the canvas pixels32.fill(0); // Loop through each particle and update its position and color for (var i = 0; i < particles.length; i++) { var particle = particles[i]; // Calculate the new x and y position of the particle based on the // current scale and time frame var dX = scale * Math.cos(i + frame); var dY = scale * Math.sin(i + frame); // Calculate the index of the pixel on the canvas corresponding to // the particle position var xPart = ~~(particle.x + dX); if(xPart >= 0 && xPart < width){ var yPart = ~~(particle.y + dY); if(yPart >= 0 && yPart < height){ var ptr = yPart * width + xPart; var color = particle.color; // Randomly set the color to white if(Math.random() < 0.05) color = colorWhite; // Set the color of the pixel and its surrounding pixels pixels32[ptr] = color; pixels32[ptr + 1] = color; pixels32[ptr + width] = color; pixels32[ptr + width + 1] = color; } } } // Draw the updated pixels on the canvas ctx.putImageData(imageData, 0, 0); // Call the animation function again for the next frame requestAnimationFrame(animation); }
(Кстати, обратите внимание на оператор двойной тильды, используемый для округления до ближайшего целого числа)
Сбой
Мой четвертый выбор — работа от Evan Jin, автора, которого я уже освещал в первой статье этой серии за его прекрасное творение Интерактивный фон с веревками.
На этот раз его умение — это текст, который выглядит искаженным, как будто возникла техническая проблема на старом телевизоре. В интернете я находил различные реализации этого эффекта, но эта мне кажется наиболее реалистичной.
Вся игра реализована с использованием свойства преобразования CSS для искажения и масштабирования текста в соответствии с двумя переменными:
h1 { font-size: 4rem; color: #f1f1f1; transform: skew(var(--skew)); transform: skew(var(--skew)) scale(var(--scale)); }
Каждую десятую секунды значение перекоса переназначается максимум на ±10 градусов, а масштаб устанавливается равным 1. Каждые 1,5 секунды перекос вместо этого может увеличиваться до ± 90 градусов, при этом масштаб меняется каждые 3 секунды на случайное значение вплоть до максимального значения 1,5.
function glitch(element) { let count = 0 setInterval(() => { // element const skew = Math.random() * 20 - 10 ... element.style.setProperty('--skew', `${skew}deg`) ... element.style.setProperty('--scale', `1`) count++ if (count % 15 === 0) { const bigSkew = Math.random() * 180 - 90 element.style.setProperty('--skew', `${bigSkew}deg`) } if (count % 30 === 0) { const bigScale = 1 + Math.random() / 2 element.style.setProperty('--scale', `${bigScale}`) } }, 100) } const h1 = document.querySelector('h1') glitch(h1)
Цветной ввод
Пятая жемчужина внешнего программирования, которую я выбрал, исходит от Haiqing Wang и состоит из отражения ввода из текстового поля в симпатичный эффект цветных букв и конфетти.
Анимация запускается событием keyup и использует библиотеку GSAP TweenLite для создания эффекта случайного подпрыгивания и подъема:
const animateLetterIn = letter => { const yOffset = (0.5+Math.random()*0.5) * textSize; TweenLite.fromTo(letter, 0.4, {scale:0}, {scale:1, ease: Back.easeOut}); TweenLite.fromTo(letter, 0.4, {opacity:0}, {opacity: 1, ease: Power3.easeOut}); TweenLite.to(letter, 0.2, {y:-yOffset, ease: Power3.easeInOut}); TweenLite.to(letter, 0.2, {y:0, ease: Power3.easeInOut, delay: 0.2}); const rotation = -50 + Math.random()*100; TweenLite.to(letter, 0.2, {rotation: rotation, ease: Power3.easeInOut}); TweenLite.to(letter, 0.2, {rotation: 0, ease: Power3.easeInOut, delay: 0.2}); }
«Конфетти» — это 8 треугольников и 8 кругов, сгенерированных как SVGElements в случайных положениях и перемещенных с помощью функций TweenLite.
Гиперпространственный текст
Мой последний выбор — работа неординарного творца Йохана Карлссона, и я рекомендую всем посетить его галерею потрясающих творений.
Этот гиперпространственный текст разбивает текст на частицы, которые двигаются хаотично, как извивающиеся черви, в то время как другие удаляются со скоростью, ускользающей от центра экрана. Курсор мыши вносит дополнительный хаос, создавая пустоту вокруг себя. Все это делается с помощью стандартного JavaScript и холста. И с большим техническим мастерством.
Это все на сегодня! Не пропустите другие выпуски:
Дополнительные материалы на PlainEnglish.io.
Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord .
Заинтересованы в масштабировании запуска вашего программного обеспечения? Ознакомьтесь с разделом Схема.