vue3使用高德地图,自定义点标记、默认点聚合样式、点击点标记获取信息

1、需求:根据不用的类型和经纬度展示不同的自定义点标记,点标记太多,使用点聚合优化,参考:https://blog.csdn.net/qq_39157025/article/details/120287561

在这里插入图片描述

2、在index.html使用CDN引入高德
<script type="module" charset="UTF-8" src="https://webapi.amap.com/loader.js"></script>
3、组件中获取地图实例
父组件:
<template>
  <div class="">
    <div class="">
      <div class="home-map">
        <div class="map-box">
          <div id="map-container"></div>
        </div>
        <site-info />
      </div>
    </div>
  </div>
  <a-modal
    title="Title"
    v-model:visible="visible"
    :confirm-loading="confirmLoading"
    @ok="handleOk"
  >
    <p>{{ modalText }}</p>
  </a-modal>
</template>

<script setup>
import { onMounted, reactive, ref, toRaw, getCurrentInstance, watchEffect } from 'vue';
import { request } from '../../utils/request';
import { initMap, clickSite } from "../../utils/newMap";
import siteInfo from "./components/siteInfo.vue";
const globalProperties = getCurrentInstance().appContext.config.globalProperties; // 获取全局挂载
const http = globalProperties.$http;
const toast = globalProperties.$toast;
const visible = ref(false);
const confirmLoading = ref(false);
const modalText = ref('');
const conObj = reactive({
  mapObj: {},
  map: {},
  markers: [],
})
// 监听地图站点信息变量的值
watchEffect(() => {
  if(!toRaw(clickSite.siteInfo)) {
  } else {
    console.log(toRaw(clickSite.siteInfo));
    visible.value = true;
    modalText.value = `你打开了id为${toRaw(clickSite.siteInfo).id}的点标记`;
  }
})
// 弹窗确定按钮
const handleOk = () => {
  confirmLoading.value = true;
  setTimeout(() => {
    confirmLoading.value = false;
    visible.value = false;
  }, 1000);
}
const getMap = async(data) => {
  let map = await initMap(data)
  if(map) {
    conObj.map = toRaw(map).map; // 获取地图map实例
  }
}
// 获取地图所有站点
const getSite = async () => {
  request(http.GET_HOME_HOME_ALL_SITE, 'get', {
    ownerUnit: 1
  })
    .then((res) => {
      toast("成功获取所有站点!");
      conObj.markers = res.station;
      getMap(toRaw(conObj.markers))
    })
    .catch(() => {
      
    })
    .finally(() => {
      
    })
}
onMounted(async() => {
  await getSite();
})
</script>
<style lang="less" scoped>
.home-map {
  position: relative;
  height: calc(100vh - 52px);
  width: calc(100vw - 64px);
  .map-box {
    height: 100%;
    width: 100%;
    #map-container {
      width: 100%;
      height: 100%;
    }
  }
}
</style>
子组件:
<template>
  <div class="site-info">
    <div class="site-info-title" @click="$emit('bySonVal', 4692)">
      测站信息区域
    </div>
  </div>
