Vue3 + vue3-openlayers:点击聚合集群显示点位名称异常问题排查
Vue3 + vue3-openlayers 集群点击显示项目名异常问题
需求
使用Vue3与vue3-openlayers开发地图功能,点击地图上的聚合集群时,显示该集群内所有点位对应的项目名称(例如标记为“3”的集群需显示3个项目名,标记为“1”的集群显示1个项目名)。
现有代码
模板代码
<ol-animated-clusterlayer :animationDuration="500" :distance="40" title="CLUSTER" preview="https://raw.githubusercontent.com/MelihAltintas/vue3-openlayers/main/src/assets/cluster.png"> <ol-source-vector ref="vectorsource"> <ol-feature v-for="index in mapCover" :key="index"> <ol-geom-point :coordinates="[ index.lon, index.lat ]"></ol-geom-point> </ol-feature> </ol-source-vector> <ol-style :overrideStyleFunction="overrideStyleFunction"> <ol-style-stroke color="red" :width="2"></ol-style-stroke> <ol-style-fill color="rgba(255,255,255,0.1)"></ol-style-fill> <ol-style-circle :radius="20"> <ol-style-stroke color="black" :width="15" :lineDash="[]" lineCap="butt"></ol-style-stroke> <ol-style-fill color="black"></ol-style-fill> </ol-style-circle> <ol-style-text> <ol-style-fill color="white"></ol-style-fill> </ol-style-text> </ol-style> </ol-animated-clusterlayer> <ol-overlay :position="selectedCityPosition" v-if="selectedCityName != '' && !drawEnable"> <template v-slot="slotProps"> <div class="overlay-content" > <div v-for="skill in selectedCityName" v-bind:key="skill[0]"> <span v-if="content" class="badge bg-primary" data-bs-toggle="modal" :data-bs-target="`#staticBackdrop${skill[0]}`" style="margin: 3px;"> {{ skill[1] }} </span> </div> </div> </template> </ol-overlay>
JS逻辑代码
featureSelected(event) { this.selectedCityName = [] if (event.selected.length == 1) { const extent = getCenter(event.selected[0].getGeometry().getExtent()); this.selectedCityPosition = extent; for (let item in this.mapCover) { console.log(event.selected[0].values_.geometry) if (event.selected[0].values_.geometry.flatCoordinates.includes(this.mapCover[item].lon, ",", this.mapCover[item].lat)) { const name = this.mapCover[item].name; const id = this.mapCover[item].id; this.selectedCityName.push([id, name]) } } } },
数据源JSON
[ { "id": 1, "idproj": [ { "uuid": "0640c688-3828-43d1-8835-f8d08def59d3", "lat": "51.4168327", "lon": "15.8986889" } ], "name": "Projektów 1" }, { "id": 2, "idproj": [ { "uuid": "c3b9e68c-ae2c-4eab-a0aa-28c9e1efc3b6", "lat": "51.2081617", "lon": "16.1603187" } ], "name": "Projekt 2" }, { "id": 3, "idproj": [ { "uuid": "d7bada02-42b3-4f4e-b71a-54d9d1712e69", "lat": "51.1089776", "lon": "17.0326689" } ], "name": "Projekt 3" }, { "id": 5, "idproj": [ { "uuid": "0640c688-3828-43d1-8835-f8d08def59d3", "lat": "51.4168327", "lon": "15.8986889" } ], "name": "Projekt 4" }, { "id": 7, "idproj": [ { "uuid": "d481881d-ea37-442c-af68-dbc8f71f234e", "lat": "51.4168327", "lon": "15.8986889" } ], "name": "Projekt 5" } ]
问题
点击标记为“1”的集群时能正常显示对应项目名称,但点击标记为“3”的集群时无任何反应。
问题排查与解决
核心问题分析
includes方法使用错误:Array.includes()仅接受两个参数(目标元素、起始索引),第三个参数会被忽略。且集群的flatCoordinates是聚合后的几何坐标,并非原始点位的坐标集合,无法通过该方式匹配集群内的原始点位。- 未正确获取集群内的原始特征:vue3-openlayers的集群特征自带
features属性,存储了该集群包含的所有原始ol-feature,无需通过坐标匹配。
修复后的代码
步骤1:给特征绑定项目ID
在模板中给每个点位特征绑定项目ID,方便后续关联:
<ol-feature v-for="item in mapCover" :key="item.id"> <ol-geom-point :coordinates="[Number(item.lon), Number(item.lat)]"></ol-geom-point> <!-- 绑定项目ID到feature属性 --> <ol-feature-properties :properties="{ projectId: item.id }"></ol-feature-properties> </ol-feature>
步骤2:修改featureSelected逻辑
直接从集群特征中提取子特征,匹配项目数据:
featureSelected(event) { this.selectedCityName = []; if (event.selected.length === 1) { const clusterFeature = event.selected[0]; // 获取集群包含的所有原始特征 const clusterFeatures = clusterFeature.get('features'); if (clusterFeatures) { // 设置弹窗位置为集群中心 const extent = getCenter(clusterFeature.getGeometry().getExtent()); this.selectedCityPosition = extent; // 遍历集群内特征,匹配项目数据 clusterFeatures.forEach(feature => { const projectId = feature.get('projectId'); const project = this.mapCover.find(item => item.id === projectId); if (project) { this.selectedCityName.push([project.id, project.name]); } }); } } }
额外优化
- 将数据源中字符串类型的
lon/lat转为数字,避免坐标解析异常 - 模板中
v-for的key使用唯一的item.id,避免重复渲染问题
内容的提问来源于stack exchange,提问作者DoDr
相关产品推荐
相关产品推荐

