@@ -33,8 +33,6 @@ export const HANDLE = {
3333export const EVENT = {
3434 /** Total bounding box size: 8 grid units = 80px */
3535 size : G . px ( 8 ) ,
36- /** Center point (size / 2): 4 grid units = 40px */
37- center : G . x4 ,
3836 /** Diamond shape size (rotated square) */
3937 diamondSize : 56 ,
4038 /** Diamond offset from center (diamondSize / 2) */
@@ -53,70 +51,23 @@ export function snapTo2G(value: number): number {
5351}
5452
5553/**
56- * Calculate node dimensions based on ports, content, and rotation.
57- *
58- * Design principles:
59- * - Node center is the local origin (positioned via CSS transform)
60- * - All dimensions are multiples of 2G (20px) for symmetric expansion
61- * - Port spacing = 2G (20px)
62- * - Ports are centered on their edge
63- *
64- * @param inputCount - Number of input ports
65- * @param outputCount - Number of output ports
66- * @param rotation - Node rotation (0, 1, 2, 3)
67- * @param contentHeight - Optional extra height for content (pinned params, etc.)
68- */
69- export function calculateNodeDimensions (
70- inputCount : number ,
71- outputCount : number ,
72- rotation : number ,
73- contentHeight : number = 0
74- ) : { width : number ; height : number } {
75- const isVertical = rotation === 1 || rotation === 3 ;
76- const maxPorts = Math . max ( inputCount , outputCount ) ;
77-
78- // Minimum dimension to fit ports with padding
79- // For N ports: need (N-1) * spacing + padding on each end
80- // Simplified: N * portSpacing gives enough room
81- const minPortDimension = Math . max ( 1 , maxPorts ) * NODE . portSpacing ;
82-
83- if ( isVertical ) {
84- // Ports on top/bottom, width accommodates them
85- const width = snapTo2G ( Math . max ( NODE . baseWidth , minPortDimension ) ) ;
86- const height = snapTo2G ( Math . max ( NODE . baseHeight , NODE . baseHeight + contentHeight ) ) ;
87- return { width, height } ;
88- }
89-
90- // Ports on left/right, height accommodates them
91- const width = snapTo2G ( Math . max ( NODE . baseWidth , NODE . baseWidth ) ) ;
92- const height = snapTo2G ( Math . max ( NODE . baseHeight , minPortDimension , NODE . baseHeight + contentHeight ) ) ;
93- return { width, height } ;
94- }
95-
96- /**
97- * Calculate the position of a port along an edge (in pixels).
98- * Returns a grid-aligned position.
54+ * Calculate port position as CSS calc() expression.
55+ * Uses offset from center to ensure grid alignment regardless of node size,
56+ * since the node center is always at a grid-aligned position.
9957 *
10058 * @param index - Port index (0-based)
10159 * @param total - Total number of ports on this edge
102- * @param edgeLength - Length of the edge in pixels
103- * @returns Position in pixels from the start of the edge
60+ * @returns CSS position value (e.g., "50%" or "calc(50% + 10px)")
10461 */
105- export function calculatePortPosition (
106- index : number ,
107- total : number ,
108- edgeLength : number
109- ) : number {
110- if ( total <= 0 ) return edgeLength / 2 ;
111- if ( total === 1 ) return edgeLength / 2 ;
112-
113- // Calculate span of all ports
62+ export function getPortPositionCalc ( index : number , total : number ) : string {
63+ if ( total <= 0 || total === 1 ) {
64+ return '50%' ; // Single port at center
65+ }
66+ // For N ports with spacing S: span = (N-1)*S, offset from center = -span/2 + i*S
11467 const span = ( total - 1 ) * NODE . portSpacing ;
115- // Center the ports on the edge
116- const startOffset = ( edgeLength - span ) / 2 ;
117- // Position of this port
118- const position = startOffset + index * NODE . portSpacing ;
119-
120- // Snap to grid for safety (should already be aligned if dimensions are correct)
121- return G . snap ( position ) ;
68+ const offsetFromCenter = - span / 2 + index * NODE . portSpacing ;
69+ if ( offsetFromCenter === 0 ) {
70+ return '50%' ;
71+ }
72+ return `calc(50% + ${ offsetFromCenter } px)` ;
12273}
0 commit comments