Home Reference Source

src/layers/windLayer.js

import {CanvasOverlayer} from './canvasOverlay';

/**
 * initWindlayer based on mapboxgl-canvas
 */
export class WindLayer extends CanvasOverlayer {
    constructor(opts) {
        let _opts = opts || {};
        super(_opts);
        this.windImage = _opts.image || new Image();
        this.radius = _opts.radius || 2; 
        // this.redraw = _redraw.bind(this);
    }
    
    /**
     * render particles based on image
     * @param {*grid wind image} image 
     */
    updateWind(image, geojson, compressRatio) {
        let canvas = this.canvas, pix2render = [],
            ctx = this.canvas.getContext("2d");
        if (this.particles == undefined) {
            console.log("generating particles...");
            this.particles = genParticles(image, geojson, compressRatio, this.radius);
        }
        // ctx.globalAlpha = 0.95;
        if (!geojson) {
            console.log("generating particles complete! num: " + this.particles.length);
            this.redraw(this.particles);
        } else {
            // wind data should be rendered as mapboxgl vector.
            console.log("generating particles complete! num: " + this.particles.features.length + " in geojson.");
        }
    }
}

function _redraw() {
    // this.particles
}

/**
 * generate particles based on got Grid wind image.
 * (actually image -> particles)
 * called after wind image loaded event..
 * return particles: Array, particles with wind strength and angle.
 */
function genParticles(image, geojson, compressRatio, radius) {
    let windImage = image || this.windImage,
        tmpCanvas = document.createElement("canvas"),
        tmpCtx = tmpCanvas.getContext("2d"),
        particles = [], features = [];
    if (geojson) {
        particles = {
            "type": "FeatureCollection",
            "name": "particles",
            "features": features
        }
    }

    tmpCanvas.width = windImage.width;
    tmpCanvas.height = windImage.height;
    tmpCtx.drawImage(windImage, 0, 0);
    // imageData.data.length: width*height*4
    let imageData = tmpCtx.getImageData(0, 0, tmpCanvas.width, tmpCanvas.height),
        dataLength = imageData.data.byteLength;
    if (compressRatio == undefined || (compressRatio !== undefined && compressRatio < 1)) {
        console.warn("Input compressRatio invalid, use default 1.");
        compressRatio = 1;
    }
    compressRatio = parseInt(Number(compressRatio));
    for (let i=1;i<tmpCanvas.height-1;i+=compressRatio) {
        // i:0~180, j:0~360
        for (let j=0;j<tmpCanvas.width;j+=compressRatio) {
            let particle = {
                'lon': -180 + j,
                'lat': -90 + i,
            };            
            let uIndex = (i * 360 + j) * 4, vIndex = uIndex + 1;
            let uVal = imageData.data[uIndex], vVal = imageData.data[vIndex],
                windPow = Math.pow(uVal, 2) + Math.pow(vVal, 2),
                angle = Number(Math.atan(vVal/uVal).toFixed(2)),
                color = 'rgba('+ (windPow/255).toFixed(0) + ', 255, 100, 0.7)';
            // return geojson dataSource for mapboxgl.vector layer.
            if (geojson) {
                particle = { "type": "Feature", 
                    "properties": {
                        "angle": angle,
                        "color": color
                    },
                    "geometry": {
                        "type": "Point",
                        "coordinates": [-180 + j, -90 + i]
                    }
                }
                features.push(particle);
            } else {
                particle.color = color;
                particle.angle = angle;
                particle.radius = radius;
                particles.push(particle);
            }
        }
    }
    return particles;
}