Черная молния на JavaScript - графика и анимация
В данном разделе рассматриваются способы создания визуального эффекта черной молнии на веб-странице с помощью JavaScript. Основное внимание уделяется рисованию на canvas, также предлагаются альтернативные подходы с использованием SVG, CSS и библиотеки p5.js. Каждый вариант сопровождается примерами кода, пояснениями и указанием типичных проблем.
Основной способ: рисование молнии на canvas
Наиболее гибкий метод - использование элемента canvas. Молния представляется в виде ломаной линии, соединяющей начальную и конечную точки со случайными отклонениями на каждом сегменте.
Пример функции, рисующей молнию между двумя точками:
function drawLightning(ctx, x1, y1, x2, y2, segments, offset) {
ctx.beginPath();
ctx.moveTo(x1, y1);
let dx = x2 - x1;
let dy = y2 - y1;
for (let i = 1; i < segments; i++) {
let t = i / segments;
let x = x1 + dx * t + (Math.random() - 0.5) * offset;
let y = y1 + dy * t + (Math.random() - 0.5) * offset;
ctx.lineTo(x, y);
}
ctx.lineTo(x2, y2);
ctx.strokeStyle = 'black';
ctx.lineWidth = 2;
ctx.stroke();
}
Gif javascript (gif анимация javascript)
Результат - черная ломаная линия от (x1,y1) до (x2,y2).
// Пример вызова (canvas id="scene", контекст ctx)
const canvas = document.getElementById('scene');
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawLightning(ctx, 50, 50, 350, 350, 20, 60);
// На canvas появляется чёрный зигзаг
как сделать черную молнию в js (создание эффекта черной молнии на javascript)
Для анимации можно перерисовывать молнию с новыми случайными значениями каждые 50–100 миллисекунд:
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawLightning(ctx, 100, 100, 500, 300, 15, 80);
requestAnimationFrame(animate);
}
animate();
Проблема: молния выглядит неестественно - все сегменты примерно одинаковой длины и направления. Решение: использовать рекурсивное разбиение отрезков (фрактальный подход), при котором каждый отрезок делится случайным образом. Это даёт более реалистичную ветвистую структуру.
Проблема производительности: при большом количестве сегментов анимация может тормозить. Решение: ограничить число сегментов до 20–30 или использовать двойную буферизацию (offline canvas).
Как создать молнию с помощью SVG и анимировать её появление?
SVG позволяет описать молнию как элемент <polyline> или <path>. Анимацию длины штриха можно выполнить с помощью CSS-свойства stroke-dasharray и stroke-dashoffset.
Пример разметки и стилей:
<svg width="400" height="300" viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg">
<polyline id="lightning"
points="50,50 120,140 180,90 250,200 320,130 380,260"
stroke="black" stroke-width="2" fill="none"
stroke-dasharray="400" stroke-dashoffset="400" />
</svg>
<style>
#lightning {
animation: drawLightning 1.5s ease-out forwards;
}
@keyframes drawLightning {
to { stroke-dashoffset: 0; }
}
</style>
Результат - линия постепенно прорисовывается слева направо.
// При загрузке страницы молния анимированно появляется за 1.5 секунды.
Проблема: SVG требует заранее заданных координат точек, что не позволяет генерировать случайную молнию без JavaScript. Решение: сформировать точки на стороне JS и обновить атрибут points элемента.
Проблема: анимация stroke-dashoffset не поддерживается в старых браузерах. Решение: использовать полифилл или перейти на canvas.
Как сделать анимацию молнии только средствами CSS?
Полноценную случайную молнию с помощью CSS создать сложно, так как CSS не поддерживает случайные вычисления. Однако для простой прямой молнии можно использовать повёрнутые блоки с градиентами или псевдоэлементы с clip-path.
Пример симуляции молнии с помощью нескольких div, повёрнутых на разные углы:
<div class="lightning">
<div class="segment" style="transform: rotate(10deg); width:100px;"></div>
<div class="segment" style="transform: rotate(-15deg); width:120px;"></div>
</div>
<style>
.lightning .segment {
height: 2px;
background: black;
margin: 0;
}
</style>
Результат - ломаная линия из трёх отрезков.
// Применение трансформаций даёт приблизительную форму молнии, но случайность отсутствует.
Проблема: каждый сегмент требует отдельного элемента, что неудобно для динамической генерации. Решение: использовать canvas или SVG для программного управления.
Проблема: анимация (мигание) реализуется сменами классов, но форма остаётся фиксированной. Решение: для реалистичного эффекта лучше применить JavaScript.
Как использовать библиотеку p5.js для рисования черной молнии?
Библиотека p5.js упрощает работу с графикой. Для молнии достаточно функции line() и random().
Пример скетча:
function setup() {
createCanvas(400, 300);
stroke(0); // чёрный цвет
strokeWeight(2);
}
function draw() {
background(255);
let x1 = 50, y1 = 50;
let x2 = 350, y2 = 250;
let segments = 15;
beginShape();
vertex(x1, y1);
for (let i = 1; i < segments; i++) {
let t = i / segments;
let x = lerp(x1, x2, t) + random(-30, 30);
let y = lerp(y1, y2, t) + random(-30, 30);
vertex(x, y);
}
vertex(x2, y2);
endShape();
}
Результат - чёрная ломаная линия, обновляемая каждый кадр.
// В браузере откроется окно с анимированной молнией.
Проблема: p5.js добавляет зависимость и увеличивает размер страницы. Решение: использовать нативный canvas, если проект не использует p5.js.
Проблема: функция draw() вызывается по умолчанию 60 fps, что может быть избыточно. Решение: управлять частотой через frameRate() или noLoop().
Дополнительные возможности: фрактальная молния и эффекты
1. Рекурсивная генерация фрактальной молнии
Для более реалистичной формы используется рекурсивное деление отрезков. Каждый отрезок делится на две части со случайным смещением середины.
function fractalLightning(ctx, x1, y1, x2, y2, displacement, detail) {
if (detail < 1) {
ctx.lineTo(x2, y2);
return;
}
let midX = (x1 + x2) / 2 + (Math.random() - 0.5) * displacement;
let midY = (y1 + y2) / 2 + (Math.random() - 0.5) * displacement;
fractalLightning(ctx, x1, y1, midX, midY, displacement * 0.6, detail - 1);
ctx.lineTo(midX, midY);
fractalLightning(ctx, midX, midY, x2, y2, displacement * 0.6, detail - 1);
}
// Использование
ctx.beginPath();
ctx.moveTo(50, 50);
fractalLightning(ctx, 50, 50, 350, 250, 100, 6);
ctx.strokeStyle = 'black';
ctx.lineWidth = 2;
ctx.stroke();
Результат - ломаная с сильно изогнутыми ответвлениями, похожая на настоящую молнию.
// При detail=6 линия состоит из 2^6 = 64 отрезков, образующих хаотичный зигзаг.
2. Ветвление молнии (создание ответвлений)
Дополнительные боковые «усики» добавляются случайным образом от точек основного ствола.
function addBranch(ctx, x, y, angle, length, displacement) {
if (length < 5) return;
let endX = x + Math.cos(angle) * length + (Math.random() - 0.5) * displacement;
let endY = y + Math.sin(angle) * length + (Math.random() - 0.5) * displacement;
ctx.moveTo(x, y);
ctx.lineTo(endX, endY);
// рекурсивно создать ответвления от конца ветки
addBranch(ctx, endX, endY, angle + Math.random() * 0.5 - 0.25, length * 0.7, displacement * 0.8);
}
Результат - молния с боковыми разрядами, как у настоящей грозы.
// При вызове addBranch от нескольких точек основного ствола получается ветвистая структура.
3. Эффект свечения (blur) вокруг чёрной линии
Имитация свечения достигается с помощью ctx.shadowBlur и ctx.shadowColor. Чтобы свечение было заметным на светлом фоне, можно задать серый или белый цвет тени.
ctx.shadowColor = 'rgba(0,0,0,0.5)'; // тень чёрная, но полупрозрачная
ctx.shadowBlur = 10;
// затем рисовать молнию как обычно
Результат - линия с размытой полупрозрачной окантовкой, создающей иллюзию свечения.
// Чёрная линия окружена мягким серым ореолом, что добавляет глубины.
4. Анимация с постепенным рисованием (эффект проявления)
Используется техника рисования молнии по частям: каждый кадр добавляется один сегмент.
let progress = 0;
const points = []; // массив точек, заранее вычисленный
function drawProgressive() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.moveTo(points[0].x, points[0].y);
for (let i = 1; i <= progress; i++) {
ctx.lineTo(points[i].x, points[i].y);
}
ctx.stroke();
if (progress < points.length - 1) {
progress++;
requestAnimationFrame(drawProgressive);
}
}
Результат - молния «вырисовывается» от начала к концу.
// За 30 кадров (около 0.5 сек) молния полностью появляется.
5. Множественные молнии с разной задержкой
Несколько независимых молний, запускаемых с задержкой, создают картину грозы.
function createMultiLightning(count) {
for (let i = 0; i < count; i++) {
setTimeout(() => {
// рисовать одну молнию со случайными координатами
drawLightning(ctx, Math.random()*400, Math.random()*100, Math.random()*400, 300, 15, 50);
}, i * 200);
}
}
Результат - последовательное появление нескольких молний.
// Каждые 200 мс появляется новая чёрная молния в случайном месте.