|
|
|
@ -14,6 +14,8 @@ import { AnimationService } from './animation.service' |
|
|
|
import type { MarkerData, MapProps } from '../types/map.types' |
|
|
|
import { createMarkerStyle, getClusterMarkerData, getStatusColor } from '../utils/map.utils' |
|
|
|
import { ANIMATION_CONFIG } from '../constants/map.constants' |
|
|
|
// 防抖
|
|
|
|
import { debounce } from 'lodash-es' |
|
|
|
export class MarkerService { |
|
|
|
private map: Map | null = null |
|
|
|
markerLayer: VectorLayer<VectorSource | Cluster> | null = null |
|
|
|
@ -38,21 +40,25 @@ export class MarkerService { |
|
|
|
/** |
|
|
|
* 创建标记图层 |
|
|
|
*/ |
|
|
|
createMarkerLayer(props: MapProps) { |
|
|
|
// console.log('createMarkerLayer')
|
|
|
|
|
|
|
|
// this.map?.removeLayer(this.markerLayer)
|
|
|
|
createMarkerLayer = debounce((props: MapProps) => { |
|
|
|
console.time('updateData') |
|
|
|
this.updateData(props) |
|
|
|
console.timeEnd('updateData') |
|
|
|
console.time('createMarkerLayerFromProps') |
|
|
|
|
|
|
|
this.createMarkerLayerFromProps(props) |
|
|
|
} |
|
|
|
|
|
|
|
console.timeEnd('createMarkerLayerFromProps') |
|
|
|
}, 1000) |
|
|
|
/** |
|
|
|
* 更新标记数据 |
|
|
|
*/ |
|
|
|
updateData(props: MapProps): void { |
|
|
|
this.animationService?.clear() |
|
|
|
this.vectorSource.clear() |
|
|
|
// 添加标记
|
|
|
|
const markers = props.markers || [] |
|
|
|
const features: Feature<Point>[] = [] |
|
|
|
markers.forEach((marker) => { |
|
|
|
const feature = new Feature({ |
|
|
|
geometry: new Point(fromLonLat(marker.coordinates)), |
|
|
|
@ -61,26 +67,84 @@ export class MarkerService { |
|
|
|
const statusColor = marker.statusColor || '' |
|
|
|
|
|
|
|
feature.setStyle(createMarkerStyle(statusColor)) |
|
|
|
this.vectorSource.addFeature(feature) |
|
|
|
features.push(feature) |
|
|
|
}) |
|
|
|
this.vectorSource.addFeatures(features) |
|
|
|
this.getSinglePointsInView() |
|
|
|
} |
|
|
|
setClusterDistance= debounce(()=> { |
|
|
|
if (!this.map) return |
|
|
|
const clusterLayer = this.markerLayer |
|
|
|
if (!clusterLayer) return |
|
|
|
const clusterSource = clusterLayer.getSource() as Cluster<Feature<Point>> |
|
|
|
if (!clusterSource) return |
|
|
|
const zoom = this.map.getView().getZoom() || 0 |
|
|
|
let distance = 2 |
|
|
|
if (zoom <= 4) { |
|
|
|
distance = 100 |
|
|
|
}else if (zoom <= 6) { |
|
|
|
distance = 80 |
|
|
|
} else if (zoom <= 10) { |
|
|
|
distance = 30 |
|
|
|
} else if (zoom <= 16) { |
|
|
|
distance = 30 |
|
|
|
}else if (zoom <= 17) { |
|
|
|
distance = 10 |
|
|
|
} |
|
|
|
console.log('zoom',zoom,'distance',distance) |
|
|
|
clusterSource?.setDistance(distance) |
|
|
|
},200) |
|
|
|
/** |
|
|
|
* 获取视图内聚合图层中没有聚合的单个点 |
|
|
|
* @returns {Array} 单个点要素数组 |
|
|
|
*/ |
|
|
|
getSinglePointsInView = debounce(() => { |
|
|
|
const map = this.map |
|
|
|
const clusterLayer = this.markerLayer |
|
|
|
if (!clusterLayer || !map) return [] |
|
|
|
|
|
|
|
const singlePoints = [] |
|
|
|
|
|
|
|
// 获取聚合图层的源
|
|
|
|
const clusterSource = clusterLayer.getSource() |
|
|
|
|
|
|
|
// 获取当前视图范围
|
|
|
|
const view = map.getView() |
|
|
|
const currentExtent = view.calculateExtent(map.getSize()) |
|
|
|
|
|
|
|
// 获取视图范围内的所有聚合要素
|
|
|
|
const featuresInView = clusterSource.getFeaturesInExtent(currentExtent) |
|
|
|
// console.log('featuresInView',featuresInView)
|
|
|
|
featuresInView.forEach((clusterFeature) => { |
|
|
|
// 关键:获取聚合要素中包含的所有原始要素
|
|
|
|
const originalFeatures = clusterFeature.get('features') |
|
|
|
// console.log('originalFeatures',originalFeatures);
|
|
|
|
|
|
|
|
if (originalFeatures && originalFeatures.length === 1) { |
|
|
|
singlePoints.push(originalFeatures[0].get('markerData')) |
|
|
|
} else if (!originalFeatures) { |
|
|
|
singlePoints.push(clusterFeature.get('markerData')) |
|
|
|
} |
|
|
|
}) |
|
|
|
this.animationService?.addAll(singlePoints || []) |
|
|
|
return singlePoints |
|
|
|
},300) |
|
|
|
|
|
|
|
/** |
|
|
|
* 从props创建markerLayer(内部方法) |
|
|
|
* |
|
|
|
*/ |
|
|
|
// : VectorLayer<VectorSource | Cluster>
|
|
|
|
private createMarkerLayerFromProps(props: MapProps) { |
|
|
|
createMarkerLayerFromProps(props: MapProps) { |
|
|
|
// console.log('createMarkerLayerFromProps')
|
|
|
|
this.animationService?.clear() |
|
|
|
this.updateData(props) |
|
|
|
|
|
|
|
// this.updateData(props)
|
|
|
|
|
|
|
|
// 检查是否应该强制使用单个marker模式
|
|
|
|
const shouldForceSingleMark = () => { |
|
|
|
if (!props.forceSingleMark || !this.map) return false |
|
|
|
const currentZoom = this.map.getView().getZoom() |
|
|
|
// console.log('currentZoom', currentZoom)
|
|
|
|
// return currentZoom && currentZoom >= props.forceSingleMark
|
|
|
|
|
|
|
|
return currentZoom && currentZoom >= ANIMATION_CONFIG.clusterThreshold |
|
|
|
} |
|
|
|
|
|
|
|
@ -89,16 +153,20 @@ export class MarkerService { |
|
|
|
if (props.enableCluster && !shouldForceSingleMark()) { |
|
|
|
if (this.currentLayerMode === 'cluster') return |
|
|
|
this.currentLayerMode = 'cluster' |
|
|
|
// this.animationService?.clear()
|
|
|
|
console.log('聚合图层') |
|
|
|
|
|
|
|
const clusterSource = new Cluster({ |
|
|
|
source: this.vectorSource, |
|
|
|
distance: Math.max(props.clusterDistance || 10, 10) |
|
|
|
distance: 20 // 单位是像素
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
newLayer = new VectorLayer({ |
|
|
|
source: clusterSource, |
|
|
|
zIndex: 1, |
|
|
|
style: (feature) => { |
|
|
|
// 视图变化新视口内所有要素的样式重计算 (如平移、缩放),所以不能调用this.animationService?.add
|
|
|
|
const features = feature.get('features') |
|
|
|
|
|
|
|
// 确保features存在且不为空
|
|
|
|
@ -111,8 +179,6 @@ export class MarkerService { |
|
|
|
// 单个marker
|
|
|
|
const markerData: MarkerData = features[0].get('markerData') |
|
|
|
|
|
|
|
this.animationService?.add(markerData) |
|
|
|
|
|
|
|
return markerData ? createMarkerStyle(markerData.statusColor || '') : new Style() |
|
|
|
} else { |
|
|
|
// 聚合marker
|
|
|
|
@ -124,14 +190,10 @@ export class MarkerService { |
|
|
|
} |
|
|
|
}) |
|
|
|
} else { |
|
|
|
// markers可能变化,必须更新
|
|
|
|
this.animationService?.addAll(props.markers || []) |
|
|
|
|
|
|
|
if (this.currentLayerMode === 'single') return |
|
|
|
this.currentLayerMode = 'single' |
|
|
|
|
|
|
|
|
|
|
|
// console.log('基础marker')
|
|
|
|
console.log('基础marker图层') |
|
|
|
|
|
|
|
newLayer = new VectorLayer({ |
|
|
|
source: this.vectorSource, |
|
|
|
@ -169,6 +231,7 @@ export class MarkerService { |
|
|
|
this.markerLayer = null |
|
|
|
this.animationService?.destroy() |
|
|
|
// this.currentProps = null
|
|
|
|
this.createMarkerLayer.cancel() |
|
|
|
this.map = null |
|
|
|
} |
|
|
|
} |
|
|
|
|