高德地图——轨迹回放和电子围栏

功能点

  • 地图的初始化
  • 显示电子围栏(先初始化在调接口显示电子围栏)
  • 显示定位
  • 显示轨迹
  • 轨迹回放 (回放速度无法控制是因为高德地图的版本问题,不要设置版本,使用默认的即可生效)
  • 获取当前城市及天气情况
  • 设置地图样式
  • 坐标拾取器

重点

  • 默认当前城市
js 复制代码
 this.map.on('complete', () => {})
js 复制代码
this.map.clearMap();
js 复制代码
this.map.setFitView();
js 复制代码
this.map.setCenter([point.longitude, point.latitude]); 
js 复制代码
<template>
  <div class="w100 h100 white relative">
    <!-- 地图区域 -->
    <div id="container" class="w100 h100"></div>
    <!-- 搜索框 -->
    <div class="absolute" style="left: .2rem; top: .5rem;z-index: 9; ">
      <div class="bg-com white pdRem-20 sizeRem-30">
        <div class="bold w100">
          <div class="item pdRem-20">正在监测人员:共{{ olderArr.length }}人</div>
          <div class="item pdRem-20">
            护理院
            <el-select v-model="info.orgId" class="w100 mtRem-20" @change="changeOrgId" :popper-append-to-body="false"
              :teleported="false">
              <el-option v-for="item in roomArr" :key="item.id" :label="item.label" :value="item.id"></el-option>
            </el-select>
          </div>
          <div class="item pdRem-20">
            老人姓名
            <el-select v-model="info.syncUserId" class="w100 mtRem-20" filterable :filter-method="remoteMethod"
              :popper-append-to-body="false" :teleported="false">
              <el-option v-for="item in olderArr" :key="item.syncUserId" :label="item.userName"
                :value="item.syncUserId"></el-option>
            </el-select>
          </div>
          <div class="item pdRem-20">
            <div class="mbRem-20">开始时间</div>
            <el-date-picker v-model="info.dateRange" @change="handleDateRange" style="width: 100%;" type="datetimerange"
              range-separator="" start-placeholder="开始日期" end-placeholder="结束日期" align="right"
              popper-class="popperClass-my" class="picker" :popper-append-to-body="false">
            </el-date-picker>
          </div>
          <div class="item pdRem-20">
            <el-tag class="btn-time" @click="getTime(0)">当天</el-tag>
            <el-tag class="btn-time mlrRem-20" @click="getTime(3)">近3天</el-tag>
            <el-tag class="btn-time" @click="getTime(7)">近7天</el-tag>
          </div>
        </div>
        <!-- 按钮 -->
        <div class="center mtRem-80">
          <el-button size="medium" class="block btn-bg" @click="submit(1)">实时定位</el-button>
          <el-button size="medium" class="block mlRem-40 btn-bg" @click="submit(2)">轨迹回放</el-button>
        </div>
      </div>
    </div>
    <!-- 告警 -->
    <div class="absolute" style="right: 1.5rem; top: .5rem;z-index: 9; ">
      <div v-for="(alarmInfo, index) in alarmList" :key="index" class="item-bg pdRem-30 sizeRem-26">
        <div class="flex_r"><el-tag type="warning" effect="dark" size="mini">{{ alarmInfo.alarmLevelName }}</el-tag>
        </div>
        <div class="flex1">
          <div style="width: 90%;">
            <div class="">{{ alarmInfo.alarmContent }}</div>
          </div>
          <div style="width:10%">
            <img :src="require('./components/img/alarm-icon.png')" alt="" style="width:0.4rem;height: 0.4rem;">
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { selectCompanyList, userInfoList, fenceList, userLocation, trajectory } from './components/js/api'

