风场可视化学习笔记:openlayers
最近在弄地图控件方面的东西,这里分享一个我找到的一个添加风场的教程和demo,需要对大家有所帮助(以下为转载内容)载于https://blog.csdn.net/u010065726/article/details/106338194/
windLayer api使用示例
这里主要为windlayer关于在openlayers3-4版本内使用的相关接口及参数说明
在加载时,主要读取的数据来源格式为json,而我们一般获取到的数据主要为netCDF或Grib等格式的数据,这里还涉及相关的数据转换操作
1.openlayers-wind
参数说明
TIP
对应于 openlayers 3-4 相关参数
图层参数
其他参数遵循 ol
基础图层参数。
windOptions
colorScale
关于颜色配置,在以往的配置中传入的是颜色数组会根据以下函数和格点数据的数据范围去计算匹配的颜色值,
1 2 3 4 5 | const indexFor = function (m) { // map velocity speed to a style return Math.max(0, Math.min((that.COLOR_SCALE.length - 1), Math.round((m - min) / (max - min) * (that.COLOR_SCALE.length - 1)))); } |
这样实现只能按照风速值范围等间隔渲染,无法做到精确匹配对应值的颜色。
在最新的版本中新增了此参数的类型,可以通过回调函数精确对应颜色值(但是会有一定的性能损失)
颜色配置支持三种方式:
String:固定颜色值
Function: 通过回调函数的风速值设定颜色(但是会有一定的性能损失)
String[]: 按照风速值范围等间隔渲染,无法做到精确匹配对应值的颜色。
2.数据来源
风场数据来源主要为气象的数据文件,可以详见另一篇文章 windy网站数据分析 。文章中提到的windy基本涵盖了大部分的气象数据来源,大家可以参考一下。
在使用wind-layer需要了解相关的数据转换,大家可以多下下功夫,有什么内容也可以分享出来,大家互相学习下。
3.图层初始化并格网分析数据源
调用相关的API接口,添加相应的图层对象
demo代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | <!DOCTYPE html> <html> <meta charset= "UTF-8" > <meta name= "viewport" content= "width=device-width, initial-scale=1" > <title> 风向demo </title> <link rel= "stylesheet" href= "https://cdn.jsdelivr.net/npm/dat.gui@0.7.6/build/dat.gui.css" > <script src= "https://cdn.jsdelivr.net/npm/openlayers/dist/ol.js" > </script> <link rel= "stylesheet" href= "https://cdn.jsdelivr.net/npm/openlayers/dist/ol.css" > <script src= "https://cdn.jsdelivr.net/npm/openlayers-wind/dist/ol-wind.js" > </script> <style type= "text/css" > html, body { margin: 0; height: 100%; width: 100% } .container { width: 100%; height: 100% } </style> <body> <div id= "map" class = "container" > </div> <script> const map = new ol.Map({ target: 'map' , view: new ol.View({ center: [113.53450137499999, 34.44104525], // center: ol.proj.fromLonLat([113.53450137499999, 34.44104525]), zoom: 5, projection: 'EPSG:4326' , }), layers: [ new ol.layer.Tile({ source: new ol.source.OSM({ url: 'https://{a-d}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png' , }) })], }); let layer; // https://sakitam-fdd.github.io/wind-layer/data/wind.json fetch( 'https://sakitam-fdd.github.io/wind-layer/data/wind.json' ).then(res => res.json()).then(res =>{ const windLayer = new OlWind.WindLayer(res, { windOptions: { colorScale: [ "rgb(36,104, 180)" , "rgb(60,157, 194)" , "rgb(128,205,193 )" , "rgb(151,218,168 )" , "rgb(198,231,181)" , "rgb(238,247,217)" , "rgb(255,238,159)" , "rgb(252,217,125)" , "rgb(255,182,100)" , "rgb(252,150,75)" , "rgb(250,112,52)" , "rgb(245,64,32)" , "rgb(237,45,28)" , "rgb(220,24,32)" , "rgb(180,0,35)" ], velocityScale: 1 / 100, paths: 1000, }, map: map, }); analysisWindyData(res); console.log(map, windLayer); layer = windLayer; // layer.appendTo(map); map.addLayer(windLayer); map. on ( 'singleclick' , e =>{ var details = getWindyDetail(e.coordinate); console.log(details); alert( ' 风向:' + details.direction + '\n 风级:' + details.level + '\n 风速:' + details.speed); }); }); var allgrid = []; function analysisWindyData(windydata) { var p = 0;0. var east, north; if (windydata[0].header.parameterNumberName == "eastward_wind" ) { east = windydata[0]; north = windydata[1]; } else { east = windydata[1]; north = windydata[0]; } for ( var j = 0; j < north.header.ny; j++) { var row = []; for ( var i = 0; i < north.header.nx; i++, p++) { row[i] = [east.data[p], north.data[p]]; } allgrid[j] = row; } } function getWindyDetail(coord) { var lng = coord[0]; var lat = coord[1]; // 与格网序列的数据转换 if (lng >= 0) { lng = Math.floor(lng); } else { lng = 360 + Math.floor(lng) } lat = 90 - Math.floor(lat); // 获取对应的格网序列 var xlength = lng; var ylength = lat; var xdata, ydata; xdata = allgrid[Math.abs(ylength)][Math.abs(xlength)][0]; ydata = allgrid[Math.abs(ylength)][Math.abs(xlength)][1]; console.log(xdata); console.log(ydata); if ( typeof xdata != "number" || typeof ydata != "number" ) { console.error( "暂无该区域风向数据!" ); return ; } var v = Math.sqrt(Math.pow(xdata, 2) + Math.pow(ydata, 2)); var angle = getWindyAngle(xdata, ydata); var result = { "direction" : getWindyDirection(angle), "level" : getWindyLevel(v), "speed" : v.toFixed(2) }; return result; } function getWindyDirection(angle) { if ((angle >= 0 && angle <= 22.5) || (angle <= 360 && angle > 337.5)) { return "北风" ; } if (angle <= 337.5 && angle > 292.5) { return "西北风" ; } if (angle <= 292.5 && angle > 247.5) { return "西风" ; } if (angle <= 247.5 && angle > 202.5) { return "西南风" ; } if (angle <= 202.5 && angle > 157.5) { return "南风" ; } if (angle <= 157.5 && angle > 112.5) { return "东南风" ; } if (angle <= 112.5 && angle > 67.5) { return "东风" ; } if (angle <= 67.5 && angle > 22.5) { return "东北风" ; } } function getWindyAngle(u, v) { var fx = 0; if (u > 0 & v > 0) { fx = 270 - Math.atan(v / u) * 180 / Math.PI; } else if (u < 0 & v > 0) { fx = 90 - Math.atan(v / u) * 180 / Math.PI; } else if (u < 0 & v < 0) { fx = 90 - Math.atan(v / u) * 180 / Math.PI; } else if (u > 0 & v < 0) { fx = 270 - Math.atan(v / u) * 180 / Math.PI; } else if (u == 0 & v > 0) { fx = 180; } else if (u == 0 & v < 0) { fx = 0; } else if (u > 0 & v == 0) { fx = 270; } else if (u < 0 & v == 0) { fx = 90; } else if (u == 0 & v == 0) { fx = 999.9; } return fx; } function getWindyLevel(v) { if (v < 0.3) { return 0; } if (v >= 0.3 && v < 1.6) { return 1; } if (v >= 1.6 && v < 3.4) { return 2; } if (v >= 3.4 && v < 5.5) { return 3; } if (v >= 5.5 && v < 8.0) { return 4; } if (v >= 8.0 && v < 10.8) { return 5; } if (v >= 10.8 && v < 13.9) { return 6; } if (v >= 13.9 && v < 17.2) { return 7; } if (v >= 17.2 && v < 20.8) { return 8; } if (v >= 20.8 && v < 24.5) { return 9; } if (v >= 24.5 && v < 28.5) { return 10; } if (v >= 28.5 && v < 32.7) { return 11; } if (v >= 32.7 && v < 37.0) { return 12; } if (v >= 37.0 && v < 41.5) { return 13; } if (v >= 41.5 && v < 46.2) { return 14; } if (v >= 46.2 && v < 51.0) { return 15; } if (v >= 51.0 && v < 56.1) { return 16; } if (v >= 56.1 && v < 61.2) { return 17; } if (v >= 61.2) { return 18; } } </script> </body> |
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。
分类:
demo分享介绍
, openlayers的正确食用方法
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 【.NET】调用本地 Deepseek 模型
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)