openlayers3 + canvas 通过粒子动画展示风场

openlayers3 + canvas 展示风场

原理:将屏幕坐标转换为经纬度,再通过经纬度获取风速风向,再通过canvas绘制
效果:

步骤:
1、随机新建粒子(显示得风得数量,确定生命周期、位置等信息),获取该粒子得风速风向(我是使用双线性内插法)。
2、变为下一个时刻,先将上一个时刻得透明度降低(粒子生命剩余得越少,他就越透明,粒子死亡后不留痕迹),遍历粒子,根据粒子得风速风向,计算出该时刻粒子所在得位置,绘制(g.moveTo(proj.x, proj.y); g.lineTo(p.oldX, p.oldY);就是画线),粒子生命周期变小
3、去除生命结束得粒子,再重新生成粒子(粒子得声明周期是随机得),重复第二步

好久之前写得,代码现在看起来乱七八糟得,主要得代码如下:


//新生成粒子
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 dx = animator ? animator.dx : 0;
    var dy = animator ? animator.dy : 0;
    var scale = animator ? animator.scale : 1;
    var safecount = 0;
    for (; ;) {
        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; //纬度
        var x = a * windParam.getx0() + (1 - a) * windParam.getx1();
        var y = b * windParam.gety0() + (1 - b) * windParam.gety1();
        var v = this.field.getValue(x, y);
        if (this.field.maxLength == 0) {
            return new Particle(x, y, 1 + 40 * Math.random());
        }
        var m = v.length() / this.field.maxLength;
        if ((v.x || v.y) && (++safecount > 10 || Math.random() > m * 0.9)) {
            var proj = this.projection.project(x, y);
            var sx = proj.x * scale + dx;
            var sy = proj.y * scale + dy;
            if (++safecount > 10 || !(sx < 0 || sy < 0 || sx > this.canvas.width || sy > this.canvas.height)) {
                return new Particle(x, y, 1 + 40 * Math.random());
            }
        } else {
            return new Particle(0, 0, -1);
        }
    }
};
//动画(移动+绘制)
MotionDisplay.prototype.animate = function (animator) {
    this.moveThings(animator);
    this.draw(animator);
}
//移动
MotionDisplay.prototype.moveThings = function (animator) {
    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 += windParam.speed * a.x
            p.y += windParam.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

    var dx = animator.dx
    var dy = animator.dy
    var scale = animator.scale

    var proj = new Vector(0, 0)
    var val = new Vector(0, 0)

    g.strokeStyle = "rgb(255,255,255)"
    var prev = g.globalCompositeOperation
    g.globalCompositeOperation = "destination-in"
    g.fillStyle = 'rgba(0,0,0,0.95)'
    g.fillRect(0, 0, w, h)
    g.globalCompositeOperation = prev
    g.beginPath()
    for (var i = 0; i < this.particles.length; i++) {
        var p = this.particles[i]
        if (!this.field.inBounds(p.x, p.y)) {
            p.age = -2
            continue
        }
        this.projection.project(p.x, p.y, proj)
        proj.x = proj.x * scale + dx
        proj.y = proj.y * scale + dy
        if (proj.x < 0 || proj.y < 0 || proj.x > w || proj.y > h) {
            p.age = -2
        }
        if (p.oldX != -1 && particledrawflag == 1) {
            var wind = this.field.getValue(p.x, p.y, val)
            var s = wind.length() / this.maxLength

            g.moveTo(proj.x, proj.y)
            g.lineTo(p.oldX, p.oldY)
        }
        p.oldX = proj.x
        p.oldY = proj.y
    }
    g.stroke()
}



你可能感兴趣的:(openlayers3 + canvas 通过粒子动画展示风场)