背景:
在移动鼠标时显示要素的详情,同时避免在同一要素上多次触发
pointermove
事件,可以使用一些技巧来检测是否已经在当前要素上显示详情,并在必要时进行优化。
效果展示:
船舶tips,优化效果
逻辑核心:
- 创建一个 OpenLayers 地图实例,并设置目标元素为
#map
。- 创建一个矢量图层,并添加一个要素作为示例。
- 获取
#tooltip
元素,用于显示提示信息。- 定义一个变量
currentFeature
用于存储当前显示详情的要素。- 使用
map.on('pointermove', function(event) {})
方法监听pointermove
事件。- 使用
map.forEachFeatureAtPixel
方法获取鼠标位置上的要素。- 检查是否是新的要素,如果是,则更新
#tooltip
的位置和内容,并显示提示信息。如果不是新的要素,则不进行任何操作。- 如果鼠标不在任何要素上,隐藏
#tooltip
元素,并重置currentFeature
。
示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>OpenLayers pointermove 事件示例</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol/ol.css" type="text/css">
<style>
.map {
height: 100vh;
width: 100%;
}
.tooltip {
position: absolute;
background-color: rgba(0, 0, 0, 0.7);
color: white;
padding: 5px;
border-radius: 4px;
white-space: nowrap;
display: none; /* 初始隐藏 */
}
</style>
</head>
<body>
<div id="map" class="map"></div>
<div id="tooltip" class="tooltip"></div>
<script src="https://cdn.jsdelivr.net/npm/ol/ol.js"></script>
<script>
// 创建地图
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: ol.proj.fromLonLat([0, 0]),
zoom: 2
})
});
// 创建一个矢量图层,并添加一些要素
var vectorSource = new ol.source.Vector({
features: [
new ol.Feature({
geometry: new ol.geom.Point(ol.proj.fromLonLat([0, 0])),
name: '中心点'
})
]
});
var vectorLayer = new ol.layer.Vector({
source: vectorSource
});
map.addLayer(vectorLayer);
// 获取 tooltip 元素
var tooltip = document.getElementById('tooltip');
var currentFeature = null;
// 监听 pointermove 事件
map.on('pointermove', function(event) {
var feature = map.forEachFeatureAtPixel(event.pixel, function(feature) {
return feature;
});
if (feature) {
if (feature !== currentFeature) {
currentFeature = feature;
var coordinates = feature.getGeometry().getCoordinates();
var coord3857 = ol.proj.transform(coordinates, 'EPSG:3857', 'EPSG:4326');
var lon = coord3857[0].toFixed(4);
var lat = coord3857[1].toFixed(4);
tooltip.innerHTML = feature.get('name') + '<br>Longitude: ' + lon + '<br>Latitude: ' + lat;
// 更新 tooltip 的位置和显示
tooltip.style.left = event.pixel[0] + 'px';
tooltip.style.top = event.pixel[1] - 15 + 'px';
tooltip.style.display = 'block';
}
} else {
tooltip.style.display = 'none';
currentFeature = null;
}
});
</script>
</body>
</html>
二、实际运用
背景:
layui弹框、openlayer库
实现思路:
1.对创建的地图监听pointermove鼠标移动事件
MAPutils.GlobalMap.on('pointermove', function (e) {
if(e.dragging){
return
}
const pixel = MAPutils.GlobalMap.getEventPixel(e.originalEvent);
const hit = MAPutils.GlobalMap.hasFeatureAtPixel(pixel);
if (hit) {
MAPutils.GlobalMap.getTargetElement().style.cursor = 'pointer';
var feature = MAPutils.GlobalMap.forEachFeatureAtPixel(e.pixel,function (feature) {return feature;});
if (feature && feature.get("layerType") == "shipLayer") {
if(feature !== MAPutils.oldFeature){
MAPutils.oldFeature = feature
MAPutils.featureMove(feature, e);
}
}else{
MAPutils.oldFeature = null
MAPutils.oldMmsi = null
}
}else{
MAPutils.GlobalMap.getTargetElement().style.cursor = 'default';
//关闭弹框
MAPutils.DialogIndex && layer.close(MAPutils.DialogIndex || 0);
}
});
重点是:
不是同一个feature要素对象,触发地图要素移动事件
if (feature && feature.get("layerType") == "shipLayer") {
//不是同一个feature
if(feature !== MAPutils.oldFeature){
MAPutils.oldFeature = feature
MAPutils.featureMove(feature, e);
}
}else{
MAPutils.oldFeature = null
MAPutils.oldMmsi = null
}
详情弹框,内部需要发起网络请求,和打开弹框。
所以,在这儿需要判断鼠标摸上去的地图要素的id是否是同一个,如果是同一个不发起网络请求+不打开弹框。
if(MAPutils.oldMmsi !== id){
MAPutils.oldMmsi = id
}else{
setTimeout(() => {
MAPutils.oldMmsi = null
}, myTimer);
return;
}
注意:因为是判断要素id是不是同一个,所以当再次触发同一个id也不会发起网络请求,所以这儿使用定时器,一定时间把oldMMsi置为null;以达到这样的效果:当再次点击同一个id也会发起网络请求 。
/**
* 船舶tips弹窗
* @param id 船舶的id(mmsi)
* @param {Array} offset 弹窗位置
*/
shipTipPop: function (id, offset) {
var data = {};
var myTimer = 1000;
if(MAPutils.oldMmsi !== id){
MAPutils.oldMmsi = id
}else{
setTimeout(() => {
MAPutils.oldMmsi = null
}, myTimer);
return;
}
//发起网络请求,打开详情弹框
省略
}
备注:没有完整可运行的项目,只有核心代码。因为原项目太大了