vue2 实现openlayers添加扩散点(水波纹效果)
- 工具类
PulsingPointManager.js
import Overlay from 'ol/Overlay';
/**
* 扩散点管理器类
*/
export default class PulsingPointManager {
/**
* @param {ol.Map} map - OpenLayers 地图实例
*/
constructor(map) {
if (!map) {
throw new Error('Map instance is required');
}
this.map = map;
// 使用 Map 存储 overlay,key 为自定义 ID,value 为 Overlay 实例
// 如果没有 ID,则使用随机生成的 UUID
this.overlays = new Map();
}
/**
* 生成简单的唯一 ID
*/
_generateId() {
return 'pulsing-' + Math.random().toString(36).substr(2, 9);
}
/**
* 创建扩散点的 DOM 元素
* @param {string} color - 颜色 (可选)
* @returns {HTMLElement}
*/
_createDOMElement(color = 'rgba(255, 0, 0, 0.8)') {
const element = document.createElement('div');
element.className = 'pulsing-point';
const style = document.createElement('style');
style.textContent = `
.pulsing-point[data-color="${color}"]::before { background-color: ${color}; }
.pulsing-point[data-color="${color}"]::after { background-color: ${color.replace('0.8', '0.6')}; }
`;
element.setAttribute('data-color', color);
return element;
}
/**
* 添加一个扩散点
* @param {Array<number>} coordinate - 经纬度坐标 [lng, lat]
* @param {string} id - 唯一标识 (可选,如果不传则自动生成)
* @param {string} color - 颜色 (可选)
* @returns {string} - 返回该点的 ID
*/
add(coordinate, id = null, color = 'rgba(255, 0, 0, 0.8)') {
const uniqueId = id || this._generateId();
// 如果该 ID 已存在,先移除旧的
if (this.overlays.has(uniqueId)) {
this.remove(uniqueId);
}
const element = this._createDOMElement(color);
const overlay = new Overlay({
element: element,
position: coordinate,
positioning: 'center-center',
stopEvent: false,
insertFirst: false
});
this.map.addOverlay(overlay);
this.overlays.set(uniqueId, overlay);
return uniqueId;
}
/**
* 移除指定的扩散点
* @param {string} id - 唯一标识
*/
remove(id) {
if (!id || !this.overlays.has(id)) return;
const overlay = this.overlays.get(id);
this.map.removeOverlay(overlay);
// 清理 DOM 引用
overlay.setElement(null);
this.overlays.delete(id);
}
/**
* 获取指定的 Overlay 实例
* @param {string} id
* @returns {Overlay|undefined}
*/
get(id) {
return this.overlays.get(id);
}
/**
* 清空所有扩散点
*/
clearAll() {
this.overlays.forEach((overlay) => {
this.map.removeOverlay(overlay);
overlay.setElement(null);
});
this.overlays.clear();
}
/**
* 销毁管理器(清空所有并解除地图引用)
*/
destroy() {
this.clearAll();
this.map = null;
}
}
- 将下面的css样式放到全局的css样式文件中或放在
app.vue里
.pulsing-point {
position: relative;
width: 20px;
height: 20px;
transform: translate(-50%, -50%);
/* 默认颜色 */
--point-color: rgba(255, 0, 0, 0.8);
}
.pulsing-point::before {
content: '';
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
background-color: var(--point-color);
border-radius: 50%;
z-index: 2;
border: 1px solid #fff;
}
.pulsing-point::after {
content: '';
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
background-color: var(--point-color);
opacity: 0.6; /* 使用固定透明度,配合动画 */
border-radius: 50%;
z-index: 1;
animation: ripple 2s infinite ease-out;
}
@keyframes ripple {
0% { transform: scale(1); opacity: 0.6; }
100% { transform: scale(4); opacity: 0; }
}
- 组件中使用
<template>
<div>
<div id="map-container" style="width: 100%; height: 500px;"></div>
<div class="controls">
<button @click="addBeijing">添加北京点</button>
<button @click="removeBeijing">移除北京点</button>
<button @click="clearAll" style="color: red;">清空所有</button>
</div>
</div>
</template>
<script>
import 'ol/ol.css';
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import XYZ from 'ol/source/XYZ';
// 引入工具类
import PulsingPointManager from './utils/PulsingPointManager';
export default {
data() {
return {
map: null,
pulsingManager: null, // 管理器实例
};
},
mounted() {
this.initMap();
},
methods: {
initMap() {
this.map = new Map({
target: 'map-container',
layers: [
new TileLayer({
source: new XYZ({
url: 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png',
}),
}),
],
view: new View({
center: [0, 0],
zoom: 2,
}),
});
// 初始化管理器
this.pulsingManager = new PulsingPointManager(this.map);
},
addBeijing() {
// 添加点位,指定 ID 为 'bj',颜色为红色
this.pulsingManager.add([116.397428, 39.90923], 'bj', 'rgba(255, 0, 0, 0.8)');
},
removeBeijing() {
this.pulsingManager.remove('bj');
},
clearAll() {
this.pulsingManager.clearAll();
}
},
beforeDestroy() {
// 组件销毁前,务必销毁管理器以释放内存
if (this.pulsingManager) {
this.pulsingManager.destroy();
}
if (this.map) {
this.map.setTarget(null);
}
},
};
</script>

2382

被折叠的 条评论
为什么被折叠?



