guonan
2025-04-17 2eeaa4693e7389df008b6763074c48e9ffa367ca
更新雨
已添加3个文件
已修改4个文件
300 ■■■■■ 文件已修改
src/assets/css/global.css 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tools/Rain.vue 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tools/SlopeAnalysis.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tools/Tools.vue 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/rain.js 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/snow.js 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/tools.js 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/css/global.css
@@ -62,3 +62,11 @@
.el-input__inner {
  color: #fff !important;
}
.el-slider__bar {
  background-color: #009688 !important;
  border-color: #009688 !important;
}
.el-slider__button {
  border-color: rgb(0, 150, 136) !important;
}
src/components/tools/Rain.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,55 @@
<template>
  <el-form :model="form" label-width="80px" class="terrain-settings">
    <el-form-item label="大小">
      <el-slider
        :step="0.1"
        v-model="form.rainSize"
        :min="0"
        :max="1"
      ></el-slider>
    </el-form-item>
    <el-form-item label="速度">
      <el-slider v-model="form.rainSpeed" :min="0" :max="150"></el-slider>
    </el-form-item>
    <el-form-item label="颜色">
      <el-color-picker v-model="form.rainColor" />
    </el-form-item>
  </el-form>
</template>
<script setup>
import { reactive, watch } from "vue";
const form = reactive({
  rainSize: 0.5,
  rainSpeed: 50,
  rainColor: "#99B3CC",
});
// å®šä¹‰ props å’Œ emit
const props = defineProps({
  modelValue: {
    type: Object,
    default: () => ({}),
  },
});
const emit = defineEmits(["update-rain"]);
// ç›‘听 form çš„变化,并将最新值传递给父组件
watch(
  () => ({ ...form }), // æ·±æ‹·è´ä»¥ç¡®ä¿å“åº”式触发
  (newVal) => {
    emit("update-rain", newVal);
  },
  { deep: true } // æ·±åº¦ç›‘听
);
</script>
<style lang="less" scoped>
.terrain-settings {
  padding: 20px;
  width: 290px;
  background: url("@/assets/img/tools/plotting_new.png") no-repeat;
  filter: opacity(83%);
  background-size: 100% 100%;
  box-sizing: border-box;
}
</style>
src/components/tools/SlopeAnalysis.vue
@@ -48,7 +48,7 @@
const form = reactive({
  terrainRender: 0,
  contourLines: false,
  color: "",
  color: "red",
  spacing: 50,
  lineWidth: 5,
});
@@ -78,14 +78,7 @@
  display: flex;
}
/deep/ .el-slider__bar {
  background-color: #009688;
  border-color: #009688;
}
/deep/ .el-slider__button {
  border-color: rgb(0, 150, 136);
}
/deep/ .el-switch.is-checked .el-switch__core {
  background-color: #009688;
src/components/tools/Tools.vue
@@ -54,6 +54,12 @@
        class="popup-menu-see"
        @update-slope="onUpdateSlope"
      />
      <!-- é›¨ -->
      <Rain
        v-show="showRain"
        class="popup-menu-see"
        @update-rain="onUpdateRain"
      />
    </div>
    <!-- å·¥å…·æ å†…容 -->
@@ -85,12 +91,12 @@
import Aspect from "@/components/tools/Aspect.vue";
import SlopeAnalysis from "@/components/tools/SlopeAnalysis.vue";
import mapUtils from "@/utils/tools.js";
import Rain from "@/components/tools/Rain.vue";
// åˆ‡æ¢å±•å¼€/收缩状态
function toggleCollapse() {
  // isCollapsed.value = !isCollapsed.value;
}
const showLayerTree = ref(false);
@@ -101,7 +107,7 @@
const isflfx = ref(false);
const isFlood = ref(false);
const isContourLabel = ref(false);
const isRain = ref(false);
const showRain = ref(false);
const isSnow = ref(false);
// å‰–面分析弹窗
@@ -197,6 +203,7 @@
    echartsShow.value = false; //剖面echarts
    showAspect.value = false; //坡向箭头
    showSlope.value = false; //坡向箭头
    showRain.value = false; //雨天
    return;
  }
