In a recent project, the UI designed a background animation with a water wave effect. However, there was no gif or svg animation. I tried to use CSS to implement it, but the animation effect was not very good. I checked online and basically used Bezier curves to achieve it. , I thought of the various waveform diagrams I had seen before, so I thought about briefly simulating it using trigonometric function images.
1. Draw the sin function imageThe expression of sin function is as follows,
y=Asin(wx+φ)+h
Among them, A represents the amplitude, ω represents the angular frequency (ω=2π/T, T is the period of the function), φ represents the initial phase, and h represents the length of translation of the image in the positive direction of the y-axis; (It should be noted here: h is in mathematics originally means upward translation, but the screen coordinate system is used in canvas, that is, the upper left corner is the origin, and h means downward translation);
The drawing code is as follows:
(1) Add canvas tag
<canvas id=canvas></canvas>
(2) Add css style and set canvas width and height
html,body { padding: 0; margin: 0; width: 100%; height: 100%;}canvas { width: 100%; height: 100%;}
(3) Draw function image
var canvas = document.getElementById(canvas), ctx = canvas.getContext('2d'), width = canvas.width = canvas.offsetWidth, height = canvas.height = canvas.offsetHeight;//Declare parameters var A=50, W=1 / 50, Q=0, H= height / 2;//Drawing method (function draw(){ ctx.clearRect(0, 0, width, height);//Clear the canvas ctx.beginPath(); //Start path ctx.strokeStyle=#000; //Set the line color ctx.lineWidth = 1; //Set the line width ctx.moveTo(0, height /2) ; //Start point position for (let x = 0; x <= width; x++) {// Draw the var of x corresponding to y = A*Math.sin(W*x+Q) +H ctx.lineTo(x, y) } ctx.stroke(); //Draw the path ctx.closePath(); //Close the path})()
This way we get the following image:
2. Add animation to function imageWhat is obtained above is a static function image, and the waveforms or water waves we generally see change continuously with time. Here we need to use the parameter phase φ in the previous step, (js is Q in the code ), we can continuously increase or decrease φ with time to obtain different images at different times; use window.requestAnimationFrame to implement frame animation;
Modify the above code to:
var canvas = document.getElementById(canvas), ctx = canvas.getContext('2d'), width = canvas.width = canvas.offsetWidth, height = canvas.height = canvas.offsetHeight;//Declare parameters var A=50, W=1 / 50, Q=0, H= height / 2;//Drawing method (function draw(){ ctx.clearRect(0, 0, width, height);//Clear the canvas ctx.beginPath(); //Start path ctx.strokeStyle=#000; //Set the line color ctx.lineWidth = 1; //Set the line width ctx.moveTo(0, height /2) ; //Start point position for (let x = 0; x <= width; x++) {// Draw the var of x corresponding to y = A*Math.sin(W*x+Q) +H ctx.lineTo(x, y) } ctx.stroke(); //Draw the path ctx.closePath(); //Close the path})()
The effect is as follows (Zhazha screenshot software):
3. Draw a complete filled pathAlthough the above path is closed, it does not meet the part we need to fill. The effect of direct filling is as follows:
The complete filled path should look like this:
After closing the path, create a gradient color as the fill color. The code is as follows:
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)'); (function draw(){ window.requestAnimationFrame(draw); ctx.clearRect(0, 0, width, height); ctx.beginPath(); ctx.strokeStyle=#000; ctx.fillStyle = lingrad; ctx.lineWidth = 1; ctx.moveTo(0, height /2); Q+ =speed; for (let x = 0; x <= width; x++) { var y = A*Math.sin(W*x+Q) +H; ctx.lineTo(x, y); } ctx.lineTo(width, height); ctx.lineTo(0, height); ctx.fill(); ctx .closePath();})()
The effect is as follows:
4. Improve water wave animation1. First, you can superimpose a higher frequency waveform on the above waveform to make the waveform irregular.
var s = 0.1*Math.sin(x/150)+1;var y = A*Math.sin(W*x+Q) +H;y=y*s;
2. Add another waveform with different phase changes, and its gradient filling is opposite to the previous gradient direction to form an overlapping shadow effect; and set the path overlap effect globalCompositeOperation;
var canvas = document.getElementById(canvas), ctx = canvas.getContext('2d'), width = canvas.width = canvas.offsetWidth, height = canvas.height = canvas.offsetHeight;var A=30, W=1 / 200, Q=0, H= height / 2;var A2=30, W2=1/300, Q2=0, H2= height / 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)'); (function draw(){ window.requestAnimationFrame(draw); ctx.clearRect(0, 0, width, height); ctx.beginPath(); ctx.fillStyle = lingrad; ctx.moveTo(0, height /2); //Draw the first waveform Q+=speed; for (let x = 0; x <= width; x++) { var s = 0.1*Math.sin(x/150)+1; var y = A*Math.sin(W*x+Q) +H; y=y*s; ctx.lineTo(x, y); } ctx.lineTo(width, height); ctx.lineTo(0, height); ctx .fill(); ctx.closePath() //Set the overlap effect ctx.globalCompositeOperation = destination-over //Draw the second waveform 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(x, y) ; } ctx.lineTo(width,height); ctx.lineTo(0,height); ctx.fill() ctx.closePath();})()
The above is the entire content of this article. I hope it will be helpful to everyone’s study. I also hope everyone will support VeVb Wulin Network.