openlayers扩展:风场可视化(wind-layer)

2024-05-04 23:58

本文主要是介绍openlayers扩展:风场可视化(wind-layer),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

windLayer api使用示例

这里主要为windlayer关于在openlayers3-4版本内使用的相关接口及参数说明

在加载时,主要读取的数据来源格式为json,而我们一般获取到的数据主要为netCDF或Grib等格式的数据,这里还涉及相关的数据转换操作

1.openlayers-wind 参数说明

TIP

对应于 openlayers 3-4 相关参数

图层参数

参数说明类型默认值
windOptions风场参数,具体配置如下object--
map地图对象,必须配置,不需要调用 addLayer,具体可以参考 openlayer 官方文档ol.Map--
zIndex图层层级number--

其他参数遵循 ol 基础图层参数。

windOptions

参数说明类型默认值
globalAlpha全局透明度,主要影响粒子路径拖尾效果number0.9
lineWidth粒子路径宽度number\|function1, 当为回调函数时,参数function(m:对应点风速值) => number
colorScale粒子颜色配置string\|function\|string[]#fff,当为回调函数时,参数function(m:对应点风速值) => string
velocityScale速度级别number1 / 25
maxAge \| particleAge(不推荐使用)粒子路径能够生成的最大帧数number90
paths生成的粒子路径数量number\|function800, 当为回调函数时,参数function(m:对应点风速值) => number
particleMultiplier粒子路径数量的系数,不推荐使用(视野宽度 * 高度 * 系数)number1 / 300
frameRate帧率(ms)number20

colorScale

关于颜色配置,在以往的配置中传入的是颜色数组会根据以下函数和格点数据的数据范围去计算匹配的颜色值,

const indexFor = function (m) {  // map velocity speed to a stylereturn 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接口,添加相应的图层对象

<!DOCTYPE html>
<html><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>ol4 wind-layer</title><link rel="stylesheet" href="//cdn.jsdelivr.net/npm/dat.gui@0.7.6/build/dat.gui.css"><script src="//cdn.jsdelivr.net/npm/openlayers/dist/ol.js"></script><link rel="stylesheet" href="//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: '//{a-d}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',})})],});let layer;// https://sakitam-fdd.github.io/wind-layer/data/wind.jsonfetch('data.json').then(res = >res.json()).then(res = >{// const range = vectorField.range || [0.02, 28.21618329965979];// const scale = chroma.scale('OrRd').domain(range);const windLayer = new OlWind.WindLayer(res, {windOptions: {/*colorScale: (m) => {// console.log(m);return '#ff473c';},*/// colorScale: scale,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)"],/*frameRate: 16,maxAge: 60,globalAlpha: 0.9,*/velocityScale: 1 / 30,paths: 3000,// particleMultiplier: 0.3 * 10,},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;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></html>

 在这里将相关的数据获取方式进行了声明,通过数据源,我们可以了解,气象预报数据是按照经纬度格网进行统计、展示的,所以我们在这里想格网数据重新做了一次数据分析,方便前台的交互展示。

 

 

这篇关于openlayers扩展:风场可视化(wind-layer)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/960385

相关文章

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

Spring框架5 - 容器的扩展功能 (ApplicationContext)

private static ApplicationContext applicationContext;static {applicationContext = new ClassPathXmlApplicationContext("bean.xml");} BeanFactory的功能扩展类ApplicationContext进行深度的分析。ApplicationConext与 BeanF

Python:豆瓣电影商业数据分析-爬取全数据【附带爬虫豆瓣,数据处理过程,数据分析,可视化,以及完整PPT报告】

**爬取豆瓣电影信息,分析近年电影行业的发展情况** 本文是完整的数据分析展现,代码有完整版,包含豆瓣电影爬取的具体方式【附带爬虫豆瓣,数据处理过程,数据分析,可视化,以及完整PPT报告】   最近MBA在学习《商业数据分析》,大实训作业给了数据要进行数据分析,所以先拿豆瓣电影练练手,网络上爬取豆瓣电影TOP250较多,但对于豆瓣电影全数据的爬取教程很少,所以我自己做一版。 目

PHP7扩展开发之数组处理

前言 这次,我们将演示如何在PHP扩展中如何对数组进行处理。要实现的PHP代码如下: <?phpfunction array_concat ($arr, $prefix) {foreach($arr as $key => $val) {if (isset($prefix[$key]) && is_string($val) && is_string($prefix[$key])) {$arr[

PHP7扩展开发之字符串处理

前言 这次,我们来看看字符串在PHP扩展里面如何处理。 示例代码如下: <?phpfunction str_concat($prefix, $string) {$len = strlen($prefix);$substr = substr($string, 0, $len);if ($substr != $prefix) {return $prefix." ".$string;} else

PHP7扩展开发之类型处理

前言 这次,我们将演示如何在PHP扩展中如何对类型进行一些操作。如,判断变量类型。要实现的PHP代码如下: <?phpfunction get_size ($value) {if (is_string($value)) {return "string size is ". strlen($value);} else if (is_array($value)) {return "array si

PHP7扩展开发之依赖其他扩展

前言 有的时候,我们的扩展要依赖其他扩展。比如,我们PHP的mysqli扩展就依赖mysqlnd扩展。这中情况下,我们怎么使用其他扩展呢?这个就是本文讲述的内容。 我们新建立一个扩展,名字叫 demo_dep , 依赖之前的say扩展。 在demo_dep扩展中,我们实现demo_say方法。这个方法调用say扩展的say方法。 代码 基础代码 确保say扩展的头文件正确安装到了php

PHP7扩展开发之函数方式使用lib库

前言 首先说下什么是lib库。lib库就是一个提供特定功能的一个文件。可以把它看成是PHP的一个文件,这个文件提供一些函数方法。只是这个lib库是用c或者c++写的。 使用lib库的场景。一些软件已经提供了lib库,我们就没必要再重复实现一次。如,原先的mysql扩展,就是使用mysql官方的lib库进行的封装。 在本文,我们将建立一个简单的lib库,并在扩展中进行封装调用。 代码 基础

PHP7扩展开发之对象方式使用lib库

前言 上一篇文章,我们使用的是函数方式调用lib库。这篇文章我们将使用对象的方式调用lib库。调用代码如下: <?php $hello = new hello(); $result = $hello->get(); var_dump($result); ?> 我们将在扩展中实现hello类。hello类中将依赖lib库。 代码 基础代码 这个扩展,我们将在say扩展上增加相关代码。sa