-
Notifications
You must be signed in to change notification settings - Fork 34
Expand file tree
/
Copy pathuseMessagePositioning.ts
More file actions
143 lines (125 loc) · 4.25 KB
/
useMessagePositioning.ts
File metadata and controls
143 lines (125 loc) · 4.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import { useMemo, useState, useEffect } from "react"
import { MessageData } from "../edges/EdgeProps"
import { IPoint } from "@/edges"
type ArrowDirection = "Up" | "Down" | "Left" | "Right"
interface MessagePositioningResult {
forwardMessages: MessageData[]
backwardMessages: MessageData[]
sourceArrowDirection: ArrowDirection
targetArrowDirection: ArrowDirection
forwardArrowRotation: number
backwardArrowRotation: number
forwardArrowBoxPosition: { x: number; y: number }
forwardLabelBoxPosition: { x: number; y: number }
backwardArrowBoxPosition: { x: number; y: number }
backwardLabelBoxPosition: { x: number; y: number }
isPositioned: boolean
}
export const useMessagePositioning = (
displayMessages: MessageData[],
sourcePosition: IPoint,
targetPosition: IPoint,
pathMiddlePosition: IPoint,
edgePoints?: IPoint[],
isHorizontalEdge?: boolean
): MessagePositioningResult => {
const [isPositioned, setIsPositioned] = useState(false)
const positioningData = useMemo(() => {
// Group messages by direction
const forwardMessages = displayMessages.filter(
(msg) => msg.direction === "target"
)
const backwardMessages = displayMessages.filter(
(msg) => msg.direction === "source"
)
// Calculate arrow directions based on which node is which relative to the middle
const sourceIsLeft = sourcePosition.x < targetPosition.x
const sourceIsAbove = sourcePosition.y < targetPosition.y
let sourceArrowDirection: ArrowDirection
let targetArrowDirection: ArrowDirection
if (isHorizontalEdge) {
sourceArrowDirection = sourceIsLeft ? "Left" : "Right"
targetArrowDirection = sourceIsLeft ? "Right" : "Left"
} else {
sourceArrowDirection = sourceIsAbove ? "Up" : "Down"
targetArrowDirection = sourceIsAbove ? "Down" : "Up"
}
const calculateRotation = (direction: ArrowDirection): number => {
switch (direction) {
case "Right":
return 0
case "Left":
return 180
case "Down":
return 90
case "Up":
return -90
default:
return 0
}
}
const forwardArrowRotation = calculateRotation(targetArrowDirection)
const backwardArrowRotation = calculateRotation(sourceArrowDirection)
const BASE_OFFSET_X = -90
const BASE_OFFSET_Y = 20
const LABEL_OFFSET = 18
// Position labels and arrows based on actual middle segment orientation
let forwardArrowBoxPosition: { x: number; y: number }
let forwardLabelBoxPosition: { x: number; y: number }
let backwardArrowBoxPosition: { x: number; y: number }
let backwardLabelBoxPosition: { x: number; y: number }
if (isHorizontalEdge) {
// Horizontal edge: labels above and below, arrow + label go left→right
forwardArrowBoxPosition = { x: 0, y: -BASE_OFFSET_Y }
forwardLabelBoxPosition = { x: LABEL_OFFSET, y: -BASE_OFFSET_Y }
backwardArrowBoxPosition = { x: 0, y: BASE_OFFSET_Y }
backwardLabelBoxPosition = { x: LABEL_OFFSET, y: BASE_OFFSET_Y }
} else {
// Vertical edge: forward label on the RIGHT side
forwardArrowBoxPosition = { x: BASE_OFFSET_X, y: 0 }
forwardLabelBoxPosition = { x: BASE_OFFSET_X + LABEL_OFFSET, y: 0 }
// Vertical edge: backward label on the LEFT side
backwardArrowBoxPosition = { x: -BASE_OFFSET_X, y: 0 }
backwardLabelBoxPosition = { x: -(BASE_OFFSET_X + LABEL_OFFSET), y: 0 }
}
return {
forwardMessages,
backwardMessages,
sourceArrowDirection,
targetArrowDirection,
forwardArrowRotation,
backwardArrowRotation,
forwardArrowBoxPosition,
forwardLabelBoxPosition,
backwardArrowBoxPosition,
backwardLabelBoxPosition,
isHorizontalEdge,
}
}, [
displayMessages,
sourcePosition,
targetPosition,
pathMiddlePosition,
isHorizontalEdge,
])
useEffect(() => {
if (displayMessages && displayMessages.length > 0) {
const timeout = setTimeout(() => {
setIsPositioned(true)
}, 0)
return () => clearTimeout(timeout)
} else {
setIsPositioned(false)
}
}, [
displayMessages,
sourcePosition,
targetPosition,
pathMiddlePosition,
edgePoints,
])
return {
...positioningData,
isPositioned,
}
}