Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

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

Open
@alex2wong

Description

拿到一张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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

        AltStyle によって変換されたページ (->オリジナル) /