</template>
<script setup>
defineEmits(['bySonVal']); // 使用defineEmits和defineProps不需要导入
</script>
<style lang="less" scoped>
.site-info {
  position: absolute;
  top: 0px;
  left: 0px;
  padding: .84rem;
  background: aquamarine;
  opacity: .8;
  .site-info-title {
    
  }
}
</style>
4、实例化地图
newMap.js
// 新窨井
import inspInline from "@/assets/imgs/maps/insp_inline.png";
import inspOffline from "@/assets/imgs/maps/insp_offline.png";
import inspAlarm from "@/assets/imgs/maps/insp_alarm.png";
import inspWarn from "@/assets/imgs/maps/insp_warn.png";
// 新内涝
import waterLogInline from "@/assets/imgs/maps/waterLog_inline.png";
import waterLogOffline from "@/assets/imgs/maps/waterLog_offline.png";
import waterLogAlarm from "@/assets/imgs/maps/waterLog_alarm.png";
import waterLogWarn from "@/assets/imgs/maps/waterLog_warn.png";
// 新管网
import networkInline from "@/assets/imgs/maps/network_inline.png";
import networkOffline from "@/assets/imgs/maps/network_offline.png";
import networkAlarm from "@/assets/imgs/maps/network_alarm.png";
import networkWarn from "@/assets/imgs/maps/network_warn.png";
// 新闸门
import gateInline from "@/assets/imgs/maps/gate_inline.png";
import gateOffline from "@/assets/imgs/maps/gate_offline.png";
import gateAlarm from "@/assets/imgs/maps/gate_alarm.png";
import gateWarn from "@/assets/imgs/maps/gate_warn.png";
// 新泵站
import pumpInline from "@/assets/imgs/maps/pump_inline.png";
import pumpOffline from "@/assets/imgs/maps/pump_offline.png";
import pumpAlarm from "@/assets/imgs/maps/pump_alarm.png";
import pumpWarn from "@/assets/imgs/maps/pump_warn.png";
// 新河道水体水位
import waterInline from "@/assets/imgs/maps/water_inline.png";
import waterOffline from "@/assets/imgs/maps/water_offline.png";
import waterAlarm from "@/assets/imgs/maps/water_alarm.png";
import waterWarn from "@/assets/imgs/maps/water_warn.png";
// 新视频站
import videoInline from "@/assets/imgs/maps/video_inline.png";
import videoOffline from "@/assets/imgs/maps/video_offline.png";
import videoAlarm from "@/assets/imgs/maps/video_alarm.png";
import videoWarn from "@/assets/imgs/maps/video_warn.png";

import {
  reactive
} from 'vue';

