Explorar o código

修复实时折线图闪烁问题

Zimo hai 4 días
pai
achega
7e5f7aef35

+ 69 - 10
src/views/oli-connection/monitoring-board/chart.vue

@@ -142,11 +142,7 @@ const handleMessageUpdate = (_topic: string, data: any) => {
   if (!updatedNames.size) return
 
   updateDimensionValues(valueMap)
-
-  const latestTs = getLatestTimestamp() ?? Date.now()
-  trimChartDataToRealtimeWindow(latestTs)
-  applyRealtimeWindow(latestTs)
-  updateSeriesByNames(Array.from(updatedNames))
+  scheduleRealtimeChartUpdate(Array.from(updatedNames))
 }
 
 watch(isConnected, (newVal) => {
@@ -205,6 +201,8 @@ let chart: echarts.ECharts | null = null
 
 const chartRealtimeMode = ref(true)
 let chartLoadVersion = 0
+let realtimeUpdateFrame: number | null = null
+const pendingRealtimeSeriesNames = new Set<string>()
 
 const TREND_AXIS_MIN = 0
 const TREND_AXIS_MAX = 100
@@ -407,12 +405,23 @@ function updateDimensionValues(valueMap: Map<string, number>) {
   })
 }
 
+function getChartAnimationOptions() {
+  return {
+    animation: !chartRealtimeMode.value,
+    animationDuration: chartRealtimeMode.value ? 0 : 200,
+    animationEasing: 'linear',
+    animationDurationUpdate: chartRealtimeMode.value ? 0 : 200,
+    animationEasingUpdate: 'linear'
+  }
+}
+
 function updateSeriesByNames(names: string[]) {
   if (!chart) render()
   if (!chart || !names.length) return
 
   chart.setOption(
     {
+      ...getChartAnimationOptions(),
       legend: {
         selected: selectedDimension.value
       },
@@ -429,6 +438,58 @@ function updateSeriesByNames(names: string[]) {
   )
 }
 
+function flushRealtimeChartUpdate() {
+  realtimeUpdateFrame = null
+
+  const names = Array.from(pendingRealtimeSeriesNames)
+  pendingRealtimeSeriesNames.clear()
+
+  if (!chart) render()
+  if (!chart || !names.length) return
+
+  const latestTs = getLatestTimestamp() ?? Date.now()
+  trimChartDataToRealtimeWindow(latestTs)
+
+  chart.setOption(
+    {
+      ...getChartAnimationOptions(),
+      xAxis: {
+        min: latestTs - REALTIME_WINDOW_MS,
+        max: getRealtimeXAxisMax(latestTs)
+      },
+      legend: {
+        selected: selectedDimension.value
+      },
+      yAxis: getTrendYAxisOptions(),
+      series: names.map((name) => ({
+        id: name,
+        name,
+        data: buildSeriesData(name)
+      }))
+    },
+    {
+      lazyUpdate: true
+    }
+  )
+}
+
+function scheduleRealtimeChartUpdate(names: string[]) {
+  names.forEach((name) => pendingRealtimeSeriesNames.add(name))
+
+  if (realtimeUpdateFrame !== null) return
+
+  realtimeUpdateFrame = window.requestAnimationFrame(flushRealtimeChartUpdate)
+}
+
+function cancelRealtimeChartUpdate() {
+  if (realtimeUpdateFrame !== null) {
+    window.cancelAnimationFrame(realtimeUpdateFrame)
+    realtimeUpdateFrame = null
+  }
+
+  pendingRealtimeSeriesNames.clear()
+}
+
 function handleClickSpec(modelName: string) {
   selectedDimension.value[modelName] = !selectedDimension.value[modelName]
   chart?.setOption({
@@ -465,11 +526,7 @@ function render() {
   chart.setOption(
     {
       color: dimensions.value.map((item) => item.color),
-      animation: true,
-      animationDuration: 200,
-      animationEasing: 'linear',
-      animationDurationUpdate: 200,
-      animationEasingUpdate: 'linear',
+      ...getChartAnimationOptions(),
       grid: {
         left: '2%',
         top: '5%',
@@ -692,6 +749,7 @@ watch(
     await cancelAllRequests()
 
     destroy()
+    cancelRealtimeChartUpdate()
     chartLoadVersion += 1
 
     if (chart) chart.clear()
@@ -703,6 +761,7 @@ watch(
 onUnmounted(() => {
   chartLoadVersion += 1
   destroy()
+  cancelRealtimeChartUpdate()
 
   window.removeEventListener('resize', resizeChart)
   chart?.dispose()

+ 67 - 10
src/views/oli-connection/monitoring/detail.vue

@@ -122,6 +122,8 @@ const chartRealtimeMode = ref(true)
 const token = ref('')
 let chart: echarts.ECharts | null = null
 let chartLoadVersion = 0
+let realtimeUpdateFrame: number | null = null
+const pendingRealtimeSeriesNames = new Set<string>()
 const { toggle, isFullscreen } = useFullscreen(targetArea)
 
 interface ChartPoint {
@@ -386,11 +388,22 @@ function appendChartPoint(name: string, point: ChartPoint) {
   chartData.value[name] = series
 }
 
+function getChartAnimationOptions() {
+  return {
+    animation: !chartRealtimeMode.value,
+    animationDuration: chartRealtimeMode.value ? 0 : 200,
+    animationEasing: 'linear',
+    animationDurationUpdate: chartRealtimeMode.value ? 0 : 200,
+    animationEasingUpdate: 'linear'
+  }
+}
+
 function updateSingleSeries(name: string) {
   if (!chart) renderChart()
   if (!chart) return
 
   chart.setOption({
+    ...getChartAnimationOptions(),
     legend: {
       selected: selectedDimension.value
     },
@@ -409,6 +422,7 @@ function updateSeriesByNames(names: string[]) {
   if (!chart) return
 
   chart.setOption({
+    ...getChartAnimationOptions(),
     legend: {
       selected: selectedDimension.value
     },
@@ -421,6 +435,53 @@ function updateSeriesByNames(names: string[]) {
   })
 }
 
+function flushRealtimeChartUpdate() {
+  realtimeUpdateFrame = null
+
+  const names = Array.from(pendingRealtimeSeriesNames)
+  pendingRealtimeSeriesNames.clear()
+
+  if (!chart) renderChart()
+  if (!chart || !names.length) return
+
+  const latestTs = getLatestTimestamp() ?? Date.now()
+  trimChartDataToRealtimeWindow(latestTs)
+
+  chart.setOption({
+    ...getChartAnimationOptions(),
+    xAxis: {
+      min: latestTs - chartWindowMs.value,
+      max: getRealtimeXAxisMax(latestTs)
+    },
+    legend: {
+      selected: selectedDimension.value
+    },
+    yAxis: getTrendYAxisOptions(),
+    series: names.map((name) => ({
+      id: name,
+      name,
+      data: chartData.value[name]?.map((item) => mapChartPoint(item, name)) ?? []
+    }))
+  })
+}
+
+function scheduleRealtimeChartUpdate(names: string[]) {
+  names.forEach((name) => pendingRealtimeSeriesNames.add(name))
+
+  if (realtimeUpdateFrame !== null) return
+
+  realtimeUpdateFrame = window.requestAnimationFrame(flushRealtimeChartUpdate)
+}
+
+function cancelRealtimeChartUpdate() {
+  if (realtimeUpdateFrame !== null) {
+    window.cancelAnimationFrame(realtimeUpdateFrame)
+    realtimeUpdateFrame = null
+  }
+
+  pendingRealtimeSeriesNames.clear()
+}
+
 function renderChart() {
   if (!chartRef.value) return
 
@@ -433,11 +494,7 @@ function renderChart() {
 
   chart.setOption(
     {
-      animation: true,
-      animationDuration: 200,
-      animationEasing: 'linear',
-      animationDurationUpdate: 200,
-      animationEasingUpdate: 'linear',
+      ...getChartAnimationOptions(),
       color: dimensions.value.map((item) => item.color),
       grid: {
         left: '2%',
@@ -588,11 +645,7 @@ function handleMessageUpdate(_topic: string, payload: any) {
   if (!updatedNames.size) return
 
   updateDimensionValues(valueMap)
-
-  const latestTs = getLatestTimestamp() ?? Date.now()
-  trimChartDataToRealtimeWindow(latestTs)
-  applyRealtimeWindow(latestTs)
-  updateSeriesByNames(Array.from(updatedNames))
+  scheduleRealtimeChartUpdate(Array.from(updatedNames))
 }
 
 async function ensureToken() {
@@ -683,6 +736,7 @@ async function resetChart() {
   selectedDate.value = getInitialDateRange()
   await cancelAllRequests()
   destroy()
+  cancelRealtimeChartUpdate()
   chart?.clear()
   await initPage(false)
 }
@@ -702,6 +756,7 @@ async function handleChartWindowMinutesChange(value?: number) {
   chartLoadVersion += 1
   await cancelAllRequests()
   destroy()
+  cancelRealtimeChartUpdate()
   chart?.clear()
   await nextTick()
   renderChart()
@@ -718,6 +773,7 @@ async function handleDateChange() {
   chartRealtimeMode.value = false
   await cancelAllRequests()
   destroy()
+  cancelRealtimeChartUpdate()
   chart?.clear()
   await nextTick()
   renderChart()
@@ -862,6 +918,7 @@ onMounted(() => {
 onUnmounted(() => {
   chartLoadVersion += 1
   destroy()
+  cancelRealtimeChartUpdate()
   window.removeEventListener('resize', resizeChart)
   chart?.dispose()
   chart = null