vue+mars3d 组件封装与应用 +简单示例

前言

很多朋友在学习和使用mars3d时,经常发现用的官方推荐组件,在实际应用中会出现很多问题。我用vuecli 4.0以上版本生成的vue项目,直接套用官方示例和官方组件会出现只显示地图,模型无法显示的问题。
如图
在这里插入图片描述以下是我重构后的代码

一、map.vue

<template>
  <div
    :id="`mars3d-container${mapKey}`"
    :class="['mars3d-container', customClass, { 'mars3d-container-compare-rh': compare }]"
  ></div>
</template>

<script>
import Vue from "vue";

// 使用免费开源版本
import "mars3d/dist/mars3d.css";
import * as mars3d from "mars3d";

// 导入插件(其他插件类似,插件清单访问:http://mars3d.cn/dev/guide/start/install.html)
// echarts插件
// import 'mars3d-echarts'

// 为了方便使用,绑定到原型链,在其他vue文件,直接 this.mars3d 来使用
Vue.prototype.mars3d = mars3d;
Vue.prototype.Cesium = mars3d.Cesium;

export default {
  name: "mars3dViewer",

  props: {
    // 初始化配置参数
    url: String,

    // 地图唯一性标识
    mapKey: {
      type: String,
      default: "",
    },

    // 自定义参数
    options: Object,

    // 是否分屏显示
    compare: {
      type: Boolean,
      default: false,
    },

    // 是否插入到body元素上
    appendToBody: {
      type: Boolean,
      default: false,
    },

    // 自定义css类名
    customClass: {
      type: String,
      default: "",
    },
  },

  mounted() {
    if (this.appendToBody) {
      document.body.appendChild(this.$el);
    }

    if (this.mapKey) {
      this.initMars3d(this.options);
    } else {
      mars3d.Resource.fetchJson({ url: this.url }).then((data) => {
        this.initMars3d(data.map3d); // 构建地图
      });
    }
  },

  beforeDestroy() {
    this[`map${this.mapKey}`].destroy();
    delete this[`map${this.mapKey}`];
  },

  methods: {
    initMars3d(options) {
      if (this[`map${this.mapKey}`]) {
        this[`map${this.mapKey}`].destroy();
      }

      const mapOptions = {
        ...options,
        ...this.options,
      };

      // 创建三维地球场景
      var map = new mars3d.Map(`mars3d-container${this.mapKey}`, mapOptions);

      this[`map${this.mapKey}`] = map;

      console.log(">>>>> 地图创建成功 >>>>", map);

      // 挂载到全局对象下,所有组件通过 this.map 访问
      Vue.prototype[`map${this.mapKey}`] = map;

      // 绑定对alert的处理,右键弹出信息更美观。
      // window.haoutil = window.haoutil || {}
      // window.haoutil.msg = (msg) => {
      //   this.$message.success(msg)
      // }
      // window.haoutil.alert = (msg) => {
      //   this.$message.success(msg)
      // }

      // 抛出事件
      this.$emit("onload", map);
    },
  },
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
.mars3d-container {
  height: 100%;
  overflow: hidden;
}

/* 重写Cesium的css */

/**cesium按钮背景色*/
.cesium-button {
  background-color: #3f4854;
  color: #e6e6e6;
  fill: #e6e6e6;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
  line-height: 32px;
}

.cesium-viewer-geocoderContainer .cesium-geocoder-input {
  background-color: rgba(63, 72, 84, 0.7);
}

.cesium-viewer-geocoderContainer .cesium-geocoder-input:focus {
  background-color: rgba(63, 72, 84, 0.9);
}

.cesium-viewer-geocoderContainer .search-results {
  background-color: #3f4854;
}

.cesium-geocoder-searchButton {
  background-color: #3f4854;
}

.cesium-infoBox-title {
  background-color: #3f4854;
}

.cesium-infoBox {
  background: rgba(63, 72, 84, 0.9);
}

.cesium-toolbar-button img {
  height: 100%;
}

.cesium-performanceDisplay-defaultContainer {
  top: auto;
  bottom: 35px;
  right: 50px;
}
.cesium-performanceDisplay-ms,
.cesium-performanceDisplay-fps {
  color: #fff;
}

/**cesium工具栏位置*/
.cesium-viewer-toolbar {
  top: auto;
  left: auto;
  right: 12px;
  bottom: 35px;
}

.cesium-viewer-toolbar > .cesium-toolbar-button,
.cesium-navigationHelpButton-wrapper,
.cesium-viewer-geocoderContainer {
  margin-bottom: 5px;
  float: right;
  clear: both;
  text-align: center;
}

.cesium-baseLayerPicker-dropDown {
  bottom: 0;
  right: 40px;
  max-height: 700px;
  margin-bottom: 5px;
}

.cesium-navigation-help {
  top: auto;
  bottom: 0;
  right: 40px;
  transform-origin: right bottom;
}

.cesium-sceneModePicker-wrapper {
  width: auto;
}

.cesium-sceneModePicker-wrapper .cesium-sceneModePicker-dropDown-icon {
  float: left;
  margin: 0 3px;
}

.cesium-viewer-geocoderContainer .search-results {
  left: 0;
  right: 40px;
  width: auto;
  z-index: 9999;
}

.cesium-infoBox-title {
  background-color: #3f4854;
}

.cesium-infoBox {
  top: 50px;
  background: rgba(63, 72, 84, 0.9);
}

/**左下工具栏菜单*/
.toolbar-dropdown-menu-div {
  background: rgba(43, 44, 47, 0.8);
  border: 1px solid #2b2c2f;
  z-index: 991;
  position: absolute;
  right: 60px;
  bottom: 40px;
  display: none;
}

.toolbar-dropdown-menu {
  min-width: 110px;
  padding: 0;
}
.toolbar-dropdown-menu > li {
  padding: 0 3px;
  margin: 2px 0;
}
.toolbar-dropdown-menu > li > a {
  color: #edffff;
  display: block;
  padding: 4px 10px;
  clear: both;
  font-weight: normal;
  line-height: 1.6;
  white-space: nowrap;
  text-decoration: none;
}

.toolbar-dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
  color: #fff;
  background-color: #444d59;
}

