Browse Source

优化地图

master
xh 6 days ago
parent
commit
0bde5525d5
  1. 16
      web/src/views/HandDevice/Home/components/OpenLayerMap.vue
  2. 10
      web/src/views/HandDevice/Home/components/composables/useMapEvents.ts
  3. 81
      web/src/views/HandDevice/Home/components/composables/useMapServices.ts
  4. 10
      web/src/views/HandDevice/Home/components/services/animation.service.ts
  5. 22
      web/src/views/HandDevice/Home/components/services/fence.service.ts
  6. 27
      web/src/views/HandDevice/Home/components/services/marker.service.ts
  7. 80
      web/src/views/HandDevice/Home/index.vue

16
web/src/views/HandDevice/Home/components/OpenLayerMap.vue

@ -107,7 +107,6 @@ enableStatus 1启用 0未启用
// 使
const {
services,
layerRefs,
initializeMapAndLayers,
setMarkersVisible,
@ -187,7 +186,7 @@ const initMap = () => {
setTrajectoriesVisible(showTrajectories.value, props.markers)
setFencesVisible(showFences.value)
//
// ,, marker
setupMapEventListeners(
map,
popupOverlay,
@ -206,9 +205,7 @@ const initMap = () => {
services.markerService?.createMarkerLayer(props)
// updateMarkers(props.markers || [],props)
},
markerLayer: layerRefs.value?.markerLayer,
refreshMarkerStyles
// refreshMarkerStyles
}
)
//
@ -270,6 +267,15 @@ watch(
},
{ deep: true, immediate: false }
)
watch(
() => props.fences,
(newFences) => {
if (newFences && newFences.length > 0 && isMapInitialized) {
refreshFences()
}
},
{ deep: true, immediate: false }
)
onMounted(() => {
setTimeout(() => {

10
web/src/views/HandDevice/Home/components/composables/useMapEvents.ts

@ -87,8 +87,8 @@ export const useMapEvents = () => {
isDrawing?: () => boolean
onMarkerClick?: (markerData: any) => void
onZoomEnd?: (zoom: number) => void
markerLayer?: any
refreshMarkerStyles?: () => void
// markerLayer?: any
// refreshMarkerStyles?: () => void
}
) => {
const popupGenerator = createPopupContentGenerator(trajectoryService, popupService)
@ -129,9 +129,9 @@ export const useMapEvents = () => {
// console.log('handleMoveEnd');
// OpenLayers的Cluster会自动重新计算聚合,只需要刷新样式
if (opts?.markerLayer) {
opts.markerLayer.changed()
}
// if (opts?.markerLayer) {
// opts.markerLayer.changed()
// }
if (opts?.onZoomEnd) {
const zoom = map.getView().getZoom() || 0
opts.onZoomEnd(zoom)

81
web/src/views/HandDevice/Home/components/composables/useMapServices.ts

@ -23,13 +23,6 @@ interface ServiceInstances {
fenceDrawService: FenceDrawService | null
}
interface LayerRefs {
markerLayer: any
rippleLayer: any
trajectoryLayer: any
fenceLayer: any
}
export const useMapServices = () => {
// 服务实例状态
const services = reactive<ServiceInstances>({
@ -42,9 +35,6 @@ export const useMapServices = () => {
fenceDrawService: null
})
// 图层引用状态
const layerRefs = ref<LayerRefs | null>(null)
/**
*
*/
@ -66,33 +56,16 @@ export const useMapServices = () => {
services.fenceDrawService = new FenceDrawService(map)
// 创建marker图层
const markerLayer = services.markerService.createMarkerLayer(props)
services.markerService.createMarkerLayer(props)
// 创建波纹图层
const rippleLayer = services.animationService.createRippleLayer(
props.markers || [],
props.enableCluster
)
services.animationService.createRippleLayer(props.markers || [], props.enableCluster)
// 创建轨迹图层
const trajectoryLayer = services.trajectoryService.createTrajectoryLayer()
services.trajectoryService.createTrajectoryLayer()
// 创建围栏图层
const fenceLayer = services.fenceService.createFenceLayer(props.fences || [])
// // 添加图层到地图
// map.addLayer(markerLayer)
map.addLayer(rippleLayer)
map.addLayer(trajectoryLayer)
map.addLayer(fenceLayer)
services.fenceService.createFenceLayer(props.fences || [])
// 初始化围栏绘制服务
services.fenceDrawService.createDrawLayer()
// 存储图层引用
layerRefs.value = {
markerLayer,
rippleLayer,
trajectoryLayer,
fenceLayer
}
return {
map,
popupOverlay
@ -103,18 +76,12 @@ export const useMapServices = () => {
*
*/
const setMarkersVisible = (visible: boolean) => {
if (!layerRefs.value || !services.animationService) return
const { markerLayer, rippleLayer } = layerRefs.value
if (visible) {
markerLayer.setVisible(true)
rippleLayer.setVisible(true)
services.animationService.startAnimation()
services.markerService?.show()
services.animationService?.show()
} else {
markerLayer.setVisible(false)
rippleLayer.setVisible(false)
services.animationService.stopAnimation()
services.markerService?.hide()
services.animationService?.hide()
}
}
@ -139,9 +106,9 @@ export const useMapServices = () => {
if (!services.fenceService) return
if (visible) {
services.fenceService.showFences()
services.fenceService.show()
} else {
services.fenceService.hideFences()
services.fenceService.hide()
}
}
@ -174,20 +141,11 @@ export const useMapServices = () => {
*
*/
const updateMarkers = (markers: any[], currentProps?: MapProps) => {
if (
services.markerService &&
services.animationService &&
layerRefs.value?.markerLayer &&
layerRefs.value?.rippleLayer
) {
if (services.markerService && services.animationService) {
const map = services.mapService?.getMap()
const enableCluster = currentProps?.enableCluster ?? true
if (map) {
// 从地图中移除旧的marker layer
// map.removeLayer(layerRefs.value.markerLayer)
// map.removeLayer(layerRefs.value.rippleLayer)
console.log('updateMarkers', markers);
console.log('updateMarkers', markers)
// 更新marker service(这会创建新的layer)
services.markerService.createMarkerLayer({
...currentProps,
@ -196,17 +154,6 @@ export const useMapServices = () => {
// 重新创建波纹图层
services.animationService.createRippleLayer(markers, enableCluster)
// 获取新的layer并添加到地图
// const newMarkerLayer = services.markerService.getMarkerLayer()
// if (newMarkerLayer && newRippleLayer) {
// // // 确保markerService有最新的地图实例
// // services.markerService.setMap(map)
// map.addLayer(newMarkerLayer)
// map.addLayer(newRippleLayer)
// layerRefs.value.markerLayer = newMarkerLayer
// layerRefs.value.rippleLayer = newRippleLayer
// }
}
}
}
@ -248,9 +195,6 @@ export const useMapServices = () => {
services.trajectoryService = null
services.fenceService = null
services.fenceDrawService = null
// 重置图层引用
layerRefs.value = null
}
// 组件卸载时自动清理
@ -261,7 +205,6 @@ export const useMapServices = () => {
return {
// 状态
services,
layerRefs,
// 方法

10
web/src/views/HandDevice/Home/components/services/animation.service.ts

@ -54,6 +54,7 @@ export class AnimationService {
this.rippleLayer = new VectorLayer({
source: source,
zIndex: 1,
style: (feature) => {
// 检查当前缩放级别,如果缩放级别较低(聚合状态),不显示波纹
const currentZoom = this.map?.getView().getZoom() || 0
@ -117,7 +118,14 @@ export class AnimationService {
return this.rippleLayer
}
show() {
this.rippleLayer?.setVisible(true)
this.startAnimation()
}
hide() {
this.stopAnimation()
this.rippleLayer?.setVisible(false)
}
/**
*
*/

22
web/src/views/HandDevice/Home/components/services/fence.service.ts

@ -26,7 +26,9 @@ export class FenceService {
*
*/
createFenceLayer(fences: FenceData[]): VectorLayer<VectorSource> {
if( this.fenceLayer) {
this.map?.removeLayer(this.fenceLayer)
}
this.fenceData = fences
const source = new VectorSource()
@ -63,9 +65,9 @@ export class FenceService {
this.fenceLayer = new VectorLayer({
source: source,
zIndex: 1 // 确保围栏在标记点下方
zIndex: 0 // 确保围栏在标记点下方
})
this.map?.addLayer(this.fenceLayer)
return this.fenceLayer
}
@ -119,8 +121,10 @@ export class FenceService {
if (coordinates.length === 0) return null
// 计算围栏中心点
const centerX = coordinates.reduce((sum, coord) => sum + coord[0], 0) / coordinates.length
const centerY = coordinates.reduce((sum, coord) => sum + coord[1], 0) / coordinates.length
// const centerX = coordinates.reduce((sum, coord) => sum + coord[0], 0) / coordinates.length
// const centerY = coordinates.reduce((sum, coord) => sum + coord[1], 0) / coordinates.length
const centerX = coordinates[0][0]
const centerY = coordinates[0][1]
const labelFeature = new Feature({
geometry: new Point([centerX, centerY]),
@ -168,7 +172,7 @@ export class FenceService {
/**
*
*/
showFences(): void {
show(): void {
if (this.fenceLayer) {
this.fenceLayer.setVisible(true)
this.isVisible = true
@ -178,7 +182,7 @@ export class FenceService {
/**
*
*/
hideFences(): void {
hide(): void {
if (this.fenceLayer) {
this.fenceLayer.setVisible(false)
this.isVisible = false
@ -190,9 +194,9 @@ export class FenceService {
*/
toggleFences(): boolean {
if (this.isVisible) {
this.hideFences()
this.hide()
} else {
this.showFences()
this.show()
}
return this.isVisible
}

27
web/src/views/HandDevice/Home/components/services/marker.service.ts

@ -13,15 +13,19 @@ import { createMarkerStyle, getClusterMarkerData } from '../utils/map.utils'
import { ANIMATION_CONFIG } from '../constants/map.constants'
export class MarkerService {
private map: Map | null = null
private markerLayer: VectorLayer<VectorSource | Cluster> | null = null
markerLayer: VectorLayer<VectorSource | Cluster> | null = null
private vectorSource: VectorSource
constructor(map: Map) {
this.map = map
this.vectorSource = new VectorSource()
}
show(){
this.markerLayer?.setVisible(true)
}
hide(){
this.markerLayer?.setVisible(false)
}
/**
*
*/
@ -73,14 +77,14 @@ export class MarkerService {
const shouldForceSingleMark = () => {
if (!props.forceSingleMark || !this.map) return false
const currentZoom = this.map.getView().getZoom()
console.log('currentZoom',currentZoom)
console.log('currentZoom', currentZoom)
// return currentZoom && currentZoom >= props.forceSingleMark
return currentZoom && currentZoom >= ANIMATION_CONFIG.clusterThreshold
}
// console.log('createMarkerLayerFromProps shouldForceSingleMark', shouldForceSingleMark())
// 如果启用聚合且不强制使用单个marker模式
console.log('shouldForceSingleMark()',shouldForceSingleMark());
console.log('shouldForceSingleMark()', shouldForceSingleMark())
if (props.enableCluster && !shouldForceSingleMark()) {
const clusterSource = new Cluster({
source: this.vectorSource,
@ -89,6 +93,7 @@ export class MarkerService {
this.markerLayer = new VectorLayer({
source: clusterSource,
zIndex: 1,
style: (feature) => {
const features = feature.get('features')
@ -112,12 +117,18 @@ export class MarkerService {
// console.log('基础marker')
this.markerLayer = new VectorLayer({
source: this.vectorSource
source: this.vectorSource,
zIndex: 1,
renderOrder: (a, b) => {
// console.log('renderOrder',a,b.get('markerData').time);
// 按priority属性降序排列
return b.get('markerData').time - a.get('markerData').time
}
})
}
this.map?.addLayer(this.markerLayer)
return this.markerLayer
}

80
web/src/views/HandDevice/Home/index.vue

@ -2,7 +2,7 @@
<OpenLayerMap
class="w-full map-container"
v-if="inited"
:showDrawFences="false"
:showDrawFences="true"
:showTrajectories="true"
:markers="markers"
:fences="fences"
@ -68,8 +68,8 @@ const getMarkers = async () => {
return await getLastDetectorData().then((res: HandDetectorData[]) => {
res = res.filter((i) => i.enableStatus === 1)
var res2 = res.map((i) => {
console.log([i.longitude, i.latitude]);
console.log([i.longitude, i.latitude])
return {
...i,
coordinates: [i.longitude, i.latitude],
@ -102,7 +102,10 @@ const getFences = async () => {
}
onMounted(() => {
getMarkers()
getFences()
setTimeout(() => {
getFences()
}, 2000)
// getFences()
console.log('定时器,暂时关掉,太烦了')
// getDataTimer.value = setInterval(() => {
@ -137,6 +140,7 @@ onUnmounted(() => {
.top-panel__left {
// flex: 0 0 260px;
width: 260px;
background: rgba(255, 255, 255, 0.7);
border: 1px solid rgba(0, 0, 0, 0.06);
border-radius: 10px;
@ -144,39 +148,27 @@ onUnmounted(() => {
height: 100%;
display: flex;
align-items: center;
gap: 8px;
padding: 10px;
.search-group {
display: flex;
align-items: center;
gap: 8px;
// .search-type {
// flex: 0 0 120px;
// }
.search-input {
width: 220px;
width: 100%;
}
}
}
.top-panel__center {
flex: 1 1 auto;
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 12px;
display: flex;
align-items: center;
.data_item {
width: 200px;
background: rgba(255, 255, 255, 0.9);
border: 1px solid rgba(0, 0, 0, 0.06);
border-radius: 8px;
padding: 12px 12px;
// min-height: 56px;
// display: flex;
// flex-direction: column;
// justify-content: center;
margin-right: 12px;
.data_item__title {
font-size: 14px;
@ -204,7 +196,7 @@ onUnmounted(() => {
display: flex;
align-items: center;
gap: 8px;
flex: 0 0 auto;
background: rgba(255, 255, 255, 0.85);
border: 1px solid rgba(0, 0, 0, 0.06);
padding: 12px 12px;
@ -217,59 +209,27 @@ onUnmounted(() => {
color: #606266;
font-size: 14px;
}
.normal-legend {
.normal-legend,
.alarm1-legend,
.alarm2-legend {
padding: 4px 8px;
border-radius: 999px;
color: #fff;
font-size: 12px;
line-height: 1;
}
.normal-legend {
background: #67c23a;
}
.alarm1-legend {
padding: 4px 8px;
border-radius: 999px;
color: #fff;
font-size: 12px;
line-height: 1;
background: #e6a23c;
}
.alarm2-legend {
padding: 4px 8px;
border-radius: 999px;
color: #fff;
font-size: 12px;
line-height: 1;
background: #f56c6c;
}
}
}
@media (max-width: 992px) {
.top-panel {
.top-panel__left {
flex: 1 1 100%;
}
.top-panel__center {
flex: 1 1 100%;
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.top-panel__right {
flex: 1 1 100%;
justify-content: flex-start;
}
}
}
@media (max-width: 600px) {
.top-panel {
.top-panel__center {
grid-template-columns: 1fr;
}
}
}
</style>

Loading…
Cancel
Save