import AMapLoader from '@amap/amap-jsapi-loader';
import redIcon from "./components/img/point-red1.png";
import originIcon from "./components/img/origin.png";
import endIcon from "./components/img/end.png";
import olderManIcon from "./components/img/olderMan.png";
window._AMapSecurityConfig = {
  securityJsCode: "bc0077d71423eedb1d25df186610f740",
};
export default {
  props: ['alarmList'], //告警列表
  data() {
    return {
      isOrgId: true, //true是卫健委账号  fase机构账号
      map: null,
      trackLineArr: [],
      fenceArr: [], //电子围栏数据
      // 搜索框
      num: 0,
      info: {
        orgId: '',
        syncUserId: '',
        dateRange: [],
      },
      roomArr: [],//护理院-下拉
      olderArr: [],//老人-下拉
      olderArrCopy: [],//老人-下拉
    }
  },
  watch: {
    "info.dateRange"(newVal) {
      if (newVal == null) {
        this.info.dateRange = [];
      }
    },
  },

  mounted() {
    console.log('mounted', 33333333333)
    this.isOrgId = localStorage.getItem("isOrgId") == 'true' ? true : false;
    this.initAMap();
  },
  beforeDestroy() {
    this.map.destroy();
  },
  methods: {
    // 机构改变
    changeOrgId() {
      console.log('changeOrgId', this.info.orgId)

      // 老人下拉
      userInfoList({
        orgId: this.info.orgId
      }).then(res => {
        this.olderArr = res.data;
        this.olderArrCopy = res.data;
        this.$set(this.info, 'syncUserId', res.data.length ? res.data[0].syncUserId : '')
      })
      // 电子围栏
      fenceList({
        orgId: this.info.orgId
      }).then(res => {
        console.log('电子围栏', res.rows)
        this.fenceArr = res.rows;
        this.getFenceInfoList(res.rows)
      })
    },
    remoteMethod(query) {
      if (query) {
        console.log('query', query)
        this.olderArr = this.olderArrCopy.filter(item => {
          console.log(item.userNamePingYin.includes(query), '999', item.userNamePingYin);
          return item.userNamePingYin.toLowerCase().includes(query.toLowerCase()) || item.userName.includes(query);
        });
      } else {
        this.olderArr = this.olderArrCopy;
      }
    },
    formatDate(date) {
      const year = date.getFullYear();
      const month = String(date.getMonth() + 1).padStart(2, '0');
      const day = String(date.getDate()).padStart(2, '0');
      const hours = String(date.getHours()).padStart(2, '0');
      const minutes = String(date.getMinutes()).padStart(2, '0');
      const seconds = String(date.getSeconds()).padStart(2, '0');
      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
    },
    getTime(day) {
      this.info.dateRange = ['', '']
      const now = new Date();
      const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate())
      this.info.dateRange[1] = now;
      this.info.dateRange[0] = day == 0 ? startOfDay : new Date(now.getTime() - day * 24 * 60 * 60 * 1000);
    },
    // 时间段筛选
    handleDateRange() {
      if (this.info.dateRange) {
        const minDate = new Date(this.info.dateRange[0]).getTime();
        const maxDate = new Date(this.info.dateRange[1]).getTime();
        if (maxDate - minDate > 7 * 24 * 60 * 60 * 1000) {
          this.msgError("选择的时间范围不能超过7天");
          // 清空日期范围选择器
          this.info.dateRange = [];
        }
      } else {
        this.info.dateRange = [];
      }
    },
    submit(type) {
      //1实时定位 2轨迹回放
      console.log(type, this.info, 999);
      if (type == 1) {
        if (!this.info.syncUserId) {
          this.msgError('请选择老人');
        } else {
          userLocation({
            syncUserId: this.info.syncUserId,
          }).then(res => {
            this.createMarker(res.data)
          })
        }
      } else {
        if (!this.info.syncUserId) {
          this.msgError('请选择老人');
        } else if (this.info.dateRange.length == 0) {
          this.msgError('请选择时间');
        } else {
          trajectory({
            syncUserId: this.info.syncUserId,
            startTime: this.formatDate(this.info.dateRange[0]),
            endTime: this.formatDate(this.info.dateRange[1]),
          }).then(res => {
            if (res.data.length == 0) {
              this.msgError('未查询到轨迹数据');
            } else {
              this.handleTrack(2, res)
              // setTimeout(() => {
              //   this.handleTrack(2, res)
              // }, 2000)
            }
          })
        }
      }
    },

    // 地图
    initAMap() {
      AMapLoader.load({
        key: "d3e34dd987d36d98958ea35f97303089", // 申请好的Web端开发者Key,首次调用 load 时必填
        // version: "v1.4.15", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
        plugins: ["AMap.ControlBar",
          "AMap.ToolBar",
          'AMap.Weather',
          'AMap.CitySearch',
          'AMap.Marker',

          "AMap.MouseTool",
          "AMap.PolyEditor",
          "AMap.Driving",
          "AMap.Polyline",
          "AMap.Geolocation",
          "AMap.GraspRoad",
          "AMap.Geocoder",
          "AMap.GeometryUtil.ringArea",
          "AMap.DistrictSearch",
          "AMap.MoveAnimation",
        ], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
      })
        .then((AMap) => {
          this.map = new AMap.Map("container", {
            // 设置地图容器id
            rotateEnable: true,
            pitchEnable: true,
            zoom: 17,
            pitch: 50,
            rotation: -15,
            viewMode: '3D', //开启3D视图,默认为关闭
            zooms: [2, 20],
            center: [116.930096, 34.758164],
            mapStyle: "amap://styles/blue", //设置地图的显示样式
          });

          // 工具条
          var controlBar = new AMap.ControlBar({
            position: {
              right: '10px',
              top: '10px'
            }
          });
          this.map.addControl(controlBar)

          // var toolBar = new AMap.ToolBar({
          //   position: {
          //     right: '40px',
          //     top: '110px'
          //   }
          // });
          // this.map.addControl(toolBar)

          this.map.on('complete', () => {
            let idObj = JSON.parse(localStorage.getItem('formJx'))
            // 机构下拉
            selectCompanyList({
              orgId: this.isOrgId ? '-1' : idObj.orgId,
              groupId: idObj.groupId,
            }).then(res => {
              this.roomArr = res.data;
              this.$set(this.info, 'orgId', res.data[0].id)
              this.changeOrgId()
            })
          })
        })
        .catch((e) => {
          console.log(e);
        });
    },
    // 获取当前定位城市------获取天气
    getWeather() {
      const city = new AMap.CitySearch()
      city.getLocalCity((status, result) => {
        if (status === 'complete' && result.info === 'OK') {
          console.log('当前城市:', result.city);
          // 天气
          // 创建天气实例
          const weather = new AMap.Weather();
          // 获取指定城市(例如:北京)的实时天气
          weather.getLive(result.city, (error, data) => {
            if (error) {
              console.error('获取天气失败:', error);
            } else {
              console.log('实时天气数据:', data, `天气${data.weather} 温度${data.temperature}℃ 风向${data.windDirection}`);
              this.$emit('getWeather', `天气${data.weather} 温度${data.temperature}℃ 风向${data.windDirection}`)
              // 数据结构中通常包含如下信息
              // data.city: 城市名称
              // data.weather: 天气状况描述
              // data.temperature: 温度
              // data.windDirection: 风向
              // data.windPower: 风力等级等其他气象参数
            }
          });
        } else {
          console.error('获取当前城市失败:', result.info);
        }
      });
    },

    // 创建两个点标记
    createMarker(arr = []) {
      if (arr.length != 0) {
        // 清除地图上所有图形
        this.map.clearMap();
        this.getFenceInfoList(this.fenceArr)
        arr.map((item) => {
          var marker = new AMap.Marker({
            position: new AMap.LngLat(item.longitude, item.latitude),
            icon: new AMap.Icon({
              image: redIcon,
              imageSize: new AMap.Size(28, 28),
            }),
            // offset: new AMap.Pixel(-13, -30),
            // label: {
            //   content: "<div class='infos'>张三</div>",
            //   direction: 'bottom' //文本标注方位 可选值:'top'|'right'|'bottom'|'left'|'center',默认值: 'right'
            // }
          });
          this.map.add(marker);
        });
        //自动适配到合适视野范围
        //无参数,默认包括所有覆盖物的情况
        this.map.setFitView();
      } else {
        this.msgError('未有相关定位消息');
      }
    },
    //获取接口返回的电子围栏数据
    getFenceInfoList(arr = []) {
      if (arr.length == 0) {
        // 清除地图上所有图形
        this.map.clearMap();
        // 使用 setCenter 方法将地图中心移动到新的位置
        let point = this.roomArr.filter(item => item.id == this.info.orgId)[0]
        console.log(point, this.roomArr, 99999999999)
        // 设置地图中心点
        this.map.setCenter([point.longitude, point.latitude]);
        return;
      }
      let arr1 = [];
      for (let i = 0; i < arr.length; i++) {
        if (arr[i].fenceType == 0) {
          if (arr[i].useFence) {
            arr1.push({
              radius: arr[i].radius,
              center: arr[i].point,
              fillColor: "#16d46b",
              fillOpacity: 0.35,
              strokeColor: "#16d46b",
              strokeOpacity: 0.8,
              strokeStyle: "solid",
              zIndex: 10,
            });
          } else {
            arr1.push({
              radius: arr[i].radius,
              center: arr[i].point,
              fillColor: "#1791fc",
              fillOpacity: 0.5,
              strokeStyle: "solid",
              strokeColor: "#FF33FF",
              strokeOpacity: 0.8,
              zIndex: 10,
            });
          }
        } else if (arr[i].fenceType == 1) {
          if (arr[i].useFence) {
            arr1.push({
              path: arr[i].optimal,
              fillColor: "#16d46b",
              fillOpacity: 0.35,
              strokeColor: "#16d46b",
              strokeOpacity: 0.8,
              strokeStyle: "solid",
              zIndex: 10,
            });
          } else {
            arr1.push({
              path: arr[i].optimal,
              fillColor: "#1791fc",
              fillOpacity: 0.5,
              strokeColor: "#FF33FF",
              strokeOpacity: 0.8,
              strokeStyle: "solid",
              zIndex: 10,
            });
          }
        } else {
          for (let j = 0; j < arr[i].optimal.length; j++) {
            if (arr[i].useFence) {
              arr1.push({
                path: arr[i].optimal[j],
                fillColor: "#16d46b",
                fillOpacity: 0.35,
                strokeColor: "#16d46b",
                strokeOpacity: 0.8,
                strokeStyle: "solid",
                zIndex: 10,
              });
            } else {
              arr1.push({
                path: arr[i].optimal[j],
                fillColor: "#1791fc",
                fillOpacity: 0.5,
                strokeColor: "#FF33FF",
                strokeOpacity: 0.8,
                strokeStyle: "solid",
                zIndex: 10,
              });
            }
          }
        }
      }
      this.handleDrawPolygon(arr1);
    },
    // 获取接口返回的绘制图形
    handleDrawPolygon(data) {
      for (let i = 0; i < data.length; i++) {
        let polygon = null;
        if (data[i].radius) {
          polygon = new AMap.Circle(data[i]);
        } else {
          polygon = new AMap.Polygon(data[i]);
        }
        this.map.add(polygon);
        // 定位到绘制图形的位置
        this.map.setFitView();
      }
    },

    // type 1查询轨迹 2轨迹播放
    handleTrack(type, res) {
      // 清除地图上所有图形
      this.map.clearMap();
      this.getFenceInfoList(this.fenceArr)
      this.trackLineArr = res.data.map(item => {
        return {
          x: parseFloat(item.longitude),
          y: parseFloat(item.latitude),
          createTime: item.createTime,
          address: item.address,
          sp: 0,
          ag: 0,
          tm: 6
        }
      });
      // console.log(444, '接口获取的数据', this.trackLineArr)
      let lineArr = res.data.map(item => [item.longitude, item.latitude])
      this.handleGraspRoad(lineArr, type)
    },
    // 轨迹纠偏(因为最多只能纠偏500个点,所以只能采用循环方式进行处理)
    handleGraspRoad(graspArr, type) {
      // 起点
      let marker1 = null;
      marker1 = new AMap.Marker({
        map: this.map,
        position: graspArr[0],
        icon: new AMap.Icon({
          image: originIcon,
          size: new AMap.Size(48, 48), //图标大小
          imageSize: new AMap.Size(32, 32),
        }),
        offset: new AMap.Pixel(-13, -26),
      });
      marker1.setMap(this.map);
      // 终点
      let marker2 = null;
      marker2 = new AMap.Marker({
        map: this.map,
        position: graspArr[graspArr.length - 1],
        icon: new AMap.Icon({
          image: endIcon,
          size: new AMap.Size(48, 48), //图标大小
          imageSize: new AMap.Size(32, 32),
        }),
        offset: new AMap.Pixel(-13, -26),
      });
      // 定位到指定位置
      this.map.setFitView();
      marker2.setMap(this.map);


      //查询轨迹
      if (type == 1) {
        console.log(666, '轨迹的坐标点', graspArr)
        // 绘制轨迹(轨迹纠偏)
        const polyline = new AMap.Polyline({
          map: this.map,
          path: graspArr,
          showDir: true,
          strokeColor: "red", //线颜色
          // strokeOpacity: 1,     //线透明度
          strokeWeight: 6, //线宽
        });
      } else {
        //轨迹播放
        var markerSign = new AMap.Marker({
          map: this.map,
          position: graspArr[0],
          icon: new AMap.Icon({
            image: olderManIcon,
            size: new AMap.Size(48, 48), //图标大小
            imageSize: new AMap.Size(44, 44),
          }),
          // icon: "https://webapi.amap.com/images/car.png",
          offset: new AMap.Pixel(-13, -26),
          autoRotation: true,
          angle: -90,
        });
        // 绘制轨迹(轨迹纠偏)
        const polyline = new AMap.Polyline({
          map: this.map,
          path: graspArr,
          showDir: true,
          strokeColor: "#28F", //线颜色
          strokeOpacity: 1,     //线透明度
          strokeWeight: 6, //线宽
        });
        // 轨迹路线样式
        const passedPolyline = new AMap.Polyline({
          map: this.map,
          strokeColor: "#68d068", //线颜色
          strokeOpacity: 1,     //线透明度
          strokeWeight: 6, //线宽
          strokeStyle: "solid"  //线样式
        });


        markerSign.on("moving", function (e) {
          passedPolyline.setPath(e.passedPath);
          // this.map.setCenter(e.target.getPosition(), true);
        });
        this.map.setFitView();
        setTimeout(() => {
          markerSign.moveAlong(graspArr, 300);
        }, 1000);

        // markerSign.moveAlong(graspArr, {
        //   // 每一段的时长
        //   duration: 200, //可根据实际采集时间间隔设置
        //   // JSAPI2.0 是否延道路自动设置角度在 moveAlong 里设置
        //   // autoRotation: true,
        // });
      }
    },

  },
}
</script>
<style lang="scss">
// 修改时间选择框的样式,不能加scoped
.popperClass-my {

  border: 1px solid #66729b;
  background-color: rgba(0, 0, 0, 0.7);
  color: white;

  .el-date-range-picker__content.is-left,
  .el-picker-panel__content .el-date-range-picker__content .is-left,
  .el-picker-panel__content .el-date-range-picker__content .is-right,
  .el-date-range-picker__time-header,
  .el-date-range-picker__time-picker-wrap,
  .el-input__inner,
  .el-picker-panel__footer,
  .el-time-panel .el-popper,
  .el-button,
  .el-time-spinner,
  .el-time-spinner__item,
  .el-time-panel .el-popper {
    border: 0;
  }

  .el-time-spinner,

  .el-picker-panel__footer,
  .el-time-spinner__item {
    background: rgba(0, 0, 0, 0.7);
    // border: 0;
    // color: white;
  }

  .is-disabled .el-input__inner {
    background: rgba(0, 20, 38, 1);
    color: white;
  }

  .el-input__inner {
    background: rgba(0, 20, 38, 1);
    color: white;
    // 点日期-时间框

  }

  .el-time-panel__footer {
    background: rgba(0, 20, 38, 1);
    border: 0;
  }

  ul.el-scrollbar_view.el-time-spinner_list::before {
    background: rgba(0, 20, 38, 1);

  }

  // 选中日期
  .available.in-range div {
    background-color: black;
    color: white;
  }

  .available.in-range div:hover {
    background-color: black;
    color: white;
  }


  .el-button,
  .el-button.is-plain:hover {
    color: white;
    background: rgba(0, 20, 38, 1);
    border: 0;
  }


  .el-time-spinner__item:hover:not(.disabled) {
    //二级下拉框
    background: rgba(0, 0, 0, 0.7);
    font-size: medium;
    color: white;
  }

}
</style>