.toolbar-dropdown-menu > .active > a,
.dropdown-menu > .active > a:hover,
.dropdown-menu > .active > a:focus {
  color: #fff;
  background-color: #444d59;
}
.marsBlackPanel .mars3d-popup-close-button {
  color: #fff ;
}
.toolbar-dropdown-menu i {
  padding-right: 5px;
}
</style>

二、示例组件 map2.vue

<template>
  <div class="mapcontainer web-map">
    <div class="tip-box">
      <button class="btn" @click="goto(1)">切换到化工厂</button>
      <button class="btn" @click="goto(2)">切换到油站</button>
    </div>
    <Map :url="configUrl" @onload="onMapload" />
  </div>
</template>

<style>
.tip-box {
  width: auto;
  height: auto;
  position: absolute;
  right: 10px;
  top: 10px;
  z-index: 999;
}
.btn {
  color: #fff;
  background-color: #3b61df;
  border-color: #3b61df;
  padding: 5px;
  margin: 0 5px;
  border-radius: 5px;
  cursor: pointer;
}

.marsBlueGradientPnl {
  text-align: center;
  padding: 5px 30px;
  margin: 0;
  color: #fff;
  background: linear-gradient(rgb(7 10 203 / 75%), rgb(16 238 220));
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  border-radius: 5px;
  max-height: 130px;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  white-space: nowrap;
}

