AnalysisSystemForRadionucli.../src/views/stationOperation/components/MapMarker.vue

261 lines
6.2 KiB
Vue
Raw Normal View History

<template>
2023-06-16 18:58:31 +08:00
<div ref="mapPopupRef" class="facility-info-popover">
<h2>{{ popupTitle }} Info</h2>
<a-spin :spinning="isGettingInfo">
<div class="facility-info-item" v-for="(item, index) in columns" :key="index">
<div class="facility-info-item-label">{{ item.label }}</div>
<div class="facility-info-item-content">{{ currStationInfo[item.key] || '--' }}</div>
</div>
</a-spin>
</div>
</template>
<script>
import Overlay from 'ol/Overlay'
import { MarkerIcon } from './markerEnum'
import { fromLonLat } from 'ol/proj'
2023-06-16 18:58:31 +08:00
import PopupColumns from './markerPopupColumns'
import { getAction } from '../../../api/manage'
import { debounce } from 'lodash'
import { decimalToDms } from '@/utils/map'
const POPUP_OVERLAY_ID = 'map_popup'
export default {
props: {
list: {
type: Array,
required: true
}
},
data() {
return {
2023-06-16 18:58:31 +08:00
currStationInfo: {},
isGettingInfo: false,
columns: {},
popupTitle: ''
}
},
mounted() {
this.map = this.$parent.getMapInstance()
2023-06-16 18:58:31 +08:00
this.getStationInfo = debounce(stationInfo => {
// 查询设施详情时去抖动
if (this.isHover) {
this._getStationInfo(stationInfo)
}
}, 500)
},
methods: {
2023-06-16 18:58:31 +08:00
// 初始化marker
initMarkers() {
this.list.forEach(eventItem => {
this.map.addOverlay(this.getMarker(eventItem))
})
},
2023-06-16 18:58:31 +08:00
// 获取marker图标
getMarker(stationInfo) {
const { lon, lat } = stationInfo
const img = document.createElement('img')
img.src = MarkerIcon[stationInfo.stationType]
img.addEventListener('click', () => {
this.$emit('markerClick')
})
img.addEventListener('mouseover', () => {
this.isHover = true
this.showMapPopup(stationInfo)
})
img.addEventListener('mouseout', () => {
this.isHover = false
this.closeMapPopup()
})
return new Overlay({
position: fromLonLat([lon, lat]),
element: img,
id: stationInfo.stationId,
positioning: 'center-center'
})
},
initRipples() {
this.list.forEach(eventItem => {
2023-06-16 18:58:31 +08:00
this.map.addOverlay(this.getRipple(eventItem))
})
},
2023-06-16 18:58:31 +08:00
getRipple({ lon, lat, stationId }) {
const rippleDiv = document.createElement('div')
rippleDiv.className = 'custom-ripple'
rippleDiv.innerHTML = ` <div class="inner-ripple-1"></div>
<div class="inner-ripple-2"></div>
`
return new Overlay({
position: fromLonLat([lon, lat]),
element: rippleDiv,
id: 'ripple_' + stationId,
positioning: 'center-center'
})
},
// 初始化地图弹窗
initMapPopup() {
this.popupOverlay = new Overlay({
element: this.$refs.mapPopupRef,
2023-06-16 18:58:31 +08:00
positioning: 'top-center',
id: POPUP_OVERLAY_ID,
offset: [0, 27]
})
this.map.addOverlay(this.popupOverlay)
},
// 显示地图弹窗
2023-06-16 18:58:31 +08:00
async showMapPopup(stationInfo) {
this.popupOverlay.setPosition(fromLonLat([stationInfo.lon, stationInfo.lat]))
2023-06-16 18:58:31 +08:00
this.columns = PopupColumns[stationInfo.stationType]
this.popupTitle = stationInfo.stationType
this.isGettingInfo = true
this.getStationInfo(stationInfo)
},
2023-06-16 18:58:31 +08:00
// 获取站点详情
async _getStationInfo(stationInfo) {
try {
const { success, result, message } = await getAction('/jeecg-station-operation/stationOperation/findInfo', {
stationId: stationInfo.stationId,
type: stationInfo.stationType
})
2023-06-16 18:58:31 +08:00
if (success) {
result.lon = decimalToDms(result.lon || result.longitude)
result.lat = decimalToDms(result.lat || result.latitude, false)
this.currStationInfo = result
} else {
this.$message.error(message)
}
} catch (error) {
console.error(error)
} finally {
this.isGettingInfo = false
}
},
2023-06-16 18:58:31 +08:00
//关闭地图弹窗
closeMapPopup() {
this.popupOverlay.setPosition(null)
}
},
watch: {
list() {
2023-06-16 18:58:31 +08:00
this.map.getOverlays().clear()
this.initMapPopup()
this.initMarkers()
2023-06-16 18:58:31 +08:00
this.initRipples()
}
}
}
</script>
<style lang="less" scoped>
2023-06-16 18:58:31 +08:00
.facility-info {
&-popover {
position: relative;
width: 350px;
background-color: rgba(2, 26, 29, 0.9);
border-radius: 4px;
box-shadow: 0 0 5px rgba(2, 26, 29, 0.9);
padding: 5px;
&::before {
position: absolute;
top: -6px;
left: 50%;
content: '';
width: 12px;
height: 12px;
border: 1px solid rgba(2, 26, 29, 0.9);
background: rgba(2, 26, 29, 0.9);
transform: translateX(-50%) rotate(45deg) skew(14deg, 14deg);
border-bottom: 0;
border-right: 0;
}
h2 {
color: #6ebad0;
font-size: 16px;
text-align: center;
line-height: 30px;
border-bottom: 1px solid #0a544e;
margin-bottom: 0;
}
}
@border: 1px solid #0a544e;
&-item {
display: flex;
border: @border;
border-top: 0;
line-height: 25px;
&-label,
&-content {
width: 50%;
padding: 0 3px;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&-label {
border-right: @border;
color: #6ebad0;
}
}
}
</style>
<style lang="less">
.custom-ripple {
width: 85px;
height: 85px;
z-index: -1;
@duration: 1.8s;
@delay: 0.9s;
.inner-ripple-1 {
position: absolute;
top: 0;
width: 100%;
height: 100%;
border-radius: 50%;
background-image: radial-gradient(circle, transparent 10%, rgba(15, 148, 28, 0.1) 30%, rgba(15, 148, 28, 0.5) 60%);
animation: rippleEffect @duration linear @delay infinite;
}
.inner-ripple-2 {
position: absolute;
top: 0;
width: 100%;
height: 100%;
border-radius: 50%;
background-image: radial-gradient(circle, transparent 10%, rgba(15, 148, 28, 0.1) 30%, rgba(15, 148, 28, 0.5) 60%);
animation: rippleEffect @duration linear @delay * 2 infinite;
}
}
@keyframes rippleEffect {
0% {
transform: scale(0.6);
opacity: 1;
}
100% {
transform: scale(1.2);
opacity: 0;
}
}
</style>