feat: simplify paths
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { getPathNodeIds, getPausedSegmentNodeIds } from '@/lib/graph/graphPath'
|
||||
import { getPathNodeIds, getPathToUpdatingSegmentNodeIds } from '@/lib/graph/graphPath'
|
||||
|
||||
/** Serialize set to a stable string for equality. */
|
||||
function setToStableKey(s: Set<string>): string {
|
||||
@@ -14,8 +14,7 @@ function setToStableKey(s: Set<string>): string {
|
||||
|
||||
export type EdgeLike = { source: string; target: string }
|
||||
|
||||
/** Short tail (ms) after last updating node ends so the path doesn't vanish instantly. */
|
||||
const CONNECTION_PATH_UPDATE_TAIL_MS = 200
|
||||
const PULSE_MS = 1500
|
||||
|
||||
export type UseCanvasConnectionPathResult = {
|
||||
connectionPathUpdatingNodeIds: string[]
|
||||
@@ -35,51 +34,13 @@ export type UseCanvasConnectionPathResult = {
|
||||
}
|
||||
|
||||
export function useCanvasConnectionPath(edges: EdgeLike[]): UseCanvasConnectionPathResult {
|
||||
const [connectionPathUpdatingNodeIds, setConnectionPathUpdatingNodeIds] = useState<string[]>([])
|
||||
const [connectionPathTriggerNodeIds, setConnectionPathTriggerNodeIds] = useState<string[]>([])
|
||||
const [connectionPathPausedNodeIds, setConnectionPathPausedNodeIds] = useState<string[]>([])
|
||||
const [pulseEndsAt, setPulseEndsAt] = useState<number | null>(null)
|
||||
const [connectionPathErrorNodeIds, setConnectionPathErrorNodeIds] = useState<string[]>([])
|
||||
|
||||
const pathUpdateNodeIdsRef = useRef<Set<string>>(new Set())
|
||||
const pathUpdateEndTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||
const connectionPathPausedNodeIdsRef = useRef<string[]>([])
|
||||
connectionPathPausedNodeIdsRef.current = connectionPathPausedNodeIds
|
||||
|
||||
const pathTriggerBatchRef = useRef<Set<string>>(new Set())
|
||||
const pathTriggerScheduledRef = useRef(false)
|
||||
|
||||
const clearPathUpdateSession = useCallback(() => {
|
||||
setConnectionPathUpdatingNodeIds([])
|
||||
if (connectionPathPausedNodeIdsRef.current.length === 0) {
|
||||
setConnectionPathTriggerNodeIds([])
|
||||
setConnectionPathPausedNodeIds([])
|
||||
}
|
||||
}, [])
|
||||
|
||||
const startConnectionPathUpdate = useCallback((nodeId: string) => {
|
||||
const ref = pathUpdateNodeIdsRef.current
|
||||
ref.add(nodeId)
|
||||
if (ref.size === 1) {
|
||||
if (pathUpdateEndTimeoutRef.current != null) {
|
||||
clearTimeout(pathUpdateEndTimeoutRef.current)
|
||||
pathUpdateEndTimeoutRef.current = null
|
||||
}
|
||||
}
|
||||
setConnectionPathUpdatingNodeIds(Array.from(ref))
|
||||
}, [])
|
||||
|
||||
const endConnectionPathUpdate = useCallback((nodeId: string) => {
|
||||
const ref = pathUpdateNodeIdsRef.current
|
||||
ref.delete(nodeId)
|
||||
if (ref.size > 0) {
|
||||
setConnectionPathUpdatingNodeIds(Array.from(ref))
|
||||
return
|
||||
}
|
||||
pathUpdateEndTimeoutRef.current = setTimeout(() => {
|
||||
pathUpdateEndTimeoutRef.current = null
|
||||
clearPathUpdateSession()
|
||||
}, CONNECTION_PATH_UPDATE_TAIL_MS)
|
||||
}, [clearPathUpdateSession])
|
||||
const pulseTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||
|
||||
const addConnectionPathTrigger = useCallback((nodeId: string) => {
|
||||
pathTriggerBatchRef.current.add(nodeId)
|
||||
@@ -95,27 +56,31 @@ export function useCanvasConnectionPath(edges: EdgeLike[]): UseCanvasConnectionP
|
||||
batch.forEach((id) => next.add(id))
|
||||
return next.size === prev.length && prev.every((id) => next.has(id)) ? prev : Array.from(next)
|
||||
})
|
||||
setPulseEndsAt(Date.now() + PULSE_MS)
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
if (pathUpdateEndTimeoutRef.current != null) {
|
||||
clearTimeout(pathUpdateEndTimeoutRef.current)
|
||||
useEffect(() => {
|
||||
if (pulseEndsAt == null) return
|
||||
const delay = Math.max(0, pulseEndsAt - Date.now())
|
||||
if (pulseTimerRef.current != null) clearTimeout(pulseTimerRef.current)
|
||||
pulseTimerRef.current = setTimeout(() => {
|
||||
pulseTimerRef.current = null
|
||||
setPulseEndsAt(null)
|
||||
setConnectionPathTriggerNodeIds([])
|
||||
}, delay)
|
||||
return () => {
|
||||
if (pulseTimerRef.current != null) {
|
||||
clearTimeout(pulseTimerRef.current)
|
||||
pulseTimerRef.current = null
|
||||
}
|
||||
},
|
||||
[]
|
||||
)
|
||||
}
|
||||
}, [pulseEndsAt])
|
||||
|
||||
const connectionPathNodeIdsRaw = useMemo(
|
||||
() =>
|
||||
getPathNodeIds(
|
||||
edges,
|
||||
connectionPathUpdatingNodeIds,
|
||||
connectionPathTriggerNodeIds,
|
||||
connectionPathPausedNodeIds
|
||||
),
|
||||
[edges, connectionPathUpdatingNodeIds, connectionPathTriggerNodeIds, connectionPathPausedNodeIds]
|
||||
getPathNodeIds(edges, [], connectionPathTriggerNodeIds, undefined),
|
||||
[edges, connectionPathTriggerNodeIds]
|
||||
)
|
||||
const connectionPathNodeIdsRef = useRef<Set<string>>(connectionPathNodeIdsRaw)
|
||||
const connectionPathNodeIdsKeyRef = useRef<string>('')
|
||||
@@ -128,37 +93,19 @@ export function useCanvasConnectionPath(edges: EdgeLike[]): UseCanvasConnectionP
|
||||
return connectionPathNodeIdsRaw
|
||||
})()
|
||||
|
||||
const connectionPathPausedSegmentNodeIdsRaw = useMemo(
|
||||
() =>
|
||||
getPausedSegmentNodeIds(
|
||||
edges,
|
||||
connectionPathNodeIds,
|
||||
connectionPathTriggerNodeIds,
|
||||
connectionPathPausedNodeIds
|
||||
),
|
||||
[edges, connectionPathNodeIds, connectionPathTriggerNodeIds, connectionPathPausedNodeIds]
|
||||
)
|
||||
const connectionPathPausedSegmentNodeIdsRef = useRef<Set<string>>(
|
||||
connectionPathPausedSegmentNodeIdsRaw
|
||||
)
|
||||
const connectionPathPausedSegmentNodeIdsKeyRef = useRef<string>('')
|
||||
const connectionPathPausedSegmentNodeIds =
|
||||
setToStableKey(connectionPathPausedSegmentNodeIdsRaw) ===
|
||||
connectionPathPausedSegmentNodeIdsKeyRef.current
|
||||
? connectionPathPausedSegmentNodeIdsRef.current
|
||||
: (() => {
|
||||
connectionPathPausedSegmentNodeIdsKeyRef.current = setToStableKey(
|
||||
connectionPathPausedSegmentNodeIdsRaw
|
||||
)
|
||||
connectionPathPausedSegmentNodeIdsRef.current = connectionPathPausedSegmentNodeIdsRaw
|
||||
return connectionPathPausedSegmentNodeIdsRaw
|
||||
})()
|
||||
const EMPTY_PAUSED_SEGMENT = useMemo(() => new Set<string>(), [])
|
||||
const connectionPathPausedSegmentNodeIds = EMPTY_PAUSED_SEGMENT
|
||||
|
||||
const connectionPathActiveSegmentNodeIdsRaw = useMemo(() => {
|
||||
const active = new Set(connectionPathNodeIds)
|
||||
connectionPathPausedSegmentNodeIds.forEach((id) => active.delete(id))
|
||||
return active
|
||||
}, [connectionPathNodeIds, connectionPathPausedSegmentNodeIds])
|
||||
const pulseActive = pulseEndsAt != null
|
||||
const connectionPathActiveSegmentNodeIdsRaw = useMemo(
|
||||
() =>
|
||||
getPathToUpdatingSegmentNodeIds(
|
||||
edges,
|
||||
connectionPathTriggerNodeIds,
|
||||
pulseActive
|
||||
),
|
||||
[edges, connectionPathTriggerNodeIds, pulseActive]
|
||||
)
|
||||
const connectionPathActiveSegmentNodeIdsRef = useRef<Set<string>>(
|
||||
connectionPathActiveSegmentNodeIdsRaw
|
||||
)
|
||||
@@ -175,13 +122,11 @@ export function useCanvasConnectionPath(edges: EdgeLike[]): UseCanvasConnectionP
|
||||
return connectionPathActiveSegmentNodeIdsRaw
|
||||
})()
|
||||
|
||||
const addConnectionPathPausedNode = useCallback((nodeId: string) => {
|
||||
setConnectionPathPausedNodeIds((prev) => (prev.includes(nodeId) ? prev : [...prev, nodeId]))
|
||||
}, [])
|
||||
const addConnectionPathPausedNode = useCallback((_nodeId: string) => {}, [])
|
||||
const removeConnectionPathPausedNode = useCallback((_nodeId: string) => {}, [])
|
||||
|
||||
const removeConnectionPathPausedNode = useCallback((nodeId: string) => {
|
||||
setConnectionPathPausedNodeIds((prev) => prev.filter((id) => id !== nodeId))
|
||||
}, [])
|
||||
const startConnectionPathUpdate = useCallback((_nodeId: string) => {}, [])
|
||||
const endConnectionPathUpdate = useCallback((_nodeId: string) => {}, [])
|
||||
|
||||
const addConnectionPathError = useCallback((nodeId: string) => {
|
||||
setConnectionPathErrorNodeIds((prev) => (prev.includes(nodeId) ? prev : [...prev, nodeId]))
|
||||
@@ -192,9 +137,9 @@ export function useCanvasConnectionPath(edges: EdgeLike[]): UseCanvasConnectionP
|
||||
}, [])
|
||||
|
||||
return {
|
||||
connectionPathUpdatingNodeIds,
|
||||
connectionPathUpdatingNodeIds: [],
|
||||
connectionPathTriggerNodeIds,
|
||||
connectionPathPausedNodeIds,
|
||||
connectionPathPausedNodeIds: [],
|
||||
connectionPathErrorNodeIds,
|
||||
connectionPathNodeIds,
|
||||
connectionPathPausedSegmentNodeIds,
|
||||
|
||||
Reference in New Issue
Block a user