高德地图 Vue3 常用操作,点、聚合、线、移动、点击事件等

高德地图 Vue3 常用操作,点、聚合、线、移动、点击事件等

初始化地图,可在设置地图样式、中心点、缩放等

let map = null;

onMounted(() => {
  initMap();
}

const initMap = () => {
  AMapLoader.load({
    key: "xxx", // 申请好的Web端开发者Key,首次调用 load 时必填
    version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
    plugins: ['AMap.MoveAnimation', 'AMap.MarkerCluster'] // 需要使用的的插件列表,如比例尺'AMap.Scale'等
  }).then((AMap) => {
    map = new AMap.Map('container1', {
      //设置地图容器id
      mapStyle: 'amap://styles/ca482dc75f8d435993e158d63b3f8695',
      viewMode: '2D', //是否为3D地图模式
      zoom: 14, //初始化地图级别
      // center: [120.576963, 30.048733] //初始化地图中心点位置
      center: [120.876508, 30.044303]
    });
    map.setDefaultCursor('pointer');

    // 根据需要创建图标(用于非聚合点位)
    stationIcon = new AMap.Icon({
      // 图标尺寸
      size: new AMap.Size(33, 49.9),
      // 图标的取图地址
      image: stationPointImg,
      // 图标所用图片大小
      imageSize: new AMap.Size(33, 49.9),
      // 图标取图偏移量
      imageOffset: new AMap.Pixel(0, 0)
    });
  })
};

<div id="container1" style="width: 100%; height: 100%"></div>

创建非聚合点位,设置点位图标、点击显示详情窗口、清除点位

function updateStationPoint(data) {
  stationMarkers = []
  data.forEach(item => {
    let marker = new AMap.Marker({
      map: map,
      position: [item.lon, item.lat],
      offset: new AMap.Pixel(-16, 0),
      icon: stationIcon,
      data: item,
    });
    marker.on('click', () => {
      showBusInfoWindow(marker._originOpts.data)
    });
    stationMarkers.push(marker);
  })
  map.add(stationMarkers)
}

const showBusInfoWindow = async (item) => {
  // 根据 item.type 动态选择组件
  let ComponentToMount;
  let siteInfo = null;
  let routeInfo = null;
  if (item.pointType === 'bus') {
    ComponentToMount = MapBusTooltip;
  } else if (item.pointType === 'site') {
    ComponentToMount = MapSiteTooltip;
    siteInfo = await queryBasicStationInfoById(item.id);
  } else if (item.pointType === 'station') {
    ComponentToMount = MapStationTooltip;
  } else if (item.pointType === 'line') {
    ComponentToMount = MapLineTooltip;
    routeInfo = await RouteApi.queryBasicRouteInfoByRouteCode(item.routeCode);
  }
  // 创建一个挂载点
  const mountPoint = document.createElement('div');
  // 挂载Vue组件
  const app = createApp(ComponentToMount, {
      item: item,
      siteInfo: siteInfo,
      routeInfo: routeInfo,
      methods: methods // 方法作为响应式对象传递
    }
  );
  app.mount(mountPoint);
  // 创建信息窗体并设置内容
  infoWindow = new AMap.InfoWindow({
    isCustom: true,
    content: mountPoint,
    offset: new AMap.Pixel(0, -0)
  });
  // 在地图上打开信息窗体
  infoWindow.open(map, [item.lon, item.lat]);

  const closeButton = document.querySelector('.close-button');
  if (closeButton) {
    closeButton.addEventListener('click', () => {
      infoWindow.close();
    });
  }

  // 在不需要时卸载组件
  infoWindow.on('close', () => {
    app.unmount();
  });
}

// 清除场站点位
function clearBusStationPoint() {
  map.remove(stationMarkers);
}

创建线条并让点跟随线条移动,调节移动速度

import busImg from '@/assets/imgs/massTransitMap/bus.svg';
import {getGpsDeTrail} from "@/api/bus/supervise";

const busTrajectoryRef = ref(null);
// 全局变量保存当前查看轨迹的线路和点位的引用
let currentPolyline = null;
let currentMarker = null;
let currentTrail = []; // 存储当前轨迹数组
let currentSpeed = 10000; // 初始速度
let showTrajectory = ref(false);
let nowPlateNum = '';

// 方法作为响应式对象传递给子组件
const methods = reactive({
  parentMethodShowTrajectory: async (plateNum) => {
    console.log(plateNum);
    console.log(nowPlateNum);
    if (plateNum) {
      nowPlateNum = plateNum;
    } else {
      plateNum = nowPlateNum;
    }
    showTrajectory.value = true;
    let dateRange = busTrajectoryRef.value.dateRange;
    // 获取轨迹
    let data = await getGpsDeTrail(plateNum, busTrajectoryformatDateTime(dateRange.start), busTrajectoryformatDateTime(dateRange.end));

    console.log(data);
    currentTrail = data.map(item => [item.lon, item.lat]);
    if (currentTrail.length > 0) {
      // 清除现有的线路和点位
      // clearMapElements();
      // closeInfoWindow();
      // clearBusEnterprisePoint();

      // 创建新的线路
      currentPolyline = new AMap.Polyline({
        map: map,
        path: currentTrail,
        showDir: true,
        strokeColor: '#28F',
        strokeWeight: 6
      });
      map.add(currentPolyline);

      // 创建新的点位
      currentMarker = new AMap.Marker({
        map: map,
        position: currentTrail[0],
        icon: busImg,
        offset: new AMap.Pixel(-13, -30)
      });

      // 移动结束事件
      currentMarker.on('moveend', function (e) {
        console.log("Movement finished");
      });

      map.setCenter(currentTrail[0], true);
    } else {
      console.log('No valid GPS data available.');
    }
  },
});

function busTrajectoryformatDateTime(dateString) {
  const date = new Date(dateString);
  return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}:${date.getSeconds().toString().padStart(2, '0')}`;
}
// 开始播放
async function startMovement() {
  // 动画移动标记
  currentMarker.moveAlong(currentTrail, {
    speed: currentSpeed,
    delay: 0
  });

}
// 暂停
function pauseMovement() {
  currentMarker.stopMove(); // 暂停移动
}
// 继续
function continueMovement() {
  currentMarker.resumeMove();
}
// 调节速度
function adjustSpeed(newSpeed) {
  currentSpeed = newSpeed;
  if (currentMarker) {
    currentMarker.moveAlong(currentTrail, {
      speed: currentSpeed,
      delay: 0
    });
  }
}

创建聚合点位,可自定义聚合样式

pointsCruiseTaxi、pointsRideHailingTaxi分开存放聚合点位,即可不同类型的点聚合到不同的聚合中

这里我初始化全部数据是用于其他全局搜索功能


// 巡游出租车、网约车数量
const taxiCount1 = ref(0);
const taxiCount2 = ref(0);

// 巡游出租车点位
let allCruiseTaxiPointData = ref([])
let cruiseTaxiPointData = ref([])
let clusterCruiseTaxi = null;
let pointsCruiseTaxi = [];
let cruiseTaxiCount = ref(pointsCruiseTaxi.length);
// 网约车点位
let allRideHailingTaxiPointData = ref([])
let rideHailingTaxiPointData = ref([])
let clusterRideHailingTaxi = null;
let pointsRideHailingTaxi = [];
let rideHailingTaxiCount = ref(pointsRideHailingTaxi.length);

async function updateCruiseTaxiData() {
  const data = await ApiTaxi.taxiCruisePoint();
  taxiCount1.value = data.length;
  // console.log(data)
  // 初始化全部数据
  if (allCruiseTaxiPointData.value.length === 0) {
    allCruiseTaxiPointData.value = data.map(item => {
      // 这里做了一次经纬度84转高德
      let gcj02 = wgs84togcj02(item.lon, item.lat);
      return {
        ...item,  // 保持其他属性不变
        lon: gcj02[0],
        lat: gcj02[1]
      };
    });
  }
  cruiseTaxiPointData.value = data.map(item => {
    let gcj02 = wgs84togcj02(item.lon, item.lat);
    return {
      ...item,
      lon: gcj02[0],
      lat: gcj02[1]
    };
  });
}

function updateCruiseTaxiPoint(data) {
  data.forEach(item => {
    pointsCruiseTaxi.push(
      {
        lnglat: [item.lon, item.lat],
        pointType: 'cruiseTaxi',
        ...item
      }
    );
  })
  cruiseTaxiCount.value = pointsCruiseTaxi.length; // 更新count以反映最新的点数量
  addCluster('cruiseTaxi');
}

function clearCruiseTaxiPoint() {
  pointsCruiseTaxi = [];
  if (clusterCruiseTaxi) {
    clusterCruiseTaxi.setMap(null); // 清除聚合点
  }
  return;
}

async function updateRideHailingTaxiData() {
  const data = await ApiTaxi.taxiRideHailingPoint();
  taxiCount2.value = data.length;
  // 初始化全部数据
  if (allRideHailingTaxiPointData.value.length === 0) {
    allRideHailingTaxiPointData.value = data.map(item => {
      let gcj02 = wgs84togcj02(item.lon, item.lat);
      return {
        ...item,  // 保持其他属性不变
        lon: gcj02[0],
        lat: gcj02[1]
      };
    });
  }
  rideHailingTaxiPointData.value = data.map(item => {
    let gcj02 = wgs84togcj02(item.lon, item.lat);
    return {
      ...item,
      lon: gcj02[0],
      lat: gcj02[1]
    };
  });
}

function updateRideHailingTaxiPoint(data) {
  data.forEach(item => {
    pointsRideHailingTaxi.push(
      {
        lnglat: [item.lon, item.lat],
        pointType: 'rideHailing',
        ...item
      }
    );
  })
  rideHailingTaxiCount.value = pointsRideHailingTaxi.length; // 更新count以反映最新的点数量
  addCluster('rideHailing');
}

function clearRideHailingPoint() {
  pointsRideHailingTaxi = [];
  if (clusterRideHailingTaxi) {
    clusterRideHailingTaxi.setMap(null); // 清除聚合点
  }
  return;
}

function addCluster(type) {
  if (type === 'cruiseTaxi') {
    if (clusterCruiseTaxi) {
      clusterCruiseTaxi.setMap(null);
    }
    clusterCruiseTaxi = new AMap.MarkerCluster(map, pointsCruiseTaxi, {
      gridSize: gridSize, // 设置网格像素大小
      renderClusterMarker: _renderClusterMarker, // 自定义聚合点样式
      renderMarker: _renderMarker, // 自定义非聚合点样式
    });
  } else if (type === 'rideHailing') {
    if (clusterRideHailingTaxi) {
      clusterRideHailingTaxi.setMap(null);
    }
    clusterRideHailingTaxi = new AMap.MarkerCluster(map, pointsRideHailingTaxi, {
      gridSize: gridSize, // 设置网格像素大小
      renderClusterMarker: _renderClusterMarker, // 自定义聚合点样式
      renderMarker: _renderMarker, // 自定义非聚合点样式
    });
  }

}

// 聚合的点位样式
const _renderClusterMarker = function (context) {
  // console.log(context)
  let count = 0;
  if (context.clusterData[0].pointType === 'cruiseTaxi') {
    count = cruiseTaxiCount.value;
  } else if (context.clusterData[0].pointType === 'rideHailing') {
    count = rideHailingTaxiCount.value;
  }
  var factor = Math.pow(context.count / count, 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 / count, 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 AMap.Pixel(-size / 2, -size / 2));
  context.marker.setContent(div)
};
// 不聚合的点位样式
const _renderMarker = function (context) {
  // console.log(context)
  let content = '<div style="background-color: hsla(180, 100%, 50%, 0.3);' +
    'height: 18px; width: 18px; ' +
    'border: 1px solid hsl(180, 100%, 40%);' +
    ' border-radius: 12px;' +
    ' box-shadow: hsl(180, 100%, 50%) 0px 0px 3px;">' +
    '</div>';
  if (context.data[0].pointType === 'cruiseTaxi') {
    content = '<div style="background-image: url(\'' + cruiseTaxiImg + '\');' +
      'height: 45.9px; ' +
      'width: 33px;' +  // 根据实际图标尺寸调整大小
      ' background-size: cover;' +  // 确保图像覆盖整个区域
      ' border-radius: 16px;' +  // 可以根据需要调整圆角
      ' box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.5);' +  // 调整阴影为适当的样式
      ' display: flex; align-items: center; justify-content: center;">' +  // 居中图标
      '</div>';
  } else if (context.data[0].pointType === 'rideHailing') {
    content = '<div style="background-image: url(\'' + rideHailingTaxiImg + '\');' +
      'height: 45.9px; ' +
      'width: 33px;' +  // 根据实际图标尺寸调整大小
      ' background-size: cover;' +  // 确保图像覆盖整个区域
      ' border-radius: 16px;' +  // 可以根据需要调整圆角
      ' box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.5);' +  // 调整阴影为适当的样式
      ' display: flex; align-items: center; justify-content: center;">' +  // 居中图标
      '</div>';
  }
  context.marker.on('click', () => {
    showInfoWindow(context.data[0])
  })
  let offset = new AMap.Pixel(-16, 0);
  context.marker.setContent(content)
  context.marker.setOffset(offset)
}


const showInfoWindow = async (item) => {
  // 根据 item.type 动态选择组件
  let ComponentToMount;
  if (item.pointType === 'cruiseTaxi') {
    ComponentToMount = MapTaxiTooltip;
  } else if (item.pointType === 'rideHailing') {
    ComponentToMount = MapTaxiTooltip;
  }
  // 创建一个挂载点
  const mountPoint = document.createElement('div');
  // 挂载Vue组件
  const app = createApp(ComponentToMount, {
      item: item,
    }
  );
  app.mount(mountPoint);
  // 创建信息窗体并设置内容
  infoWindow = new AMap.InfoWindow({
    isCustom: true,
    content: mountPoint,
    offset: new AMap.Pixel(0, -0)
  });
  // 在地图上打开信息窗体
  infoWindow.open(map, [item.lon, item.lat]);

  const closeButton = document.querySelector('.close-button');
  if (closeButton) {
    closeButton.addEventListener('click', () => {
      infoWindow.close();
    });
  }

  // 在不需要时卸载组件
  infoWindow.on('close', () => {
    app.unmount();
  });
}

创建线条,定义不同类型样式,线条点击事件

// 线路数据
let lineMapArr = []
let lineJsonData = []
let allRouteInfoList = ref([])
let currentSelectPolyline = null; // 存储当前点击的线路

function updateLine(jsonData) {
  const path = [];
  lineMapArr = [];
  jsonData.forEach((item) => {
    // 判断当前线路的类型是否在选中的类型数组中
    if (selectedBusLine.value.includes(item.routeCityType)) {
      const lineAllPath = [];
      const lineArr = item.linePoints.split(',');
      lineArr.forEach((i) => {
        const linePath = [];
        const gcj02 = wgs84togcj02(i.split(' ')[0], i.split(' ')[1]);
        linePath.push(gcj02[0], gcj02[1]);
        lineAllPath.push(linePath);
      });
      path.push(lineAllPath);
      let color = '';
      if (item.routeCityType == 1) {
        color = '#2ebd05';
      } else if (item.routeCityType == 2) {
        color = '#1784fc';
      } else if (item.routeCityType == 3) {
        color = '#FCC881';
      }
      var polyline = new AMap.Polyline({
        path: lineAllPath,
        isOutline: false,
        // outlineColor: '#ffffff',
        borderWeight: 3,
        strokeColor: color,
        strokeOpacity: 1,
        strokeWeight: 4,
        // 折线样式还支持 'dashed'
        strokeStyle: 'solid',
        // strokeStyle是dashed时有效
        strokeDasharray: [15, 5],
        lineJoin: 'round',
        lineCap: 'round',
        zIndex: 50,
        routeCode: item.routeCode
      });
      polyline.setMap(map);

      // 为线图层添加点击事件
      polyline.on('click', (e) => {
        // 如果有之前点击的线路,将其颜色恢复
        if (currentSelectPolyline) {
          currentSelectPolyline.setOptions({
            strokeColor: currentSelectPolyline.getExtData().originalColor
          });
        }

        // 将当前点击的线路设置为红色
        polyline.setOptions({
          strokeColor: '#FEA373'
        });

        // 保存当前点击的线路
        currentSelectPolyline = polyline;

        // 保存原始颜色到扩展数据
        polyline.setExtData({
          originalColor: color
        });

        // 显示信息窗口
        showBusInfoWindow({
          routeCode: item.routeCode,
          pointType: 'line',
          lon: e.lnglat.getLng(),
          lat: e.lnglat.getLat()
        });
      });
      lineMapArr.push(polyline);
    }
  });

  map.add(lineMapArr);
}

适应分辨率

如果使用了分辨率适应框架,可以让地图监听也做适应,否则点击事件会出问题,比如创建线条的点击事件时;

const initMap = () => {
  AMapLoader.load({
    key: "xxx", // 申请好的Web端开发者Key,首次调用 load 时必填
    version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
    plugins: ['AMap.MoveAnimation', 'AMap.MarkerCluster'] // 需要使用的的插件列表,如比例尺'AMap.Scale'等
  }).then((AMap) => {
    map = new AMap.Map('container1', {
      //设置地图容器id
      mapStyle: 'amap://styles/ca482dc75f8d435993e158d63b3f8695',
      viewMode: '2D', //是否为3D地图模式
      zoom: 14, //初始化地图级别
      // center: [120.576963, 30.048733] //初始化地图中心点位置
      center: [120.876508, 30.044303]
    });
    map.setDefaultCursor('pointer')

    publicBicycleStationIcon = new AMap.Icon({
      // 图标尺寸
      size: new AMap.Size(33, 49.9),
      // 图标的取图地址
      image: stationPointImg,
      // 图标所用图片大小
      imageSize: new AMap.Size(33, 49.9),
      // 图标取图偏移量
      imageOffset: new AMap.Pixel(0, 0)
    });
      
    window.addEventListener('resize', resetMapSize);
    resetMapSize(); // 初始调用,确保地图容器在首次渲染时也正确
  })
};

// 定义 fnResize 方法,计算当前缩放比例
const fnResize = () => {
  let screenWidth = document.body.clientWidth || document.documentElement.clientWidth;
  let screenHeight = document.body.clientHeight || document.documentElement.clientHeight;
  let defWidth = 1920;
  let defHeight = 1080;
  let scaleX = screenWidth / defWidth;
  let scaleY = screenHeight / defHeight;
  return {scaleX: scaleX, scaleY: scaleY};
};

// 定义 resetMapSize 方法
const resetMapSize = () => {
  const scaleWH = fnResize();
  console.log(scaleWH)
  const mapContent = document.getElementById("container1");
  if (mapContent) {
    mapContent.style.transform = `scale(${1 / scaleWH.scaleX}, ${1 / scaleWH.scaleY})`;
  }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

摘星喵Pro

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值