# 《每周一点canvas动画》——差分函数的妙用

### 3.代码实现

#### 1.准备工作

``````function Vertex(x,y,baseY){
this.baseY = baseY;         //基线
this.x = x;                 //点的坐标
this.y = y;
this.vy = 0;                //竖直方向的速度
this.targetY = 0;           //目标位置
this.friction = 0.15;       //摩擦力
this.deceleration = 0.95;   //减速
}
//y坐标更新
Vertex.prototype.updateY = function(diffVal){
this.targetY = diffVal + this.baseY;   //改变目标位置
this.vy += (this.targetY - this.y);       //速度
this.vy *= this.deceleration;
this.y += this.vy * this.friction;     //改变坐标竖直方向的位置
}
``````

``````var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
W = window.innerWidth;
H = window.innerHeight;

canvas.width = W;
canvas.height = H;

var color1 = "#6ca0f6",    //矩形1的颜色
color2 = "#367aec";   //矩形2的颜色

var vertexes = [],    //顶点坐标
verNum = 250,     //顶点数
diffPt = [],      //差分值``````

``````for(var i=0; i<verNum; i++){
vertexes[i] = new Vertex(W/(verNum-1)*i, H/2, H/2);
diffPt[i] = 0;                                         //初始值都为0
}``````

``````function draw(){

//矩形1
ctx.save()
ctx.fillStyle = color1;
ctx.beginPath();
ctx.moveTo(0, H);
ctx.lineTo(vertexes[0].x, vertexes[0].y);
for(var i=1; i<vertexes.length; i++){
ctx.lineTo(vertexes[i].x, vertexes[i].y);
}
ctx.lineTo(W,H);
ctx.lineTo(0,H);
ctx.fill();
ctx.restore();

//矩形2
ctx.save();
ctx.fillStyle = color2;
ctx.beginPath();
ctx.moveTo(0, H);
ctx.lineTo(vertexes[0].x, vertexes[0].y+5);
for(var i=1; i<vertexes.length; i++){
ctx.lineTo(vertexes[i].x, vertexes[i].y+5);
}
ctx.lineTo(W, H);
ctx.lineTo(0, H);
ctx.fill();
ctx.restore();
}``````

#### 2.核心代码

``````var vPos = 125;  //震荡点
var dd = 15;     //缓冲
var autoDiff = 1000;  //初始差分值``````

``````function update(){
autoDiff -= autoDiff*0.9;        //1
diffPt[vPos] = autoDiff;

//左侧
for(var i=vPos-1; i>0; i--){     //2
var d = vPos-i;
if(d > dd){
d=dd;
}
diffPt[i]-=(diffPt[i] - diffPt[i+1])*(1-0.01*d);
}
//右侧
for(var i=vPos+1; i<verNum; i++){   //3
var d = i-vPos;
if(d>dd){
d=dd;
}
diffPt[i] -= (diffPt[i] - diffPt[i-1])*(1-0.01*d);
}

//更新Y坐标
for(var i=0; i<vertexes.length; i++){  //4
vertexes[i].updateY(diffPt[i]);
}
}``````

``````(function drawframe(){
ctx.clearRect(0, 0, W, H);
window.requestAnimationFrame(drawframe, canvas);
update()
draw();
})()
``````

#### 3.鼠标交互

``````canvas.addEventListener('mousedown', function(e){
var mouse = {x:null, y:null};

if(e.pageX||e.pageY){
mouse.x = e.pageX;
mouse.y = e.pageY;
}else{
mouse.x = e.clientX + document.body.scrollLeft +document.documentElement.scrollLeft;
mouse.y = e.clientY + document.body.scrollTop +document.documentElement.scrollTop;
}

//重设差分值
if(mouse.y>(H/2-50) && mouse.y<(H/2 +50)){
autoDiff = 1000;
vPos = 1 + Math.floor((verNum - 2) * mouse.x / W);
diffPt[vPos] = autoDiff;
}

console.log(mouse.x, mouse.y)

}, false)
``````

#### 你可能感兴趣的

19 条评论

+1 回复

chengquan223 · 2016年10月18日

sophsis · 2016年10月19日

rainwangjie · 2016年10月22日

privateeye · 2016年10月24日

@我的印象笔记

Junping · 2016年11月11日

top_tobewell · 2016年11月23日