riku
2024-05-08 d0f5933cb7fe9196ca0250252efc820a1a9d947e
新增历史轨迹菜单
已修改6个文件
已添加2个文件
316 ■■■■ 文件已修改
src/assets/3dmap.css 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components.d.ts 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/BaseCard.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/animation/HistoricalTrajectory.vue 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/3dLayer.js 164 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/animation.js 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/util.js 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/historymode/HistoryMode.vue 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/3dmap.css
@@ -247,6 +247,7 @@
.btn-search {
    cursor: pointer;
    padding: 4px 0;
}
.map-btn-group .btn-search {
src/components.d.ts
@@ -12,7 +12,6 @@
    CardButton: typeof import('./components/CardButton.vue')['default']
    CoreHeader: typeof import('./components/core/CoreHeader.vue')['default']
    CoreMenu: typeof import('./components/core/CoreMenu.vue')['default']
    DataStatistic: typeof import('./components/monitor/DataStatistic.vue')['default']
    DataSummary: typeof import('./components/monitor/DataSummary.vue')['default']
    DataTable: typeof import('./components/monitor/DataTable.vue')['default']
    ElButton: typeof import('element-plus/es')['ElButton']
@@ -40,6 +39,7 @@
    FactorCheckbox: typeof import('./components/monitor/FactorCheckbox.vue')['default']
    FactorLegend: typeof import('./components/monitor/FactorLegend.vue')['default']
    FactorRadio: typeof import('./components/monitor/FactorRadio.vue')['default']
    HistoricalTrajectory: typeof import('./components/animation/HistoricalTrajectory.vue')['default']
    LineChart: typeof import('./components/monitor/LineChart.vue')['default']
    MapToolbox: typeof import('./components/map/MapToolbox.vue')['default']
    OptionDevice: typeof import('./components/search/OptionDevice.vue')['default']
src/components/BaseCard.vue
@@ -9,7 +9,7 @@
    <div class="ff-footer">
      <slot name="footer"></slot>
    </div>
    <div v-if="type == 'content' && size != 'small'" class="ff-triangle">
    <div v-if="type == 'content' && size == 'medium'" class="ff-triangle">
      <div class="ff-triangle-border"></div>
    </div>
  </div>
src/components/animation/HistoricalTrajectory.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,86 @@
<template>
  <BaseCard size="middle-s" direction="up">
    <template #content>
      <el-row align="middle" style="gap: 6px">
        <div>历史轨迹</div>
        <div class="map-btn-group">
          <font-awesome-icon
            :icon="btnStop.icon"
            :class="'btn-search m-r-2 ' + btnStop.clz"
            @click="handleStop"
          />
          <font-awesome-icon
            :icon="btnPlay.icon"
            class="btn-search"
            @click="handlePlayOrPause"
          />
        </div>
        <div class="label-date margin-left-2">
          <span class="label-date-title">倍速</span>
          <el-select v-model="speed" size="small" class="w-80">
            <el-option label="1.0X" :value="1" />
            <el-option label="4.0X" :value="4" />
            <el-option label="8.0X" :value="8" />
            <el-option label="16X" :value="16" />
          </el-select>
        </div>
      </el-row>
    </template>
  </BaseCard>
</template>
<script>
export default {
  props: {},
  emits: ['change'],
  data() {
    return {
      speed: 1,
      // åŠ¨ç”»çŠ¶æ€ï¼Œ0:停止;1:播放;2:暂停
      status: 0
    };
  },
  computed: {
    btnStop() {
      return {
        icon: 'fa fa-stop',
        clz: this.status == 0 ? 'btn-disable' : 'btn-able'
      };
    },
    btnPlay() {
      return {
        icon: this.status == 1 ? 'fa fa-pause' : 'fa fa-play'
      };
    }
  },
  methods: {
    handleStop() {
      if (this.status != 0) {
        this.status = 0;
        this.handleChange();
      }
    },
    handlePlayOrPause() {
      if (this.status == 1) {
        this.status = 2;
      } else {
        this.status = 1;
      }
      this.handleChange();
    },
    handleChange() {
      console.log(this.status);
      this.$emit('change', this.status);
    }
  },
  mounted() {}
};
</script>
<style scoped>
.btn-able {
  color: red;
}
.btn-disable {
  color: gray;
}
</style>
src/utils/map/3dLayer.js
@@ -87,88 +87,90 @@
  return scale;
}
/**
 * ç»˜å›¾
 */
