接上篇添加标点,当点击标点的时候出现弹框
思路:当地图初始化完成之后就直接将 弹框 和点击事件挂载在地图上,只是没有显示,后续只是点击哪个点使弹框出现在哪个点的位置上。注意,此处是 vue3 setup,如需 vue2 可自行更改
1、引入需要的方法,创建弹框变量
<!-- 弹框 dom -->
<div id="popup" ref="mapContent" v-html="mapText"></div>
// 此处引用替换即可
import 'ol/ol.css'
import TileLayer from 'ol/layer/Tile'
import VectorLayer from 'ol/layer/Vector'
import VectorSource from 'ol/source/Vector'
import XYZ from 'ol/source/XYZ'
import { Map, View, Feature, Overlay } from 'ol'
import { Style, Fill, Icon, Text } from 'ol/style'
import { Point } from 'ol/geom'
import { fromLonLat, transform } from 'ol/proj'
import { onMounted, reactive, ref } from 'vue'
// 弹框
const overlay = ref(null) // 弹框实例
const mapContent = ref(null) // 弹框挂载的 dom 元素
const mapText = ref(null) // 弹框内容
2、创建弹框方法
// 创建弹框
const createOverlay = () => {
overlay.value = new Overlay({
element: mapContent.value, // 将弹框挂载在 dom 上
autoPan: true, // 如果弹框显示不全则自动归位
positioning: 'bottom-center', // 相对标点的实际位置
stopEvent: true, // 冒泡
autoPanAnimation: {
duration: 300 // 地图移动速度
}
})
map.value.addOverlay(overlay.value) // 将弹框添加到地图上
}
3、地图添加点击事件
在点击标点的时候需要将弹框显示出来,在点击没有标点的区域时标点要关闭
// 地图点击事件
const mapClick = (e) => {
const lonlat = transform(e.coordinate, 'EPSG:3857', 'EPSG:4326')
console.log(lonlat, '点击经纬度')
// 判断当前点击是否点击在图标上
const feature = map.value.forEachFeatureAtPixel(e.pixel, (feature) => feature)
console.log(feature, 'feature')
console.log(e.coordinate, '点击坐标')
if (feature) {
// 弹框内容
mapText.value = `<p>${feature.values_.address}<p>`
// 把 overlay 显示到指定的坐标位置
overlay.value.setPosition(fromLonLat(feature.values_.long))
} else {
// 弹框关闭
closeMapPopup()
}
}
4、关闭弹框
避免后续还有其他关闭弹框操作,这里将关闭弹框写成方法
// 关闭弹框
const closeMapPopup = () => {
overlay.value.setPosition(undefined)
}
5、初始化地图之后将点击事件和初始化弹框挂载在 map 上
// 初始化地图
const init = () => {
const tileLayer = new TileLayer({
source: new XYZ({
// 瓦片加载地址
url: 'http://127.0.0.1:9098/arcgis/{z}/{x}/{y}.png'
})
})
map.value = new Map({
layers: [tileLayer],
view: new View(mapView),
target: 'map'
})
// 初始化地图之后就将弹框挂载好,后续只是修改显示的位置
createOverlay()
// 地图点击
map.value.on('click', (e) => mapClick(e))
}
6、弹框出来啦,看看效果
7、最后附上完整代码
<template>
<div id="map" />
<!-- 弹框 dom -->
<div id="popup" ref="mapContent" v-html="mapText"></div>
</template>
<script setup>
import 'ol/ol.css'
import TileLayer from 'ol/layer/Tile'
import VectorLayer from 'ol/layer/Vector'
import VectorSource from 'ol/source/Vector'
import XYZ from 'ol/source/XYZ'
import { Map, View, Feature, Overlay } from 'ol'
import { Style, Fill, Icon, Text } from 'ol/style'
import { Point } from 'ol/geom'
import { fromLonLat, transform } from 'ol/proj'
import { onMounted, reactive, ref } from 'vue'
const mapView = reactive({
center: fromLonLat([108.939062, 34.374741]), // 地图中心点
zoom: 11, // 初始缩放级别
minZoom: 10, // 最小缩放级别
maxZoom: 17 // 最大缩放级别
})
let map = ref(null)
// 弹框
const overlay = ref(null)
const mapContent = ref(null)
const mapText = ref(null)
// 初始化地图
const init = () => {
const tileLayer = new TileLayer({
source: new XYZ({
// 此处瓦片地址和 vue2 中的一样,可在本地测
url: 'http://127.0.0.1:9098/arcgis/{z}/{x}/{y}.png'
})
})
map.value = new Map({
layers: [tileLayer],
view: new View(mapView),
target: 'map'
})
// 初始化地图之后就将弹框挂载好,后续只是修改显示的位置
createOverlay()
// 地图点击
map.value.on('click', (e) => mapClick(e))
}
// 添加点位
const addLayer = (v) => {
const layer = new VectorLayer({
source: new VectorSource()
})
// 添加图层
map.value.addLayer(layer)
// 创建 feature 坐标信息
const feature = new Feature({
// 经纬度转换成坐标信息
geometry: new Point(fromLonLat(v.long)),
// 可以带别的参数,key 可以随便写,不冲突就行,这里将所有的参数都放进来,供后续使用
...v
})
feature.setStyle(
new Style({
// 标点的图片,如果要标不同类型的点,这个图片可以判断加
image: new Icon({
crossOrigin: 'anonymous',
src: require('../assets/people_mark.png')
}),
// 标点的文字
text: new Text({
// 文字
text: v.name,
// 文字样式
fill: new Fill({
color: 'red'
}),
font: '20px Calibri',
// 偏移量
offsetY: 20
})
})
)
// 将 feature 坐标信息添加在地图上
layer.getSource().addFeatures([feature])
}
// 创建弹框
const createOverlay = () => {
overlay.value = new Overlay({
element: mapContent.value, // 将弹框挂载在 dom 上
autoPan: true, // 如果弹框显示不全则自动归位
positioning: 'bottom-center', // 相对于其位置属性的实际位置
stopEvent: true, // 事件冒泡
autoPanAnimation: {
duration: 300 // 地图移动速度
}
})
map.value.addOverlay(overlay.value) // 将弹框添加到地图上
}
// 关闭弹框
const closeMapPopup = () => {
overlay.value.setPosition(undefined)
}
// 地图点击
const mapClick = (e) => {
const lonlat = transform(e.coordinate, 'EPSG:3857', 'EPSG:4326')
console.log(lonlat, '点击经纬度')
// 判断当前点击是否点击在图标上
const feature = map.value.forEachFeatureAtPixel(e.pixel, (feature) => feature)
console.log(feature, 'feature')
console.log(e.coordinate, '点击坐标')
if (feature) {
// 弹框内容
mapText.value = `<p>${feature.values_.title}<p>`
// 把 overlay 显示到指定的坐标位置
overlay.value.setPosition(fromLonLat(feature.values_.long))
} else {
// 弹框关闭
closeMapPopup()
}
}
onMounted(() => {
// 初始化地图
init()
// 创建点位数组
const peoples = [
{
name: '张三',
title: '化工大院',
long: [108.93311, 34.272099]
},
{
name: '李四',
title: '东仪小区',
long: [108.936751, 34.209511]
},
{
name: '王五',
title: '紫郡长安',
long: [108.937921, 34.189151]
}
]
// 循环将每个人都添加在地图上
peoples.forEach((v) => {
addLayer(v)
})
})
</script>
<style scoped>
#map {
width: 100%;
height: 100%;
position: absolute;
}
#popup {
background-color: #fff;
filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2));
padding: 15px;
border-radius: 10px;
border: 1px solid #cccccc;
top: 0;
left: 0;
}
</style>