import {
  wgs_gcj_encrypts
} from "./transformLonLat"
window._AMapSecurityConfig = {
  securityJsCode: '39800a1cd4581dbcc97dcfac34bc074e', // 安全秘钥
}
let obj = reactive({
  cluster: undefined
})
// 获取地图上站点的信息
export let clickSite = reactive({
  siteInfo: null
})
// 地图初始化
export const initMap = (markersList) => AMapLoader.load({
  "key": "32bc822dd7ff40652fc9fd78c546729a", // 申请好的Web端开发者Key,首次调用 load 时必填
  "version": "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
  "plugins": ["AMap.Pixel", "AMap.MarkerClusterer", "AMap.ToolBar"], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
}).then((AMap) => {
  const map = new AMap.Map("map-container", {
    resizeEnable: true,
    viewMode: '3D',
  });
  // 添加缩放
  map.addControl(new AMap.ToolBar());
  // 点聚合数据
  var markers = [];
  for (let i = 0; i < markersList.length; i++) {
    // 标准转高德
    let oldLat, oldLon
    // 防止有多个点而返回了NAN
    if (wgs_gcj_encrypts(markersList[i].latitude, markersList[i].longitude).lat && (wgs_gcj_encrypts(markersList[i].latitude, markersList[i].longitude).lat).length >= 9) {
      oldLat = (wgs_gcj_encrypts(markersList[i].latitude, markersList[i].longitude).lat).substr(0, 9);
    } else {
      oldLat = "0"
    }
    if (wgs_gcj_encrypts(markersList[i].latitude, markersList[i].longitude).lon && (wgs_gcj_encrypts(markersList[i].latitude, markersList[i].longitude).lon).length >= 10) {
      oldLon = (wgs_gcj_encrypts(markersList[i].latitude, markersList[i].longitude).lon).substr(0, 10);
    } else {
      oldLon = "0"
    }
    // 判断最后一位是否为 "."
    if (oldLat.length && (oldLat.charAt(oldLat.length - 1) == ".")) {
      oldLat = oldLat.substr(0, oldLat.length - 1)
    }
    if (oldLon.length && (oldLon.charAt(oldLon.length - 1) == ".")) {
      oldLon = oldLon.substr(0, oldLon.length - 1)
    }
    let lat = parseFloat(oldLat)
    let lon = parseFloat(oldLon)
    markers.push({
      lnglat: [lon, lat], // 必传参数,统一格式
      code: markersList[i].hexCode,
      id: markersList[i].id,
      status: markersList[i].status
    })
  }
  // 自定义点标记
  var _renderMarker = function (context) {
    var icon
    // 根据hexCode与status判断赋值点标记图标
    let code = context.data[0].code;
    let status = context.data[0].status;
    if (code == '62H' && status == 1) {
      icon = inspInline
    } else if (code == '62H' && status == 2) {
      icon = inspWarn
    } else if (code == '62H' && status == 3) {
      icon = inspOffline
    } else if (code == '62H' && status == 4) {
      icon = inspAlarm
    } else if (code == '60H' && status == 1) {
      icon = waterLogInline
    } else if (code == '60H' && status == 2) {
      icon = waterLogWarn
    } else if (code == '60H' && status == 3) {
      icon = waterLogOffline
    } else if (code == '60H' && status == 4) {
      icon = waterLogAlarm
    } else if (code == '61H' && status == 1) {
      icon = networkInline
    } else if (code == '61H' && status == 2) {
      icon = networkWarn
    } else if (code == '61H' && status == 3) {
      icon = networkOffline
    } else if (code == '61H' && status == 4) {
      icon = networkAlarm
    } else if (code == '5AH' && status == 1) {
      icon = gateInline
    } else if (code == '5AH' && status == 2) {
      icon = gateWarn
    } else if (code == '5AH' && status == 3) {
      icon = gateOffline
    } else if (code == '5AH' && status == 4) {
      icon = gateAlarm
    } else if (code == '44H' && status == 1) {
      icon = pumpInline
    } else if (code == '44H' && status == 2) {
      icon = pumpWarn
    } else if (code == '44H' && status == 3) {
      icon = pumpOffline
    } else if (code == '44H' && status == 4) {
      icon = pumpAlarm
    } else if (code == '48H' && status == 1) {
      icon = waterInline
    } else if (code == '48H' && status == 2) {
      icon = waterWarn
    } else if (code == '48H' && status == 3) {
      icon = waterOffline
    } else if (code == '48H' && status == 4) {
      icon = waterAlarm
    } else if (code == '70H' && status == 1) {
      icon = videoInline
    } else if (code == '70H' && status == 2) {
      icon = videoWarn
    } else if (code == '70H' && status == 3) {
      icon = videoOffline
    } else if (code == '70H' && status == 4) {
      icon = videoAlarm
    }
    // 点标记样式
    var content = `<div style="height: 30px; width: 30px;"><img style="width: 100%; height: 100%" src="${icon}"></img></div>`;
    var offset = new AMap.Pixel(-9, -9);
    context.marker.setContent(content);
    context.marker.setOffset(offset);
    // 设置标记携带的数据,点击事件会使用
    context.marker.setExtData({
      id: context.data[0].id,
      hexCode: context.data[0].code
    });
    // 单个标记点击事件
    context.marker.on('click', ev => {
      // 当前标记居中, 第一个参数为缩放级别
      map.setZoomAndCenter(18, ev.target.getPosition());
      // 获取标记携带的数据
      const extData = ev.target.getExtData();
      clickSite.siteInfo = extData; // 点击获取当前站点的信息,触发监听事件
    });

  }
  if (markers && markers.length) {
    obj.cluster = new AMap.MarkerClusterer(map, markers, {
      gridSize: 80,
      clusterByZoomChange: true,
      renderMarker: _renderMarker
    });
    // 点击点聚合
    obj.cluster.on('click', (item) => {
      //此处是通过包含点的数量判断是否是聚合点,不是聚合点就执行上方单个点的点击方式
      if (item.clusterData.length <= 1) {
        return;
      }
      //这里是计算所有聚合点的中心点
      let alllng = 0,
        alllat = 0;
      for (const mo of item.clusterData) {
        alllng += mo.lnglat.lng;
        alllat += mo.lnglat.lat;
      }
      const lat = alllat / item.clusterData.length;
      const lng = alllng / item.clusterData.length;
      //这里是放大地图,此处写死了每次点击放大的级别,可以根据点的数量和当前大小适应放大,体验更佳
      map.setZoomAndCenter(map.getZoom() + 2, [lng, lat]);
    });
  }
  return {
    AMap,
    map
  }
}).catch(e => {
  console.log(e);
})
5、国标转高德
transformLonLat.js:
//转换常数
var pi = 3.14159265358979324;
var a = 6378245.0;
var ee = 0.00669342162296594323;
function transformLon(x, y) {
  var ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
  ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
  ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
  ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0;
  return ret;
};
function transformLat(x, y) {
  var ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
  ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
  ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
  ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
  return ret;
}
function outOfChina(lat, lon) {
  if (lon < 72.004 || lon > 137.8347)
    return true;
  if (lat < 0.8293 || lat > 55.8271)
    return true;
  return false;
}
/*    
 * WGS-84:是国际标准,GPS坐标(Google Earth使用、或者GPS模块、天地图)
 * GCJ-02:中国坐标偏移标准,Google Map、高德、腾讯使用
 * BD-09:百度坐标偏移标准,Baidu Map使用
 */

