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