直接上代码 注意的点 需要引入css文件 不然地图会混乱 其他的代码简介可直接借鉴
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import L from 'leaflet'
import 'leaflet/dist/leaflet.css'
import { getLineinfos } from '@/api/dashboard/map/index'
import 'leaflet.markercluster' // 引入 MarkerCluster 插件
defineOptions({
name: 'DashboardMap'
})
const mapContainer = ref(null)
const initMap = () => {
if (mapContainer.value) {
// 初始化 Leaflet 地图
const map = L.map(mapContainer.value, {
// center: [30.5928, 114.3055], // 地图中心坐标
zoom: 13, // 默认缩放级别
attributionControl: false // 禁用默认的版权信息
})
// 配置离线瓦片
const offlineTilesUrl = 'http://113.57.103.251:5001/map?x={x}&y={y}&z={z}' // 离线瓦片的 URL 模板
L.tileLayer(offlineTilesUrl, {
minZoom: 0,
maxZoom: 13,
tileSize: 256,
subdomains: 'abcd', // 使用多个子域名加载瓦片
errorTileUrl: '/assets/imgs/logo.png' // 错误瓦片的 URL
}).addTo(map)
setValues(map)
}
}
onMounted(initMap)
const setValues = async (map) => {
const res = await getLineinfos()
if (res.data) {
// 创建 LayerGroup
const layerGroup = L.layerGroup()
// 处理数据
res.data.forEach((item) => {
const points = item.infos
// 绘制线路
const polyline = L.polyline(
points.map((p) => [p.lat, p.lng]),
{
color: 'red',
weight: 4,
opacity: 0.9,
smoothFactor: 1
}
).addTo(map)
// 创建标记并添加到组
points.forEach((point) => {
const marker = L.circleMarker([point.lat, point.lng], {
radius: 5, // 可以根据需要调整半径
fillColor: 'blue',
color: 'blue',
weight: 1,
opacity: 1,
fillOpacity: 0.8
})
// 将标记加入到组
layerGroup.addLayer(marker)
// 鼠标悬停事件
marker.on('mouseover', function () {
const popupContent = `<p style="font-size:18px;font-weight:700;text-align: center;margin:5px 0">${item.lname}</p>
<span style="font-size:16px;font-weight:700;margin:2px 0">span:</span><span style="font-size:16px"> ${point.id}</span><br/>
<span style="font-size:16px;font-weight:700;margin:2px 0">lon:</span> <span style="font-size:16px"> ${point.lng}°</span><br/>
<span style="font-size:16px;font-weight:700;margin:2px 0">lat:</span> <span style="font-size:16px"> ${point.lat}°</span><br/>
<span style="font-size:16px;font-weight:700;margin:2px 0">alt:</span> <span style="font-size:16px"> ${point.alt}m</span>`
marker.bindPopup(popupContent).openPopup()
})
// 鼠标移出事件
marker.on('mouseout', function () {
marker.closePopup()
})
})
})
// 将 LayerGroup 添加到地图
map.addLayer(layerGroup)
// 调整地图视野以适应所有点
const allPoints = res.data.flatMap((item) => item.infos.map((p) => [p.lat, p.lng]))
const bounds = L.latLngBounds(allPoints)
map.fitBounds(bounds)
}
}
</script>
<template>
<div id="map-container" ref="mapContainer"></div>
</template>
<style scoped lang="less">
#map-container {
padding: 0px;
margin: 0px;
width: 100%;
height: 100%;
}
#map-container :deep(.description) {
background-color: #fff;
height: 50px;
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
box-sizing: border-box;
border: 2px solid #f05b72;
border-radius: 5px;
font-size: 14px;
}
#map-container :deep(.point) {
display: inline-block;
width: 9px;
height: 9px;
border-radius: 50%;
background-color: #f05b72;
margin-bottom: 1px;
margin-right: 2px;
}
#map-container :deep(.name-box) {
display: inline;
margin-right: 8px;
}
#map-container :deep(.alarmDevice) {
text-align: center;
margin: 0 auto;
width: 30px;
height: 30px;
background-color: #f13737;
box-shadow: 0px 0px 15px #f61212;
border-radius: 50%;
--webkit-animation-name: 'alarmDeviceBreath'; /*动画属性名,也就是我们前面keyframes定义的动画名*/
--webkit-animation-duration: 1s; /*动画持续时间*/
--webkit-animation-timing-function: ease; /*动画频率,和transition-timing-function是一样的*/
--webkit-animation-delay: 0s; /*动画延迟时间*/
--webkit-animation-iteration-count: infinite; /*定义循环资料,infinite为无限次*/
--webkit-animation-direction: alternate; /*定义动画方式*/
}
</style>
<style>
@keyframes alarmDeviceBreath {
0% {
margin-left: 0;
margin-top: 0;
width: 30px;
height: 30px;
box-shadow: 0px 0px 15px #f61212;
opacity: 1.2;
}
100% {
margin-left: 5px;
margin-top: 5px;
width: 20px;
height: 20px;
box-shadow: 0px 0px 10px #f61212;
opacity: 0.6;
}
}
</style>