Files
map-demo/CampusMap.vue
2026-03-06 06:03:12 +00:00

277 lines
7.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="campus-map-container">
<div ref="mapContainer" class="campus-map"></div>
<div class="map-controls">
<button @click="goToBuildingDetail" class="control-btn">进入建筑详情</button>
<button @click="resetView" class="control-btn">重置视图</button>
</div>
</div>
</template>
<script>
import L from 'leaflet'
import 'leaflet/dist/leaflet.css'
export default {
name: 'CampusMap',
emits: ['navigate'],
data() {
return {
map: null,
mapConfig: {
// 园区地图的边界坐标(使用更合理的默认尺寸)
imageWidth: 1200, // 假设图片宽度
imageHeight: 800, // 假设图片高度
// 标点位置(使用相对位置,更容易看到)
markers: [
{ id: 'building1', position: [530, 280], name: '建筑A', target: 'helloWorld' },
{ id: 'building2', position: [800, 500], name: '建筑B', target: 'helloWorld' }
]
}
}
},
mounted() {
this.initMap()
},
beforeUnmount() {
if (this.map) {
this.map.remove()
this.map = null
}
},
methods: {
initMap() {
if (!this.$refs.mapContainer) return
// 创建地图实例
this.map = L.map(this.$refs.mapContainer, {
crs: L.CRS.Simple, // 使用简单坐标系
minZoom: -2,
maxZoom: 4
})
// 使用配置的图片尺寸
const imageWidth = this.mapConfig.imageWidth
const imageHeight = this.mapConfig.imageHeight
// 设置地图边界
const southWest = this.map.unproject([0, imageHeight], this.map.getMaxZoom())
const northEast = this.map.unproject([imageWidth, 0], this.map.getMaxZoom())
const bounds = new L.LatLngBounds(southWest, northEast)
// 添加图片作为底图
L.imageOverlay('/zhenggui.png', bounds).addTo(this.map)
// 设置地图视图到整个图片范围
this.map.fitBounds(bounds)
// 添加标点
this.addMarkers()
// 添加缩放控件
L.control.zoom({
position: 'topright'
}).addTo(this.map)
},
addMarkers() {
this.mapConfig.markers.forEach(markerConfig => {
// 将自定义坐标转换为地图坐标
const mapPoint = this.map.unproject(markerConfig.position, this.map.getMaxZoom())
// 创建更醒目的自定义图标
const customIcon = L.divIcon({
html: `
<div class="custom-marker" style="cursor: pointer;">
<div class="marker-pin" style="background: #ff4444; border: 3px solid white; width: 40px; height: 40px; border-radius: 50% 50% 50% 0; transform: rotate(-45deg); box-shadow: 0 0 10px rgba(255, 0, 0, 0.8);"></div>
<div class="marker-label" style="position: absolute; top: -35px; left: 50%; transform: translateX(-50%); background: #ff4444; color: white; padding: 4px 12px; border-radius: 20px; font-size: 14px; font-weight: bold; white-space: nowrap; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); border: 2px solid white;">${markerConfig.name}</div>
</div>
`,
className: 'custom-div-icon',
iconSize: [40, 50],
iconAnchor: [20, 50]
})
// 添加标记
const marker = L.marker(mapPoint, { icon: customIcon }).addTo(this.map)
// 添加调试信息
console.log(`添加标记: ${markerConfig.name},位置:`, markerConfig.position)
// 添加点击事件
marker.on('click', () => {
this.handleMarkerClick(markerConfig)
})
// 添加悬停效果(使用不改变位置的样式)
marker.on('mouseover', () => {
const element = marker.getElement()
if (element) {
const pin = element.querySelector('.marker-pin')
const label = element.querySelector('.marker-label')
if (pin) {
pin.style.background = '#ff0000'
pin.style.boxShadow = '0 0 15px rgba(255, 0, 0, 1)'
pin.style.transform = 'rotate(-45deg) scale(1.1)'
}
if (label) {
label.style.background = '#ff0000'
label.style.boxShadow = '0 4px 12px rgba(255, 0, 0, 0.6)'
}
}
})
marker.on('mouseout', () => {
const element = marker.getElement()
if (element) {
const pin = element.querySelector('.marker-pin')
const label = element.querySelector('.marker-label')
if (pin) {
pin.style.background = '#ff4444'
pin.style.boxShadow = '0 0 10px rgba(255, 0, 0, 0.8)'
pin.style.transform = 'rotate(-45deg) scale(1)'
}
if (label) {
label.style.background = '#ff4444'
label.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.3)'
}
}
})
})
},
handleMarkerClick(markerConfig) {
console.log(`点击了标记: ${markerConfig.name}`)
// 根据标记配置跳转到对应页面
if (markerConfig.target === 'helloWorld') {
this.$emit('navigate', 'helloWorld')
}
},
goToBuildingDetail() {
// 触发导航事件跳转到HelloWorld页面平面图
this.$emit('navigate', 'helloWorld')
},
resetView() {
if (this.map) {
// 重新计算边界并重置视图
const imageWidth = 2000
const imageHeight = 1500
const southWest = this.map.unproject([0, imageHeight], this.map.getMaxZoom())
const northEast = this.map.unproject([imageWidth, 0], this.map.getMaxZoom())
const bounds = new L.LatLngBounds(southWest, northEast)
this.map.fitBounds(bounds)
}
}
}
}
</script>
<style scoped>
.campus-map-container {
position: relative;
width: 100%;
height: 100vh;
overflow: hidden;
}
.campus-map {
width: 100%;
height: 100%;
}
.map-controls {
position: absolute;
top: 20px;
right: 20px;
z-index: 1000;
display: flex;
flex-direction: column;
gap: 10px;
}
.control-btn {
padding: 10px 16px;
background: #fff;
border: 2px solid #1890ff;
border-radius: 6px;
color: #1890ff;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.3s ease;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
.control-btn:hover {
background: #1890ff;
color: #fff;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.4);
}
.control-btn:active {
transform: translateY(0);
}
/* 自定义标记样式 */
.custom-marker {
position: relative;
text-align: center;
}
.marker-pin {
width: 30px;
height: 30px;
background: #ff6b6b;
border: 3px solid #fff;
border-radius: 50% 50% 50% 0;
transform: rotate(-45deg);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}
.marker-label {
position: absolute;
top: -25px;
left: 50%;
transform: translateX(-50%);
background: #fff;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: bold;
white-space: nowrap;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
border: 1px solid #ddd;
}
.marker-hover .marker-pin {
background: #ff5252;
transform: rotate(-45deg) scale(1.1);
}
.marker-hover .marker-label {
background: #1890ff;
color: #fff;
}
/* Leaflet 样式调整 */
:deep(.leaflet-control-zoom) {
border: none;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
:deep(.leaflet-control-zoom a) {
background: #fff;
border: none;
color: #333;
font-weight: bold;
}
:deep(.leaflet-control-zoom a:hover) {
background: #f5f5f5;
}
</style>