优化:拖拽视图性能优化,拖拽期间禁止重绘canvas
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
import { ref, watch, nextTick, onMounted, computed } from 'vue'
|
import { ref, watch, nextTick, onMounted, computed } from 'vue'
|
||||||
import type { Task } from '../models/classes/Task'
|
import type { Task } from '../models/classes/Task'
|
||||||
import { getPredecessorIds } from '../utils/predecessorUtils'
|
import { getPredecessorIds } from '../utils/predecessorUtils'
|
||||||
|
// import { perfMonitor } from '../utils/perfMonitor'
|
||||||
|
|
||||||
// 定义 TaskBar 位置信息类型
|
// 定义 TaskBar 位置信息类型
|
||||||
interface TaskBarPosition {
|
interface TaskBarPosition {
|
||||||
@@ -49,6 +50,8 @@ const isDarkTheme = computed(() => {
|
|||||||
* 性能优势:相比 SVG 提升 18 倍渲染性能
|
* 性能优势:相比 SVG 提升 18 倍渲染性能
|
||||||
*/
|
*/
|
||||||
const drawLinks = () => {
|
const drawLinks = () => {
|
||||||
|
// const startTime = performance.now()
|
||||||
|
|
||||||
const canvas = canvasRef.value
|
const canvas = canvasRef.value
|
||||||
if (!canvas) return
|
if (!canvas) return
|
||||||
|
|
||||||
@@ -78,13 +81,13 @@ const drawLinks = () => {
|
|||||||
ctx.strokeStyle = lineColor
|
ctx.strokeStyle = lineColor
|
||||||
ctx.lineWidth = 1
|
ctx.lineWidth = 1
|
||||||
|
|
||||||
// 绘制每条垂直线
|
// 优化:一次性绘制所有垂直线,避免多次 stroke() 调用
|
||||||
|
ctx.beginPath()
|
||||||
for (const line of props.verticalLines) {
|
for (const line of props.verticalLines) {
|
||||||
ctx.beginPath()
|
|
||||||
ctx.moveTo(line.left, 0)
|
ctx.moveTo(line.left, 0)
|
||||||
ctx.lineTo(line.left, rect.height)
|
ctx.lineTo(line.left, rect.height)
|
||||||
ctx.stroke()
|
|
||||||
}
|
}
|
||||||
|
ctx.stroke()
|
||||||
|
|
||||||
ctx.restore()
|
ctx.restore()
|
||||||
}
|
}
|
||||||
@@ -179,6 +182,16 @@ const drawLinks = () => {
|
|||||||
ctx.globalAlpha = 1
|
ctx.globalAlpha = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 性能监控
|
||||||
|
// const endTime = performance.now()
|
||||||
|
// const duration = endTime - startTime
|
||||||
|
// perfMonitor.log('Canvas 重绘', {
|
||||||
|
// 耗时: `${duration.toFixed(2)}ms`,
|
||||||
|
// 关系线数量: props.tasks.filter(t => t.predecessor).length,
|
||||||
|
// 垂直线数量: props.verticalLines?.length || 0,
|
||||||
|
// Canvas尺寸: `${rect.width}x${rect.height}`,
|
||||||
|
// })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -224,8 +237,24 @@ watch(
|
|||||||
() => props.hoveredTaskId,
|
() => props.hoveredTaskId,
|
||||||
() => props.width,
|
() => props.width,
|
||||||
() => props.height,
|
() => props.height,
|
||||||
|
() => props.verticalLines,
|
||||||
|
() => props.showVerticalLines,
|
||||||
],
|
],
|
||||||
() => {
|
(newVals, oldVals) => {
|
||||||
|
// 记录是什么触发了重绘
|
||||||
|
// const changes: string[] = []
|
||||||
|
// if (newVals[0] !== oldVals[0]) changes.push('taskBarPositions')
|
||||||
|
// if (newVals[1] !== oldVals[1]) changes.push('tasks.length')
|
||||||
|
// if (newVals[2] !== oldVals[2]) changes.push('highlightedTaskId')
|
||||||
|
// if (newVals[3] !== oldVals[3]) changes.push('highlightedTaskIds')
|
||||||
|
// if (newVals[4] !== oldVals[4]) changes.push('hoveredTaskId')
|
||||||
|
// if (newVals[5] !== oldVals[5]) changes.push('width')
|
||||||
|
// if (newVals[6] !== oldVals[6]) changes.push('height')
|
||||||
|
// if (newVals[7] !== oldVals[7]) changes.push('verticalLines')
|
||||||
|
// if (newVals[8] !== oldVals[8]) changes.push('showVerticalLines')
|
||||||
|
|
||||||
|
// perfMonitor.log('Canvas 触发重绘', { 变化属性: changes.join(', ') })
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
drawLinks()
|
drawLinks()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1019,8 +1019,8 @@ const handleTimelineContainerResized = () => {
|
|||||||
|
|
||||||
// 处理任务行悬停事件
|
// 处理任务行悬停事件
|
||||||
const handleTaskRowHover = (taskId: number | null) => {
|
const handleTaskRowHover = (taskId: number | null) => {
|
||||||
// 如果正在拖拽Splitter,则不响应悬停事件
|
// 如果正在拖拽Splitter或拖动滚动,则不响应悬停事件
|
||||||
if (isSplitterDragging.value) {
|
if (isSplitterDragging.value || isDragging.value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1047,6 +1047,10 @@ const contentHeight = computed(() => {
|
|||||||
|
|
||||||
// 监听TaskList的悬停事件
|
// 监听TaskList的悬停事件
|
||||||
const handleTaskListHover = (event: CustomEvent) => {
|
const handleTaskListHover = (event: CustomEvent) => {
|
||||||
|
// 如果正在拖动滚动,则不响应悬停事件
|
||||||
|
if (isDragging.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
hoveredTaskId.value = event.detail
|
hoveredTaskId.value = event.detail
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2341,6 +2345,9 @@ const handleMouseUp = () => {
|
|||||||
timelineContainer.value.style.userSelect = 'auto'
|
timelineContainer.value.style.userSelect = 'auto'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 清空 hover 状态,避免拖动结束后立即触发 hover 重绘
|
||||||
|
hoveredTaskId.value = null
|
||||||
|
|
||||||
// 移除全局事件监听器
|
// 移除全局事件监听器
|
||||||
document.removeEventListener('mousemove', handleMouseMove)
|
document.removeEventListener('mousemove', handleMouseMove)
|
||||||
document.removeEventListener('mouseup', handleMouseUp)
|
document.removeEventListener('mouseup', handleMouseUp)
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* 性能监控工具
|
||||||
|
*/
|
||||||
|
|
||||||
|
let lastLogTime = 0
|
||||||
|
const LOG_THROTTLE = 100 // 最多每 100ms 输出一次日志
|
||||||
|
|
||||||
|
export const perfMonitor = {
|
||||||
|
/**
|
||||||
|
* 记录性能日志(自动节流)
|
||||||
|
*/
|
||||||
|
log(tag: string, data: unknown) {
|
||||||
|
const now = Date.now()
|
||||||
|
if (now - lastLogTime < LOG_THROTTLE) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lastLogTime = now
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(`[Perf] ${tag}:`, data)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测量函数执行时间
|
||||||
|
*/
|
||||||
|
measure<T>(tag: string, fn: () => T): T {
|
||||||
|
const start = performance.now()
|
||||||
|
const result = fn()
|
||||||
|
const end = performance.now()
|
||||||
|
const duration = end - start
|
||||||
|
|
||||||
|
if (duration > 5) {
|
||||||
|
// 只记录耗时超过 5ms 的操作
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(`[Perf] ${tag}: ${duration.toFixed(2)}ms`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user