# 数据可视化之风向图

## 如何实现

```var Vector = function(x, y) {
this.x = x;
this.y = y;
}```

```VectorField.read= function(data, correctForSphere) {
var field = [];
var w = data.gridWidth;
var h = data.gridHeight;
for (var x = 0; x < w; x++) {
field[x] = [];
for (var y = 0; y < h; y++) {
var vx = data.field[i++];
var vy = data.field[i++];
var v = new Vector(vx,vy);
……
field[x][y] = v;
}
}
var result = newVectorField(field,data.x0,data.y0,data.x1,data.y1);
return result;
};```

```VectorField.prototype.bilinear= function(coord, a, b) {
var na = Math.floor(a);
var nb = Math.floor(b);
var ma = Math.ceil(a);
var mb = Math.ceil(b);
var fa = a - na;
var fb = b - nb;
return this.field[na][nb][coord] * (1 - fa)* (1 - fb) +
this.field[ma][nb][coord] * fa * (1 - fb) +    this.field[na][mb][coord] * (1 - fa) * fb +    this.field[ma][mb][coord] * fa * fb;
};```

```var Particle =function(x, y, age) {
this.x = x;
this.y = y;
this.oldX = -1;
this.oldY = -1;
this.age = age;
}```

```varMotionDisplay = function(canvas, imageCanvas, field, numParticles,opt_projection) {
this.field = field;
this.numParticles = numParticles;
this.x0 = this.field.x0;
this.x1 = this.field.x1;
this.y0 = this.field.y0;
this.y1 = this.field.y1;
this.makeNewParticles(null, true);
};```

```MotionDisplay.prototype.makeNewParticles= function(animator) {
this.particles = [];
for (var i = 0; i < this.numParticles;i++) {
this.particles.push(this.makeParticle(animator));
}
};

MotionDisplay.prototype.makeParticle= function(animator) {
var a = Math.random();
var b = Math.random();
var x = a * this.x0 + (1 - a) *this.x1;
var y = b * this.y0 + (1 - b) * this.y1;
return new Particle(x,y,1 + 40 * Math.random());
};```

```MotionDisplay.prototype.animate= function(animator) {
this.moveThings(animator);//update
this.draw(animator); // render
}```

```MotionDisplay.prototype.moveThings= function(animator) {
var speed = .01 * this.speedScale /animator.scale;
for (var i = 0; i <this.particles.length; i++) {
var p = this.particles[i];
if (p.age > 0 &&this.field.inBounds(p.x, p.y)) {
var a = this.field.getValue(p.x,p.y);
p.x += speed * a.x;
p.y += speed * a.y;
p.age--;
} else {
this.particles[i] = this.makeParticle(animator);
}
}
};```

```MotionDisplay.prototype.draw= function(animator) {
var g = this.canvas.getContext('2d');
var w = this.canvas.width;
var h = this.canvas.height;
if (this.first) {
g.fillStyle = this.background;
this.first = false;
} else {
g.fillStyle = this.backgroundAlpha;
}

g.fillRect(dx, dy, w , h );
for (var i = 0; i <this.particles.length; i++) {
var p = this.particles[i];
if (p.oldX != -1) {
g.beginPath();
g.moveTo(proj.x, proj.y);
g.lineTo(p.oldX, p.oldY);
g.stroke();
}
p.oldX = proj.x;
p.oldY = proj.y;
}
};```

## WebGL

```surfaceLayers:[{
type: 'particle',
distance: 3,
size: [4096, 2048],
particle: {
vectorField: field,
color: 'white',
speedScaling: 1,
sizeScaling: 1,
number: 512 * 512,
motionBlurFactor: 0.99
}
}]```

### VectorFieldParticleSurface这个就是一个风向图图层，记录风向图图层中的关键属性，关键是update函数，每一帧负责驱动状态更新。

```update: function(deltaTime) {
this._particlePass.setUniform('velocityTexture',this.vectorFieldTexture);

particlePass.attachOutput(this._particleTexture1);
particlePass.setUniform('particleTexture', this._particleTexture0);
particlePass.setUniform('deltaTime', deltaTime);
particlePass.setUniform('elapsedTime', this._elapsedTime);
particlePass.render(this.renderer,frameBuffer);
this._particleMesh.material.set('particleTexture',this._particleTexture1);

frameBuffer.attach(this.renderer.gl, this._thisFrameTexture);
frameBuffer.bind(this.renderer);
this.renderer.render(this._scene,this._camera);
}```

```    vec4 p =texture2D(particleTexture, v_Texcoord);
if (p.w > 0.0) {
vec4 vTex = texture2D(velocityTexture,p.xy);
vec2 v = vTex.xy;
v = (v - 0.5) * 2.0;
p.z = length(v);
p.xy += v * deltaTime / 50.0 *speedScaling;        // Make the particle surface seamless
p.xy = fract(p.xy);
p.w -= deltaTime;
}

gl_FragColor = p;```

```voidmain()
{
vec4 p = texture2D(particleTexture,texcoord);
gl_Position = worldViewProjection *vec4(p.xy * 2.0 - 1.0, 0.0, 1.0);
}```

0 条评论