# 风向图

vc-windmap 组件用于加载风向图,其实质搬运自开源项目3D-Wind-Field (opens new window)

# 示例

# 加载风向图

# 预览

maxParticles
particleHeight
fadeOpacity
dropRate
dropRateBump
speedFactor
lineWidth
switch data
收起
  <template>
    <div class="viewer">
      <vc-viewer scene3DOnly animation timeline       :fullscreenButton="fullscreenButton"
      :fullscreenElement="fullscreenElement" @ready="ready">
        <vc-layer-imagery>
          <vc-provider-imagery-tile-single :url="urlLayer"></vc-provider-imagery-tile-single>
        </vc-layer-imagery>
        <vc-windmap ref="windmap" :data="windData" :particleSystemOptions="particleSystemOptions"> </vc-windmap>
            <!-- <vc-kriging-map v-if="values.length !== 0" :breaks="breaks" :values="values" :lngs="lngs" :lats="lats" :colors="colors"  :clipCoords="clipCoords">
            </vc-kriging-map> -->
      </vc-viewer>
      <div class="demo-tool">
            <el-select v-model="data" placeholder="切换数据" @selected="switchData">
          <el-option v-for="item in options" :key="item.value" :value="item.value"
          :label="item.label">
          </el-option>
        </el-select>
        <el-button size="small" class="md-raised md-accent" @click="toggle"
          >移除数据</el-button>
        <div>
        <span>maxParticles</span>
        <el-slider v-model="particleSystemOptions.maxParticles" :min="1" :max="65536" :interval="1"></el-slider>
        <span>particleHeight</span>
        <el-slider v-model="particleSystemOptions.particleHeight" :min="1" :max="10000" :interval="1"></el-slider>
        <span>fadeOpacity</span>
        <el-slider v-model="particleSystemOptions.fadeOpacity" :min="0.90" :max="0.999" :interval="0.001"></el-slider>
        <span>dropRate</span>
        <el-slider v-model="particleSystemOptions.dropRate" :min="0.0" :max="0.1" :interval="0.001"></el-slider>
        <span>dropRateBump</span>
        <el-slider v-model="particleSystemOptions.dropRateBump" :min="0.0" :max="0.2" :interval="0.001"></el-slider>
        <span>speedFactor</span>
        <el-slider v-model="particleSystemOptions.speedFactor" :min="0.5" :max="100" :interval="0.1"></el-slider>
        <span>lineWidth</span>
        <el-slider v-model="particleSystemOptions.lineWidth" :min="0.01" :max="16" :step="0.01"></el-slider>
        <span>switch data</span>
        </div>        
      </div>
    </div>
  </template>

  <script>
    import  NetCDFReader from 'netcdfjs'
    export default {
      data() {
        return {
          showWind:true,
          urlLayer: '/statics/SampleData/worldimage.jpg',
          urlNetCDF: '/statics/SampleData/windData/demo.nc',
          windData: {},
          values: [],
          lngs: [],
          lats: [],
          fullscreenButton: true,
           fullscreenElement: null,
          breaks: [0.1, 10, 25, 50, 100, 250, 500],
          clipCoords:[],
          // colors:['#d0c9ec','#9f8de6','#6046c5','#382190','#340cd0','#3502fb','#59b7e4','#1981b3','#0aa6f1'
          // ,'#63cfda','#28cfe0'],
          colors:[],
          options: [
            {
              label: 'Global Data',
              value: 1
            },
            {
              label: 'China Data',
              value: 2
            }
          ],
          data: 0,
          particleSystemOptions: {
            particlesTextureSize: 100,
            maxParticles: 100 * 100,
            particleHeight: 1.0,
            fadeOpacity: 0.984,
            dropRate: 0.003,
            dropRateBump: 0.01,
            speedFactor: 1.2,
            lineWidth: 9.0
          }
        }
      },
      methods: {
        toggle(){
          this.showWind=!this.showWind
          if(this.showWind){
            this.$refs.windmap.reload()
          }else{
          this.$refs.windmap.unload()
          }
        },
        LEFT_CLICK(movement){
          const { Cesium, viewer } = this.cesiumInstance
          var pos=viewer.scene.pickPosition(movement.position)
          var position=GisEye.CoordinatesTransform.windowPositionToDegrees(movement.position,viewer)
          console.log(position[0],position[1])
          var label=this.product.getPickData(position[0],position[1])
          viewer.entities.removeAll();
          viewer.entities.add({
            position:pos,
            label:{
              text:label,
              fillColor: Cesium.Color.RED,
              disableDepthTestDistance:100000000000000
            }
          })
        },
        ready(cesiumInstance) {
          this.cesiumInstance = cesiumInstance
          this.data = 1
          this.switchData(1)
        },
        switchData(val) {
          const { Cesium, viewer } = this.cesiumInstance
          viewer.screenSpaceEventHandler.setInputAction(
            this.LEFT_CLICK,
            Cesium.ScreenSpaceEventType.LEFT_CLICK
          )
          let _this = this
          if (val === 1) {
          this.product = new GisEye.ProductData('https://hyyj-stream.oss-cn-beijing.aliyuncs.com/slik/data/oscar/202011211200-surface-currents-oscar-0.33.json')
          this.product.getData()
            .then(data => {
               _this.windData = data
               const {lon,lat}=data
               var canvas = document.createElement('canvas')
              //  var canvas = document.getElementById('test')
              let scale=4
               canvas.width=lon.size
               canvas.height=lat.size
                var context = canvas.getContext("2d");
                context.fillStyle = "rgba(255, 0, 0, 1)";
                context.fill();
                var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
                var imgdata = imageData.data; 
                // context.clearRect(0, 0, canvas.width, canvas.height)
                function set(x, y, rgba){
                  try{
                    // context.fillStyle=rgba
                    // context.fillRect(x,y,1,1)
                  let i = (y * canvas.width + x) * 4;
                  imgdata[i    ] = rgba[0];
                  imgdata[i + 1] = rgba[1];
                  imgdata[i + 2] = rgba[2];
                  imgdata[i + 3] = rgba[3]; 
                  }
                  catch(e){
                    console.log(e)
                  }                 
                } 
                // layout: [r, g, b, a, r, g, b, a, ...]                
               debugger
               var datatemp=_this.product.getGridFeatures('current')
               _this.values=datatemp.values
               _this.lngs=datatemp.lngs
               _this.lats=datatemp.lats,
               _this.breaks=datatemp.breaks
               _this.clipCoords=datatemp.polygon
               _this.colors=datatemp.colors
               let obj=datatemp.obj
               let x=0
               while(x<lon.size){
                 for(let y=0 ;y< lat.size;y+=1){
                  try{
                    let color=[0,0,0,0]
                   let key=`${x}_${y}`;
                   let value=obj[key]
                   if(value) {
                   color=value[1]
                   }
                  //  set(Number(x),Number(y),color)
                   set(Number(x)+1,Number(y),color)
                   set(Number(x),Number(y)+1,color)
                   set(Number(x)+1,Number(y)+1,color)
                  }
                  catch(e){
                    console.log(e)
                  }                    
                 }
                 x+=1
               }
               context.clearRect(0, 0, canvas.width, canvas.height)
               context.putImageData(imageData,0,0)   
               var datasource=new Cesium.CustomDataSource('xx')   
               viewer.dataSources.add(datasource)         
              datasource.entities.add({
                rectangle: {
                  coordinates: Cesium.Rectangle.fromDegrees(data.lon.min, data.lat.min, data.lon.max, data.lat.max),
                  material: new Cesium.ImageMaterialProperty({
                    image: canvas,
                    // color: Cesium.Color.WHITE.withAlpha(0.7)
                  })
                }
              })
          })
            return            
            this.loadNetCDF(this.urlNetCDF).then((data) => {
              _this.windData = data
            })
          } else if (val === 2) {
            Cesium.Resource.fetchJson({ url: './statics/SampleData/windData/wind.json' }).then((data) => {
              data.lon.array = new Float32Array(data.lon.array.slice(0,20))
              data.lat.array = new Float32Array(data.lat.array.slice(0,20))
              data.lev.array = new Float32Array(data.lev.array)
              data.U.array = new Float32Array(data.U.array.slice(0,400))
              data.V.array = new Float32Array(data.V.array.slice(0,400))
              // debugger
              // data.lon.array = data.lon.array.silce(0,29);
              // data.lat.array = data.lat.array.silce(0,29);
              // data.U.array = data.U.array.silce(0,899);
              // data.V.array = data.V.array.silce(0,899);
              data.dimensions.lat = 20;
              data.dimensions.lon = 20;
              let _base_lon = 104.0141756630243;
      let _base_lat = 30.71715735036010;
      var x1 = _base_lon-0.002-1;
      var x2 = _base_lon+0.002+1;
      var y1 = _base_lat-0.0014-1;
      var y2 = _base_lat+0.0014+1;
       var lenX = 20; var stepX = (x2 - x1) / lenX;
      var lenY = 20;var stepY = (y2 - y1) / lenY;
      for (var i = 0;i<lenX;i++){
        data.lon.array[i]= x1+i*stepX;
      };
       data.lon.max=x2;
       data.lon.min=x1;
       data.lat.max=y2;
       data.lat.min=y1;
      for (var i = 0;i<lenY;i++){
        data.lat.array[i]= y1+i*stepY;
      };
              _this.windData = data
          //     console.log('wind.json',data)
          //     viewer.scene.camera.flyTo({
          //   destination: {
          //     x: -1327779.8149322902,
          //     y: 5320165.247685926,
          //     z: 3257916.830723023
          //   },
          //   orientation: {
          //     pitch: -0.34163087120619107,
          //     heading: 0.9705565449837765,
          //     roll: 6.283185307179579
          //   },
          //   duration: 0.5
          // });
          //     let imgLabel = new Cesium.UrlTemplateImageryProvider({
          //     url:
          //       "http://114.116.101.122:7769/gisserver/rest/services/mapserver/tdt-image/{z}/{x}/{y}"
          //   });
          //   viewer.imageryLayers.addImageryProvider(imgLabel); 
          //       let imgLabel2 = new Cesium.UrlTemplateImageryProvider({
          //     url:
          //       "http://114.116.101.122:7769/gisserver/rest/services/mapserver/tdt-image-label/{z}/{x}/{y}"
          //   });
          //   viewer.imageryLayers.addImageryProvider(imgLabel2);
            });
          }
        },
        async loadNetCDF(filePath) {
          let _this = this
          return new Promise(function(resolve) {
            var request = new XMLHttpRequest()
            request.open('GET', filePath)
            request.responseType = 'arraybuffer'
            request.onload = function() {
              var arrayToMap = function(array) {
                return array.reduce(function(map, object) {
                  map[object.name] = object
                  return map
                }, {})
              }
              var NetCDF = new NetCDFReader(request.response)
              let data = {}
              var dimensions = arrayToMap(NetCDF.dimensions)
              data.dimensions = {}
              data.dimensions.lon = dimensions['lon'].size
              data.dimensions.lat = dimensions['lat'].size
              data.dimensions.lev = dimensions['lev'].size
              var variables = arrayToMap(NetCDF.variables)
              var uAttributes = arrayToMap(variables['U'].attributes)
              var vAttributes = arrayToMap(variables['V'].attributes)
              data.lon = {}
              data.lon.array = new Float32Array(NetCDF.getDataVariable('lon').flat())
              data.lon.min = Math.min(...data.lon.array)
              data.lon.max = Math.max(...data.lon.array)
              data.lat = {}
              data.lat.array = new Float32Array(NetCDF.getDataVariable('lat').flat())
              data.lat.min = Math.min(...data.lat.array)
              data.lat.max = Math.max(...data.lat.array)
              data.lev = {}
              data.lev.array = new Float32Array(NetCDF.getDataVariable('lev').flat())
              data.lev.min = Math.min(...data.lev.array)
              data.lev.max = Math.max(...data.lev.array)
              data.U = {}
              data.U.array = new Float32Array(NetCDF.getDataVariable('U').flat())
              data.U.min = uAttributes['min'].value
              data.U.max = uAttributes['max'].value
              data.V = {}
              data.V.array = new Float32Array(NetCDF.getDataVariable('V').flat())
              data.V.min = vAttributes['min'].value
              data.V.max = vAttributes['max'].value
              resolve(data)
            }
            request.send()
          })
        }
      }
    }
  </script>

# 属性

属性名 类型 默认值 描述
data Object required 指定风向数据。
particleSystemOptions Object optional 指定粒子参数。

# 事件

事件名 参数 描述
ready {Cesium, viewer} 该组件渲染完毕时触发,返回 Cesium 类, viewer 实例。

# Vue 方法

方法名 参数 描述
destroy 清除风向图。

# 其他说明