vue2 implements Gaode Map JSAPI 2.0 trajectory playback component (MoveAnimation)

vue2 implements Gaode Map JSAPI 2.0 trajectory playback component (MoveAnimation)

Disclaimer: I am working on java backend, so please forgive me if the component extraction is not very standardized.

Prerequisite: You need to register for the Amap open platform, then create an application and activate Web端(JS API)the platform, and then get securityJsCodethekey

Realization effect:

image-20230504111101438

1. Basic extraction

Notice:

  • Just change securityJsCodeand keyto your own
  • v-show="true"It is displayed on the control panel. When I set it to true when extracting the basics, it will always be displayed.

Component code:

<template>
  <div>
    <a-row>
      <div id="container"></div>
      <div class='input-card' v-show="true">
        <div class="input-item">
          <a-button type="primary" size="small" style="width: 90px" @click="startAnimation">
            开始动画
          </a-button>
        </div>

        <div class="input-item">
          <a-button type="primary" size="small" style="width: 90px" @click="pauseAnimation">
            暂停动画
          </a-button>
        </div>

        <div class="input-item">
          <a-button type="primary" size="small" style="width: 90px" @click="resumeAnimation">
            继续动画
          </a-button>
        </div>

        <div class="input-item">
          <a-button type="primary" size="small" style="width: 90px" @click="stopAnimation">
            停止动画
          </a-button>
        </div>

      </div>
    </a-row>

  </div>

</template>

<script>
  //这里可以导入其他文件(比如: 组件, 工具 js, 第三方插件 js, json文件, 图片文件等等)
  //例如: import 《组件名称》 from '《组件路径》 ';

  import AMapLoader from "@amap/amap-jsapi-loader";
  // 设置安全密钥
  window._AMapSecurityConfig = {
    
    
    securityJsCode: 'xxxx',
  }
  export default {
    
    
    name: 'TrackContainer',
    //import 引入的组件需要注入到对象中才能使用
    components: {
    
    },
    props: {
    
    
      visible: Boolean,
    },
    data() {
    
    
      //这里存放数据
      return {
    
    
        AMap: null,
        //此处不声明 map 对象,可以直接使用 this.map赋值或者采用非响应式的普通对象来存储。
        map: null,
        mouseTool: null,
        marker: null,
        lineArr: [],
      };
    },
    //计算属性 类似于 data 概念
    computed: {
    
    },
    //监控 data 中的数据变化
    watch: {
    
    
    },
    //方法集合
    methods: {
    
    
      pauseAnimation () {
    
    
        this.marker.pauseMove();
      },
      resumeAnimation () {
    
    
        this.marker.resumeMove();
      },
      stopAnimation () {
    
    
        this.marker.stopMove();
      },
      startAnimation () {
    
    
        this.marker.moveAlong(this.lineArr, {
    
    
          // 每一段的时长
          duration: 500,//可根据实际采集时间间隔设置
          // JSAPI2.0 是否延道路自动设置角度在 moveAlong 里设置
          autoRotation: true,
        });
      },
      initMap() {
    
    
        AMapLoader.load({
    
    
          key: "xxxx",             // 申请好的Web端开发者Key,首次调用 load 时必填
          version: "2.0",      // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
          "plugins": [
            "AMap.Scale",
            "AMap.HawkEye",
            "AMap.ToolBar",
            "AMap.AutoComplete",
            "AMap.PlaceSearch",
            "AMap.ControlBar",
            "AMap.MouseTool",
            "AMap.DragRoute",
            "AMap.MoveAnimation"],         // 需要使用的的插件列表,如比例尺'AMap.Scale'等
        }).then((AMap) => {
    
    
          this.AMap=AMap
          this.marker=null;
          this.lineArr = [[116.478935,39.997761],[116.478939,39.997825],[116.478912,39.998549],[116.478912,39.998549],[116.478998,39.998555],[116.478998,39.998555],[116.479282,39.99856],[116.479658,39.998528],[116.480151,39.998453],[116.480784,39.998302],[116.480784,39.998302],[116.481149,39.998184],[116.481573,39.997997],[116.481863,39.997846],[116.482072,39.997718],[116.482362,39.997718],[116.483633,39.998935],[116.48367,39.998968],[116.484648,39.999861]];
          this.map = new AMap.Map("container", {
    
      //设置地图容器id
            viewMode: "2D",  //  是否为3D地图模式
            zoom: 13,   // 初始化地图级别
            center: [116.478935,39.997761], //中心点坐标  成都 104.065735, 30.659462
            resizeEnable: true
          });

          this.marker = new AMap.Marker({
    
    
            map: this.map,
            position: [116.478935,39.997761],
            icon: "https://a.amap.com/jsapi_demos/static/demo-center-v2/car.png",
            offset: new AMap.Pixel(-13, -26),
          });

          // 绘制轨迹
          var polyline = new AMap.Polyline({
    
    
            map: this.map,
            path: this.lineArr,
            showDir:true,
            strokeColor: "#28F",  //线颜色
            // strokeOpacity: 1,     //线透明度
            strokeWeight: 6,      //线宽
            // strokeStyle: "solid"  //线样式
          });

          var passedPolyline = new AMap.Polyline({
    
    
            map: this.map,
            strokeColor: "#AF5",  //线颜色
            strokeWeight: 6,      //线宽
          });

          this.marker.on('moving', function (e) {
    
    
            passedPolyline.setPath(e.passedPath);
            this.map.setCenter(e.target.getPosition(),true)
          }.bind(this));

          this.map.setFitView();




        }).catch(e => {
    
    
          console.log(e);
        })
      },
    },
    //生命周期 - 创建完成(可以访问当前 this 实例)
    created() {
    
    
    },
    //生命周期 - 挂载完成(可以访问 DOM 元素)
    mounted() {
    
    
      this.initMap();
    },
    //生命周期 - 创建之前
    beforeCreate() {
    
    
    },
    //生命周期 - 挂载之前
    beforeMount() {
    
    
    },
    //生命周期 - 更新之前
    beforeUpdate() {
    
    
    },
    //生命周期 - 更新之后
    updated() {
    
    
    },
    //生命周期 - 销毁之前
    beforeDestroy() {
    
    
    },
    //生命周期 - 销毁完成
    destroyed() {
    
    
    },
    //如果页面有 keep-alive 缓存功能, 这个函数会触发
    activated() {
    
    
    },
  }
