vue结合高德地图JS API2.0实现地图路线展示、轨迹纠偏、聚合点、聚合点点击以及弹窗、车辆移动

vue结合高德地图JS API2.0实现地图路线展示、轨迹纠偏、聚合点、聚合点点击以及弹窗、车辆移动

地图

<template>
  <div style="width: 100%; height: 100%">
    <div id="map-container"></div>
    <div style="display: none">
      <MarkerInfo
        :roadList="roadList"
        :infoContent="nowClusterType"
        ref="MarkerInfo"
      />
    </div>
  </div>
</template>
<script lang="ts">
  import { defineComponent, ref, nextTick } from 'vue';
  import { loadAMap, mapStyle } from '@/utils/amap';
  import { highway } from '@/api';
  import coordtransform from 'coordtransform';
  import MarkerInfo from './MarkerInfo.vue';
  //import * as turf from '@turf/turf';
  export default defineComponent({
    name: 'Map',
    props: {
      roadRecord: {
        default: [],
      },
      sickList: {
        default: [],
      },
      sickId: {
        default: '',
        type: String,
      },
      roadList: {
        default: [],
      },
    },
    components: { MarkerInfo },
    setup(prop: any) {
      const map = ref<any>(null);
      const record = ref<any>({
        line: null,
        start: null,
        end: null,
        car: null,
      });
      const roadList = ref<any>([]);
      const fakeMarker = ref<any>(null);
      nextTick(() => {
        loadAMap()
          .then((AMap: any) => {
            AMap.plugin('AMap.MoveAnimation', () => {
              map.value = new AMap.Map('map-container', {
                mapStyle: mapStyle,
                resizeEnable: true,
                zoom: 12,
                rotateEnable: true,
                showLabel: true,
                pitchEnable: true,
              });
              //层级变换,清空窗体信息
              var logMapChange = function () {
                map.value.clearInfoWindow();
                if (fakeMarker.value) map.value.remove(fakeMarker.value);
              };
              map.value.on('zoomchange', logMapChange);
              map.value.on('click', logMapChange);
            });
          })
          .finally(() => {
            getRoad();
          });
      });
      const getRoad = () => {
        highway
          .getRouteLineInfo()
          .then((res: any) => {
            roadList.value = [];
            //轨迹纠偏插件引入
            window.AMap.plugin('AMap.GraspRoad', () => {
              var grasp = new window.AMap.GraspRoad();
              res.list.forEach((item: any) => {
                let path: any = [],
                  nowIndex: number = 0;
                //减少点的获取,高德只允许传参小于500个
                item.forEach((items: any, index: number) => {
                  if (
                    ((item.length < 5000 && index % 10 === 0) ||
                      (item.length >= 5000 && item.length < 10000 && index % 20 === 0) ||
                      (item.length >= 10000 && item.length < 50000 && index % 100 === 0) ||
                      (item.length >= 50000 && index % 200 === 0)) &&
                    path.length < 500
                  ) {
                    if (path.length === 0) {
                      path.push({
                        x: coordtransform.wgs84togcj02(items.longitude, items.latitude)[0],
                        y: coordtransform.wgs84togcj02(items.longitude, items.latitude)[1],
                        sp: items.speed,
                        ag: items.heading,
                        tm: items.gpsTime,
                      });
                    } else {
                      nowIndex++;
                      path.push({
                        x: coordtransform.wgs84togcj02(items.longitude, items.latitude)[0],
                        y: coordtransform.wgs84togcj02(items.longitude, items.latitude)[1],
                        sp: 10,
                        ag: 0,
                        tm: nowIndex,
                      });
                    }
                  }
                });
                //轨迹纠偏
                grasp.driving(path, (error: any, result: any) => {
                  if (!error) {
                    var path2 = [];
                    var newPath = result.data.points;
                    for (var i = 0; i < newPath.length; i += 1) {
                      path2.push([newPath[i].x, newPath[i].y]);
                    }
                    var newLine = new window.AMap.Polyline({
                      path: path2,
                      strokeWeight: 3,
                      strokeOpacity: 1,
                      strokeColor: '#00FF67',
                    });
                    roadList.value.push(newLine);
                    map.value.add(newLine);
                    map.value.setFitView(roadList.value);
                  }
                });
              });
            });
          })
          .finally(() => {
            setTimeout(() => {
              if (prop.sickList && prop.sickList.length > 0)
                setCluster();//添加JSAPI2.0下的聚合点
            }, 400);
          });
      };
      //清空地图
      const removeRecord = (needRemoveLine: boolean = true) => {
        map.value?.clearInfoWindow();
        if (fakeMarker.value) map.value.remove(fakeMarker.value);
        if (needRemoveLine) {
          roadList.value.forEach((item: any) => {
            if (item) map.value.remove(item);
          });
        }
        if (record.value.line) map.value.remove(record.value.line);
        if (record.value.start) map.value.remove(record.value.start);
        if (record.value.end) map.value.remove(record.value.end);
        if (cluster.value) cluster.value.setMap(null);
        if (record.value.car) {
          record.value.car.stopMove();
          map.value.remove(record.value.car);
        }
      };
      const nowClusterType = ref<any>([]);
      const cluster = ref<any>(null);
      const MarkerInfo = ref();
      //打开设备标记点窗体信息
      const clusterCallback = (e: any) => {
        nowClusterType.value = [];
        //判断点击的是聚合点
        if (e.clusterData.length > 0)
          e.clusterData.forEach((item: any) => {
            nowClusterType.value.push(item.info);
          });
        else nowClusterType.value.push(e.marker.info);
        var infoWindow: any = new window.AMap.InfoWindow({
          offset: new window.AMap.Pixel(0, nowClusterType.value.length > 1 ? -40 : -70),
          content: MarkerInfo.value.$el,
          anchor: 'bottom-center',
        });
        infoWindow.open(map.value, [e.lnglat.lng, e.lnglat.lat]);
        if (fakeMarker.value) map.value.remove(fakeMarker.value);
        if (nowClusterType.value.length === 1) {
          fakeMarker.value = new window.AMap.Marker({
            map: map.value,
            position: [e.lnglat.lng, e.lnglat.lat],
            offset: new window.AMap.Pixel(-16, -66),
            icon: new window.AMap.Icon({
              size: new window.AMap.Size(32, 74), // 图标尺寸
              image: require('../../../assets/images/map/alarm-yellow.png'), // Icon的图像
              imageOffset: new window.AMap.Pixel(0, 0), // 图像相对展示区域的偏移量,适于雪碧图等
              imageSize: new window.AMap.Size(32, 74), // 根据所设置的大小拉伸或压缩图片
            }),
          });
        }
        //高德 InfoWindow解决2.0版本无法滚动问题
        infoWindow.on('mouseover', () => map.value.setStatus({ zoomEnable: false }));
        infoWindow.on('mouseout', () => {
          map.value.setStatus({ zoomEnable: true });
        });
        infoWindow.on('mousewheel', (e: any) => {
          const { originEvent } = e;
          let doc: any = document.querySelector('.marker-content');
          if (doc) doc.scrollTop -= originEvent.wheelDelta / 5;
        });
      };
      const setCluster = () => {
        map.value?.clearInfoWindow();
        if (cluster.value) cluster.value.setMap(null);
        if (!prop.sickList || prop.sickList.length === 0 || !window.AMap) return;
        let markerList: any = [];
        let allPath: any = [];
        roadList.value.forEach((items: any) => {
          allPath = allPath.concat(items._opts.path);
        });
        prop.sickList.forEach((item: any) => {
          /*let pointsList: any = []
          roadList.value[0].$x.forEach((items: any)=>{
            items.forEach((itemss: any)=>{
              pointsList.push(turf.point(itemss))
            })
          })
          let points: any = turf.featureCollection(pointsList);
          var targetPoint = turf.point([
            coordtransform.wgs84togcj02(item.lon, item.lat)[0],
            coordtransform.wgs84togcj02(item.lon, item.lat)[1],
          ]);*/
          // 计算path上距离pos最近的点
          markerList.push({
            info: item,
            lnglat: window.AMap.GeometryUtil.closestOnLine(
              coordtransform.wgs84togcj02(item.lon, item.lat),
              allPath
            ),
          });
        });
        var _renderMarker = function (context: any) {
          let icon = new window.AMap.Icon({
            size: new window.AMap.Size(32, 74), // 图标尺寸
            image: require('../../../assets/images/map/alarm-blue.png'), // Icon的图像
            imageOffset: new window.AMap.Pixel(0, 0), // 图像相对展示区域的偏移量,适于雪碧图等
            imageSize: new window.AMap.Size(32, 74), // 根据所设置的大小拉伸或压缩图片
          });
          context.marker.setOffset(new window.AMap.Pixel(-16, -66));
          context.marker.setIcon(icon);
          context.marker.info = context.data[0].info;
        };
        var _renderClusterMarker = function (context: any) {
          var factor = Math.pow(context.count / prop.sickList.length, 1 / 18);
          var div = document.createElement('div');
          var Hue = 180 - factor * 180;
          var bgColor = 'hsla(' + Hue + ',100%,40%,0.7)';
          var fontColor = 'hsla(' + Hue + ',100%,90%,1)';
          var borderColor = 'hsla(' + Hue + ',100%,40%,1)';
          var shadowColor = 'hsla(' + Hue + ',100%,90%,1)';
          div.style.backgroundColor = bgColor;
          var size = Math.round(30 + Math.pow(context.count / prop.sickList.length, 1 / 5) * 20);
          div.style.width = div.style.height = size + 'px';
          div.style.border = 'solid 1px ' + borderColor;
          div.style.borderRadius = size / 2 + 'px';
          div.style.boxShadow = '0 0 5px ' + shadowColor;
          div.innerHTML = context.count;
          div.style.lineHeight = size + 'px';
          div.style.color = fontColor;
          div.style.fontSize = '14px';
          div.style.textAlign = 'center';
          context.marker.setOffset(new window.AMap.Pixel(-size / 2, -size / 2));
          context.marker.setContent(div);
        };
        cluster.value = new window.AMap.MarkerCluster(map.value, markerList, {
          gridSize: 80,
          averageCenter: false,
          renderClusterMarker: _renderClusterMarker, // 自定义聚合点样式
          renderMarker: _renderMarker, // 自定义非聚合点样式
        });
        cluster.value.on('click', clusterCallback);
        //map.value.setFitView();
      };
      watch(
        () => prop.sickList,
        () => {
          setCluster();
        }
      );
      watch(
        () => prop.sickId,
        () => {
          if (cluster.value && cluster.value.it.length > 0) {
            map.value.clearInfoWindow();
            if (fakeMarker.value) map.value.remove(fakeMarker.value);
            nowClusterType.value = [];
            cluster.value.it.forEach((item: any) => {
              if (item.info.id === prop.sickId) {
                nowClusterType.value.push(item.info);
                map.value.setCenter([item.lnglat.lng, item.lnglat.lat + 0.0002], true);
                map.value.setZoom(20, true);
                var infoWindow: any = new window.AMap.InfoWindow({
                  offset: new window.AMap.Pixel(0, -70),
                  content: MarkerInfo.value.$el,
                  anchor: 'bottom-center',
                });
                setTimeout(() => {
                  infoWindow.open(map.value, [item.lnglat.lng, item.lnglat.lat]);
                  fakeMarker.value = new window.AMap.Marker({
                    map: map.value,
                    position: [item.lnglat.lng, item.lnglat.lat],
                    offset: new window.AMap.Pixel(-16, -66),
                    icon: new window.AMap.Icon({
                      size: new window.AMap.Size(32, 74), // 图标尺寸
                      image: require('../../../assets/images/map/alarm-yellow.png'), // Icon的图像
                      imageOffset: new window.AMap.Pixel(0, 0), // 图像相对展示区域的偏移量,适于雪碧图等
                      imageSize: new window.AMap.Size(32, 74), // 根据所设置的大小拉伸或压缩图片
                    }),
                  });
                }, 200);
              }
            });
          }
        }
      );
      watch(
        () => prop.roadRecord,
        () => {
          let path: any = [];
          removeRecord(false);
          if (prop.roadRecord.length === 0) return;
          prop.roadRecord.forEach((items: any) => {
            path.push([
              coordtransform.wgs84togcj02(items.longitude, items.latitude)[0],
              coordtransform.wgs84togcj02(items.longitude, items.latitude)[1],
            ]);
          });
          record.value.line = new window.AMap.Polyline({
            path: path,
            strokeColor: '#00F9FF',
            strokeOpacity: 1,
            strokeWeight: 3,
            strokeStyle: 'solid',
          });
          record.value.car = new window.AMap.Marker({
            map: map.value,
            position: path[0],
            offset: new window.AMap.Pixel(-14, -25),
            icon: new window.AMap.Icon({
              size: new window.AMap.Size(28, 50), // 图标尺寸
              image: require('../../../assets/images/map/car.png'), // Icon的图像
              imageOffset: new window.AMap.Pixel(0, 0), // 图像相对展示区域的偏移量,适于雪碧图等
              imageSize: new window.AMap.Size(28, 50), // 根据所设置的大小拉伸或压缩图片
            }),
          });
          record.value.start = new window.AMap.Marker({
            map: map.value,
            position: path[0],
            offset: new window.AMap.Pixel(-16, -55),
            icon: new window.AMap.Icon({
              size: new window.AMap.Size(32, 55), // 图标尺寸
              image: require('../../../assets/images/map/start.png'), // Icon的图像
              imageOffset: new window.AMap.Pixel(0, 0), // 图像相对展示区域的偏移量,适于雪碧图等
              imageSize: new window.AMap.Size(32, 55), // 根据所设置的大小拉伸或压缩图片
            }),
          });
          record.value.end = new window.AMap.Marker({
            map: map.value,
            position: path[path.length - 1],
            offset: new window.AMap.Pixel(-16, -55),
            icon: new window.AMap.Icon({
              size: new window.AMap.Size(32, 55), // 图标尺寸
              image: require('../../../assets/images/map/end.png'), // Icon的图像
              imageOffset: new window.AMap.Pixel(0, 0), // 图像相对展示区域的偏移量,适于雪碧图等
              imageSize: new window.AMap.Size(32, 55), // 根据所设置的大小拉伸或压缩图片
            }),
          });
          record.value.start.dom.classList.add('marker-bottom');
          record.value.end.dom.classList.add('marker-bottom');

          record.value.car.moveAlong(path, {
            duration: 100, //可根据实际采集时间间隔设置
            autoRotation: true,
          });
          map.value.add(record.value.line);
          map.value.setFitView(record.value.line);
        },
        { deep: true }
      );
      return {
        nowClusterType,
        MarkerInfo,
      };
    },
  });