/**
 * wgLat 纬度
 * wgLon 经度
 * WGS-84 到 GCJ-02 的转换(即 GPS 加偏)
 * */
export const wgs_gcj_encrypts = (wgLat, wgLon) => {
  var point = {};
  if (outOfChina(wgLat, wgLon)) {
    point.lat = wgLat;
    point.lon = wgLon;
    return point;
  }
  var dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
  var dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
  var radLat = wgLat / 180.0 * pi;
  var magic = Math.sin(radLat);
  magic = 1 - ee * magic * magic;
  var sqrtMagic = Math.sqrt(magic);
  dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
  dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
  var lat = wgLat + dLat;
  var lon = wgLon + dLon;
  point.lat = lat;
  point.lon = lon;
  return point;
};
6、完成,效果:

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

很多时候,很多事儿,想开了或者不多想,也就那回事儿。

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Vue使用高德地图聚合功能,首先需要安装并引入高德地图JavaScript API。 1. 在`index.html`文件中,添加如下代码引入高德地图API: ```html <script src="https://webapi.amap.com/maps?v=1.4.15&key=your_api_key"></script> ``` 其中,`your_api_key`是你在高德地图开放平台申请的API Key。 2. 在Vue组件中,首先在`mounted`生命周期钩子中初始化地图,并创建一个地图实例: ```javascript mounted() { // 初始化地图 AMap.initAMapApiLoader({ key: 'your_api_key', plugin: ['AMap.MarkerClusterer'] }); // 创建地图实例 this.map = new AMap.Map('mapContainer', { center: [lng, lat], // 地图中心经纬度 zoom: 13 // 地图缩放级别 }); } ``` 3. 在数据加载完成后,将需要聚合数据添加到地图上: ```javascript addMarkers() { this.points.forEach(point => { let marker = new AMap.Marker({ position: [point.lng, point.lat] // 标记位置经纬度 }); this.map.add(marker); }); } ``` 其中,`this.points`是包含标记经纬度的数组。 4. 最后,启用聚合功能,将添加的标记进行聚合: ```javascript clusterMarkers() { let cluster = new AMap.MarkerClusterer(this.map, this.map.getAllOverlays(), { gridSize: 80, // 聚合的像素大小 renderCluserMarker(cluster) { let count = cluster.getMarkers().length; let div = document.createElement('div'); div.className = 'cluster-marker'; div.innerHTML = count; return new AMap.Icon({ size: new AMap.Size(40, 40), image: 'cluster.png', imageSize: new AMap.Size(40, 40), // 自定义聚合样式和内容 div: div }); } }); } ``` 通过`AMap.MarkerClusterer`类创建一个聚合器对象,将地图实例、添加的标记聚合选项传入。 以上就是在Vue使用高德地图聚合功能的基本步骤。根据实际需求,可以进一步添加交互、自定义样式等功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值