Skip to content

Commit 6fc3f42

Browse files
committed
feat: Introduce performance logging for backend service initialization and add utilities for trimming quadratic Bézier curves.
1 parent 8ca661d commit 6fc3f42

5 files changed

Lines changed: 307 additions & 92 deletions

File tree

src/NodeCanvas.jsx

Lines changed: 138 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ import { getPortPosition, calculateStaggeredPosition } from './utils/canvas/port
8787
import { computeCleanPolylineFromPorts, generateManhattanRoutingPath, generateCleanRoutingPath } from './utils/canvas/edgeRouting.js';
8888
import * as GeometryUtils from './utils/canvas/geometryUtils.js';
8989
import EdgeRenderer from './components/EdgeRenderer.jsx';
90-
import { calculateParallelEdgePath, distanceToQuadraticBezier, calculateCurveControlPoint } from './utils/canvas/parallelEdgeUtils.js';
90+
import { calculateParallelEdgePath, distanceToQuadraticBezier, calculateCurveControlPoint, getTrimmedBezierPath } from './utils/canvas/parallelEdgeUtils.js';
9191
import Panel from './Panel'; // This is now used for both sides
9292
import TypeList from './TypeList'; // Re-add TypeList component
9393
import SaveStatusDisplay from './SaveStatusDisplay'; // Import the save status display
@@ -10390,25 +10390,17 @@ function NodeCanvas() {
1039010390
nodeGroupMemberIds.has(e.sourceId) || nodeGroupMemberIds.has(e.destinationId)
1039110391
);
1039210392

10393-
// Group edges by node pairs to calculate curve offsets for multiple edges between same nodes
10394-
const edgePairGroups = new Map();
10395-
visibleEdges.forEach(e => {
10396-
const key = [e.sourceId, e.destinationId].sort().join('--');
10397-
if (!edgePairGroups.has(key)) edgePairGroups.set(key, []);
10398-
edgePairGroups.get(key).push(e.id);
10399-
});
10393+
// edgeCurveInfo is computed via useMemo and available in scope
10394+
// (used for parallel edge curve offset calculation)
1040010395

10401-
// Build a map of edge ID -> { pairIndex, totalInPair } for curve offset calculation
10402-
const edgeCurveInfo = new Map();
10403-
edgePairGroups.forEach((edgeIds, key) => {
10404-
const total = edgeIds.length;
10405-
edgeIds.forEach((edgeId, idx) => {
10406-
edgeCurveInfo.set(edgeId, { pairIndex: idx, totalInPair: total });
10407-
});
10396+
// #region agent log - build edgePairGroups locally just for debug logging
10397+
const edgePairGroupsDebug = new Map();
10398+
visibleEdges.forEach(e => {
10399+
const key = [e.sourceId, e.destinationId].sort().join('-');
10400+
if (!edgePairGroupsDebug.has(key)) edgePairGroupsDebug.set(key, []);
10401+
edgePairGroupsDebug.get(key).push(e.id);
1040810402
});
10409-
10410-
// #region agent log
10411-
const multiEdgePairs = Array.from(edgePairGroups.entries()).filter(([k, v]) => v.length > 1);
10403+
const multiEdgePairs = Array.from(edgePairGroupsDebug.entries()).filter(([k, v]) => v.length > 1);
1041210404
if (multiEdgePairs.length > 0) {
1041310405
debugLogSync('NodeCanvas.jsx:edgeRender', 'Edge rendering info', { totalEdges: visibleEdges.length, multiEdgePairs: multiEdgePairs.map(([k, v]) => ({ pair: k, edgeCount: v.length, edgeIds: v })), enableAutoRouting, routingStyle, willUseCurves: !(enableAutoRouting && (routingStyle === 'manhattan' || routingStyle === 'clean')) }, 'debug-session', 'D-E');
1041410406
}
@@ -10520,9 +10512,19 @@ function NodeCanvas() {
1052010512
? edge.directionality.arrowsToward
1052110513
: new Set(Array.isArray(edge.directionality?.arrowsToward) ? edge.directionality.arrowsToward : []);
1052210514

10515+
// Check if this is a curved edge (parallel edge)
10516+
const curveInfo = edgeCurveInfo.get(edge.id);
10517+
const isCurvedEdge = curveInfo && curveInfo.totalInPair > 1;
10518+
1052310519
// Only shorten connections at ends with arrows or hover state
10524-
let shouldShortenSource = isHovered || arrowsToward.has(sourceNode.id);
10525-
let shouldShortenDest = isHovered || arrowsToward.has(destNode.id);
10520+
// For curved edges, never shorten for hover - only for arrows
10521+
// This ensures the curve shape stays consistent when hovered
10522+
let shouldShortenSource = isCurvedEdge
10523+
? arrowsToward.has(sourceNode.id)
10524+
: (isHovered || arrowsToward.has(sourceNode.id));
10525+
let shouldShortenDest = isCurvedEdge
10526+
? arrowsToward.has(destNode.id)
10527+
: (isHovered || arrowsToward.has(destNode.id));
1052610528
if (enableAutoRouting && routingStyle === 'manhattan') {
1052710529
// In Manhattan mode, never shorten for hover—only for actual arrows
1052810530
shouldShortenSource = arrowsToward.has(sourceNode.id);
@@ -10693,10 +10695,22 @@ function NodeCanvas() {
1069310695
}
1069410696

1069510697
// Calculate parallel edge path using centralized utility
10696-
const curveInfo = edgeCurveInfo.get(edge.id);
10698+
// Note: curveInfo was already retrieved earlier for shouldShorten logic
1069710699
const parallelPath = calculateParallelEdgePath(startX, startY, endX, endY, curveInfo);
1069810700
const useCurve = parallelPath.type === 'curve';
1069910701

10702+
// For hover effect on curved edges, trim the curve to create "shorten" visual
10703+
// This keeps the curve shape consistent but renders a shorter portion
10704+
let trimmedPath = null;
10705+
if (useCurve && isHovered && parallelPath.ctrlX !== null) {
10706+
trimmedPath = getTrimmedBezierPath(
10707+
parallelPath.startX, parallelPath.startY,
10708+
parallelPath.ctrlX, parallelPath.ctrlY,
10709+
parallelPath.endX, parallelPath.endY,
10710+
0.08, 0.92 // Trim 8% from each end
10711+
);
10712+
}
10713+
1070010714
return (
1070110715
<g key={`edge-above-${edge.id}-${idx}`}>
1070210716
{/* Main edge line - always same thickness */}
@@ -10720,7 +10734,7 @@ function NodeCanvas() {
1072010734
/>
1072110735
) : useCurve ? (
1072210736
<path
10723-
d={parallelPath.path}
10737+
d={trimmedPath ? trimmedPath.path : parallelPath.path}
1072410738
fill="none"
1072510739
stroke={edgeColor}
1072610740
strokeWidth="12"
@@ -10769,7 +10783,7 @@ function NodeCanvas() {
1076910783
</>
1077010784
) : useCurve ? (
1077110785
<path
10772-
d={parallelPath.path}
10786+
d={trimmedPath ? trimmedPath.path : parallelPath.path}
1077310787
fill="none"
1077410788
stroke={edgeColor}
1077510789
strokeWidth={showConnectionNames ? "16" : "6"}
@@ -11010,6 +11024,80 @@ function NodeCanvas() {
1101011024
definingNodeId = edge.typeNodeId;
1101111025
}
1101211026

11027+
// Open the panel tab for the defining node
11028+
if (definingNodeId) {
11029+
storeActions.openRightPanelNodeTab(definingNodeId);
11030+
}
11031+
}}
11032+
/>
11033+
) : useCurve ? (
11034+
<path
11035+
d={parallelPath.path}
11036+
fill="none"
11037+
stroke="transparent"
11038+
strokeWidth="40"
11039+
style={{ cursor: 'pointer' }}
11040+
onPointerDown={(e) => {
11041+
if (e.pointerType && e.pointerType !== 'mouse') {
11042+
e.preventDefault?.();
11043+
e.stopPropagation?.();
11044+
ignoreCanvasClick.current = true;
11045+
setLongPressingInstanceId(null);
11046+
setDrawingConnectionFrom(null);
11047+
if (e.ctrlKey || e.metaKey) {
11048+
if (selectedEdgeIds.has(edge.id)) {
11049+
storeActions.removeSelectedEdgeId(edge.id);
11050+
} else {
11051+
storeActions.addSelectedEdgeId(edge.id);
11052+
}
11053+
} else {
11054+
storeActions.clearSelectedEdgeIds();
11055+
storeActions.setSelectedEdgeId(edge.id);
11056+
}
11057+
}
11058+
handleEdgePointerDownTouch(edge.id, e);
11059+
}}
11060+
onTouchStart={(e) => {
11061+
e.preventDefault?.();
11062+
e.stopPropagation?.();
11063+
ignoreCanvasClick.current = true;
11064+
setLongPressingInstanceId(null);
11065+
setDrawingConnectionFrom(null);
11066+
storeActions.clearSelectedEdgeIds();
11067+
storeActions.setSelectedEdgeId(edge.id);
11068+
}}
11069+
onClick={(e) => {
11070+
e.stopPropagation();
11071+
ignoreCanvasClick.current = true;
11072+
11073+
// Handle multiple selection with Ctrl/Cmd key
11074+
if (e.ctrlKey || e.metaKey) {
11075+
// Toggle this edge in the multiple selection
11076+
if (selectedEdgeIds.has(edge.id)) {
11077+
storeActions.removeSelectedEdgeId(edge.id);
11078+
} else {
11079+
storeActions.addSelectedEdgeId(edge.id);
11080+
}
11081+
} else {
11082+
// Single selection - clear multiple selection and set single edge
11083+
storeActions.clearSelectedEdgeIds();
11084+
storeActions.setSelectedEdgeId(edge.id);
11085+
}
11086+
}}
11087+
onDoubleClick={(e) => {
11088+
e.stopPropagation();
11089+
11090+
// Find the defining node for this edge's connection type
11091+
let definingNodeId = null;
11092+
11093+
// Check definitionNodeIds first (for custom connection types)
11094+
if (edge.definitionNodeIds && edge.definitionNodeIds.length > 0) {
11095+
definingNodeId = edge.definitionNodeIds[0];
11096+
} else if (edge.typeNodeId) {
11097+
// Fallback to typeNodeId (for base connection type)
11098+
definingNodeId = edge.typeNodeId;
11099+
}
11100+
1101311101
// Open the panel tab for the defining node
1101411102
if (definingNodeId) {
1101511103
storeActions.openRightPanelNodeTab(definingNodeId);
@@ -11584,9 +11672,19 @@ function NodeCanvas() {
1158411672
? edge.directionality.arrowsToward
1158511673
: new Set(Array.isArray(edge.directionality?.arrowsToward) ? edge.directionality.arrowsToward : []);
1158611674

11675+
// Check if this is a curved edge (parallel edge)
11676+
const curveInfo = edgeCurveInfo.get(edge.id);
11677+
const isCurvedEdge = curveInfo && curveInfo.totalInPair > 1;
11678+
1158711679
// Only shorten connections at ends with arrows or hover state
11588-
let shouldShortenSource = isHovered || arrowsToward.has(sourceNode.id);
11589-
let shouldShortenDest = isHovered || arrowsToward.has(destNode.id);
11680+
// For curved edges, never shorten for hover - only for arrows
11681+
// This ensures the curve shape stays consistent when hovered
11682+
let shouldShortenSource = isCurvedEdge
11683+
? arrowsToward.has(sourceNode.id)
11684+
: (isHovered || arrowsToward.has(sourceNode.id));
11685+
let shouldShortenDest = isCurvedEdge
11686+
? arrowsToward.has(destNode.id)
11687+
: (isHovered || arrowsToward.has(destNode.id));
1159011688
if (enableAutoRouting && routingStyle === 'manhattan') {
1159111689
// In Manhattan mode, never shorten for hover—only for actual arrows
1159211690
shouldShortenSource = arrowsToward.has(sourceNode.id);
@@ -11757,10 +11855,22 @@ function NodeCanvas() {
1175711855
}
1175811856

1175911857
// Calculate parallel edge path using centralized utility
11760-
const curveInfo = edgeCurveInfo.get(edge.id);
11858+
// Note: curveInfo was already retrieved earlier for shouldShorten logic
1176111859
const parallelPath = calculateParallelEdgePath(startX, startY, endX, endY, curveInfo);
1176211860
const useCurve = parallelPath.type === 'curve';
1176311861

11862+
// For hover effect on curved edges, trim the curve to create "shorten" visual
11863+
// This keeps the curve shape consistent but renders a shorter portion
11864+
let trimmedPath = null;
11865+
if (useCurve && isHovered && parallelPath.ctrlX !== null) {
11866+
trimmedPath = getTrimmedBezierPath(
11867+
parallelPath.startX, parallelPath.startY,
11868+
parallelPath.ctrlX, parallelPath.ctrlY,
11869+
parallelPath.endX, parallelPath.endY,
11870+
0.08, 0.92 // Trim 8% from each end
11871+
);
11872+
}
11873+
1176411874
return (
1176511875
<g key={`edge-above-${edge.id}-${idx}`}>
1176611876
{/* Main edge line - always same thickness */}
@@ -11784,7 +11894,7 @@ function NodeCanvas() {
1178411894
/>
1178511895
) : useCurve ? (
1178611896
<path
11787-
d={parallelPath.path}
11897+
d={trimmedPath ? trimmedPath.path : parallelPath.path}
1178811898
fill="none"
1178911899
stroke={edgeColor}
1179011900
strokeWidth="12"
@@ -11833,7 +11943,7 @@ function NodeCanvas() {
1183311943
</>
1183411944
) : useCurve ? (
1183511945
<path
11836-
d={parallelPath.path}
11946+
d={trimmedPath ? trimmedPath.path : parallelPath.path}
1183711947
fill="none"
1183811948
stroke={edgeColor}
1183911949
strokeWidth={showConnectionNames ? "16" : "6"}

0 commit comments

Comments
 (0)