</script>

<style scoped>
  #container {
    
    
    padding: 0px;
    margin: 0px;
    width: 100%;
    height: 800px;
  }
  .input-item {
    
    
    height: 2.2rem;
  }

  .input-card {
    
    
    display: flex;
    flex-direction: column;
    min-width: 0;
    word-wrap: break-word;
    background-color: #fff;
    background-clip: border-box;
    border-radius: .25rem;
    width: 10rem;
    border-width: 0;
    border-radius: 0.4rem;
    box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);
    position: fixed;
    bottom: 12rem;
    right: 2rem;
    -ms-flex: 1 1 auto;
    flex: 1 1 auto;
    padding: 0.75rem 1.25rem;
  }
</style>

2. Basic extraction and use

image-20230504111402678

3. Advanced extraction-customized route

Idea:

  • Pass the lineArr path variable through the parent component instead of hard-coding it in the child component
    • Taking into account performance issues ( because it is necessary to query the lineArr of all devices when viewing the parent component, but if the user only views one, there will be a performance loss ), so I did not directly lineArrpass it directly to the child component through the parent component. I did It will be passed to the child component through the parent component equipmentId, and then the child component equipmentIdcan query the corresponding device by calling the backend interface lineArr( the reader can directly pass the lineArr over, no problem )
  • At the same time, the control panel is displayed through the parent component.v-show="visible"
  • At the same time, I also added a date selection function to the component, which can query the path of a certain device on a certain day.
    • Of course, due to different businesses, the back-end interface needs to be written by yourself, but the overall return value is onelineArr

Code description:

  • getTrackListThe method is the backend interface I call

  • Map and car starting point settings

    image-20230504114523273

Component code:

<template>
  <div>
    <a-row>
      <div id="container"></div>
      <div class='input-card' v-show="visible">
        <div class="input-item">
          <a-button type="primary" size="small" style="width: 90px" @click="startAnimation">
            开始动画
          </a-button>
        </div>

        <div class="input-item">
          <a-button type="primary" size="small" style="width: 90px" @click="pauseAnimation">
            暂停动画
          </a-button>
        </div>

        <div class="input-item">
          <a-button type="primary" size="small" style="width: 90px" @click="resumeAnimation">
            继续动画
          </a-button>
        </div>

        <div class="input-item">
          <a-button type="primary" size="small" style="width: 90px" @click="stopAnimation">
            停止动画
          </a-button>
        </div>

        <div class="input-item">
          <a-date-picker @change="onChange" />
        </div>


      </div>
    </a-row>

  </div>

</template>

<script>
  //这里可以导入其他文件(比如: 组件, 工具 js, 第三方插件 js, json文件, 图片文件等等)
  //例如: import 《组件名称》 from '《组件路径》 ';

  import AMapLoader from "@amap/amap-jsapi-loader";
  import moment from "moment";
  import {
    
    getTrackList} from '@/services/attendance/statistics.js'
  // 设置安全密钥
  window._AMapSecurityConfig = {
    
    
    securityJsCode: 'xxxxx',
  }
  export default {
    
    
    name: 'TrackContainer',
    //import 引入的组件需要注入到对象中才能使用
    components: {
    
    },
    props: {
    
    
      visible: Boolean,
      equipmentId: String,
    },
    data() {
    
    
      //这里存放数据
      return {
    
    
        AMap: null,
        //此处不声明 map 对象,可以直接使用 this.map赋值或者采用非响应式的普通对象来存储。
        map: null,
        mouseTool: null,
        marker: null,
        lineArr: [],
      };
    },
    //计算属性 类似于 data 概念
    computed: {
    
    },
    //监控 data 中的数据变化
    watch: {
    
    
    },
    //方法集合
    methods: {
    
    
      getLineArr(equipmentId, date) {
    
    
        getTrackList(equipmentId,date).then(res => {
    
    
          this.lineArr = res.data.data
          this.initTrackBefore(this.AMap);
        })
      },
      initTrack () {
    
    
        this.map = new AMap.Map("container", {
    
      //设置地图容器id
          viewMode: "2D",  //  是否为3D地图模式
          zoom: 13,   // 初始化地图级别
          center: this.lineArr[0], //中心点坐标  成都 104.065735, 30.659462
          resizeEnable: true
        });

        this.marker = new AMap.Marker({
    
    
          map: this.map,
          position: this.lineArr[0],
          icon: "https://a.amap.com/jsapi_demos/static/demo-center-v2/car.png",
          offset: new AMap.Pixel(-13, -26),
        });

        // 绘制轨迹
        var polyline = new AMap.Polyline({
    
    
          map: this.map,
          path: this.lineArr,
          showDir: true,
          strokeColor: "#28F",  //线颜色
          // strokeOpacity: 1,     //线透明度
          strokeWeight: 6,      //线宽
          // strokeStyle: "solid"  //线样式
        });

        var passedPolyline = new AMap.Polyline({
    
    
          map: this.map,
          strokeColor: "#AF5",  //线颜色
          strokeWeight: 6,      //线宽
        });
        this.marker.on('moving', function (e) {
    
    
          passedPolyline.setPath(e.passedPath);
          this.map.setCenter(e.target.getPosition(), true)
        }.bind(this));

        this.map.setFitView();
      },
      onChange(date, dateString) {
    
    
        console.log(date, dateString);
        this.getLineArr(this.equipmentId,date.valueOf())
      },
      pauseAnimation () {
    
    
        this.marker.pauseMove();
      },
      resumeAnimation () {
    
    
        this.marker.resumeMove();
      },
      stopAnimation () {
    
    
        this.marker.stopMove();
      },
      startAnimation () {
    
    
        this.marker.moveAlong(this.lineArr, {
    
    
          // 每一段的时长
          duration: 500,//可根据实际采集时间间隔设置
          // JSAPI2.0 是否延道路自动设置角度在 moveAlong 里设置
          autoRotation: true,
        });
      },
      initTrackBefore (AMap) {
    
    
        if (this.lineArr.length > 0) {
    
    
          this.initTrack();
        } else {
    
    
          this.$message.error("该设备在当天无定位信息")
          this.map = new AMap.Map("container", {
    
      //设置地图容器id
            viewMode: "2D",  //  是否为3D地图模式
            zoom: 13,   // 初始化地图级别
            center: [104.065735, 30.659462], //中心点坐标  成都 104.065735, 30.659462
            resizeEnable: true
          });
          this.map.setFitView();
        }
      },
      initMap() {
    
    
        AMapLoader.load({
    
    
          key: "xxxx",             // 申请好的Web端开发者Key,首次调用 load 时必填
          version: "2.0",      // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
          "plugins": [
            "AMap.Scale",
            "AMap.HawkEye",
            "AMap.ToolBar",
            "AMap.AutoComplete",
            "AMap.PlaceSearch",
            "AMap.ControlBar",
            "AMap.MouseTool",
            "AMap.DragRoute",
            "AMap.MoveAnimation"],         // 需要使用的的插件列表,如比例尺'AMap.Scale'等
        }).then((AMap) => {
    
    
          this.AMap=AMap
          this.marker=null;
          // this.lineArr = [[116.478935,39.997761],[116.478939,39.997825],[116.478912,39.998549],[116.478912,39.998549],[116.478998,39.998555],[116.478998,39.998555],[116.479282,39.99856],[116.479658,39.998528],[116.480151,39.998453],[116.480784,39.998302],[116.480784,39.998302],[116.481149,39.998184],[116.481573,39.997997],[116.481863,39.997846],[116.482072,39.997718],[116.482362,39.997718],[116.483633,39.998935],[116.48367,39.998968],[116.484648,39.999861]];
          this.initTrackBefore(AMap);





        }).catch(e => {
    
    
          console.log(e);
        })
      },
    },
    //生命周期 - 创建完成(可以访问当前 this 实例)
    created() {
    
    
      this.getLineArr(this.equipmentId,moment().valueOf())
    },
    //生命周期 - 挂载完成(可以访问 DOM 元素)
    mounted() {
    
    
      this.initMap();
    },
    //生命周期 - 创建之前
    beforeCreate() {
    
    
    },
    //生命周期 - 挂载之前
    beforeMount() {
    
    
    },
    //生命周期 - 更新之前
    beforeUpdate() {
    
    
    },
    //生命周期 - 更新之后
    updated() {
    
    
    },
    //生命周期 - 销毁之前
    beforeDestroy() {
    
    
    },
    //生命周期 - 销毁完成
    destroyed() {
    
    
    },
    //如果页面有 keep-alive 缓存功能, 这个函数会触发
    activated() {
    
    
    },
  }
</script>

<style scoped>
  #container {
    
    
    padding: 0px;
    margin: 0px;
    width: 100%;
    height: 800px;
  }
  .input-item {
    
    
    height: 2.2rem;
  }

  .input-card {
    
    
    display: flex;
    flex-direction: column;
    min-width: 0;
    word-wrap: break-word;
    background-color: #fff;
    background-clip: border-box;
    border-radius: .25rem;
    width: 10rem;
    border-width: 0;
    border-radius: 0.4rem;
    box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);
    position: fixed;
    bottom: 12rem;
    right: 2rem;
    -ms-flex: 1 1 auto;
    flex: 1 1 auto;
    padding: 0.75rem 1.25rem;
  }
</style>

4. Advanced extraction and use

  • trackVisibleYou only need to synchronize the display of the map component in the parent component to achieve synchronized switching with the map component.
  • You only need to pass these two values ​​​​to the parent component. If it is lineArr, you need to modify the component and pass lineArr directly.
      <Track-Container
        :visible="trackVisible"
        :equipmentId ="form.equipmentImei"
      >
      </Track-Container>

The effect is as follows:

image-20230504113726303

Guess you like

Origin blog.csdn.net/qq_31745863/article/details/130484253