mapbox 疊加canvas渲染風力圖

拿到一張UV風速圖

其實數據是來源于NOAA 的Grid 格點風力數據,分辨率是1度,全球共360*180 個格點 (總計64,800個). 那么就我之前的了解,風力數據一般都是分為U/V 兩個方向,包括NetCDF 數據也是,坐標信息是隱含在grid 的索引中,風力記錄在了 U/ V 兩個垂直的方向.

把水平U 方向的風力和 垂直V 方向的風力數值分別作為 RGB波段的 R,G 兩個數值,合成一張png就如圖所示。

由于我沒有采用官網的數據下載API,所以沒有拿到原始的json 數據,只拿到一張png,所以無法反演出 U/V 數值的符號,只有正值. 所以最后渲染出來只有第一象限的風向,當然作為演示應該沒問題。

2016112000 UV風力圖
根據UV 圖提取出每個格點的
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;
    }
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],
              // 根據UV計算風力,和風向.
                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 {
                // 如果不用geojson 的數據,就用自定義的canvas 去渲染,為了動畫方便,我們采用這種方式.
                particle.color = color;
                particle.angle = angle;
                particle.radius = radius;
                particles.push(particle);
            }
        }
    }

Canvas 渲染風向

當解析出這么多點之后,就可以開始寫渲染的函數了,可以用mapbox 原生的 fill layer 來做渲染(基于webgl,效率更高)。但是為了方便動畫,這里就采用自己之前寫的動畫控制器Alex.myTween 和 CanvasOverLayer 擴展來渲染

// genWindTarget 函數其實就是根據風向來模擬一個風粒子的動畫效果,產生動畫的目標對象,Alex.myTween為根據source 和target 自動計算中間坐標和狀態.

objs = windlayer.particles; targets = genWindTarget(objs);
// calc targets depend on its angle, use 6 degree as dist.
Alex.myTween.get(objs).to(targets, 8000, windlayer.redraw);
map.on('moveend', function(){
    windlayer.redraw(objs);
});

渲染的效果如下圖:


windy.gif

其實就是做起來好玩,這個項目起源于對動畫的實驗,API全部采用ES6 + webpack,為了自己寫起來方便,采用的給mapbox 疊加自定義CanvasOverlayer的形式 來快速開發自己想要的效果。之后還是打算切換到 webgl,畢竟那個效率才高。 項目中還有些 其他插件,歡迎大家把玩,提issue

Mapbox plugin 項目示例

項目地址 : https://github.com/alex2wong/mapbox-plugins

歡迎Star ? ,歡迎PR

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 你說你是人間的四月天;笑音點亮了四面風;輕靈在春的光艷中交舞著變。 ——《你是人間的四月天》 在若干年前的一個睡眼...
    鰻魚菇涼閱讀 316評論 0 4
  • 一名大一的計算機專業學生。各種女生不適合這個專業的話我都不放在耳里 ,但確實感到自己學習編程很被動。成績不錯,但能...
    程序熊閱讀 242評論 1 0
  • ? 因為得不到所有不想要。 轉眼而逝的二十年青春,我已從牙牙學語的小女孩成長為亭亭玉立的女生了,不知道能不能用亭亭...
    玥先森閱讀 378評論 0 2
  • Chapter3 分支 參考自 https://git-scm.com/book/zh/v1/Git-%E5%88...
    董噠噠閱讀 476評論 0 0