
<template>
<!-- 使用 OpenLayers 的 Overlay 弹窗 -->
<div ref="popupEl" class="ol_log_popup_container">
<a class="popup-closer" @click="closePopup">×</a>
<div class="popup-content">
<slot name="popup" :feature="currentFeature">
<p>{{ dialogInfo.file_name }}</p>
</slot>
</div>
</div>
</template>
<script setup>
import { ref, reactive, toRefs, onMounted, onUnmounted, watch,nextTick } from 'vue';
import { Map, View, Overlay } from 'ol';
import OSM from 'ol/source/OSM';
import TileLayer from 'ol/layer/Tile';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import { Point } from 'ol/geom';
import { fromLonLat } from 'ol/proj';
import Feature from 'ol/Feature.js';
import { Style, Circle, Fill, Stroke } from 'ol/style';
import { storeToRefs } from 'pinia';
import { useUavInfoStore } from '@/stores/uavInfo';
const uavInfo = useUavInfoStore();
const { logInfoList } = storeToRefs(uavInfo);
const state = reactive({
dialogInfo: {},
layers: [],
});
const { dialogInfo, layers } = toRefs(state);
const popupEl = ref(null);
const map = ref(null);
const overlay = ref(null);
const vectorSource = ref(new VectorSource());
const currentFeature = ref(null);
let clickHandler = null;
const initDot = () => {
map.value = window.viewer2D;
layers.value = new VectorLayer({
source: vectorSource.value,
style: new Style({
image: new Circle({
radius: 10,
fill: new Fill({ color: 'red' }),
stroke: new Stroke({ color: 'white', width: 2 }),
}),
}),
zIndex: 1000,
});
map.value.addLayer(layers.value);
overlay.value = new Overlay({
element: popupEl.value,
autoPan: true,
positioning: 'center-center',
offset: [0, 0],
autoPanAnimation: {
duration: 250,
},
});
map.value.addOverlay(overlay.value);
clickHandler = map.value?.addEventListener('click', handleMapClick);
};
const handleMapClick = (evt) => {
const feature = map.value.forEachFeatureAtPixel(evt.pixel, (f) => f);
if (feature && feature.values_?.info?.featureType == 'dotModule') {
currentFeature.value = feature;
console.log(feature.getGeometry().getCoordinates(), 'setPosition');
overlay.value.setPosition(feature.getGeometry().getCoordinates());
console.log(currentFeature.value.values_.info, 'feature');
dialogInfo.value = feature.values_?.info;
} else {
overlay.value.setPosition(undefined);
dialogInfo.value = {};
}
};
const closePopup = () => {
overlay.value.setPosition(undefined);
currentFeature.value = null;
};
const updateFeatures = () => {
if (clickHandler) {
console.log('先移除旧监听');
unByKey(clickHandler);
}
vectorSource.value.clear();
logInfoList.value.forEach((point) => {
let temp = [point?.metadata?.shootPosition?.lng, point?.metadata?.shootPosition?.lat];
const feature = new Feature({
geometry: new Point(temp),
info: { ...point, featureType: 'dotModule' },
});
vectorSource.value.addFeature(feature);
});
};
onMounted(() => {
nextTick(() => {
initDot();
});
});
onUnmounted(() => {
closePopup();
vectorSource.value.clear();
dialogInfo.value = {};
});
watch(
logInfoList,
(val) => {
if (val.length > 0) {
updateFeatures();
} else {
closePopup();
vectorSource.value.clear();
dialogInfo.value = {};
}
},
{ deep: true }
);
</script>
<style>
.ol_log_popup_container {
position: absolute;
background: linear-gradient(133deg, rgba(17, 64, 158, 0.87) 2%, rgba(5, 16, 38, 0.86) 100%);
color:#fff;
padding: 15px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
min-width: 300px;
transform: translateX(-50%);
left: 0;
top: -80px;
}
.popup-closer {
position: absolute;
top: 5px;
right: 8px;
cursor: pointer;
color: #666;
}
</style>
<template>
<div class="map_main">
<div id="mapContainer" ></div>
<DotModule />
</div>
</template>
import AddDotModule from './component/addDotModule.vue';