vue高德地图实现轨迹回放

vue yekong

数据可视化大屏项目开发中,有一个需求是实现汽车的轨迹回放效果,今天我们实现这个功能

vue高德地图实现轨迹回放

动态效果

功能介绍

主要包含以下功能:

  1. 车辆选择
  2. 地图展示
  3. 路线绘制
  4. 车辆动画
  5. 车辆信息展示

核心实现

1. 初始化地图

initMap() {
  if (this.map) {
    this.map.destroy();
  }
  this.map = new AMap.Map(this.$refs.mapContainer, {
    zoom: 16,
    center: [119.565775, 39.929105],
    mapStyle: 'amap://styles/eebad0d61cdc83f8253e3fbcdf5cd2bc',
    viewMode: '2D',
  });
  this.initDriving();
}

这段代码初始化了高德地图,设置了地图的中心点、缩放级别和样式。

2. 路线绘制

async drawRoute(start, end) {
  // ... 省略部分代码
  const result = await new Promise((resolve, reject) => {
    this.driving.search(start, end, function (status, result) {
      if (status === 'complete') {
        resolve(result);
      } else {
        reject(result);
      }
    });
  });

  const steps = result.routes[0].steps;
  const path = steps.reduce((accumulator, step) => accumulator.concat(step.path), []);
  this.drawPolyline(path);
  this.animateMarker(path);
}

这个方法使用高德地图的驾车路线规划API,获取起点到终点的路线,然后绘制路线并开始车辆动画。

3. 车辆动画

animateMarker(path) {
  this.currentMarker = new AMap.Marker({
    map: this.map,
    position: path[0],
    icon: new AMap.Icon({
      size: new AMap.Size(52, 26),
      image: car,
      imageSize: new AMap.Size(52, 26),
    }),
    offset: new AMap.Pixel(-26, -13),
    autoRotation: true,
  });

  this.currentMarker.moveAlong(path, 200);
}

这段代码创建了一个表示车辆的标记,并使用moveAlong方法让车辆沿着路径移动。

4. 车辆信息更新

updateVehicleInfo(selectedVehicle) {
  const vehicle = this.vehicleList.find(v => v.value === selectedVehicle);
  if (vehicle) {
    this.vehicleInfo = {
      name: vehicle.name,
      startAddress: vehicle.startAddress,
      endAddress: vehicle.endAddress,
      loadRate: vehicle.loadRate,
      usageTime: vehicle.usageTime
    };
  }
}

当选择不同车辆时,这个方法会更新显示的车辆信息。

完整实例代码

<template>
  <div class="gdMap">
    <div class="searchBody">
      <div class="searchItem">
        <selected class="ml200" placeholder="选择车辆" v-model:active="selectedVehicle"
                  :list="vehicleList"></selected>
      </div>
    </div>
    <div class="popInfo">
      <p>车牌号: {{ vehicleInfo?.name || '' }}</p>
      <p>起点: {{ vehicleInfo?.startAddress || '' }}</p>
      <p>终点: {{ vehicleInfo?.endAddress || '' }}</p>
      <p>满载率: {{ vehicleInfo?.loadRate || '' }}%</p>
      <p>行驶时间: {{ vehicleInfo?.usageTime || '' }}</p>
    </div>
    <div class="container" ref="mapContainer" id="container"></div>
  </div>
</template>

<script>
import car from './assets/car.png';
import selected from "./selected/index.vue";

