Skip to content

Commit 92f9716

Browse files
authored
Merge pull request #300 from ls1intum/fix/sfc-edges
Fix/sfc edges
2 parents 47085a3 + dff3162 commit 92f9716

File tree

4 files changed

+69
-63
lines changed

4 files changed

+69
-63
lines changed

library/lib/edges/edgeTypes/CommunicationDiagramEdge.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,9 @@ export const CommunicationDiagramEdge = ({
155155
isReconnectingRef={isReconnectingRef}
156156
sourcePosition={{ x: sourceX, y: sourceY }}
157157
targetPosition={{ x: targetX, y: targetY }}
158-
edgePoints={edgeData.activePoints} // Pass the edge points
159158
textColor={textColor}
159+
edgePoints={edgeData.activePoints}
160+
isHorizontalEdge={edgeData.isMiddlePathHorizontal}
160161
/>
161162

162163
<CommonEdgeElements

library/lib/edges/edgeTypes/SfcDiagramEdge.tsx

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useStepPathEdge } from "@/hooks/useStepPathEdge"
44
import { useDiagramStore, usePopoverStore } from "@/store/context"
55
import { useShallow } from "zustand/shallow"
66
import { useToolbar } from "@/hooks"
7-
import { useRef } from "react"
7+
import { useMemo, useRef } from "react"
88
import { EDGE_HIGHTLIGHT_STROKE_WIDTH } from "@/constants"
99
import { FeedbackDropzone } from "@/components/wrapper/FeedbackDropzone"
1010
import { AssessmentSelectableWrapper } from "@/components"
@@ -37,7 +37,7 @@ function getParsedEdgeData(data: unknown): {
3737
return { isNegated: false, displayName: label, showBar: true }
3838
}
3939
}
40-
40+
const crossbarLength = 20
4141
export const SfcDiagramEdge = ({
4242
id,
4343
type,
@@ -103,6 +103,45 @@ export const SfcDiagramEdge = ({
103103
const { isNegated, displayName, showBar } = getParsedEdgeData(data)
104104
const { strokeColor, textColor } = getCustomColorsFromDataForEdge(data)
105105

106+
const labelPosition = {
107+
x: edgeData.isMiddlePathHorizontal
108+
? edgeData.pathMiddlePosition.x
109+
: edgeData.pathMiddlePosition.x + 30,
110+
y: edgeData.isMiddlePathHorizontal
111+
? edgeData.pathMiddlePosition.y - 30
112+
: edgeData.pathMiddlePosition.y,
113+
textAnchor: edgeData.isMiddlePathHorizontal ? "middle" : ("start" as const),
114+
dominantBaseline: edgeData.isMiddlePathHorizontal
115+
? "middle"
116+
: ("middle" as const),
117+
}
118+
119+
const crossbarCoordinates = useMemo(() => {
120+
if (edgeData.isMiddlePathHorizontal) {
121+
// If middle segment is horizontal, make crossbar vertical
122+
return {
123+
x1: edgeData.pathMiddlePosition.x,
124+
y1: edgeData.pathMiddlePosition.y - crossbarLength,
125+
x2: edgeData.pathMiddlePosition.x,
126+
y2: edgeData.pathMiddlePosition.y + crossbarLength,
127+
orientation: "vertical" as const,
128+
}
129+
} else {
130+
// If middle segment is vertical, make crossbar horizontal
131+
return {
132+
x1: edgeData.pathMiddlePosition.x - crossbarLength,
133+
y1: edgeData.pathMiddlePosition.y,
134+
x2: edgeData.pathMiddlePosition.x + crossbarLength,
135+
y2: edgeData.pathMiddlePosition.y,
136+
orientation: "horizontal" as const,
137+
}
138+
}
139+
}, [
140+
edgeData.isMiddlePathHorizontal,
141+
edgeData.pathMiddlePosition,
142+
crossbarLength,
143+
])
144+
106145
return (
107146
<AssessmentSelectableWrapper elementId={id} asElement="g">
108147
<FeedbackDropzone elementId={id} asElement="path">
@@ -156,25 +195,26 @@ export const SfcDiagramEdge = ({
156195

157196
{/* SFC Transition - show crossbar and label */}
158197
<g>
159-
{/* Crossbar - thick horizontal line at the middle */}
198+
{/* Crossbar - perpendicular to middle segment direction */}
160199
{showBar && (
161200
<line
162-
x1={edgeData.pathMiddlePosition.x - 20}
163-
y1={edgeData.pathMiddlePosition.y}
164-
x2={edgeData.pathMiddlePosition.x + 20}
165-
y2={edgeData.pathMiddlePosition.y}
201+
x1={crossbarCoordinates.x1}
202+
y1={crossbarCoordinates.y1}
203+
x2={crossbarCoordinates.x2}
204+
y2={crossbarCoordinates.y2}
166205
stroke={strokeColor}
167206
strokeWidth="10"
168207
/>
169208
)}
170209

210+
{/* SFC Label - positioned based on edge orientation */}
171211
{displayName && (
172212
<text
173-
x={edgeData.pathMiddlePosition.x}
174-
y={edgeData.pathMiddlePosition.y - 20}
175213
fill={textColor}
176-
textAnchor="middle"
177-
dominantBaseline="middle"
214+
x={labelPosition.x}
215+
y={labelPosition.y}
216+
textAnchor={labelPosition.textAnchor}
217+
dominantBaseline={labelPosition.dominantBaseline}
178218
fontSize="14"
179219
textDecoration={isNegated ? "overline" : undefined}
180220
>

library/lib/edges/labelTypes/EdgeMultipleLabels.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,28 @@ import { EdgeLabelRenderer } from "@xyflow/react"
44
import { MessageData } from "../EdgeProps"
55
import { useMessagePositioning } from "../../hooks"
66

7-
export const EdgeMultipleLabels: React.FC<{
7+
interface EdgeMultipleLabelsProps {
88
messages?: MessageData[]
99
pathMiddlePosition: IPoint
1010
showRelationshipLabels: boolean
1111
isReconnectingRef?: React.MutableRefObject<boolean>
1212
sourcePosition: IPoint
1313
targetPosition: IPoint
14-
edgePoints?: Array<{ x: number; y: number }>
14+
edgePoints?: IPoint[]
15+
isHorizontalEdge?: boolean
1516
textColor: string
16-
}> = ({
17+
}
18+
export const EdgeMultipleLabels = ({
1719
messages,
1820
pathMiddlePosition,
1921
showRelationshipLabels,
2022
isReconnectingRef,
2123
sourcePosition,
2224
targetPosition,
2325
edgePoints,
26+
isHorizontalEdge,
2427
textColor,
25-
}) => {
28+
}: EdgeMultipleLabelsProps) => {
2629
const displayMessages: MessageData[] = messages || []
2730

2831
const {
@@ -35,13 +38,13 @@ export const EdgeMultipleLabels: React.FC<{
3538
backwardArrowBoxPosition,
3639
backwardLabelBoxPosition,
3740
isPositioned,
38-
isHorizontalEdge,
3941
} = useMessagePositioning(
4042
displayMessages,
4143
sourcePosition,
4244
targetPosition,
4345
pathMiddlePosition,
44-
edgePoints
46+
edgePoints,
47+
isHorizontalEdge
4548
)
4649

4750
if (

library/lib/hooks/useMessagePositioning.ts

Lines changed: 7 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useMemo, useState, useEffect } from "react"
22
import { MessageData } from "../edges/EdgeProps"
3+
import { IPoint } from "@/edges"
34

45
type ArrowDirection = "Up" | "Down" | "Left" | "Right"
56

@@ -15,15 +16,15 @@ interface MessagePositioningResult {
1516
backwardArrowBoxPosition: { x: number; y: number }
1617
backwardLabelBoxPosition: { x: number; y: number }
1718
isPositioned: boolean
18-
isHorizontalEdge?: boolean
1919
}
2020

2121
export const useMessagePositioning = (
2222
displayMessages: MessageData[],
23-
sourcePosition: { x: number; y: number },
24-
targetPosition: { x: number; y: number },
25-
pathMiddlePosition: { x: number; y: number },
26-
edgePoints?: Array<{ x: number; y: number }> // Add edge points parameter
23+
sourcePosition: IPoint,
24+
targetPosition: IPoint,
25+
pathMiddlePosition: IPoint,
26+
edgePoints?: IPoint[],
27+
isHorizontalEdge?: boolean
2728
): MessagePositioningResult => {
2829
const [isPositioned, setIsPositioned] = useState(false)
2930

@@ -36,45 +37,6 @@ export const useMessagePositioning = (
3637
(msg) => msg.direction === "source"
3738
)
3839

39-
// Calculate edge direction from the middle segment
40-
const calculateMiddleSegmentDirection = (
41-
points?: Array<{ x: number; y: number }>,
42-
fallbackSource?: { x: number; y: number },
43-
fallbackTarget?: { x: number; y: number }
44-
) => {
45-
let isHorizontalEdge = false
46-
if (points && points.length >= 2) {
47-
// Find the middle point index
48-
const middleIndex = Math.floor(points.length / 2) - 1
49-
const middlePoint = points[middleIndex]
50-
const nextPoint = points[Math.min(middleIndex + 1, points.length - 1)]
51-
52-
// If we're at the last point, use the previous point instead
53-
const referencePoint =
54-
middleIndex === points.length - 1
55-
? points[Math.max(middleIndex - 1, 0)]
56-
: nextPoint
57-
const dx = Math.abs(referencePoint.x - middlePoint.x)
58-
const dy = Math.abs(referencePoint.y - middlePoint.y)
59-
isHorizontalEdge = dx > dy
60-
} else {
61-
// Fallback to source/target comparison if no points available
62-
if (fallbackSource && fallbackTarget) {
63-
const dx = Math.abs(fallbackTarget.x - fallbackSource.x)
64-
const dy = Math.abs(fallbackTarget.y - fallbackSource.y)
65-
isHorizontalEdge = dx > dy
66-
}
67-
}
68-
69-
return isHorizontalEdge
70-
}
71-
72-
const isHorizontalEdge = calculateMiddleSegmentDirection(
73-
edgePoints,
74-
sourcePosition,
75-
targetPosition
76-
)
77-
7840
// Calculate arrow directions based on which node is which relative to the middle
7941
const sourceIsLeft = sourcePosition.x < targetPosition.x
8042
const sourceIsAbove = sourcePosition.y < targetPosition.y
@@ -151,7 +113,7 @@ export const useMessagePositioning = (
151113
sourcePosition,
152114
targetPosition,
153115
pathMiddlePosition,
154-
edgePoints,
116+
isHorizontalEdge,
155117
])
156118

157119
useEffect(() => {

0 commit comments

Comments
 (0)