339 lines
9.2 KiB
JavaScript
339 lines
9.2 KiB
JavaScript
import * as Cesium from 'cesium'
|
|
import { WindCore, isArray, removeDomNode, defaultOptions, formatData, assign } from 'wind-core'
|
|
import windData from './data/wind/14-1.json'
|
|
|
|
export default class WindField {
|
|
constructor(data, options = {}) {
|
|
this.canvas = null
|
|
this.wind = null
|
|
this.field = null
|
|
this.viewer = null
|
|
this.options = assign({}, options)
|
|
this.pickWindOptions()
|
|
|
|
const canvas = document.createElement('canvas')
|
|
canvas.style.cssText = 'position:absolute; left:0; top:0;user-select:none;pointer-events: none;'
|
|
canvas.className = 'cesium-wind-j'
|
|
this.canvas = canvas
|
|
|
|
if (data) {
|
|
this.setData(data)
|
|
}
|
|
}
|
|
|
|
addTo(viewer) {
|
|
this.viewer = viewer
|
|
this.appendCanvas()
|
|
this.render(this.canvas)
|
|
}
|
|
|
|
remove() {
|
|
if (!this.viewer) {
|
|
return
|
|
}
|
|
if (this.wind) {
|
|
this.wind.stop()
|
|
}
|
|
if (this.canvas) {
|
|
removeDomNode(this.canvas)
|
|
}
|
|
delete this.canvas
|
|
}
|
|
|
|
removeLayer() {
|
|
this.remove()
|
|
}
|
|
|
|
setData(data) {
|
|
if (data && data.checkFields && data.checkFields()) {
|
|
this.field = data
|
|
} else if (isArray(data)) {
|
|
this.field = formatData(data)
|
|
} else {
|
|
console.error('Illegal data')
|
|
}
|
|
|
|
if (this.viewer && this.canvas && this.field) {
|
|
this.wind.updateData(this.field)
|
|
this.appendCanvas()
|
|
this.render(this.canvas)
|
|
}
|
|
|
|
return this
|
|
}
|
|
|
|
getData() {
|
|
return this.field
|
|
}
|
|
|
|
getWindOptions() {
|
|
return this.options.windOptions || {}
|
|
}
|
|
|
|
pickWindOptions() {
|
|
Object.keys(defaultOptions).forEach((key) => {
|
|
if (key in this.options) {
|
|
if (this.options.windOptions === undefined) {
|
|
this.options.windOptions = {}
|
|
}
|
|
this.options.windOptions[key] = this.options[key]
|
|
}
|
|
})
|
|
}
|
|
|
|
getContext() {
|
|
if (this.canvas === null) {
|
|
return
|
|
}
|
|
return this.canvas.getContext('2d')
|
|
}
|
|
|
|
appendCanvas() {
|
|
if (!this.viewer || !this.canvas) {
|
|
return
|
|
}
|
|
if (document.querySelector('.cesium-wind-j')) {
|
|
return
|
|
}
|
|
this.adjustSize()
|
|
const cesiumWidget = this.viewer.canvas.parentNode
|
|
cesiumWidget.appendChild(this.canvas)
|
|
}
|
|
|
|
adjustSize() {
|
|
const viewer = this.viewer
|
|
const canvas = this.canvas
|
|
const { width, height } = viewer.canvas
|
|
const devicePixelRatio = 1
|
|
canvas.width = width * devicePixelRatio
|
|
canvas.height = height * devicePixelRatio
|
|
canvas.style.width = width + 'px'
|
|
canvas.style.height = height + 'px'
|
|
}
|
|
|
|
render(canvas) {
|
|
if (!this.getData() || !this.viewer) {
|
|
return this
|
|
}
|
|
const opt = this.getWindOptions()
|
|
if (canvas && !this.wind) {
|
|
const data = this.getData()
|
|
|
|
const ctx = this.getContext()
|
|
|
|
if (ctx) {
|
|
this.wind = new WindCore(ctx, opt, data)
|
|
|
|
this.wind.project = this.project.bind(this)
|
|
this.wind.unproject = this.unproject.bind(this)
|
|
this.wind.intersectsCoordinate = this.intersectsCoordinate.bind(this)
|
|
this.wind.postrender = () => {}
|
|
}
|
|
}
|
|
|
|
if (this.wind) {
|
|
this.wind.prerender()
|
|
this.wind.render()
|
|
}
|
|
|
|
return this
|
|
}
|
|
|
|
project(coordinate) {
|
|
const position = Cesium.Cartesian3.fromDegrees(coordinate[0], coordinate[1])
|
|
const scene = this.viewer.scene
|
|
const sceneCoor = Cesium.SceneTransforms.worldToWindowCoordinates(scene, position)
|
|
return [sceneCoor.x, sceneCoor.y]
|
|
}
|
|
|
|
unproject(pixel) {
|
|
const viewer = this.viewer
|
|
const pick = new Cesium.Cartesian2(pixel[0], pixel[1])
|
|
const cartesian = viewer.scene.globe.pick(viewer.camera.getPickRay(pick), viewer.scene)
|
|
|
|
if (!cartesian) {
|
|
return null
|
|
}
|
|
|
|
const ellipsoid = viewer.scene.globe.ellipsoid
|
|
const cartographic = ellipsoid.cartesianToCartographic(cartesian)
|
|
const lat = Cesium.Math.toDegrees(cartographic.latitude)
|
|
const lng = Cesium.Math.toDegrees(cartographic.longitude)
|
|
return [lng, lat]
|
|
}
|
|
|
|
intersectsCoordinate(coordinate) {
|
|
const ellipsoid = Cesium.Ellipsoid.WGS84
|
|
const camera = this.viewer.camera
|
|
const occluder = new Cesium.EllipsoidalOccluder(ellipsoid, camera.position)
|
|
const point = Cesium.Cartesian3.fromDegrees(coordinate[0], coordinate[1])
|
|
return occluder.isPointVisible(point)
|
|
}
|
|
}
|
|
|
|
let windLayer = null
|
|
|
|
const getInitWindOptions = () => {
|
|
return {
|
|
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)',
|
|
],
|
|
frameRate: 16 * 4,
|
|
maxAge: 60,
|
|
globalAlpha: 0.9,
|
|
velocityScale: 1 / 30,
|
|
paths: 2000,
|
|
},
|
|
windU: {
|
|
header: {
|
|
parameterCategory: 1,
|
|
parameterNumber: 2,
|
|
lo1: 111.144,
|
|
la2: 42.456,
|
|
lo2: 132.86,
|
|
la1: 35.359,
|
|
extent: [111.144, 42.456, 132.86, 35.359],
|
|
nx: 92,
|
|
ny: 73,
|
|
dx: 0.1,
|
|
dy: 0.1,
|
|
min: -20.7940673828125,
|
|
max: 30.645931243896484,
|
|
GRIB_COMMENT: 'u-component of wind [m/s]',
|
|
GRIB_DISCIPLINE: '0(Meteorological)',
|
|
GRIB_ELEMENT: 'UGRD',
|
|
GRIB_FORECAST_SECONDS: '0 sec',
|
|
GRIB_IDS:
|
|
'CENTER=7(US-NCEP) SUBCENTER=0 MASTER_TABLE=2 LOCAL_TABLE=1 SIGNF_REF_TIME=1(Start_of_Forecast) REF_TIME=2020-06-20T00:00:00Z PROD_STATUS=0(Operational) TYPE=1(Forecast)',
|
|
GRIB_PDS_PDTN: '0',
|
|
GRIB_PDS_TEMPLATE_ASSEMBLED_VALUES: '2 2 2 0 81 0 0 1 0 103 0 10 255 0 0',
|
|
GRIB_PDS_TEMPLATE_NUMBERS: '2 2 2 0 81 0 0 0 1 0 0 0 0 103 0 0 0 0 10 255 0 0 0 0 0',
|
|
GRIB_REF_TIME: '1592611200 sec UTC',
|
|
GRIB_SHORT_NAME: '10-HTGL',
|
|
GRIB_UNIT: '[m/s]',
|
|
GRIB_VALID_TIME: '1592611200 sec UTC',
|
|
},
|
|
data: [],
|
|
},
|
|
windV: {
|
|
header: {
|
|
parameterCategory: 1,
|
|
parameterNumber: 3,
|
|
lo1: 111.144,
|
|
la2: 42.456,
|
|
lo2: 132.86,
|
|
la1: 35.359,
|
|
extent: [111.144, 42.456, 132.86, 35.359],
|
|
nx: 92,
|
|
ny: 73,
|
|
dx: 0.1,
|
|
dy: 0.1,
|
|
min: -22.734182357788086,
|
|
max: 22.645816802978516,
|
|
GRIB_COMMENT: 'v-component of wind [m/s]',
|
|
GRIB_DISCIPLINE: '0(Meteorological)',
|
|
GRIB_ELEMENT: 'VGRD',
|
|
GRIB_FORECAST_SECONDS: '0 sec',
|
|
GRIB_IDS:
|
|
'CENTER=7(US-NCEP) SUBCENTER=0 MASTER_TABLE=2 LOCAL_TABLE=1 SIGNF_REF_TIME=1(Start_of_Forecast) REF_TIME=2020-06-20T00:00:00Z PROD_STATUS=0(Operational) TYPE=1(Forecast)',
|
|
GRIB_PDS_PDTN: '0',
|
|
GRIB_PDS_TEMPLATE_ASSEMBLED_VALUES: '2 3 2 0 81 0 0 1 0 103 0 10 255 0 0',
|
|
GRIB_PDS_TEMPLATE_NUMBERS: '2 3 2 0 81 0 0 0 1 0 0 0 0 103 0 0 0 0 10 255 0 0 0 0 0',
|
|
GRIB_REF_TIME: '1592611200 sec UTC',
|
|
GRIB_SHORT_NAME: '10-HTGL',
|
|
GRIB_UNIT: '[m/s]',
|
|
GRIB_VALID_TIME: '1592611200 sec UTC',
|
|
},
|
|
data: [],
|
|
},
|
|
}
|
|
}
|
|
|
|
export const loadWindfield = (viewer) => {
|
|
debugger
|
|
const testData = windData.result[1]
|
|
const { windU, windV, windOptions } = getInitWindOptions()
|
|
testData.forEach((item) => {
|
|
windU.data.push(item[2])
|
|
windV.data.push(item[3])
|
|
})
|
|
const wind = [windU, windV]
|
|
console.log('111111111111111111111111111111111', wind)
|
|
windLayer = new WindField(wind, { windOptions })
|
|
|
|
windLayer.addTo(viewer)
|
|
}
|
|
|
|
export const removeWindfield = () => {
|
|
if (windLayer) {
|
|
windLayer.removeLayer()
|
|
windLayer = null
|
|
}
|
|
}
|
|
|
|
export const loadWindfieldWithData = (viewer, windData) => {
|
|
debugger
|
|
const { windU, windV, windOptions } = getInitWindOptions()
|
|
const { minLong: lo1, maxLat: la2, maxLong: lo2, minLat: la1 } = windData
|
|
Object.assign(windU.header, { lo1, la2, lo2, la1, extent: [lo1, la2, lo2, la1] })
|
|
Object.assign(windV.header, { lo1, la2, lo2, la1, extent: [lo1, la2, lo2, la1] })
|
|
const testData = windData.dataList
|
|
testData.forEach((item) => {
|
|
windU.data.push(item[2])
|
|
windV.data.push(item[3])
|
|
})
|
|
const wind = [windU, windV]
|
|
if (windLayer) {
|
|
windLayer.setData(wind)
|
|
} else {
|
|
windLayer = new WindField(wind, { windOptions })
|
|
windLayer.addTo(viewer)
|
|
}
|
|
}
|
|
|
|
export const loadWindfieldWithDataNew = (viewer, windData, num) => {
|
|
const { windU, windV, windOptions } = getInitWindOptions()
|
|
|
|
const { lon_min: lo1, lat_max: la2, lon_max: lo2, lat_min: la1 } = windData
|
|
Object.assign(windU.header, { lo1, la2, lo2, la1, extent: [lo1, la2, lo2, la1] })
|
|
Object.assign(windV.header, { lo1, la2, lo2, la1, extent: [lo1, la2, lo2, la1] })
|
|
|
|
const testData = windData.wind_result.map(subArr => {
|
|
[subArr[0], subArr[1], subArr[2], subArr[3]] = [subArr[1], subArr[0], subArr[2], subArr[3]];
|
|
return subArr;
|
|
});
|
|
|
|
testData.forEach((item) => {
|
|
windU.data.push(item[2])
|
|
windV.data.push(item[3])
|
|
})
|
|
|
|
windU.header.nx = windV.header.nx = num * 2 + 1
|
|
windU.header.ny = windV.header.ny = num * 2 + 1
|
|
windU.header.dx = windV.header.dx = 1
|
|
windU.header.dy = windV.header.dy = 1
|
|
|
|
const wind = [windU, windV]
|
|
if (windLayer) {
|
|
windLayer.setData(wind)
|
|
} else {
|
|
windLayer = new WindField(wind, { windOptions })
|
|
windLayer.addTo(viewer)
|
|
}
|
|
}
|