ES6写了一个水纹效果。还有点计算的问题。直接上代码Copy一下吧。
export default class Vertex {
static BASE_Y = 150;
static BASE_R = 10;
static FRICTION = 0.1;//波形抖动后回复到正常状态的速率指数
static DECELERATION = 0.95;
static SPEED_OF_BASE_WAVE = 3;
theta = 0;
goalY = 0;
amp = 0;
x;
y;
constructor(prmID, parent) {
this.theta = 360 * prmID / ( parent.NUM - 1);//角度的弧度值。根据NUM值将舞台上分为NUM块,然后将2π的弧度分配给各块,这样舞台上平静的时候正好是一段完整的波形。
this.x = prmID * parent.STAGE_W / (parent.NUM - 1);
this.y = Vertex.BASE_Y + Vertex.BASE_R * Math.sin(this.theta * Math.PI / 180);
}
//让波形不断波动的函数,不断更新各点的y坐标
updatePos(diffVal) {
this.theta += Vertex.SPEED_OF_BASE_WAVE;
if (this.theta >= 360) {
this.theta -= 360;
}
this.goalY = Vertex.BASE_Y + Vertex.BASE_R * Math.sin(this.theta * Math.PI / 180);
this.goalY += diffVal;
this.amp += this.goalY - this.y;
this.y += this.amp * Vertex.FRICTION;//y坐标以FRICTION的缓冲速率缓冲到正常状态
this.amp *= Vertex.DECELERATION;
}
}
/**
* Created by EricXie on 2019/6/19.
*/
import Vertex from "./Vertex.js";
export default class Wave{
STAGE_W=800;
STAGE_H=300;
NUM=800;
MOUSE_DIFF_RATIO=1;
AUTO_INTERVAL=3000;
vertexes=[];
mdlPt=[];
diffPt=[[],[]];
startIndex=[0,0];
mouseOldY;
mouseNewY;
mouseDiff=0;//mouseDiffGoal的缓冲
mouseDiffGoal=0;//鼠标拖动后产生的位相差
autoTimer;
autoDiff=0;//计时器自动生成的位相差
mouseY=0;
mouseX=0;
constructor(){
this.canvas=this.createCanvas();
this.ctx=this.canvas.getContext("2d");
this.init();
this.animation();
}
createCanvas(){
if(this.canvas) return this.canvas;
let canvas=document.createElement("canvas");
Object.assign(canvas.style,{
width:"800px",
height:"300px",
backgroundColor:"#FFFFFF",
margin:"auto"
});
canvas.addEventListener("mousemove",this.mouseHandler.bind(this));
return canvas;
}
mouseHandler(e){
this.mouseX=e.clientX;
this.mouseY=e.clientY;
}
appendTo(parent){
parent.appendChild(this.canvas);
}
animation(){
requestAnimationFrame(this.animation.bind(this));
this.updateMouseDiff();
this.updateWave();
}
init(){
for (let i=0; i<this.NUM; i++) {
let vertex=new Vertex(i,this);
this.vertexes.push(vertex);
//中点作成
if (i>1) {
this.mdlPt.push( {x:(this.vertexes[i-1].x+this.vertexes[i].x)*0.5,y:(this.vertexes[i-1].y+this.vertexes[i].y)*0.5});
}
//差分
this.diffPt[0].push( 0 );
this.diffPt[1].push( 0 );
}
this.mouseNewY=this.mouseY;
if (this.mouseNewY<0) {
this.mouseNewY=0;
} else if (this.mouseNewY > this.STAGE_H) {
this.mouseNewY=this.STAGE_H;
}
this.mouseOldY=this.mouseNewY;
setInterval(this.generateAutoWave.bind(this),this.AUTO_INTERVAL);
}
updateMouseDiff(){
this.mouseOldY=this.mouseNewY;
this.mouseNewY=this.mouseY;
if (this.mouseNewY<0) {
this.mouseNewY=0;
} else if (this.mouseNewY > this.STAGE_H) {
this.mouseNewY=this.STAGE_H;
}
this.mouseDiffGoal = (this.mouseNewY - this.mouseOldY) * this.MOUSE_DIFF_RATIO;
}
updateWave(){
this.ctx.clearRect(0,0,this.STAGE_W,this.STAGE_H);
this.mouseDiff -= (this.mouseDiff - this.mouseDiffGoal)*0.3;
this.autoDiff-=this.autoDiff*0.9;//波形自动波动时的速率
let mX=this.mouseX;
if (mX<0) {
mX=0;
} else if (mX > this.STAGE_W-2) {
mX=this.STAGE_W-2;
}
this.startIndex[0] = 1+Math.floor( (this.NUM-2) * mX / this.STAGE_W );//startIndex[0]表示波形图上,鼠标拖动的那个点,用Math.floor是
//可以取到NUM个点里面x坐标小于当前鼠标x坐标的最大值
this.diffPt[0][this.startIndex[0]] -= ( this.diffPt[0][this.startIndex[0]] - this.mouseDiff )*0.99;
//自动波
this.diffPt[1][this.startIndex[1]] -= ( this.diffPt[1][this.startIndex[1]] - this.autoDiff )*0.99;
let d;
let i;
for ( i=this.startIndex[0]-1; i >=0; i--) {
d=this.startIndex[0]-i;
if (d>15) {
d=15;
}
this.diffPt[0][i] -= ( this.diffPt[0][i] - this.diffPt[0][i+1] )*(1-0.01*d);
}
for ( i=this.startIndex[0]+1; i < this.NUM; i++) {
d=i-this.startIndex[0];
if (d>15) {
d=15;
}
this.diffPt[0][i] -= ( this.diffPt[0][i] - this.diffPt[0][i-1] )*(1-0.01*d);
}
for ( i=this.startIndex[1]-1; i >=0; i--) {
d=this.startIndex[1]-i;
if (d>15) {
d=15;
}
this.diffPt[1][i] -= ( this.diffPt[1][i] - this.diffPt[1][i+1] )*(1-0.01*d);
}
for ( i=this.startIndex[1]+1; i < this.NUM; i++) {
d=i-this.startIndex[1];
if (d>15) {
d=15;
}
this.diffPt[1][i] -= ( this.diffPt[1][i] - this.diffPt[1][i-1] )*(1-0.01*d);
}
for ( i=0; i < this.NUM; i++) {
this.vertexes[i].updatePos( this.diffPt[0][i]+this.diffPt[1][i]);//更新波形上各点的位相,位相差等于鼠标抖动的和自动产生的,即为diffPt[0][i]+diffPt[1][i]
}
for ( i=0; i < this.NUM-2; i++) {
this.mdlPt[i].y = (this.vertexes[i+1].y + this.vertexes[i+2].y)*0.5;//更新波形图上两点中点的位相,使波形图看起来更流畅
}
this.drawWave();
}
drawWave(){
this.ctx.fillStyle="#666666";
this.ctx.beginPath();
this.ctx.moveTo(this.STAGE_W, this.STAGE_H);
this.ctx.lineTo(0, this.STAGE_H);
this.ctx.lineTo(this.vertexes[0].x, this.vertexes[0].y-50);
this.ctx.quadraticCurveTo(this.vertexes[1].x, this.vertexes[1].y-50, this.mdlPt[0].x, this.mdlPt[0].y-50);
for (let i=2; i<this.NUM-2; i++) {
this.ctx.quadraticCurveTo(this.vertexes[i].x, this.vertexes[i].y-50, this.mdlPt[i-1].x, this.mdlPt[i-1].y-50);
}
this.ctx.quadraticCurveTo( this.vertexes[this.NUM-2].x, this.vertexes[this.NUM-2].y-50, this.vertexes[this.NUM-1].x, this.vertexes[this.NUM-1].y-50);
this.ctx.closePath();
this.ctx.fill();
}
generateAutoWave(){
this.autoDiff=200;//自动生成100的位相差
this.startIndex[1] = Math.round( Math.random()*(this.NUM-1) );
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script type="module">
import Wave from "./js/wave.js";
let wave=new Wave();
wave.appendTo(document.body);
</script>
</body>
</html>