实现原理
看到波浪特征的时候,难免会有人想到正余弦曲线。对于波陡很小的波动,一般都选择正弦或者余弦曲线来表示波形。
正弦曲线示意图
正弦曲线公式: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>