其實數據是來源於NOAA 的Grid 格點風力數據,分辨率是1度,全球共360*180 個格點 (總計64,800個). 那麼就我以前的瞭解,風力數據通常都是分爲U/V 兩個方向,包括NetCDF 數據也是,座標信息是隱含在grid 的索引中,風力記錄在了 U/ V 兩個垂直的方向.webpack
把水平U 方向的風力和 垂直V 方向的風力數值分別做爲 RGB波段的 R,G 兩個數值,合成一張png就如圖所示。git
因爲我沒有采用官網的數據下載API,因此沒有拿到原始的json 數據,只拿到一張png,因此沒法反演出 U/V 數值的符號,只有正值. 因此最後渲染出來只有第一象限的風向,固然做爲演示應該沒問題。github
根據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);
}
}
}
複製代碼
當解析出這麼多點以後,就能夠開始寫渲染的函數了,能夠用mapbox 原生的 fill layer 來作渲染(基於webgl,效率更高)。可是爲了方便動畫,這裏就採用本身以前寫的動畫控制器Alex.myTween 和 CanvasOverLayer 擴展來渲染web
// 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);
});
複製代碼
渲染的效果以下圖:json
其實就是作起來好玩,這個項目起源於對動畫的實驗,API所有采用ES6 + webpack,爲了本身寫起來方便,採用的給mapbox 疊加自定義CanvasOverlayer的形式 來快速開發本身想要的效果。以後仍是打算切換到 webgl,畢竟那個效率才高。 項目中還有些 其餘插件,歡迎你們把玩,提issuecanvas
昨天剛更新的將 Chart.js 集成到地圖的dom 疊加層,直接配置插件中的domOverlay 便可,簡單好用。bash