一、技术栈
Vue 3 + Typescript +Openlayers 7 + Element plus
二、组件代码
- OLPopup.vue
<template>
<div id="popup" class="olPopup" v-show="selectState">
<a href="#" id="popupCloser" class="olPopupCloser" @click="removePopup"></a>
<div id="popupContent" v-show="featureAmount > -1">
<table>
<tr>
<th>当前坐标:</th>
<td>{{ lonAndLat }}</td>
</tr>
</table>
<div v-show="featureAmount > 0">
<table>
<tr>
<th>矢量类型:</th>
<td>{{ type[layerIndex] }}</td>
</tr>
<tr>
<th>图层名称:</th>
<td>{{ name[layerIndex] }}</td>
</tr>
</table>
<el-button v-show="featureAmount > 1" @click="changePopup"
>切换</el-button
>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { Feature, Map } from "ol";
import { toLonLat } from "ol/proj";
import Overlay from "ol/Overlay.js";
import bus from "@/utils/bus.ts"; //定义声明文件再引入
import { Coordinate, toStringHDMS } from "ol/coordinate";
import { FeatureLike } from "ol/Feature";
import { Pixel } from "ol/pixel";
let mapCopy: Map;
let popupContainer: HTMLElement;
let popup: Overlay;
let lonAndLat = ref(""); //经纬度
const name = ref<string[]>([]); //图层名称
const type = ref<string[]>([]); //矢量类型
const selectState = ref<boolean>(false); //弹窗状态
let featureAmount = ref<number>(0); //选中矢量要素个数
let layerIndex = ref<number>(0); //图层显示索引
// 添加弹窗
const addPopup = (clickCrd: Coordinate, clickPixel: Pixel) => {
//获取弹出框DOM
popupContainer = document.getElementById("popup") as HTMLElement;
//创建弹出层并绑定DOM
popup = new Overlay({
element: popupContainer as HTMLElement,
autoPan: {
animation: {
duration: 250,
},
},
});
lonAndLat.value = toStringHDMS(toLonLat(clickCrd, "EPSG:4548")); //转换为经纬度坐标
// 判断点击位置的要素
let featuresVector: Feature[] = [];
mapCopy.forEachFeatureAtPixel(clickPixel, (f: FeatureLike) => {
featuresVector.push(f as Feature);
});
featureAmount.value = featuresVector.length; //获取到的元素的个数
for (let i = 0; i < featureAmount.value; i++) {
//循环获取元素名称与类型
name.value.push(featuresVector[i].get("district"));
type.value.push(featuresVector[i].getGeometry()?.getType() as string);
}
mapCopy.addOverlay(popup);
//设置位置
popup.setPosition(clickCrd);
};
//关闭弹窗
const removePopup = () => {
popup.setPosition(undefined);
selectState.value = false; //关闭弹窗状态
};
//切换要素信息弹窗
const changePopup = () => {
if (layerIndex.value < featureAmount.value - 1) {
layerIndex.value++;
} else {
alert("已经没有更多图层了");
}
};
//监听map数据
bus.on("mapToChecked", (res: Map) => {
// 传参由回调函数中的形参接受
mapCopy = res;
//监听click事件
mapCopy.on("click", (event) => {
//更新弹窗状态为开启
selectState.value = true;
//判断地图实例上是否存在绘制交互,如果存在,关闭弹窗
mapCopy
.getInteractions()
.getArray()
.some((item) => {
if (item.getProperties().name === "Draw") {
selectState.value = false;
}
});
const clickCoordinate: Coordinate = event.coordinate; //获取点击坐标
const clickPixel: Pixel = event.pixel; //获取点击位置
featureAmount.value = 0; //每次点击都置空个数
name.value = []; //置空名称数组
type.value = []; //置空类型数组
layerIndex.value = 0; //归零显示图层索引
addPopup(clickCoordinate, clickPixel); //挂载添加弹窗函数
});
});
</script>
<style>
.olPopup {
position: absolute;
background-color: white;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
padding: 15px;
border-radius: 10px;
border: 1px solid #cccccc;
bottom: 12px;
left: -50px;
min-width: 350px;
}
.olPopup:after,
.olPopup:before {
top: 100%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
.olPopup:after {
border-top-color: white;
border-width: 10px;
left: 48px;
margin-left: -10px;
}
.olPopup:before {
border-top-color: #cccccc;
border-width: 11px;
left: 48px;
margin-left: -11px;
}
.olPopupCloser {
text-decoration: none;
position: absolute;
top: 2px;
right: 8px;
}
.olPopupCloser:after {
content: "✖";
}
</style>