Browse Source

性能优化

master
xh 1 week ago
parent
commit
8868a991e2
  1. 2
      web/src/views/HandDevice/Home/components/OpenLayerMap.vue
  2. 12
      web/src/views/HandDevice/Home/components/constants/map.constants.ts
  3. 21
      web/src/views/HandDevice/Home/components/services/animation.service.ts
  4. 16
      web/src/views/HandDevice/Home/components/services/map.service.ts
  5. 39
      web/src/views/HandDevice/Home/components/services/marker.service.ts
  6. 2
      web/src/views/HandDevice/Home/components/utils/map.utils.ts
  7. 47
      web/src/views/HandDevice/Home/index.vue

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

@ -289,7 +289,7 @@ const refreshFences = () => {
watch(
() => props.markers,
(newMarkers, oldMarkers) => {
console.log('markers changed', newMarkers, oldMarkers)
// console.log('markers changed', newMarkers, oldMarkers)
services.markerService?.updateData(newMarkers)
if (oldMarkers == undefined || newMarkers.length !== oldMarkers.length) {
fitToMarkers()

12
web/src/views/HandDevice/Home/components/constants/map.constants.ts

@ -61,19 +61,19 @@ export const ANIMATION_CONFIG = {
/**
*
*/
duration: 3,
duration: 2.4,
/**
*
*/
rippleCount: 5,
rippleCount: 3,
/**
*
*/
phaseOffset: 0.6,
phaseOffset: 0.8,
/**
*
*/
targetFPS: 60,
targetFPS: 25,
/**
*
*/
@ -81,11 +81,11 @@ export const ANIMATION_CONFIG = {
/**
*
*/
minRadius: 6,
minRadius: 2,
/**
*
*/
maxRadius: 31,
maxRadius: 25,
/**
*
*/

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

@ -22,6 +22,9 @@ export class AnimationService {
this.map = map
this.createRippleLayer()
}
private transparentFill: Fill = new Fill({
color: 'transparent'
})
/**
*
*/
@ -63,9 +66,7 @@ export class AnimationService {
new Style({
image: new Circle({
radius: radius,
fill: new Fill({
color: 'transparent'
}),
fill: this.transparentFill,
stroke: new Stroke({
color: strokeColor,
width: Math.max(1, 3 - i * 0.4) // 动态调整线宽
@ -86,21 +87,9 @@ export class AnimationService {
clear() {
const source = this.rippleLayer?.getSource()
source?.clear()
source?.clear(true)
}
add(marker: MarkerData) {
const source = this.rippleLayer?.getSource()
const feature = new Feature({
geometry: new Point(fromLonLat(marker.coordinates)),
markerData: marker
})
// 设置动画开始时间
feature.set('animationStart', Date.now())
feature.set('rippleColor', marker.statusColor)
source?.addFeature(feature)
}
addAll(markers: MarkerData[]) {
this.clear()
const source = this.rippleLayer?.getSource()

16
web/src/views/HandDevice/Home/components/services/map.service.ts

@ -3,8 +3,11 @@
*/
import { Map, View } from 'ol'
import { Tile as TileLayer } from 'ol/layer'
import { OSM, XYZ } from 'ol/source'
// import { Tile as TileLayer } from 'ol/layer'
import WebGLTileLayer from 'ol/layer/WebGLTile';
import XYZSource from 'ol/source/XYZ';
// import { OSM, XYZ } from 'ol/source'
import { fromLonLat, transformExtent } from 'ol/proj'
import { boundingExtent } from 'ol/extent'
@ -15,7 +18,7 @@ import type { MapProps } from '../types/map.types'
export class MapService {
map: Map | null = null
tileLayer: TileLayer<XYZ | OSM> | null = null
tileLayer: WebGLTileLayer | null = null
popupOverlay: Overlay | null = null
/**
@ -46,13 +49,14 @@ export class MapService {
/**
*
*/
private createTileLayer(props: MapProps): TileLayer<XYZ | OSM> {
const source = new XYZ({
private createTileLayer(props: MapProps): WebGLTileLayer {
const source = new XYZSource({
url: props.tileUrl!,
tileSize: 256,
maxZoom: props.maxZoom,
minZoom: props.minZoom
})
return new TileLayer({
return new WebGLTileLayer({
source: source
})
}

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

@ -1,7 +1,8 @@
/**
*
*/
import type { Map } from 'ol'
import { nextTick } from 'vue'
import type { Map as OpenLayersMap } from 'ol'
import { Vector as VectorLayer } from 'ol/layer'
import { Vector as VectorSource, Cluster } from 'ol/source'
import { Feature } from 'ol'
@ -17,13 +18,13 @@ import { createMarkerStyle, getClusterMarkerData, getStatusColor } from '../util
// 防抖
import { debounce } from 'lodash-es'
export class MarkerService {
private map: Map | null = null
private map: OpenLayersMap | null = null
markerLayer: VectorLayer<Cluster> | null = null
private vectorSource: VectorSource
private animationService: AnimationService | null = null
constructor(map: Map) {
constructor(map: OpenLayersMap) {
this.map = map
this.vectorSource = new VectorSource()
this.animationService = new AnimationService(map)
@ -37,14 +38,19 @@ export class MarkerService {
this.markerLayer?.setVisible(false)
this.animationService?.hide()
}
/**
*
*/
updateData(markers: MarkerData[]): void {
async updateData(markers: MarkerData[]) {
console.time('animationService clear')
this.animationService?.clear()
this.vectorSource.clear()
// debugger
console.timeEnd('animationService clear')
await nextTick()
console.time('vectorSource clear')
this.vectorSource.clear(true)
console.timeEnd('vectorSource clear')
await nextTick()
console.time('create features')
const features: Feature<Point>[] = []
markers.forEach((marker) => {
const feature = new Feature({
@ -56,7 +62,12 @@ export class MarkerService {
feature.setStyle(createMarkerStyle(statusColor))
features.push(feature)
})
console.timeEnd('create features')
await nextTick()
console.time('add features')
this.vectorSource.addFeatures(features)
console.timeEnd('add features')
this.getSinglePointsInView()
}
setClusterDistance = debounce(() => {
@ -72,9 +83,9 @@ export class MarkerService {
} else if (zoom <= 6) {
distance = 80
} else if (zoom <= 10) {
distance = 30
distance = 50
} else if (zoom <= 16) {
distance = 30
distance = 20
} else if (zoom <= 17) {
distance = 10
}
@ -94,7 +105,7 @@ export class MarkerService {
// 获取聚合图层的源
const clusterSource = clusterLayer.getSource()
if (!clusterSource) return
if (!clusterSource) return
// 获取当前视图范围
const view = map.getView()
@ -105,7 +116,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) {
@ -115,7 +126,6 @@ export class MarkerService {
}
})
this.animationService?.addAll(singlePoints || [])
}, 300)
/**
@ -142,7 +152,7 @@ export class MarkerService {
// 确保features存在且不为空
if (!features || features.length === 0) {
return new Style() // 返回空样式,隐藏无效的feature
return [] // 返回空样式,隐藏无效的feature
}
// console.log('聚合元素', features)
@ -180,7 +190,8 @@ export class MarkerService {
destroy(): void {
this.markerLayer = null
this.animationService?.destroy()
this.animationService = null
this.map = null
}
}

2
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/4, 40),
radius: Math.min(20 + clusterSize/20, 40),
fill: new Fill({
color: color + '80' // 添加透明度
}),

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

@ -170,7 +170,38 @@ const filterMarkers = computed(() => {
const filterMarkers2 = function getFilterMarkers2() {
var arr: MarkerData[] = []
var nowTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
for (let i = 0; i < 50000; i++) {
const arr2=[
{
statusStr: 'normal',
statusColor: '#67c23a',
statusLabel: '正常',
statusPriority: 7,
},{
statusStr: 'offline',
statusColor: '#909399',
statusLabel: '离线',
statusPriority: 6,
},{
statusStr: 'fenceStatus_1',
statusColor: '#e6a23c',
statusLabel: '电子围栏报警',
statusPriority: 5,
},{
statusStr: 'gasStatus_1',
statusColor: '#f56c6c',
statusLabel: '报警',
statusPriority: 4,
},{
statusStr: 'batteryStatus_1',
statusColor: '#f56c6c',
statusLabel: '电池报警',
statusPriority: 3,
}
]
for (let i = 0; i < 10000; i++) {
const statusInfo = arr2[Math.floor(Math.random() * arr2.length)]
const lon = 100 + Math.random() * 2
const lat = 30 + Math.random() * 2
arr.push({
@ -189,18 +220,18 @@ const filterMarkers2 = function getFilterMarkers2() {
gasChemical: 'CO',
batteryAlarmValue: 20,
accuracy: 1,
alarmLevel: -1,
alarmLevel: 1,
maxAlarmLevel: null,
firstValue: null,
maxValue: null,
gpsType: 0,
gasStatus: 0,
gasStatus: 2,
alarmId: 200,
batteryStatus: 0,
batteryStatusAlarmId: null,
fenceStatus: 0,
fenceAlarmId: null,
onlineStatus: 0,
onlineStatus: 1,
enableStatus: 1,
distance: null,
maxDistance: null,
@ -209,10 +240,10 @@ const filterMarkers2 = function getFilterMarkers2() {
talarmEnd: null,
coordinates: [lon, lat],
timeStr: nowTime,
statusStr: 'offline',
statusColor: '#909399',
statusLabel: '离线',
statusPriority: 7,
statusStr: statusInfo.statusStr,
statusColor: statusInfo.statusColor,
statusLabel: statusInfo.statusLabel,
statusPriority: statusInfo.statusPriority,
expanded: false
})
}

Loading…
Cancel
Save