编辑
2022-10-21
Cesium
00
请注意,本文编写于 761 天前,最后修改于 525 天前,其中某些信息可能已经过时。

目录

甲、需要准备一个canvas与Cesium初始化后的图层
讲解过程
乙、设置Cesiumwindy参数params
丙、初始化风场粒子
丁、讲解根据风速设置不同粒子颜色
CanvasParticle参数解析
给粒子赋值颜色
戊、至此风场粒子效果已经完成后续操作注意如下
己、相关文档

初学 使用Canvas + NCEP数据创建动态风场效果 封装基于Cesium的canvas渲染风场API

集成npm插件

https://www.npmjs.com/package/cesium-windy-canvas npm i cesium-windy-canvas -S

github传送门
gitee传送门
codesandbox.io效果代码段
效果图

甲、需要准备一个canvasCesium初始化后的图层

Cesium初始化后的图层详见:vue3.0+vite+Cesium使用记录

讲解过程

1、先初始化Cesium 2、提供NCEP风场数据 详见 cesium-windy-canvas/mock20万行风场数据,直接复制即可 3、在进行CanvasWindy初始化 CanvasWindy详见 cesium-windy-canvas 4、设置风场必要参数 5、非常简单的创建具有动态粒子效果的风场

JavaScript
CanvasWindy(data, params);

乙、设置Cesiumwindy参数params

参数名参数解释类型默认值
viewerCesium初始化后赋值变量Objectnull
canvas风场画布DOMnull
canvasContextcanvas上下文DOMparams.canvas.getContext('2d')
canvasWidth画布宽度Number300
canvasHeight画布高度Number180
speedRate风前进速度Number100
extent风场绘制地图范围Array[]
particlesNumber粒子总数Number20000
maxAge每个粒子的最大生存周期Number120
frameTime每秒刷新次数Number100
lineWidth粒子线条宽度Number1
initExtent风场初始范围Array[]
calc_speedRate根据speedRate参数计算经纬度步进长度Array[0, 0]
windField风场网格Objectnull
particles风场粒子存储Array[]
animateFramerequestAnimationFrame事件句柄,用来清除操作Objectnull
isdistory是否进行销毁boolfalse
windyColor风场颜色集合(根据风速不同设置不同颜色)classnew WindyColor()

丙、初始化风场粒子

在初始化Cesiumwindy构造函数时,需要传入风场数据,以及相应的参数 执行构造函数时自动执行init()进行粒子创造


丁、讲解根据风速设置不同粒子颜色

在初始化粒子中有一个画线的操作,在画线过程中进行颜色赋值 在使用this.particles对所有粒子遍历进行画轨迹操作

创建粒子

JavaScript
/// randomParticle生成随机粒子 /// CanvasParticle() 粒子参数 this.particles.push(this.randomParticle(new CanvasParticle()));

CanvasParticle参数解析

参数名参数解释类型默认值
lng粒子初始经度null
lat粒子初始纬度null
tlng粒子下一步将要移动的经度,这个需要计算得来null
tlat粒子下一步将要移动的y纬度,这个需要计算得来null
x粒子初始x位置Numbernull
y粒子初始y位置Numbernull
age粒子生命周期计时器,每次-1Numbernull
speed粒子移动速度Numbernull
color粒子颜色Stringnull

给粒子赋值颜色

1、在生成随机粒子时根据风速计算不同颜色 this.windyColor.getWindColor(particle.speed) 详细见Cesiumwindy源码第333行 2、画粒子轨迹线时进行画布粒子颜色添加 this.canvasContext.strokeStyle = particle.color this.canvasContext.stroke(); 详见Cesiumwindy源码第244行

戊、至此风场粒子效果已经完成后续操作注意如下

1、粒子效果完成之后不会随着地图缩放变换,需要在操作之后重新进行渲染 (1)、电脑屏幕缩放 需要进行onresize监听

JavaScript
window.onresize = resizeCanvas; const resizeCanvas = () => { /// windycanvas = document.getElementById('windycanvas') 画布 if (windycanvas == null) return; windycanvas.width = window.innerWidth; windycanvas.height = cesiumRef.value?.clientHeight; if (windy) { // 重新设置画布大小 // eslint-disable-next-line no-underscore-dangle windy._resize(windycanvas.width, windycanvas.height); } };

(2)、地图缩放 地图缩放时需要对鼠标事件,滚轮事件进行监听 参考vue3.0+vite+Cesium使用记录监听viewer操作事件讲解 伪代码

JavaScript
handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); // 鼠标滚动、旋转后是否需要重新生成风场---如果需要,打开以下注释--旋转或者移动到北半球的时候计算会有问题 handler.setInputAction(() => { clearTimeout(refreshTimer); ...设置风场隐藏 refreshTimer = setTimeout(() => { if (windy) { windy.extent = ...获取当前三维窗口左上、右上、左下、右下坐标集合; windy.redraw(); } ...设置风场显示 }, 200); }, Cesium.ScreenSpaceEventType.WHEEL); // 鼠标左键、右键按下 handler.setInputAction(() => { mouseDown = true; }, Cesium.ScreenSpaceEventType.LEFT_DOWN); handler.setInputAction(() => { mouseDown = true; }, Cesium.ScreenSpaceEventType.RIGHT_DOWN); // 鼠标移动 handler.setInputAction(() => { if (mouseDown) { ...设置风场隐藏 mouseMove = true; } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); // 鼠标左键、右键抬起 handler.setInputAction(() => { if (mouseDown && mouseMove) { if (windy) { windy.extent = globalExtent; windy.redraw(); } } ...设置风场显示 mouseDown = false; mouseMove = false; }, Cesium.ScreenSpaceEventType.LEFT_UP); handler.setInputAction(() => { if (mouseDown && mouseMove) { if (windy) { windy.extent = globalExtent; windy.redraw(); } } ...设置风场显示 mouseDown = false; mouseMove = false; }, Cesium.ScreenSpaceEventType.RIGHT_UP);

解释: ...设置风场显示:在鼠标操作以及滚轮操作后将渲染后的风场重新进行展示,属于display操作 ...设置风场隐藏:在鼠标操作以及滚轮操作时将画布进行隐藏

(3)、监听当前地球操作,时刻计算窗口坐标进行globalExtent赋值

JavaScript
viewer.scene.postRender.addEventListener(() => { getCesiumExtent(); });
JavaScript
// 获取当前三维窗口左上、右上、左下、右下坐标 const getCesiumExtent = () => { const canvaswidth = window.innerWidth; const canvasheight = cesiumRef.value?.clientHeight || 0 - 50; // eslint-disable-next-line camelcase const left_top_pt = new Cesium.Cartesian2(0, 0); // eslint-disable-next-line camelcase const left_bottom_pt = new Cesium.Cartesian2(0, canvasheight); // eslint-disable-next-line camelcase const right_top_pt = new Cesium.Cartesian2(canvaswidth, 0); // eslint-disable-next-line camelcase const right_bottom_pt = new Cesium.Cartesian2(canvaswidth, canvasheight); const pick1 = viewer.scene.globe.pick(viewer.camera.getPickRay(left_top_pt), viewer.scene); const pick2 = viewer.scene.globe.pick(viewer.camera.getPickRay(left_bottom_pt), viewer.scene); const pick3 = viewer.scene.globe.pick(viewer.camera.getPickRay(right_top_pt), viewer.scene); const pick4 = viewer.scene.globe.pick(viewer.camera.getPickRay(right_bottom_pt), viewer.scene); if (pick1 && pick2 && pick3 && pick4) { // 将三维坐标转成地理坐标---只需计算左下右上的坐标即可 const geoPt1 = viewer.scene.globe.ellipsoid.cartesianToCartographic(pick2); const geoPt2 = viewer.scene.globe.ellipsoid.cartesianToCartographic(pick3); // 地理坐标转换为经纬度坐标 const point1 = [(geoPt1.longitude / Math.PI) * 180, (geoPt1.latitude / Math.PI) * 180]; const point2 = [(geoPt2.longitude / Math.PI) * 180, (geoPt2.latitude / Math.PI) * 180]; // console.log(point1,point2); // 此时说明extent需要分为东西半球 if (point1[0] > point2[0]) { globalExtent = [point1[0], 180, point1[1], point2[1], -180, point2[0], point1[1], point2[1]]; } else { globalExtent = [point1[0], point2[0], point1[1], point2[1]]; } } else { globalExtent = []; } };

己、相关文档

  1. vue3.0+vite+Cesium使用记录
  2. cesium-windy-canvas源码
  3. cesium轨迹讲解
如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:还是夸张一点

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

还是夸张一点技术专栏 © 2019 - 2023 | 滇ICP备2022001556号
世间情动不过盛夏白瓷梅子汤,碎冰碰壁当啷响。