В недавнем проекте пользовательский интерфейс разработал фоновую анимацию с эффектом волны воды. Однако анимации в формате gif или svg не было. Я пытался использовать CSS для ее реализации, но эффект анимации, который я проверил в Интернете, оказался не очень хорошим. Для этого я использовал кривые Безье, я подумал о различных диаграммах сигналов, которые видел раньше, поэтому подумал о том, чтобы кратко смоделировать их с использованием изображений тригонометрических функций.
1. Нарисуйте изображение функции греха.Выражение функции sin выглядит следующим образом:
y=Asin(wx+φ)+h
Среди них A представляет собой амплитуду, ω представляет собой угловую частоту (ω = 2π/T, T — период функции), φ представляет начальную фазу, а h представляет длину перемещения изображения в положительном направлении. ось Y (здесь следует отметить: h в математике изначально означает перемещение вверх, но в холсте используется экранная система координат, то есть левый верхний угол является началом координат, а h означает перемещение вниз);
Код рисования следующий:
(1) Добавьте тег холста
<canvas id=canvas></canvas>
(2) Добавьте стиль CSS и установите ширину и высоту холста.
html,body {заполнение: 0; ширина: 100%; высота: 100%;}холст {ширина: 100%; высота: 100%;}
(3) Нарисуйте изображение функции
var Canvas = document.getElementById(canvas), ctx = Canvas.getContext('2d'), width = Canvas.width = Canvas.offsetWidth, height = Canvas.height = Canvas.offsetHeight;//Объявляем параметры var A=50, W=1/50, Q=0, H= height/2;//Метод рисования (функция draw(){ ctx.clearRect(0, 0, width, height);//Очистить холст ctx.beginPath(); //Начальный путь ctx.strokeStyle=#000; //Установить цвет линии ctx.lineWidth = 1; //Установить ширину линии ctx.moveTo(0, height); /2) ; //Положение начальной точки for (let x = 0; x <= width; x++) {// Нарисуйте переменную x, соответствующую y = A*Math.sin(W*x+Q) +H ctx.lineTo(x, y) } ctx.stroke(); //Рисуем путь ctx.closePath() //Закрываем путь})();
Таким образом мы получаем следующее изображение:
2. Добавьте анимацию к изображению функции.То, что получается выше, представляет собой изображение статической функции, а формы сигналов или волн на воде, которые мы обычно видим, постоянно меняются со временем. Здесь нам нужно использовать параметр фазы φ на предыдущем шаге (js — это Q в коде), мы можем непрерывно. увеличивайте или уменьшайте φ со временем, чтобы получать разные изображения в разное время, используйте window.requestAnimationFrame для реализации покадровой анимации;
Измените приведенный выше код так:
var Canvas = document.getElementById(canvas), ctx = Canvas.getContext('2d'), width = Canvas.width = Canvas.offsetWidth, height = Canvas.height = Canvas.offsetHeight;//Объявляем параметры var A=50, W=1/50, Q=0, H= height/2;//Метод рисования (функция draw(){ ctx.clearRect(0, 0, width, height);//Очистить холст ctx.beginPath(); //Начальный путь ctx.strokeStyle=#000; //Установить цвет линии ctx.lineWidth = 1; //Установить ширину линии ctx.moveTo(0, height); /2) ; //Положение начальной точки for (let x = 0; x <= width; x++) {// Нарисуйте переменную x, соответствующую y = A*Math.sin(W*x+Q) +H ctx.lineTo(x, y) } ctx.stroke(); //Рисуем путь ctx.closePath() //Закрываем путь})();
Эффект следующий (программа скриншота Жажа):
3. Нарисуйте полный заполненный путь.Хотя указанный выше путь закрыт, он не соответствует той части, которую нам нужно заполнить. Эффект от прямого заполнения следующий:
Полный заполненный путь должен выглядеть так:
После закрытия контура создайте цвет градиента в качестве цвета заливки. Код выглядит следующим образом:
var lingrad = ctx.createLinearGradient(0,0,width,0); lingrad.addColorStop(0, 'rgba(0,186,128,0.8)'); lingrad.addColorStop(1, 'rgba(111,224,195,1)'; draw() { window.requestAnimationFrame(draw); ctx.clearRect(0, 0, ширина, высота); ctx.beginPath(); ctx.strokeStyle = #000; ctx.fillStyle = lingrad; ctx.moveTo(0, высота /2); = скорость для (пусть x = 0; x <= ширина; x++) { var y = A*Math.sin(W*x+Q) +H; ctx.lineTo(x, y); } ctx.lineTo(ширина, высота); ctx.lineTo(0, высота); .closePath();})()
Эффект следующий:
4. Улучшена анимация водных волн.1. Во-первых, вы можете наложить более высокочастотный сигнал на приведенный выше сигнал, чтобы сделать его нерегулярным.
var s = 0,1*Math.sin(x/150)+1;var y = A*Math.sin(W*x+Q) +H;y=y*s;
2. Добавьте еще одну форму волны с разными изменениями фазы, и ее градиентная заливка будет противоположной предыдущему направлению градиента, чтобы сформировать эффект перекрывающейся тени, и установите эффект перекрытия пути globalCompositeOperation;
var Canvas = document.getElementById(canvas), ctx = Canvas.getContext('2d'), ширина = Canvas.width = Canvas.offsetWidth, высота = Canvas.height = Canvas.offsetHeight;var A=30, W=1 / 200, Q=0, H= высота / 2;вар A2=30, W2=1/300, Q2=0, H2= высота / 2;var Speed=-0.01;var Speed2=-0.02;var lingrad = ctx.createLinearGradient(0,0,width,0);lingrad.addColorStop(0, 'rgba(0,186,128,0.8)');lingrad.addColorStop( 1, 'rgba(111 224 195,1)'); var lingrad2 = ctx.createLinearGradient(0,0,width,0);lingrad2.addColorStop(0,'rgba(111,224,195,1)');lingrad2.addColorStop(1, 'rgba(0,186,128,0.8)'); draw() { window.requestAnimationFrame(draw); ctx.clearRect(0, 0, width, height); ctx.beginPath(); ctx.fillStyle = lingrad; ctx.moveTo(0, height /2); //Рисуем первый сигнал Q+=speed; = 0; x <= ширина; x++) { var s = 0,1*Math.sin(x/150)+1; A*Math.sin(W*x+Q) +H; y=y*s; ctx.lineTo(x, y); } ctx.lineTo(ширина, высота); .fill(); ctx.closePath() //Устанавливаем эффект перекрытия ctx.globalCompositeOperation = Destination-over //Рисуем второй сигнал ctx.beginPath(); ctx.fillStyle = lingrad2; Q2+=speed2; for (let x = 0; x < width; x++) { var y = A2*Math.sin(x*W2+Q2) +H2; } ctx.lineTo(ширина,высота); ctx.lineTo(0,height()); ctx.closePath();})()
Выше приведено все содержание этой статьи. Я надеюсь, что она будет полезна для изучения всеми. Я также надеюсь, что все поддержат сеть VeVb Wulin.