<style scoped lang="scss">
@import "./components/css/rem.scss";

// 下拉框样式的修改
::v-deep .el-input,
::v-deep .el-input__inner,
::v-deep .btn-bg,
::v-deep .el-range-editor--medium .el-range-input {
  background: url("./components/img/search1.png") no-repeat center center;
  background-size: 100% 100%;
  color: #fff;
  border: 0px;
  text-align: center;
}

::v-deep .el-select-dropdown,
::v-deep .popperClass .el-date-picker .el-range-input {
  border: 0;
  background-image: url("./components/img/search-bg.png");
  background-position: center;
  background-repeat: no-repeat;
  background-size: 100% 100%;

  .el-select-dropdown__item {
    color: #fff;
  }
}

.btn-time {
  background: url("./components/img/search1.png") no-repeat center center;
  background-size: 100% 100%;
  color: white;
  border: 0;
}

.picker .el-date-range-picker {
  background-color: transparent !important;
  //   border: 0;
  // background-image: url("./components/img/search-bg.png");
  // background-position: center;
  // background-repeat: no-repeat;
  // background-size: 100% 100%;

}



::v-deep .amap-marker-label {
  background-color: transparent !important;

  color: #ffcd09;
  border: 0px solid #00f;
  white-space: nowrap;
  font-size: 16px;
  transform: translateX(-50%);
  font-weight: 700;
}

.bg-com {
  width: 18vw;
  padding: .375rem;
  background: url('./components/img/bg-2.png') no-repeat center center;
  background-size: 100% 100%;

  z-index: 10;

  .item {
    max-width: 26vw;
  }
}

.item-bg {
  width: 4.125rem;
  background: url('./components/img/alarm-bg.png') no-repeat center center;
  background-size: 100% 100%;
}
</style>
相关推荐
上官花雨29 分钟前
什么是axios?怎么使用axios封装Ajax?
前端·ajax·okhttp
米奇妙妙wuu31 分钟前
React中 setState 是同步的还是异步的?调和阶段 setState 干了什么?
前端·javascript·react.js
李刚大人33 分钟前
react-amap海量点优化
前端·react.js·前端框架
闹闹没有闹1 小时前
socket连接封装
前端
qq_364371722 小时前
Vue 内置组件 keep-alive 中 LRU 缓存淘汰策略和实现
前端·vue.js·缓存
y先森3 小时前
CSS3中的弹性布局之侧轴的对齐方式
前端·css·css3
y先森8 小时前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy8 小时前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu10830189118 小时前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿9 小时前
CSS查缺补漏(补充上一条)
前端·css