.marsBlueGradientPnl:after {
  content: "";
  position: absolute;
  bottom: -60px;
  left: calc(50% - 3px);
  display: block;
  width: 3px;
  height: 60px;
  border-right: 3px solid #2bcdbb;
}
.marsBlueGradientPnl-err {
  background: linear-gradient(rgb(203 7 7 / 75%), rgb(238 16 16));
}
.marsBlueGradientPnl-alarm {
  background: linear-gradient(rgb(203 116 7 / 75%), rgb(238 149 16));
}
.marsBlueGradientPnl-offline {
  background: linear-gradient(#303336cf, #aaa);
  color: #ddd;
}

/* .marsBlueGradientPnl-err {
  border: 2px solid #f00;
} */
.marsBlueGradientPnl-err:after {
  border-right: 3px solid #f00;
}
.marsBlueGradientPnl-alarm:after {
  border-right: 3px solid #ff8b0d;
}
.marsBlueGradientPnl-offline:after {
  border-right: 3px solid #aaa;
}
</style>
<script>
import Map from "@/components/mars3d/Map.vue"; // 此处用的map在官网模板代码里有
const echarts = require('echarts');
import 'echarts-liquidfill'//在这里引入
export default {
  components: {
    Map,
  },
  data() {
    return {
      configUrl: "config/config.json", // mars3D配置文件
      map: "",
      graphicLayer: "",
      arrData: [],
    };
  },
  mounted() {},
  methods: {
    // 地图构造完成回调
    onMapload(map) {
      this.map = map;
      //定位切换视角
      this.map.setCameraView({
        lat: 31.808039,
        lng: 117.100629,
        alt: 559,
        heading: 329,
        pitch: -28,
      });
      this.arrData = [
        {
          name: "油罐一",
          position: [117.09521, 31.814404, 47.3],
          state: "报警",
          divice: "898600a6980349081601",
          val: "0.4",
          unit: "PPM",
          bjcolor: "#f00",
          online: "1",
          err: "1",
          projectname: "监控测试项目",
        },
        {
          name: "油罐二",
          position: [117.095206, 31.814878, 47.3],
          state: "异常",
          divice: "898600a6980349081602",
          val: "0.4",
          unit: "PPM",
          bjcolor: "#ff8b0d",
          online: "1",
          err: "2",
          projectname: "监控测试项目",
        },
        {
          name: "油罐三",
          position: [117.094653, 31.814428, 47.3],
          state: "报警",
          divice: "898600a6980349081603",
          val: "0.4",
          unit: "PPM",
          bjcolor: "#f00",
          online: "1",
          err: "1",
          projectname: "监控测试项目",
        },
        {
          name: "发电机",
          position: [117.093428, 31.816959, 31.8],
          state: "异常",
          divice: "898600a6980349081604",
          val: "0.4",
          unit: "PPM",
          bjcolor: "#f00",
          online: "1",
          err: "2",
          projectname: "监控测试项目",
        },
        {
          name: "指挥室",
          position: [117.093953, 31.814397, 36],
          state: "正常",
          divice: "898600a6980349081605",
          val: "0.4",
          unit: "PPM",

          bjcolor: "#04ba19",
          online: "1",
          err: "3",
          projectname: "监控测试项目",
        },
        {
          name: "加热罐",
          position: [117.09385, 31.815837, 36.9],
          state: "正常",
          divice: "898600a6980349081606",
          val: "0.4",
          unit: "PPM",
          bjcolor: "#04ba19",
          online: "1",
          err: "3",
          projectname: "监控测试项目",
        },
        {
          name: "冷却室",
          position: [117.094662, 31.816403, 32.9],
          state: "正常",
          divice: "898600a6980349081607",
          val: "0.4",
          unit: "PPM",
          bjcolor: "#04ba19",
          online: "2",
          err: "3",
          projectname: "监控测试项目",
        },
      ];
      this.graphicLayer = new this.mars3d.layer.DivLayer();
      map.addLayer(this.graphicLayer);
      //生成油站
      let tiles3dLayer = new this.mars3d.layer.TilesetLayer({
        pid: 2020,
        type: "3dtiles",
        name: "油田联合站",
        url: "//data.mars3d.cn/3dtiles/max-ytlhz/tileset.json",
        position: { lng: 117.094224, lat: 31.815859, alt: 26.4 },
        rotation: { z: 116.2 },
        highlight: { type: "click", color: "#00ffff" },
        maximumScreenSpaceError: 1,
        center: { lat: 32.407076, lng: 117.459703, alt: 3361, heading: 358, pitch: -51 },
        popup: "all",
      });
      this.map.addLayer(tiles3dLayer);
      this.divGraphicYellow();

      // 加载石化工厂模型
      let tiles3dLayer2 = new this.mars3d.layer.TilesetLayer({
        name: "石化工厂",
        url: "http://data.mars3d.cn/3dtiles/max-shihua/tileset.json",
        position: { lng: 117.077158, lat: 31.659116, alt: 24.6 },

        highlight: { type: "click", color: "#00ffff" },
        maximumScreenSpaceError: 1,
        maximumMemoryUsage: 1024,
        popup: "all",
      });
      this.map.addLayer(tiles3dLayer2);
      // 添加矢量数据
      this.addDemoGraphic([117.077462, 31.657745, 60], { value: 0.53, color: "#fb980b" });
      this.addDemoGraphic([117.079091, 31.65898, 90], { value: 0.45, color: "#00ff00" });
      this.addDemoGraphic([117.079766, 31.658268, 70], { value: 0.35, color: "#00ffff" });
      this.addDemoGraphic([117.07913, 31.655748, 80], { value: 0.21, color: "#ff0000" });

      // 单击.事件
      tiles3dLayer.on(mars3d.EventType.click, function (event) {
        console.log("单击了3dtiles图层", event);
      });
    },
    addDemoGraphic(position, attr) {
      let that=this
      const graphic = new this.mars3d.graphic.DivGraphic({
        position: position,
        style: {
          html: `<div style="width: 80px;height:80px;"></div>`,
          horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
        },
        attr: attr,
      });
      graphic.on(mars3d.EventType.add, function (e) {
        let dom = e.target.container.firstChild;
        let attr = e.target.attr;
        let liquidfillchartChart = echarts.init(dom);

        // 参考API:https://github.com/ecomfe/echarts-liquidfill
        // 参考示例:https://www.makeapie.com/explore.html#tags=liquidFill~sort=rank~timeframe=all~author=all
        let option = {
          series: [
            {
              type: "liquidFill",
              radius: "100%",
              outline: { show: false },
              color: [attr.color],
              data: [attr.value],
              label: {
                color: "#294D99",
                insideColor: "#fff",
                fontSize: 20,
              },
            },
          ],
        };
        liquidfillchartChart.setOption(option);
      });
      that.graphicLayer.addGraphic(graphic);
    },

    //切换模型
    goto(e) {
      switch (e) {
        case 1:
          this.map.setCameraView({
            lat: 31.647382,
            lng: 117.084888,
            alt: 719,
            heading: 329,
            pitch: -28,
          });
          break;

        case 2:
          this.map.setCameraView({
            lat: 31.808039,
            lng: 117.100629,
            alt: 559,
            heading: 329,
            pitch: -28,
          });
          break;
      }
    },
    //生成描述
    divGraphicYellow() {
      let arrData = this.arrData;
      let that = this;
      for (let i = 0; i < arrData.length; i++) {
        let item = arrData[i];

        var divGraphic = new this.mars3d.graphic.DivGraphic({
          position: item.position,
          style: {
            html: that.addPoupTitle(item),
            offsetY: -60,
            horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
            verticalOrigin: Cesium.VerticalOrigin.BTOOM,
          },
          popup: that.addPoup(item),
          popupOptions: {
            offsetY: -150, // 显示Popup的偏移值,是DivGraphic本身的像素高度值
            offsetX: -150,
            scaleByDistance: true, //是否按视距缩放
            template: `<div class="marsBlackPanel animation-spaceInDown">
                        <div class="marsBlackPanel-text">{content}</div>
                        <span class="mars3d-popup-close-button closeButton" >×</span>
                      </div>`,
            horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
            verticalOrigin: Cesium.VerticalOrigin.CENTER,
          },
        });
        that.graphicLayer.addGraphic(divGraphic);
      }
    },
    // 生成弹框标签
    addPoupTitle(item) {
      let colorclass = "";
      switch (item.err) {
        case "2":
          colorclass = "marsBlueGradientPnl-alarm";
          break;
        case "1":
          colorclass = "marsBlueGradientPnl-err";
          break;

        default:
          colorclass = "";
          break;
      }
      if (item.online != "1") {
        colorclass = "marsBlueGradientPnl-offline";
      }
      let html = `<div class="marsBlueGradientPnl ${colorclass}">
                    <div>${item.name}</div>
                </div>`;
      return html;
    },

    //弹框html
    addPoup(item) {
      let html = `<ul class="rel-pop">
      <li> 项目名称: <span > ${item.projectname}</span></li>
      <li> 设备编号: <span > ${item.divice}</span></li>
      <li> 检测值: <span > ${item.val}${item.unit}</span></li>
      <li> 报警状态: <span style="color:${item.bjcolor}"> ${item.state}</span></li>
      <li> 在线状态: <span > ${item.online == "1" ? "在线" : "离线"}</span></li>
      
      </ul>
  `;
      return html;
    },
    removeLayer() {
      if (this.layer) {
        this.map.removeLayer(this.layer, true);
        this.layer = null;
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.mapcontainer {
  overflow: hidden;
  height: 100vh;
  .bottomLayer {
    position: relative;
    bottom: 150px;
    text-align: center;
    button {
      font-size: 24px;
      width: 90px;
      background: rgba(63, 72, 84, 0.88);
      /*border-color: #00ffff;*/
      border: 0;
    }
    .activeBtn {
      color: #00ffff;
    }
  }

  .el-dialog__wrapper {
    .el-dialog {
      background: rgba(36, 45, 52, 0.9);
      border: 1px solid #66b1ff;
      .el-dialog__title {
        color: #eee;
      }
      .el-dialog__body {
        text-align: center;
      }
    }
  }
}
</style>

效果如下
在这里插入图片描述

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以尝试以下步骤来封装一个Vue 3和TypeScript下使用Element Plus的表单提交组件: 1. 安装必要的依赖: - Vue 3:`npm install vue@next` - TypeScript:`npm install -D typescript` - Element Plus:`npm install element-plus` 2. 创建一个新的Vue组件,并为其选择一个合适的名称,例如`FormSubmit.vue`。 3. 在`FormSubmit.vue`文件中,导入必要的模块和样式: ```vue <template> <!-- 表单内容 --> </template> <script lang="ts"> import { defineComponent } from 'vue'; import { ElButton, ElForm, ElFormItem } from 'element-plus'; export default defineComponent({ components: { ElButton, ElForm, ElFormItem, }, }); </script> <style scoped> /* Element Plus 样式 */ @import 'element-plus/packages/theme-chalk/src/index.scss'; /* 自定义样式 */ /* ... */ </style> ``` 4. 在模板中编写表单内容,并使用Element Plus的组件来构建表单: ```vue <template> <el-form ref="form" :model="formData" label-width="120px"> <el-form-item label="姓名" prop="name"> <el-input v-model="formData.name"></el-input> </el-form-item> <!-- 更多表单项 --> <el-form-item> <el-button type="primary" @click="submitForm">提交</el-button> </el-form-item> </el-form> </template> <script lang="ts"> // ... export default defineComponent({ // ... data() { return { formData: { name: '', // 更多表单字段 } }; }, methods: { submitForm() { // 表单提交逻辑 if (this.$refs.form.validate()) { // 表单验证通过,执行提交操作 // ... } } } }); </script> ``` 这样,你就可以使用封装好的表单提交组件来方便地处理表单提交了。你可以根据实际需求添加更多的表单项,并在`submitForm`方法中实现你的提交逻辑。希望这可以帮到你!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值