AttributioClassification/src/views/chart/pages/WindMap/WindField.js
2025-12-05 21:26:22 +08:00

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)
}
}