@@ -209,6 +216,7 @@
  echartsShow.value = false; //剖面echarts
  showAspect.value = false; //坡向箭头
  showSlope.value = false; //坡向箭头
  showRain.value = false; //雨天
}
// å¤„理弹窗选项点击事件
@@ -219,12 +227,7 @@
    æ˜¾ç¤ºå›¾å±‚: () => (showLayerTree.value = true),
    éšè—å›¾å±‚: () => (showLayerTree.value = false),
    é›¨å¤©æ¨¡å¼: () => {
      isRain.value = !isRain.value;
      if (isRain.value === false) {
        mapUtils.toggleRain("rain", false);
      } else {
        mapUtils.toggleRain("rain", true);
      }
      showRain.value = true;
    },
    é›ªå¤©æ¨¡å¼: () => {
      isSnow.value = !isSnow.value;
@@ -402,6 +405,18 @@
  Object.assign(formData, newOption);
  mapUtils.pdfx(formData);
};
//ʎݬ
const rainForm = reactive({
  rainSize: 0.5,
  rainSpeed: 50,
  rainColor: "#99B3CC",
});
const onUpdateRain = (newOption) => {
  console.log(newOption, "new");
  Object.assign(rainForm, newOption);
  mapUtils.toggleRain(rainForm, true);
};
</script>
<style lang="less" scoped>
src/utils/rain.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,82 @@
class RainEffect {
  constructor(viewer, options) {
    if (!viewer) throw new Error("no viewer object!");
    options = options || {};
    //倾斜角度,负数向右,正数向左
    this.tiltAngle = Cesium.defaultValue(options.tiltAngle, -0.6);
    this.rainSize = Cesium.defaultValue(options.rainSize, 0.3);
    this.rainSpeed = Cesium.defaultValue(options.rainSpeed, 60.0);
    this.color = Cesium.defaultValue(options.color, new Cesium.Color(0.6, 0.7, 0.8, 1.0));
    this.viewer = viewer;
    this.init();
  }
  init() {
    this.rainStage = new Cesium.PostProcessStage({
      name: "czm_rain",
      fragmentShader: this.rain(),
      uniforms: {
        tiltAngle: () => {
          return this.tiltAngle;
        },
        rainSize: () => {
          return this.rainSize;
        },
        rainColor: () => {
          return this.color;
        },
        rainSpeed: () => {
          return this.rainSpeed;
        },
      },
    });
    this.viewer.scene.postProcessStages.add(this.rainStage);
  }
  destroy() {
    if (!this.viewer || !this.rainStage) return;
    this.viewer.scene.postProcessStages.remove(this.rainStage);
    const isDestroyed = this.rainStage.isDestroyed();
    // å…ˆæ£€æŸ¥æ˜¯å¦è¢«é”€æ¯è¿‡ï¼Œå¦‚果已经被销毁过再调用destroy会报错
    if (!isDestroyed) {
      this.rainStage.destroy();
    }
    delete this.tiltAngle;
    delete this.rainSize;
    delete this.rainSpeed;
  }
  show(visible) {
    this.rainStage.enabled = visible;
  }
  rain() {
    return "uniform sampler2D colorTexture;\n\
              in vec2 v_textureCoordinates;\n\
              uniform float tiltAngle;\n\
              uniform vec4 rainColor;\n\
              uniform float rainSize;\n\
              uniform float rainSpeed;\n\
              float hash(float x) {\n\
                  return fract(sin(x * 133.3) * 13.13);\n\
              }\n\
              out vec4 fragColor;\n\
              void main(void) {\n\
                 float time = czm_frameNumber * (rainSpeed / 10000.0);\n\
                  vec2 resolution = czm_viewport.zw;\n\
                  vec2 uv = (gl_FragCoord.xy * 2. - resolution.xy) / min(resolution.x, resolution.y);\n\
                  vec3 c = rainColor.rgb;\n\
                  float a = tiltAngle;\n\
                  float si = sin(a), co = cos(a);\n\
                  uv *= mat2(co, -si, si, co);\n\
                   uv *= length(uv + vec2(0, 4.9)) / (rainSize * 3.0 + 0.1) + 0.5;\n\
                  float v = 1. - sin(hash(floor(uv.x * 100.)) * 2.);\n\
                  float b = clamp(abs(sin(20. * time * v + uv.y * (5. / (2. + v)))) - .95, 0., 1.) * 20.;\n\
                  c *= v * b;\n\
                  fragColor = mix(texture(colorTexture, v_textureCoordinates), vec4(c, 1), .5);\n\
              }\n\
              ";
  }
}
export default RainEffect;
src/utils/snow.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,82 @@
class SnowEffect {
  constructor(viewer, options) {
    if (!viewer) throw new Error("no viewer object!");
    options = options || {};
    this.snowSize = Cesium.defaultValue(options.snowSize, 0.02); // â„️大小,最好小于0.02
    this.snowSpeed = Cesium.defaultValue(options.snowSpeed, 100.0); // é€Ÿåº¦
    this.snowColor = Cesium.defaultValue(options.snowColor, new Cesium.Color(1.0, 1.0, 1.0, 1.0)); // é¢œè‰²
    this.viewer = viewer;
    this.init();
  }
  init() {
    this.snowStage = new Cesium.PostProcessStage({
      name: "czm_snow",
      fragmentShader: this.snow(),
      uniforms: {
        snowSize: () => {
          return this.snowSize;
        },
        snowSpeed: () => {
          return this.snowSpeed;
        },
        snowColor: () => {
          return this.snowColor;
        },
      },
    });
    this.viewer.scene.postProcessStages.add(this.snowStage);
  }
  destroy() {
    if (!this.viewer || !this.snowStage) return;
    this.viewer.scene.postProcessStages.remove(this.snowStage);
    const isDestroyed = this.snowStage.isDestroyed();
    // å…ˆæ£€æŸ¥æ˜¯å¦è¢«é”€æ¯è¿‡ï¼Œå¦‚果已经被销毁过再调用destroy会报错
    if (!isDestroyed) {
      this.snowStage.destroy();
    }
    delete this.snowSize;
    delete this.snowSpeed;
  }
  show(visible) {
    this.snowStage.enabled = visible;
  }
  snow() {
    return "uniform sampler2D colorTexture;\n\
          in vec2 v_textureCoordinates;\n\
          uniform float snowSpeed;\n\
          uniform float snowSize;\n\
          uniform vec4 snowColor;\n\
          float snow(vec2 uv,float scale)\n\
          {\n\
              float time=czm_frameNumber/snowSpeed;\n\
              float w=smoothstep(1.,0.,-uv.y*(scale/10.));if(w<.1)return 0.;\n\
              uv+=time/scale;uv.y+=time*2./scale;uv.x+=sin(uv.y+time*.5)/scale;\n\
              uv*=scale;vec2 s=floor(uv),f=fract(uv),p;float k=3.,d;\n\
              p=.5+.35*sin(11.*fract(sin((s+p+scale)*mat2(7,3,6,5))*5.))-f;d=length(p);k=min(d,k);\n\
              k=smoothstep(0.,k,sin(f.x+f.y)*snowSize);\n\
              return k*w;\n\
          }\n\
          out vec4 fragColor;\n\
          void main(void){\n\
              vec2 resolution=czm_viewport.zw;\n\
              vec2 uv=(gl_FragCoord.xy*2.-resolution.xy)/min(resolution.x,resolution.y);\n\
              vec3 finalColor=vec3(0);\n\
              //float c=smoothstep(1.,0.3,clamp(uv.y*.3+.8,0.,.75));\n\
              float c=0.;\n\
              c+=snow(uv,30.)*.0;\n\
              c+=snow(uv,20.)*.0;\n\
              c+=snow(uv,15.)*.0;\n\
              c+=snow(uv,10.);\n\
              c+=snow(uv,8.);\n\
              c+=snow(uv,6.);\n\
              c+=snow(uv,5.);\n\
              finalColor=(vec3(c) * snowColor.rgb);\n\
              fragColor=mix(texture(colorTexture,v_textureCoordinates),vec4(finalColor,1),.5);\n\
              }\n\
              ";
  }
}
export default SnowEffect;
src/utils/tools.js
@@ -2,6 +2,7 @@
// import cameraIcon from "../assets/images/base/视频测点.png"
// import cameraIconSel from "../assets/images/base/视频测点sel.png"
import { ElLoading, ElMessage } from "element-plus";
import RainEffect from './rain'
let layerIsOpen = false;
const Cesium = SmartEarth.Cesium;
const colorAll = {
@@ -19,10 +20,33 @@
  analysisDXPMRes: [],
  slopeArrow: null,
  elevationTool: null,
  rainEffect: null,
  init(earthCtrl) {
    this.earthCtrl = earthCtrl;
    return this;
  },
  hexToColor(hexColor) {
    const hex = hexColor.replace('#', '');
    const r = parseInt(hex.substring(0, 2), 16) / 255;
    const g = parseInt(hex.substring(2, 4), 16) / 255;
    const b = parseInt(hex.substring(4, 6), 16) / 255;
    return new Cesium.Color(r, g, b, 1.0);
  },
  // å¤©æ°”
  toggleRain(option, show) {
    console.log(option, 'option')
    // å…ˆé”€æ¯æ—§å®žä¾‹
    if (this.rainEffect) {
      this.rainEffect.destroy()
      this.rainEffect = null
    }
    this.rainEffect = new RainEffect(earthCtrl.viewer, {
      tiltAngle: -0.2, //倾斜角度
      rainSize: option.rainSize, // é›¨çš„大小
      rainSpeed: option.rainSpeed, // é›¨çš„速度
      color: this.hexToColor(option.rainColor)  // é›¨çš„颜色
    })
  },
  // å¡åº¦åˆ†æž
  pdfx(option) {
@@ -79,14 +103,7 @@
    }
  },
  // å¤©æ°”
  toggleRain(weather = "rain", show) {
    if (show) {
      earthCtrl.environment.showEffect(weather);
    } else {
      earthCtrl.environment.disableEffect(weather);
    }
  },
  toggleSnow(weather = "snow", show) {
    if (show) {
      earthCtrl.environment.showEffect(weather);