function drawMesh(fDatas, factor, center, merge) {
  const lnglats_GD = fDatas.lnglats_GD;
  const coors = fDatas.coors_GD;
  const heights = factor.heights;
  const colors = factor.colors;
  const bColor = factor.bottomColor;
  if (center) {
    map.setZoomAndCenter(16, center);
  }
  // eslint-disable-next-line no-undef
  var cylinder = new AMap.Object3D.Mesh();
  cylinder.backOrFront = 'both';
  cylinder.transparent = true;
  var geometry = cylinder.geometry;
  const scale = _getScale(_minH, _maxH);
  for (let i = 0; i < coors.length; i++) {
    var r = lnglats_GD[i];
    var lastP = lnglats_GD[i - 1];
    var p = coors[i];
    var h = (heights[i] - _minH) * scale + _minHeight;
    if (heights[i] == -1) {
      h = -1;
    }
    geometry.vertices.push(p.x, p.y, 0); //底部顶点
    geometry.vertices.push(p.x, p.y, 0 - h); //顶部顶点
    if (i > 0) {
      // eslint-disable-next-line no-undef
      var distance = AMap.GeometryUtil.distance(r, lastP);
      //两个数据点最小间隔时间为4s,假设车速按照120km/h计算,4s行驶最大距离作为132米,
      //设定超过1分钟的数据绘制特殊的连线
      if (distance <= 500 && h != -1) {
        var bottomIndex = i * 2;
        var topIndex = bottomIndex + 1;
        var lastBottomIndex = bottomIndex - 2;
        var lastTopIndex = bottomIndex - 1;
        geometry.faces.push(bottomIndex, topIndex, lastTopIndex);
        geometry.faces.push(bottomIndex, lastBottomIndex, lastTopIndex);
      }
    }
    // var bColor = bColor
    var tColor = colors[i];
    geometry.vertexColors.push.apply(geometry.vertexColors, bColor); //底部顶点颜色
    geometry.vertexColors.push.apply(geometry.vertexColors, tColor); //顶部顶点颜色
  }
  // 7.根据合并选项重置或新增当前缓存数据
  if (merge != true) {
    _factorDatas = fDatas;
    _factor = factor;
    if (_cylinder != undefined) {
      object3Dlayer.remove(_cylinder);
    }
  } else {
    // _factorDatas.lnglats.push.apply(
    //   _factorDatas.lnglats,
    //   lnglats_GD
    // );
    // _factorDatas.coors.push.apply(_factorDatas.coors, coors);
    // _factorDatas.heights.push.apply(_factorDatas.heights, heights);
    // _factorDatas.colors.push.apply(_factorDatas.colors, colors);
    // _factorDatas.bottomColor = bColor;
  }
  object3Dlayer.add(cylinder);
  /**************test ****************/
  // object3Dlayer.on('mouseover', function (e) {
  //   console.log(
  //     `鼠标移入覆盖物! [${e.lnglat.getlng()}, ${e.lnglat.getLat()}]`
  //   );
  // });
  /**************test ****************/
  _cylinder = cylinder;
}
export default {
  /**
   * ç»˜å›¾
   */
  drawMesh(fDatas, factor, center, merge) {
    const lnglats_GD = fDatas.lnglats_GD;
    const coors = fDatas.coors_GD;
    const heights = factor.heights;
    const colors = factor.colors;
    const bColor = factor.bottomColor;
    if (center) {
      map.setZoomAndCenter(16, center);
    }
    // eslint-disable-next-line no-undef
    var cylinder = new AMap.Object3D.Mesh();
    cylinder.backOrFront = 'both';
    cylinder.transparent = true;
    var geometry = cylinder.geometry;
    const scale = _getScale(_minH, _maxH);
    for (let i = 0; i < coors.length; i++) {
      var r = lnglats_GD[i];
      var lastP = lnglats_GD[i - 1];
      var p = coors[i];
      var h = (heights[i] - _minH) * scale + _minHeight;
      if (heights[i] == -1) {
        h = -1;
      }
      geometry.vertices.push(p.x, p.y, 0); //底部顶点
      geometry.vertices.push(p.x, p.y, 0 - h); //顶部顶点
      if (i > 0) {
        // eslint-disable-next-line no-undef
        var distance = AMap.GeometryUtil.distance(r, lastP);
        //两个数据点最小间隔时间为4s,假设车速按照120km/h计算,4s行驶最大距离作为132米,
        //设定超过1分钟的数据绘制特殊的连线
        if (distance <= 500 && h != -1) {
          var bottomIndex = i * 2;
          var topIndex = bottomIndex + 1;
          var lastBottomIndex = bottomIndex - 2;
          var lastTopIndex = bottomIndex - 1;
          geometry.faces.push(bottomIndex, topIndex, lastTopIndex);
          geometry.faces.push(bottomIndex, lastBottomIndex, lastTopIndex);
        }
      }
      // var bColor = bColor
      var tColor = colors[i];
      geometry.vertexColors.push.apply(geometry.vertexColors, bColor); //底部顶点颜色
      geometry.vertexColors.push.apply(geometry.vertexColors, tColor); //顶部顶点颜色
    }
    // 7.根据合并选项重置或新增当前缓存数据
    if (merge != true) {
      _factorDatas = fDatas;
      _factor = factor;
      if (_cylinder != undefined) {
        object3Dlayer.remove(_cylinder);
      }
    } else {
      // _factorDatas.lnglats.push.apply(
      //   _factorDatas.lnglats,
      //   lnglats_GD
      // );
      // _factorDatas.coors.push.apply(_factorDatas.coors, coors);
      // _factorDatas.heights.push.apply(_factorDatas.heights, heights);
      // _factorDatas.colors.push.apply(_factorDatas.colors, colors);
      // _factorDatas.bottomColor = bColor;
    }
    object3Dlayer.add(cylinder);
    /**************test ****************/
    // object3Dlayer.on('mouseover', function (e) {
    //   console.log(
    //     `鼠标移入覆盖物! [${e.lnglat.getlng()}, ${e.lnglat.getLat()}]`
    //   );
    // });
    /**************test ****************/
    _cylinder = cylinder;
  },
  drawMesh: drawMesh,
  /**
   * ç»˜åˆ¶3D走行路线图
   * @param fDatas å®Œæ•´ç›‘测数据
src/utils/map/animation.js
@@ -2,7 +2,10 @@
import calculate from '@/utils/map/calculate';
import Layer from '@/utils/map/3dLayer';
import sector from '@/utils/map/sector';
import map from '@/utils/map/index_old';
import { map } from '@/utils/map/index_old';
import util from "@/utils/map/util";
import car_driving from '@/assets/mipmap/car_driving.png';
import boat_driving from '@/assets/mipmap/boat_driving.png';
function MapAnimation() {
  // éžè¿žç»­åæ ‡ç‚¹æœ€å¤§è·ç¦»(ç±³)
@@ -264,16 +267,16 @@
      var url;
      switch (this.vehicleType) {
        case 0:
          url = './asset/mipmap/car_driving.png';
          url = car_driving;
          break;
        case 1:
          url = './asset/mipmap/car_driving.png';
          url = car_driving;
          break;
        case 2:
          url = './asset/mipmap/boat_driving.png';
          url = boat_driving;
          break;
        default:
          url = './asset/mipmap/car_driving.png';
          url = car_driving;
          break;
      }
      // var url = "./asset/mipmap/car_offline.png";
@@ -292,26 +295,33 @@
      //     break;
      // }
      // eslint-disable-next-line no-undef
      var icon = new AMap.Icon({
        // eslint-disable-next-line no-undef
        size: new AMap.Size(60, 30),
        // eslint-disable-next-line no-undef
        imageSize: new AMap.Size(54, 21),
        image: url
        // imageOffset: new AMap.Pixel(-16, -16) // ç›¸å¯¹äºŽåŸºç‚¹çš„偏移位置
      });
      // eslint-disable-next-line no-undef
      var car = new AMap.Marker({
        icon: icon,
        position: lnglat, // åŸºç‚¹ä½ç½®
        // eslint-disable-next-line no-undef
        offset: new AMap.Pixel(-20, -15) // ç›¸å¯¹äºŽåŸºç‚¹çš„偏移位置
      });
      MapUtil._map.add(car);
      map.add(car);
      this.moveViews['car'] = car;
      // æ—¶é—´
      // eslint-disable-next-line no-undef
      var text = new AMap.Text({
        text: time,
        position: lnglat,
        // eslint-disable-next-line no-undef
        offset: new AMap.Pixel(5, 20),
        style: {
          'font-size': '13px',
@@ -324,10 +334,10 @@
          padding: '0 4px'
        }
      });
      MapUtil._map.add(text);
      map.add(text);
      this.moveViews['text'] = text;
    } else {
      MapUtil.setCenter(lnglat);
      util.setCenter(lnglat);
      this.moveViews['car'].setPosition(lnglat);
      this.moveViews['text'].setPosition(lnglat);
      this.moveViews['text'].setText(time);
src/utils/map/util.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
import { map, isDragging } from '@/utils/map/index_old';
export default {
  setCenter(lnglat) {
    if (isDragging) {
      return;
    }
    var now = new Date();
    if (
      this.lasttime == undefined ||
      now.getTime() - this.lasttime.getTime() >= 1000
    ) {
      map.setCenter(lnglat);
      this.lasttime = now;
    }
  }
};
src/views/historymode/HistoryMode.vue
@@ -1,6 +1,6 @@
<template>
  <div class="p-events-none m-t-2">
    <el-row justify="center">
    <el-row v-show="status == 0" justify="center">
      <SearchBar
        :search-time="searchTime"
        @search="fetchHistroyData"
@@ -32,6 +32,11 @@
      :factor-datas="factorDatas"
      :device-type="deviceType"
    ></DataSheet>
    <el-row class="historical" justify="center">
      <HistoricalTrajectory
        @change="(e) => (status = e)"
      ></HistoricalTrajectory>
    </el-row>
  </div>
</template>
@@ -70,7 +75,9 @@
      drawMode: 0,
      searchTime: [],
      // å½“前选中高亮的数据点索引
      locateIndex: undefined
      locateIndex: undefined,
      // è½¨è¿¹åŠ¨ç”»çŠ¶æ€
      status: 0
    };
  },
  watch: {
@@ -192,4 +199,11 @@
  right: 0;
  top: 0;
}
.historical {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
}
</style>