Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

canvas 奇巧淫技(一) 绘制风向动画 #3

Open
alex2wong opened this issue Aug 26, 2018 · 0 comments
Open

canvas 奇巧淫技(一) 绘制风向动画 #3

alex2wong opened this issue Aug 26, 2018 · 0 comments

Comments

@alex2wong
Copy link
Owner

alex2wong commented Aug 26, 2018

拿到一张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,效率更高)。但是为了方便动画,这里就采用自己之前写的动画控制器和 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);
});

渲染的效果如下图:

canvas渲染风轨迹效果

其实就是做起来好玩,这个项目起源于对动画的实验,API全部采用ES6 + webpack,为了自己写起来方便,采用的给mapbox 叠加自定义CanvasOverlayer的形式 来快速开发自己想要的效果。之后还是打算切换到 webgl,毕竟那个效率才高。 项目中还有些 其他插件,欢迎大家把玩,提issue

昨天刚更新的将 Chart.js 集成到地图的dom 叠加层,直接配置插件中的domOverlay 即可,简单好用。

Mapbox plugin 项目示例

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

欢迎Star ❤ ,欢迎PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant