Newer
Older
baseResourceFront / src / views / overview / trail.vue
zhangyingjie on 24 Mar 2021 14 KB 合并master分支
<template>
  <app-container id="overview">
    <!--筛选条件-->
    <div class="search-div">
      <el-form ref="selectForm" :inline="true" :model="listQuery" class="form-container">
        <el-row >
          <el-col style="width: fit-content;">
            <el-date-picker
              v-model="dateTimeRange"
              type="datetimerange"
              range-separator="至"
              size="small"
              value-format="yyyy-MM-dd HH:mm:ss"
              start-placeholder="开始时间"
              end-placeholder="结束时间"
            />
            <!--</el-form-item>-->
            <el-button class="filter-item" type="primary" icon="el-icon-search" size="small" @click="search">查询</el-button>
            <el-button class="filter-item" type="primary" size="small" @click="play">开始</el-button>
            <el-button class="filter-item" type="primary" size="small" @click="pause">暂停</el-button>
            <el-button class="filter-item" type="primary" size="small" @click="stop">停止</el-button>

          </el-col>
          <el-col style="display:flex;width: fit-content;">
            <span style="padding-left: 10px;padding-top: 10px;font-size: 14px">回放速度</span>
            <span style="padding-left:10px;padding-right: 10px;padding-top: 10px;font-size: 14px">快</span>
            <el-slider v-model="sec" :format-tooltip="formatTooltip" :step="10" :min="10" :show-tooltip="false" style="width: 100px;" @change="settimer"/>
            <span style="padding-left: 10px;padding-top: 10px;font-size: 14px;">慢</span>
          </el-col>
          <el-col style="padding-top: 4px;width: fit-content; float: right;">
            <el-button class="filter-item" type="primary" style="margin-left: 10px;background-color: #286090;border: #286090" size="small" @click="staticspeed">时间速度曲线</el-button>
          </el-col>
        </el-row>
        <el-row>
          <el-slider v-model="showindex" :format-tooltip="timeTooltip" :max="list.length!==0?list.length-1:0" :disabled="list.length==0" class="timeslide" @change="changepos"/>
        </el-row>
      </el-form>
    </div>
    <div id="map">
      <div class="namecard" >{{ carName }}</div>
    </div>
    <trail-static v-show="dialogFormVisible" ref="trailStatic" @watchChild="fetchData"/>
  </app-container>
</template>
<script>
import trailStatic from '@/views/overview/trailStatic'
import { trail } from '@/api/overview'
import L from 'leaflet'
import 'leaflet/dist/leaflet.css'
import 'leaflet-rotatedmarker/leaflet.rotatedMarker.js'
export default {
  name: 'Trail',
  components: { trailStatic },
  data() {
    return {
      dialogFormVisible: false, // 是否显示编辑框
      refresh: '10',
      sec: 50,
      showindex: 0,
      state: 0, // 1:开始 2:暂停 3:停止
      showtable: true,
      deptShow: true,
      listQuery: {
        carId: '',
        startTime: '',
        endTime: ''
      }, // 查询条件
      baselayer: [],
      carName: '',
      dateTimeRange: [],
      pathlist: [], // 列表数据
      list: [], // 列表数据
      map: null,
      listLoading: true, // 加载动画
      fullscreenLoading: false, // 全屏加载动画
      timer: null,
      carpoint: null
    }
  },
  watch: {
    dateTimeRange(val) {
      if (val && val.length > 0) {
        this.listQuery.startTime = val[0]
        this.listQuery.endTime = val[1]
      } else {
        this.listQuery.startTime = ''
        this.listQuery.endTime = ''
      }
    }
  },
  mounted() {
    if (this.$route.query) {
      this.listQuery.carId = this.$route.query.id
      this.carName = this.$route.query.name
    }
    const date = new Date()
    const year = date.getFullYear() // 年
    const month = date.getMonth() + 1 // 月
    const day = date.getDate() // 日
    this.dateTimeRange = [year + '-' + month + '-' + day + ' 00:00:00', year + '-' + month + '-' + day + ' 23:59:59']
    this.initMap()
    this.settimer()
  },
  methods: {
    settimer() {
      clearTimeout(this.timer)
      this.timer = setInterval(() => {
        this.showcar()
      }, this.sec * 10)
    },
    staticspeed() {
      this.dialogFormVisible = true
      this.$refs.trailStatic.initDialog(this.dialogFormVisible, this.listQuery, this.carName)
    },
    showcar() {
      if (this.state !== 1) {
        return
      }
      this.showindex++
      if (this.showindex === this.list.length) {
        clearTimeout(this.timer)
        var that = this
        setTimeout(function() { that.stop() }, this.sec * 10)
        return
      }
      this.carpoint.remove()
      // add point
      var Icon = L.icon({
        iconUrl: require('../../assets/global_images/car.png'),
        iconSize: [40, 40]
      })
      var str = '<div style="font-size: 15px;padding: 6px"> <div style="font-weight: bold;padding-bottom: 10px">车辆轨迹点信息</div>' +
      '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">定位</label>' + this.list[this.showindex].lng + ' , ' + this.list[this.showindex].lat + '</div>' +
      '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">时间</label>' + this.list[this.showindex].upTime + '</div>' +
      '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">速度</label>' + this.list[this.showindex].speed + '(km/h)</div>' +
      '</div>'
      var popup = L.popup().setContent(str)
      this.carpoint = L.marker([this.list[this.showindex].lat, this.list[this.showindex].lng], {
        icon: Icon,
        rotationAngle: this.list[this.showindex].direction
      }).addTo(this.map).bindPopup(popup)
      this.carpoint.openPopup()
    },
    play() {
      this.state = 1
      this.settimer()
    },
    pause() {
      this.state = 2
    },
    changepos() {
      if (this.list.length !== 0) {
        if (this.carpoint !== null) {
          this.carpoint.remove()
        }
        var Icon = L.icon({
          iconUrl: require('../../assets/global_images/car.png'),
          iconSize: [40, 40]
        })
        var str = '<div style="font-size: 15px;padding: 6px"> <div style="font-weight: bold;padding-bottom: 10px">车辆轨迹点信息</div>' +
          '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">定位</label>' + this.list[this.showindex].lng + ' , ' + this.list[this.showindex].lat + '</div>' +
          '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">时间</label>' + this.list[this.showindex].upTime + '</div>' +
          '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">速度</label>' + this.list[this.showindex].speed + '(km/h)</div>' +
          '</div>'
        var popup = L.popup().setContent(str)
        this.carpoint = L.marker([this.list[this.showindex].lat, this.list[this.showindex].lng], {
          icon: Icon,
          rotationAngle: Number(this.list[this.showindex].direction)
        }).addTo(this.map).bindPopup(popup)
        this.carpoint.openPopup()
      }
    },
    stop() {
      this.state = 3
      if (this.list.length !== 0) {
        if (this.carpoint !== null) {
          this.carpoint.remove()
        }
        var Icon = L.icon({
          iconUrl: require('../../assets/global_images/car.png'),
          iconSize: [40, 40]
        })
        var str = '<div style="font-size: 15px;padding: 6px"> <div style="font-weight: bold;padding-bottom: 10px">车辆轨迹点信息</div>' +
          '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">定位</label>' + this.list[0].lng + ' , ' + this.list[0].lat + '</div>' +
          '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">时间</label>' + this.list[0].upTime + '</div>' +
          '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">速度</label>' + this.list[0].speed + '(km/h)</div>' +
          '</div>'
        var popup = L.popup().setContent(str)
        this.carpoint = L.marker([this.list[0].lat, this.list[0].lng], {
          icon: Icon,
          rotationAngle: Number(this.list[0].direction)
        }).addTo(this.map).bindPopup(popup)
        this.carpoint.openPopup()
        this.showindex = 0
      }
    },
    formatTooltip(val) {
      return val / 100
    },
    timeTooltip(val) {
      if (this.list.length !== 0) {
        return this.list[val].upTime
      }
    },
    initMap() {
      const map = L.map('map', {
        minZoom: 3,
        maxZoom: 18,
        center: [27.75962, 116.06021],
        zoom: 11,
        zoomControl: false,
        attributionControl: false,
        crs: L.CRS.EPSG3857
      })
      this.map = map // data上需要挂载
      window.map = map
      this.baselayer.push(L.tileLayer(
        'https://t0.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=216ee92889e17ab1b083fae665d522b8',
        { subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'] }
      ).addTo(map))
      this.baselayer.push(L.tileLayer(
        'https://t0.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=216ee92889e17ab1b083fae665d522b8',
        { subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'] }
      ).addTo(map))
      this.search()
    },
    search() {
      this.fetchData(false)
    },
    setZoom(points) {
      console.log(points)
      if (points.length > 0) {
        var maxLng = points[0][1]
        var minLng = points[0][1]
        var maxLat = points[0][0]
        var minLat = points[0][0]
        var res
        for (var i = points.length - 1; i >= 0; i--) {
          res = points[i]
          if (res[1] > maxLng) maxLng = res[1]
          if (res[1] < minLng) minLng = res[1]
          if (res[0] > maxLat) maxLat = res[0]
          if (res[0] < minLat) minLat = res[0]
        }
        var cenLng = (parseFloat(maxLng) + parseFloat(minLng)) / 2
        var cenLat = (parseFloat(maxLat) + parseFloat(minLat)) / 2
        var zoom = this.getZoom(maxLng, minLng, maxLat, minLat)
        this.map.setView({ lat: cenLat, lng: cenLng }, zoom)
      } else {
        // 没有坐标,显示全中国
        this.map.setView({ lat: 103.388611, lng: 35.563611 }, 5)
      }
    },
    getZoom(maxLng, minLng, maxLat, minLat) {
      var zoom = ['50', '100', '200', '500', '1000', '2000', '5000', '10000', '20000', '25000', '50000', '100000', '200000', '500000', '1000000', '2000000']// 级别18到3。
      var latlng = L.latLng(maxLat, maxLng)
      var distance = latlng.distanceTo(L.latLng(minLat, minLng))
      // var distance = pointA.distanceTo(pointB)// 获取两点距离,保留小数点后两位
      for (var i = 0, zoomLen = zoom.length; i < zoomLen; i++) {
        if (zoom[i] - distance > 0) {
          console.log(i)
          return 18 - i + 2 // 之所以会多2,是因为地图范围常常是比例尺距离的10倍以上。所以级别会增加3。
        }
      }
    },
    setCenter(points) {
      // 获取折线中心点坐标
      if (points.length > 0) {
        let maxLng = points[0][1]
        let minLng = points[0][1]
        let maxLat = points[0][0]
        let minLat = points[0][0]
        let res
        for (let i = points.length - 1; i >= 0; i--) {
          res = points[i]
          if (res[1] > maxLng) maxLng = res[1]
          if (res[1] < minLng) minLng = res[1]
          if (res[0] > maxLat) maxLat = res[0]
          if (res[0] < minLat) minLat = res[0]
        }
        const cenLng = (parseFloat(maxLng) + parseFloat(minLng)) / 2
        const cenLat = (parseFloat(maxLat) + parseFloat(minLat)) / 2

        this.map.setView({ lat: cenLat, lng: cenLng })
      }
    },
    fetchData() { // 划线
      this.listLoading = true
      trail(this.listQuery).then(response => {
        this.list = response.data
        var base = this.baselayer
        this.map.eachLayer(function(layer) {
          if (layer !== base[0] && layer !== base[1]) {
            layer.remove()
          }
        })
        if (this.list.length === 0) {
          this.$message.warning('查询结果为空')
        }
        if (this.list.length !== 0) {
          var myStyle = {
            'color': '#e69010',
            'weight': 5
          }
          this.pathlist = []
          for (var i = 0; i < this.list.length; i++) {
            var item = [Number(this.list[i].lat), Number(this.list[i].lng)]
            this.pathlist.push(item)
          }
          L.polyline(this.pathlist, myStyle).addTo(this.map)
          this.setZoom(this.pathlist)
          var Icon = L.icon({
            iconUrl: require('../../assets/global_images/start.png'),
            iconSize: [40, 40]
          })
          L.marker([this.list[0].lat, this.list[0].lng], {
            icon: Icon
          }).addTo(this.map)
          Icon = L.icon({
            iconUrl: require('../../assets/global_images/end.png'),
            iconSize: [40, 40]
          })
          L.marker([this.list[this.list.length - 1].lat, this.list[this.list.length - 1].lng], {
            icon: Icon
          }).addTo(this.map)
        }
        this.stop()
      })
    }
  }
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
  .search-div{
    padding:12px;
    padding-bottom: 2px; /* 本身输入框有10px下边距*/
    background-color: #fff;
    /*display: -webkit-flex; !* Safari *!*/
    /*display: flex;*/
    justify-content:space-between;
    .search-btn{
      margin-bottom:10px;
    }
  }
  .namecard{
    width: 300px;
    height: 20px;
    z-index: 10000;
    position: absolute;
    left:10px;
    top:10px;
    font-size: 16px;
    font-weight: bold;
    color: #1f2d3d;
  }
  #map {
    border-top: 12px solid #ebebeb;
    width:100%;
    height:67.5vh;
  }
  .my-div-icon {
    width: 10px;
    height: 10px;
    background-color: orange;
    border-radius: 50%;
  }
  .timeslide{
    padding-left: 20px;padding-right: 20px;
    /deep/ .el-slider__button{
      border-radius: 20%;
      width: 40px;
      height: 20px;
    }
    /deep/ .el-slider__button-wrapper{
      width: 40px;
    }
  }
</style>