1. Requirements: Different custom point markers are displayed according to different types and latitude and longitude. There are too many point markers. Use point aggregation optimization. Reference: https://blog.csdn.net/qq_39157025/article/details/120287561
2. Use CDN to introduce Gaode in index.html
<script type="module" charset="UTF-8" src="https://webapi.amap.com/loader.js"></script>
3. Get the map instance from the component
父组件:
<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. Instantiate the map
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": "32bc832dd7ff40652fc9cd78c546729a", // 申请好的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. National standard to high morality
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, complete, the effect: