diff --git a/web/src/components/VirtualCollapsePanel/index.vue b/web/src/components/VirtualCollapsePanel/index.vue index 0ee99fa..59a6ff6 100644 --- a/web/src/components/VirtualCollapsePanel/index.vue +++ b/web/src/components/VirtualCollapsePanel/index.vue @@ -1,229 +1,240 @@ diff --git a/web/src/views/HandDevice/Home/components/OpenLayerMap.vue b/web/src/views/HandDevice/Home/components/OpenLayerMap.vue index e9e7194..e7416da 100644 --- a/web/src/views/HandDevice/Home/components/OpenLayerMap.vue +++ b/web/src/views/HandDevice/Home/components/OpenLayerMap.vue @@ -93,8 +93,7 @@ const { setTrajectoriesVisible, setFencesVisible, toggleFenceDrawing, - clearFenceDrawLayer, - updateMarkers + clearFenceDrawLayer } = useMapServices() const { @@ -175,22 +174,21 @@ const init = () => { { isDrawing: () => !!services.fenceDrawService?.isCurrentlyDrawing?.(), onMarkerClick: (marker: MarkerData) => { - console.log('marker clicked', marker) + // console.log('marker clicked', marker) emit('on-click-marker', marker) }, onClusterClick: (features: FeatureLike[]) => { - console.log('onClusterClick', features) + // console.log('onClusterClick', features) const markerCoords = features.map((feature) => feature.get('markerData').coordinates) services.mapService?.fitToMarkers(markerCoords) }, onZoomEnd: (zoom: number) => { console.log('onZoomEnd', zoom) // 防抖更新标记层 - // services.markerService?.createMarkerLayerFromProps(props) + services.markerService?.setClusterDistance() services.markerService?.getSinglePointsInView() - // console.log('marker', marker) } } ) @@ -252,6 +250,7 @@ const setCenter = (coords: [number, number]) => { if (isMapInitialized) { services.mapService?.setCenter(coords) + services.mapService?.setZoom(17) } } /** @@ -290,25 +289,24 @@ const refreshFences = () => { watch( () => props.markers, (newMarkers, oldMarkers) => { - updateMarkers(newMarkers, props) - if (newMarkers.length !== oldMarkers.length) { + console.log('markers changed', newMarkers, oldMarkers) + services.markerService?.updateData(newMarkers) + if (oldMarkers == undefined || newMarkers.length !== oldMarkers.length) { fitToMarkers() } }, - { deep: true, immediate: false } + { deep: false, immediate: true } ) watch( () => props.fences, () => { refreshFences() }, - { deep: true, immediate: false } + { deep: false, immediate: false } ) onMounted(() => { - setTimeout(() => { - init() - }, 100) + init() }) defineExpose({ refreshFences, fitToMarkers, setCenter, showTrajectory }) diff --git a/web/src/views/HandDevice/Home/components/composables/useMapServices.ts b/web/src/views/HandDevice/Home/components/composables/useMapServices.ts index 58bfb22..aeaeee7 100644 --- a/web/src/views/HandDevice/Home/components/composables/useMapServices.ts +++ b/web/src/views/HandDevice/Home/components/composables/useMapServices.ts @@ -16,7 +16,7 @@ import { FenceDrawService } from '../services/fence-draw.service' interface ServiceInstances { mapService: MapService | null markerService: MarkerService | null - + popupService: PopupService | null trajectoryService: TrajectoryService | null fenceService: FenceService | null @@ -28,7 +28,7 @@ export const useMapServices = () => { const services: ServiceInstances = { mapService: null, markerService: null, - + popupService: null, trajectoryService: null, fenceService: null, @@ -48,14 +48,12 @@ export const useMapServices = () => { // 重新初始化服务,确保markerService有地图实例 services.mapService = mapService services.markerService = new MarkerService(mapService.map) - + services.popupService = new PopupService() services.trajectoryService = new TrajectoryService(mapService.map) services.fenceService = new FenceService(mapService.map) services.fenceDrawService = new FenceDrawService(mapService.map) - // 创建marker图层 - services.markerService.createMarkerLayer(props) // 创建轨迹图层 services.trajectoryService.createTrajectoryLayer() // 创建围栏图层 @@ -70,10 +68,8 @@ export const useMapServices = () => { const setMarkersVisible = (visible: boolean) => { if (visible) { services.markerService?.show() - } else { services.markerService?.hide() - } } @@ -129,35 +125,7 @@ export const useMapServices = () => { } } - /** - * 更新标记数据 - */ - const updateMarkers = (markers: any[], currentProps?: MapProps) => { - if (services.markerService) { - const map = services.mapService?.getMap() - - if (map) { - // console.log('updateMarkers', markers) - // 更新marker service(这可能会创建新的layer) - console.time('createMarkerLayer'); - services.markerService.createMarkerLayer({ - ...currentProps, - markers - }) - console.timeEnd('createMarkerLayer'); - } - } - } - - /** - * 刷新标记样式 - */ - const refreshMarkerStyles = () => { - if (services.markerService) { - services.markerService.refreshStyles() - } - } - + /** * 销毁所有服务 */ @@ -204,8 +172,8 @@ export const useMapServices = () => { setFencesVisible, toggleFenceDrawing, clearFenceDrawLayer, - updateMarkers, - refreshMarkerStyles, + + destroyServices } } diff --git a/web/src/views/HandDevice/Home/components/composables/useMapWatchers.ts b/web/src/views/HandDevice/Home/components/composables/useMapWatchers.ts index 714adf6..195420b 100644 --- a/web/src/views/HandDevice/Home/components/composables/useMapWatchers.ts +++ b/web/src/views/HandDevice/Home/components/composables/useMapWatchers.ts @@ -86,21 +86,6 @@ export const useMapWatchers = (options: WatchOptions) => { }) } - /** - * 设置标记数据变化监听器 - */ - // const setupMarkersDataWatcher = () => { - // return watch( - // markers, - // (newMarkers = []) => { - // // if (newMarkers && newMarkers.length > 0) { - // console.log('Markers data changed, updating markers:', newMarkers.length) - // updateMarkers(newMarkers) - // // } - // }, - // { deep: true, immediate: false } - // ) - // } /** * 初始化所有监听器 diff --git a/web/src/views/HandDevice/Home/components/services/map.service.ts b/web/src/views/HandDevice/Home/components/services/map.service.ts index 65aeffb..2c9b8e4 100644 --- a/web/src/views/HandDevice/Home/components/services/map.service.ts +++ b/web/src/views/HandDevice/Home/components/services/map.service.ts @@ -108,7 +108,11 @@ export class MapService { center = fromLonLat(center) this.map.getView().setCenter(center) } - + // 设置缩放级别 + setZoom(zoom: number): void { + if (!this.map) return + this.map.getView().setZoom(zoom) + } /** * 获取地图实例 */ diff --git a/web/src/views/HandDevice/Home/components/services/marker.service.ts b/web/src/views/HandDevice/Home/components/services/marker.service.ts index 39eb8a8..3ea81cd 100644 --- a/web/src/views/HandDevice/Home/components/services/marker.service.ts +++ b/web/src/views/HandDevice/Home/components/services/marker.service.ts @@ -13,14 +13,13 @@ 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 | null = null - // 当前图层模式(single或cluster聚合):避免重复创建图层 - private currentLayerMode: 'single' | 'cluster' | '' = '' + markerLayer: VectorLayer | null = null + private vectorSource: VectorSource private animationService: AnimationService | null = null @@ -28,6 +27,7 @@ export class MarkerService { this.map = map this.vectorSource = new VectorSource() this.animationService = new AnimationService(map) + this.createMarkerLayer() } show() { this.markerLayer?.setVisible(true) @@ -37,27 +37,14 @@ export class MarkerService { this.markerLayer?.setVisible(false) this.animationService?.hide() } - /** - * 创建标记图层 - */ - 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 { + updateData(markers: MarkerData[]): void { this.animationService?.clear() this.vectorSource.clear() - // 添加标记 - const markers = props.markers || [] +// debugger const features: Feature[] = [] markers.forEach((marker) => { const feature = new Feature({ @@ -72,7 +59,7 @@ export class MarkerService { this.vectorSource.addFeatures(features) this.getSinglePointsInView() } - setClusterDistance= debounce(()=> { + setClusterDistance = debounce(() => { if (!this.map) return const clusterLayer = this.markerLayer if (!clusterLayer) return @@ -80,20 +67,20 @@ export class MarkerService { if (!clusterSource) return const zoom = this.map.getView().getZoom() || 0 let distance = 2 - if (zoom <= 4) { + if (zoom <= 4) { distance = 100 - }else if (zoom <= 6) { + } else if (zoom <= 6) { distance = 80 } else if (zoom <= 10) { distance = 30 } else if (zoom <= 16) { distance = 30 - }else if (zoom <= 17) { + } else if (zoom <= 17) { distance = 10 } - console.log('zoom',zoom,'distance',distance) + console.log('zoom', zoom, 'distance', distance) clusterSource?.setDistance(distance) - },200) + }, 200) /** * 获取视图内聚合图层中没有聚合的单个点 * @returns {Array} 单个点要素数组 @@ -107,6 +94,7 @@ export class MarkerService { // 获取聚合图层的源 const clusterSource = clusterLayer.getSource() + if (!clusterSource) return // 获取当前视图范围 const view = map.getView() @@ -117,7 +105,7 @@ export class MarkerService { // console.log('featuresInView',featuresInView) featuresInView.forEach((clusterFeature) => { // 关键:获取聚合要素中包含的所有原始要素 - const originalFeatures = clusterFeature.get('features') + const originalFeatures = clusterFeature.get('features') // console.log('originalFeatures',originalFeatures); if (originalFeatures && originalFeatures.length === 1) { @@ -127,89 +115,51 @@ export class MarkerService { } }) this.animationService?.addAll(singlePoints || []) - return singlePoints - },300) + + }, 300) /** * 从props创建markerLayer(内部方法) * */ // : VectorLayer - createMarkerLayerFromProps(props: MapProps) { - // console.log('createMarkerLayerFromProps') - - // this.updateData(props) + createMarkerLayer() { + let newLayer: VectorLayer | null = null - // 检查是否应该强制使用单个marker模式 - const shouldForceSingleMark = () => { - if (!props.forceSingleMark || !this.map) return false - const currentZoom = this.map.getView().getZoom() + console.log('聚合图层') - return currentZoom && currentZoom >= ANIMATION_CONFIG.clusterThreshold - } + const clusterSource = new Cluster({ + source: this.vectorSource, + distance: 20 // 单位是像素 + }) - let newLayer: VectorLayer | null = null - // 如果启用聚合且不强制使用单个marker模式 - 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: 20 // 单位是像素 - }) - + newLayer = new VectorLayer({ + source: clusterSource, + zIndex: 1, + style: (feature) => { + // 视图变化新视口内所有要素的样式重计算​ (如平移、缩放),所以不能调用this.animationService?.add + const features = feature.get('features') - newLayer = new VectorLayer({ - source: clusterSource, - zIndex: 1, - style: (feature) => { - // 视图变化新视口内所有要素的样式重计算​ (如平移、缩放),所以不能调用this.animationService?.add - const features = feature.get('features') - - // 确保features存在且不为空 - if (!features || features.length === 0) { - return new Style() // 返回空样式,隐藏无效的feature - } - // console.log('聚合元素', features) - - if (features.length === 1) { - // 单个marker - const markerData: MarkerData = features[0].get('markerData') - - return markerData ? createMarkerStyle(markerData.statusColor || '') : new Style() - } else { - // 聚合marker - const highestStatus = getClusterMarkerData(features) - - const color = getStatusColor(highestStatus) - return createMarkerStyle(color, true, features.length) - } + // 确保features存在且不为空 + if (!features || features.length === 0) { + return new Style() // 返回空样式,隐藏无效的feature } - }) - } else { - if (this.currentLayerMode === 'single') return - this.currentLayerMode = 'single' - - console.log('基础marker图层') - - newLayer = new VectorLayer({ - source: this.vectorSource, - zIndex: 1, - renderOrder: (a, b) => { - // 按xxx属性排列 - return b.get('markerData').statusPriority - a.get('markerData').statusPriority - } - }) - } + // console.log('聚合元素', features) - if (this.markerLayer) { - const isVisible = this.markerLayer?.getVisible() || false - newLayer.setVisible(isVisible) // 新图层保持当前可见状态 - this.map?.removeLayer(this.markerLayer) - } + if (features.length === 1) { + // 单个marker + const markerData: MarkerData = features[0].get('markerData') + + return markerData ? createMarkerStyle(markerData.statusColor || '') : new Style() + } else { + // 聚合marker + const highestStatus = getClusterMarkerData(features) + + const color = getStatusColor(highestStatus) + return createMarkerStyle(color, true, features.length) + } + } + }) this.markerLayer = newLayer this.map?.addLayer(this.markerLayer) @@ -230,8 +180,7 @@ export class MarkerService { destroy(): void { this.markerLayer = null this.animationService?.destroy() - // this.currentProps = null - this.createMarkerLayer.cancel() + this.map = null } } diff --git a/web/src/views/HandDevice/Home/components/utils/map.utils.ts b/web/src/views/HandDevice/Home/components/utils/map.utils.ts index ce81e60..ba025fc 100644 --- a/web/src/views/HandDevice/Home/components/utils/map.utils.ts +++ b/web/src/views/HandDevice/Home/components/utils/map.utils.ts @@ -158,7 +158,7 @@ export const createMarkerStyle = ( styleCache[key]= new Style({ image: new Circle({ - radius: Math.min(20 + clusterSize, 40), + radius: Math.min(20 + clusterSize/4, 40), fill: new Fill({ color: color + '80' // 添加透明度 }), diff --git a/web/src/views/HandDevice/Home/index.vue b/web/src/views/HandDevice/Home/index.vue index 06ae525..c75211b 100644 --- a/web/src/views/HandDevice/Home/index.vue +++ b/web/src/views/HandDevice/Home/index.vue @@ -30,10 +30,7 @@