export default {
  data() {
    return {
      map: null,
      driving: null,
      selectedVehicle: '',
      vehicleList: this.generateVehicleList(),
      currentPolyline: null,
      currentMarker: null,
      vehicleInfo: null,
    };
  },
  components: { selected },
  mounted() {
    this.initMap();
    this.selectedVehicle = this.vehicleList[0].value; // 默认选中第一辆车
    this.updateVehicleInfo(this.selectedVehicle);
  },
  watch: {
    selectedVehicle(newVal) {
      if (newVal) {
        const vehicle = this.vehicleList.find(v => v.value === newVal);
        if (vehicle) {
          this.initMap(); // 重新初始化地图
          this.drawRoute(vehicle.start, vehicle.end);
          this.updateVehicleInfo(newVal);
        }
      }
    }
  },
  methods: {
    initMap() {
      if (this.map) {
        this.map.destroy(); // 销毁之前的地图实例
      }
      this.map = new AMap.Map(this.$refs.mapContainer, {
        zoom: 16,
        center: [119.565775, 39.929105], // 默认中心点
        mapStyle: 'amap://styles/eebad0d61cdc83f8253e3fbcdf5cd2bc',
        viewMode: '2D',
      });
      this.initDriving();
    },
    initDriving() {
      this.driving = new AMap.Driving();
    },
    async drawRoute(start, end) {
      try {
        // 移除之前的轨迹线和车辆标记
        if (this.currentPolyline) {
          this.currentPolyline.setMap(null);
        }
        if (this.currentMarker) {
          this.currentMarker.setMap(null);
        }

        // 设置地图中心点为车辆的起点
        this.map.setCenter(start);

        const result = await new Promise((resolve, reject) => {
          this.driving.search(start, end, function (status, result) {
            if (status === 'complete') {
              resolve(result);
            } else {
              reject(result);
            }
          });
        });

        const steps = result.routes[0].steps;
        const path = steps.reduce((accumulator, step) => accumulator.concat(step.path), []);
        this.drawPolyline(path);
        this.animateMarker(path);
      } catch (error) {
        console.log('获取驾车数据失败:' + error);
      }
    },
    drawPolyline(path) {
      this.currentPolyline = new AMap.Polyline({
        path: path,
        strokeColor: '#FF0000',
        strokeWeight: 6,
        map: this.map,
      });
    },
    animateMarker(path) {
      this.currentMarker = new AMap.Marker({
        map: this.map,
        position: path[0],
        icon: new AMap.Icon({
          size: new AMap.Size(52, 26),
          image: car,
          imageSize: new AMap.Size(52, 26),
        }),
        offset: new AMap.Pixel(-26, -13),
        autoRotation: true,
      });

      this.currentMarker.moveAlong(path, 200);

      // 添加点击事件
      this.currentMarker.on('click', () => {
        const vehicle = this.vehicleList.find(v => v.value === this.selectedVehicle);
        if (vehicle) {
          this.vehicleInfo = {
            name: vehicle.name,
            startAddress: vehicle.startAddress,
            endAddress: vehicle.endAddress,
            loadRate: vehicle.loadRate,
            usageTime: vehicle.usageTime
          };
        }
      });
    },
    updateVehicleInfo(selectedVehicle) {
      const vehicle = this.vehicleList.find(v => v.value === selectedVehicle);
      if (vehicle) {
        this.vehicleInfo = {
          name: vehicle.name,
          startAddress: vehicle.startAddress,
          endAddress: vehicle.endAddress,
          loadRate: vehicle.loadRate,
          usageTime: vehicle.usageTime
        };
      }
    },
    generateVehicleList() {
      const addresses = ['山东路', '人民路', '解放路', '建设路', '和平路'];
      const vehicles = [];
      for (let i = 0; i < 10; i++) {
        const start = [119.565775 + Math.random() * 0.01, 39.929105 + Math.random() * 0.01];
        const end = [119.565775 + Math.random() * 0.01, 39.929105 + Math.random() * 0.01];
        const startAddress = addresses[Math.floor(Math.random() * addresses.length)];
        const endAddress = addresses[Math.floor(Math.random() * addresses.length)];
        const loadRate = Math.floor(Math.random() * 100);
        const usageTime = `${Math.floor(Math.random() * 5) + 1}小时${Math.floor(Math.random() * 60)}分钟`;
        const plateNumber = `冀T${Math.random().toString(36).substr(2, 4).toUpperCase()}X`;
        vehicles.push({
          value: plateNumber,
          name: plateNumber,
          start: start,
          end: end,
          startAddress: startAddress,
          endAddress: endAddress,
          loadRate: loadRate,
          usageTime: usageTime
        });
      }
      return vehicles;
    }
  },
  beforeDestroy() {
    if (this.map) {
      this.map.destroy();
    }
  },
};
</script>

项目应用

物流云大数据看板

喜欢