</script>

地图样式

<style scoped lang="less">
  #map-container {
    width: 100%;
    height: 100%;
    background-color: black;
    :deep(.amap-info-content) {
      padding: 0;
      background-color: transparent;
      box-shadow: none;
    }
    :deep(.amap-info-sharp) {
      border-top: 0 solid transparent;
      bottom: 20px;
    }
    :deep(.amap-layer) {
      background-color: black;
    }
    :deep(.amap-marker) {
	  &.marker-bottom {
	    &::after {
	      content: '';
	      position: absolute;
	      bottom: -9px;
	      left: 7px;
	      height: 18px;
	      width: 18px;
	      border-radius: 50%;
	      background: linear-gradient(180deg, #99f4f6, #00f9ff);
	      transform: rotateX(30deg);
	    }
	  }
	}
  }
</style>

地图加载方法

export function loadAMap() {
  return new Promise((resolve, reject) => {
    AMapLoader.load({
      key: '', // 申请好的Web端开发者Key,首次调用 load 时必填
      version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
      plugins: [
        'AMap.ControlBar',
        'AMap.LineSearch',
        'AMap.StationSearch',
        'AMap.PolylineEditor',
        'AMap.PolygonEditor',
        'AMap.CircleEditor',
        'AMap.AutoComplete',
        'AMap.DistrictSearch',
        'AMap.PlaceSearch',
        'AMap.MouseTool',
        'AMap.moveAnimation',
        'AMap.MarkerCluster',
      ], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
    })
      .then((AMap: any) => {
        window.AMap = AMap;
        resolve(window.AMap);
      })
      .catch((e: any) => {
        console.log(e);
        reject();
      });
  });
}

车辆移动

let position: number[] = [
  coordtransform.wgs84togcj02(
    position_3d.lon,
    position_3d.lat
  )[0],
  coordtransform.wgs84togcj02(
    position_3d.lon,
    position_3d.lat
  )[1],
]const currentPosition = [
  obuMarker.value.getPosition().lng,
  obuMarker.value.getPosition().lat,
];
const currentDis = window.AMap.GeometryUtil.distance(currentPosition, position);
const currentMileage = 5;
if (currentDis >= currentMileage) {
  window.AMap.plugin(['AMap.MoveAnimation'], () => {
    obuMarker.value.moveTo(position, {
      duration: 1000,
      autoRotation: true,
    });
  });
}

展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值