forked from ccmostmosthandsome/olMeteo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 464c764
Showing
13 changed files
with
11,830 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
.DS_Store | ||
node_modules | ||
/dist | ||
|
||
# local env files | ||
.env.local | ||
.env.*.local | ||
|
||
# Log files | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
pnpm-debug.log* | ||
|
||
# Editor directories and files | ||
.idea | ||
.vscode | ||
*.suo | ||
*.ntvs* | ||
*.njsproj | ||
*.sln | ||
*.sw? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# openlayers 气象可视化 🌈 | ||
|
||
openlayers 气象要素可视化,做出类似 [Ventusky](https://ventusky.com) 的效果。 | ||
|
||
![ol meteo](public/images/ol_meteo.png) | ||
|
||
## 关于 | ||
|
||
本项目是基于 vue-cli3 搭建的基础项目,因此不涉及路由处理等请知悉。 | ||
|
||
## 数据 | ||
|
||
GFS grib2 数据生成灰度图。如何读取 grib2 文件并生成图片,请参考:[grib2-plot](https://github.com/vensing/grib2-plot),该项目生成彩色图,生成灰度图只需设置单通道颜色即可。 | ||
|
||
|
||
## 原理 | ||
|
||
前台读取灰度图数据;获取屏幕坐标转行为经纬度坐标,经纬度坐标经双线性插值获取对应点的气象要素值;通过值找到对应色阶区域的颜色值,canvas 绘制矩形填色。 | ||
|
||
## 如何运行 | ||
|
||
``` | ||
npm install | ||
npm run serve | ||
``` | ||
|
||
## 参考 | ||
|
||
- [Ventusky.com](https://ventusky.com) | ||
- [Windy.com](https://windy.com) | ||
- [earth](https://earth.nullschool.net) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module.exports = { | ||
presets: [ | ||
'@vue/cli-plugin-babel/preset' | ||
] | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
{ | ||
"name": "hello-world", | ||
"version": "0.1.0", | ||
"private": true, | ||
"scripts": { | ||
"serve": "vue-cli-service serve", | ||
"build": "vue-cli-service build", | ||
"lint": "vue-cli-service lint" | ||
}, | ||
"dependencies": { | ||
"chroma-js": "^2.1.0", | ||
"core-js": "^3.6.5", | ||
"ol": "^6.4.0", | ||
"vue": "^2.6.11" | ||
}, | ||
"devDependencies": { | ||
"@vue/cli-plugin-babel": "~4.4.0", | ||
"@vue/cli-plugin-eslint": "~4.4.0", | ||
"@vue/cli-service": "~4.4.0", | ||
"babel-eslint": "^10.1.0", | ||
"eslint": "^6.7.2", | ||
"eslint-plugin-vue": "^6.2.2", | ||
"vue-template-compiler": "^2.6.11" | ||
}, | ||
"eslintConfig": { | ||
"root": true, | ||
"env": { | ||
"node": true | ||
}, | ||
"extends": [ | ||
"plugin:vue/essential", | ||
"eslint:recommended" | ||
], | ||
"parserOptions": { | ||
"parser": "babel-eslint" | ||
}, | ||
"rules": {} | ||
}, | ||
"browserslist": [ | ||
"> 1%", | ||
"last 2 versions", | ||
"not dead" | ||
] | ||
} |
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||
<meta name="viewport" content="width=device-width,initial-scale=1.0"> | ||
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> | ||
<title>openlayers 气象可视化</title> | ||
</head> | ||
<body> | ||
<noscript> | ||
<strong>We're sorry but web doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> | ||
</noscript> | ||
<div id="app"></div> | ||
<!-- built files will be auto injected --> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<template> | ||
<div id="app"> | ||
<Map/> | ||
</div> | ||
</template> | ||
|
||
<script> | ||
import Map from './components/Map.vue' | ||
export default { | ||
name: 'App', | ||
components: { | ||
Map | ||
} | ||
} | ||
</script> | ||
|
||
<style> | ||
html, body { | ||
width: 100%; | ||
height: 100%; | ||
margin: unset; | ||
} | ||
</style> |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
<template> | ||
<div class="ol-map" ref="olmap"></div> | ||
</template> | ||
|
||
<script> | ||
import 'ol/ol.css' | ||
import { Map, View } from 'ol' | ||
import { transform, toLonLat } from 'ol/proj' | ||
import TileLayer from 'ol/layer/Tile' | ||
import XYZ from 'ol/source/XYZ' | ||
import ImageLayer from 'ol/layer/Image' | ||
import ImageCanvasSource from 'ol/source/ImageCanvas' | ||
import chroma from 'chroma-js' | ||
const MERCATOR = 'EPSG:3857' | ||
const WGS84 = 'EPSG:4326' | ||
const temColors = [ | ||
'rgba( 238, 238, 238 ,0.85)', 'rgba( 255, 170, 255 ,0.85)', | ||
'rgba( 145, 9, 145 ,0.85)', 'rgba( 36, 24, 106 ,0.85)', | ||
'rgba( 85, 78, 177 ,0.85)', 'rgba( 62, 121, 198 ,0.85)', | ||
'rgba( 75, 182, 152 ,0.85)', 'rgba( 89, 208, 73 ,0.85)', | ||
'rgba( 190, 228, 61 ,0.85)', 'rgba( 235, 215, 53 ,0.85)', | ||
'rgba( 234, 164, 62 ,0.85)', 'rgba( 229, 109, 83 ,0.85)', | ||
'rgba( 190, 48, 102 ,0.85)', 'rgba( 107, 21, 39 ,0.85)', | ||
'rgba( 43, 0, 1 ,1)']; | ||
const colors = chroma.scale(temColors).domain([98, 103, 108, 113, 118, 123, 128, 133, 138, 143, 148, 153, 158, 163, 168]); | ||
export default { | ||
name: 'HelloWorld', | ||
data () { | ||
return { | ||
map: {}, | ||
imageArray: [], | ||
canvasLayer: null, | ||
image: null | ||
} | ||
}, | ||
props: { | ||
msg: String | ||
}, | ||
mounted () { | ||
this.canvasLayer = new ImageLayer({opacity: 0.7}); | ||
var map = new Map({ | ||
target: this.$refs.olmap, | ||
layers: this.getBaseLayers().concat([this.canvasLayer]), | ||
view: new View({ | ||
projection: MERCATOR, | ||
center: this.transformPoint(116, 40), | ||
zoom: 4, | ||
maxZoom: 14, | ||
minZoom: 4, | ||
enableRotation: false | ||
}) | ||
}); | ||
this.map = map; | ||
this.images2Canvas(); | ||
this.image.src = '/images/icon_teplota_2_m_20200728_03.jpg'; | ||
}, | ||
methods: { | ||
getBaseLayers () { | ||
var warmlayer = new TileLayer({ | ||
source: new XYZ({ | ||
url: 'https://www.google.cn/maps/vt?lyrs=m@189&gl=cn&x={x}&y={y}&z={z}' | ||
}) | ||
}) | ||
var graylayer = new TileLayer({ | ||
source: new XYZ({ | ||
url: 'https://map.geoq.cn/arcgis/rest/services/ChinaOnlineStreetGray/MapServer/tile/{z}/{y}/{x}' | ||
}) | ||
}) | ||
var bluelayer = new TileLayer({ | ||
source: new XYZ({ | ||
url: 'https://map.geoq.cn/arcgis/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}' | ||
}) | ||
}) | ||
return [bluelayer, graylayer, warmlayer] | ||
}, | ||
transformPoint (lon, lat) { | ||
return transform([lon, lat], WGS84, MERCATOR) | ||
}, | ||
images2Canvas () { | ||
var self = this; | ||
var img = new Image; | ||
self.image = img; | ||
img.crossOrigin = "anonymous"; | ||
img.onload = function() { | ||
var canvasPic = document.createElement('canvas'); | ||
var ctxPic = canvasPic.getContext("2d"); | ||
canvasPic.width = this.width; | ||
canvasPic.height = this.height; | ||
ctxPic.drawImage(this, 0, 0); | ||
var imageData = ctxPic.getImageData(0, 0, this.width, this.height).data; | ||
canvasPic.style.display = 'none'; | ||
self.imageArray = new Float32Array(imageData.length/4); | ||
Float32Array.prototype.getValue = function(lon,lat){ | ||
var a = lon; | ||
var b = lat; | ||
var na = Math.floor(a)<-360?na+=720:Math.floor(a); | ||
var nb = Math.floor(b)<-180?nb+=360:Math.floor(b); | ||
var ma = Math.ceil(a)>360?ma-=720:Math.ceil(a); | ||
var mb = Math.ceil(b)>180?mb-=360:Math.ceil(b); | ||
var fa = a - na; | ||
var fb = b - nb; | ||
var value= this[((90-nb)*2*720+(na+180)*2)] * (1 - fa) * (1 - fb) + | ||
this[((90-nb)*2*720+(ma+180)*2)] * fa * (1 - fb) + | ||
this[((90-mb)*2*720+(na+180)*2)] * (1 - fa) * fb + | ||
this[((90-mb)*2*720+(ma+180)*2)] * fa * fb; | ||
return value; | ||
} | ||
for (var i = 0; i < imageData.length; i+=4 ) { | ||
self.imageArray[i/4] = imageData[i] | ||
} | ||
self.canvasLayer.setSource(new ImageCanvasSource({ | ||
canvasFunction : self.canvasFunction, | ||
ratio : 1, | ||
projection : MERCATOR, | ||
imageSmoothing : true | ||
})) | ||
} | ||
}, | ||
canvasFunction (extent, resolution, pixelRatio, size, projection) { | ||
var width = Math.round(size[0])*pixelRatio; | ||
var height = Math.round(size[1])*pixelRatio; | ||
var can = document.createElement('canvas'); | ||
can.width = width; | ||
can.height = height; | ||
var ctx = can.getContext('2d'); | ||
var dx = Math.floor(3*pixelRatio); | ||
var halfdx = Math.ceil(dx/2); | ||
for (var j = 0; j <= height; j += dx) { | ||
for (var i = 0; i <= width; i += dx ) { | ||
var coord = new toLonLat(this.map.getCoordinateFromPixel([i/pixelRatio, j/pixelRatio]), projection); | ||
var value = this.imageArray.getValue(coord[0],coord[1]); | ||
ctx.fillStyle = colors(value).css(); | ||
ctx.fillRect(i-halfdx,j-halfdx,dx,dx) | ||
} | ||
} | ||
return can; | ||
} | ||
} | ||
} | ||
</script> | ||
|
||
<!-- Add "scoped" attribute to limit CSS to this component only --> | ||
<style scoped> | ||
.ol-map { | ||
height: calc(100vh); | ||
width: auto; | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import Vue from 'vue' | ||
import App from './App.vue' | ||
|
||
Vue.config.productionTip = false | ||
|
||
new Vue({ | ||
render: h => h(App), | ||
}).$mount('#app') |