canvas--模拟水波波浪(利用三角函数正弦曲线实现)--完整代码

实现原理

看到波浪特征的时候,难免会有人想到正余弦曲线。对于波陡很小的波动,一般都选择正弦或者余弦曲线来表示波形。

正弦曲线示意图

在这里插入图片描述

正弦曲线公式:y=Asin(ωx+φ)+h

A:表示振幅,值越大曲线越陡峭。用来控制波浪的高度
ω:表示角频率(ω=2π/T,T为函数的周期)
       T值大于1时:T值越大周期越短。用来控制波浪的宽度
       T值小于1大于0时:周期变长
φ:表示初相
       相移是-φ/ω 在ω不变的情况下,φ为正值:曲线向左移动;φ为负值:曲线向右移动。控制波浪的水平移动
h:表示图像向y轴正方向平移的长度,控制曲线上下移动。控制水位的高度

动画效果实现思路

主要是利用相移,通过不断水平移动曲线,产生出波浪移动的感觉,可以绘制多条曲线,曲线之间通过控制属性(高度、宽度、移动速度)产生视觉差

上代码

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>三角函数模拟水波</title>
		<style>
			html,
			body {
     
     
				padding: 0;
				margin: 0;
				width: 100%;
				height: 100%;
			}
			canvas {
     
     
				width: 100%;
				height: 500px;
			}
		</style>
	</head>
	<body>
		<div>
			<canvas id="canvas"></canvas>
		</div>
		<script type="text/javascript">
			var canvas = document.getElementById("canvas"),
				ctx = canvas.getContext('2d'),
				width = canvas.width = canvas.offsetWidth,
				height = canvas.height = canvas.offsetHeight;
			console.log(height)
			//声明参数
			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() {
     
     
				/**
				 * 将Q随时间不断增加或减小,即可得到不同时间的不同图像
				 * 使用window.requestAnimationFrame实现帧动画
				 */
				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); //起始点位置    moveTo(x,y)可把窗口的左上角移动到一个指定的坐标
				Q += speed;
				for(let x = 0; x <= width; x++) {
     
      //绘制x对应y的
					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() //闭合路径
				/**
				 * globalCompositeOperation 属性设置或返回如何将一个源(新的)图像绘制到目标(已有)的图像上。
						源图像 = 您打算放置到画布上的绘图。
						目标图像 = 您已经放置在画布上的绘图。
					destination-over:在源图像上方显示目标图像
				 */
				ctx.globalCompositeOperation = "destination-over"
				
				ctx.beginPath();
				ctx.strokeStyle = "#000";
				ctx.lineWidth = 1;
				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();

			})()
		</script>
	</body>
</html>

猜你喜欢

转载自blog.csdn.net/weixin_45406850/article/details/123270938