@@ -49,30 +49,77 @@ class Renderer {
4949
5050 getNodeDimensions ( node , ctx ) {
5151 const nodeType = nodeTypes [ node . type ] ;
52+ const maxPorts = Math . max ( nodeType . inputs . length , nodeType . outputs . length ) ;
53+
54+ // Set font for measurements
5255 ctx . font = `600 14px ${ FONT_FAMILY } ` ;
53- const titleWidth = ctx . measureText ( node . type ) . width ;
54-
55- ctx . font = `400 13px ${ FONT_FAMILY } ` ;
56- const descriptionLines = this . renderDescription ? this . wrapText ( ctx , nodeType . description , 180 ) : [ ] ;
57- const descriptionHeight = this . renderDescription ? descriptionLines . length * 14 : 0 ;
58-
59- const inputsHeight = nodeType . inputs . length * 20 ;
60- const outputsHeight = nodeType . outputs . length * 20 ;
61- const propertiesHeight = nodeType . properties ? nodeType . properties . reduce ( ( height , prop ) => {
62- const isVisible = prop . visible === undefined ||
63- ( typeof prop . visible === 'function' ?
64- prop . visible ( node . properties ) :
65- prop . visible ) ;
66- return height + ( isVisible ? 20 : 0 ) ;
67- } , 0 ) : 0 ;
68-
69- const width = Math . max ( 200 , titleWidth + 20 , ...( this . renderDescription ? descriptionLines . map ( line => ctx . measureText ( line ) . width + 20 ) : [ ] ) ) ;
70- const height = 35 + descriptionHeight + Math . max ( inputsHeight , outputsHeight ) + propertiesHeight ;
71-
56+
57+ // Calculate title height
58+ const titleHeight = 25 ;
59+
60+ // Calculate ports area height with tighter spacing
61+ const portSpacing = 14 ;
62+ const portVerticalGap = 5 ; // Gap between input and output sections
63+ const portsHeight = maxPorts > 0 ? ( maxPorts - 1 ) * portSpacing + 20 + portVerticalGap : 0 ;
64+
65+ // Calculate properties height - only for visible properties
66+ let propertiesHeight = 0 ;
67+ if ( nodeType . properties ) {
68+ const visibleProps = nodeType . properties . filter ( prop => {
69+ if ( prop . type === 'array' ) return false ;
70+ if ( prop . visible === undefined ) return true ;
71+ if ( typeof prop . visible === 'function' ) {
72+ return prop . visible ( node . properties ) ;
73+ }
74+ return prop . visible ;
75+ } ) ;
76+
77+ propertiesHeight = visibleProps . length * 16 ;
78+ }
79+
80+ // Calculate required width based on port names
81+ let maxInputWidth = 0 ;
82+ let maxOutputWidth = 0 ;
83+
84+ ctx . font = `500 12px ${ FONT_FAMILY } ` ;
85+
86+ // Measure input port names
87+ nodeType . inputs . forEach ( input => {
88+ const textWidth = ctx . measureText ( input . name ) . width ;
89+ maxInputWidth = Math . max ( maxInputWidth , textWidth ) ;
90+ } ) ;
91+
92+ // Measure output port names
93+ nodeType . outputs . forEach ( output => {
94+ const textWidth = ctx . measureText ( output . name ) . width ;
95+ maxOutputWidth = Math . max ( maxOutputWidth , textWidth ) ;
96+ } ) ;
97+
98+ // Calculate total width needed with guaranteed minimum spacing
99+ const portPadding = 40 ;
100+ const centerPadding = 40 ;
101+ const inputSection = maxInputWidth + portPadding ;
102+ const outputSection = maxOutputWidth + portPadding ;
103+
104+ const width = inputSection + outputSection + centerPadding
105+
106+ // Calculate total height with minimal padding
107+ const height = titleHeight +
108+ ( maxPorts > 0 ? portsHeight : 0 ) +
109+ ( propertiesHeight > 0 ? propertiesHeight + 10 : 0 ) +
110+ 5 ;
111+
112+ // Calculate where ports should start (right after title)
113+ const portStartY = titleHeight ;
114+
72115 return {
73116 width,
74117 height,
75- portStartY : 35 + descriptionHeight
118+ portStartY,
119+ maxInputWidth,
120+ maxOutputWidth,
121+ inputSection,
122+ outputSection
76123 } ;
77124 }
78125
@@ -136,11 +183,11 @@ class Renderer {
136183 }
137184
138185 const startPort = edge . start . isInput
139- ? { x : startNode . x , y : startNode . y + startDims . portStartY + edge . start . index * 20 }
140- : { x : startNode . x + startDims . width , y : startNode . y + startDims . portStartY + edge . start . index * 20 } ;
186+ ? { x : startNode . x , y : startNode . y + startDims . portStartY + ( edge . start . index * 14 ) + 8 }
187+ : { x : startNode . x + startDims . width , y : startNode . y + startDims . portStartY + ( edge . start . index * 14 ) + 8 } ;
141188 const endPort = edge . end . isInput
142- ? { x : endNode . x , y : endNode . y + endDims . portStartY + edge . end . index * 20 }
143- : { x : endNode . x + endDims . width , y : endNode . y + endDims . portStartY + edge . end . index * 20 } ;
189+ ? { x : endNode . x , y : endNode . y + endDims . portStartY + ( edge . end . index * 14 ) + 8 }
190+ : { x : endNode . x + endDims . width , y : endNode . y + endDims . portStartY + ( edge . end . index * 14 ) + 8 } ;
144191
145192 // Calculate control points for the Bezier curve
146193 const dx = endPort . x - startPort . x ;
@@ -177,16 +224,17 @@ class Renderer {
177224 drawPortIcon ( ctx , x , y , isInput ) {
178225 const offset = 5 ; // Distance from node border
179226 const arrowX = isInput ? x - offset : x + offset ;
227+ const portY = y ;
180228
181229 ctx . beginPath ( ) ;
182230 if ( isInput ) {
183- ctx . moveTo ( arrowX - 6 , y - 5 ) ;
184- ctx . lineTo ( arrowX - 6 , y + 5 ) ;
185- ctx . lineTo ( arrowX , y ) ;
231+ ctx . moveTo ( arrowX - 6 , portY - 5 ) ;
232+ ctx . lineTo ( arrowX - 6 , portY + 5 ) ;
233+ ctx . lineTo ( arrowX , portY ) ;
186234 } else {
187- ctx . moveTo ( arrowX , y - 5 ) ;
188- ctx . lineTo ( arrowX , y + 5 ) ;
189- ctx . lineTo ( arrowX + 6 , y ) ;
235+ ctx . moveTo ( arrowX , portY - 5 ) ;
236+ ctx . lineTo ( arrowX , portY + 5 ) ;
237+ ctx . lineTo ( arrowX + 6 , portY ) ;
190238 }
191239 ctx . closePath ( ) ;
192240 ctx . strokeStyle = '#999999' ;
@@ -225,7 +273,7 @@ class Renderer {
225273
226274 drawNodes ( ctx , nodes , edges , selectedNodes ) {
227275 nodes . forEach ( node => {
228- const { width, height } = this . getNodeDimensions ( node , ctx ) ;
276+ const { width, height, inputSection , outputSection } = this . getNodeDimensions ( node , ctx ) ;
229277
230278 if ( ! this . isRectInView ( node . x , node . y , width , height , ctx . canvas . width , ctx . canvas . height ) ) {
231279 return ;
@@ -290,10 +338,9 @@ class Renderer {
290338
291339 // Input ports
292340 nodeType . inputs . forEach ( ( input , i ) => {
293- const portY = node . y + currentHeight + i * 20 ;
341+ const portY = node . y + currentHeight + ( i * 14 ) ;
294342 const isControl = input . type === 'control' ;
295343
296- // Check if port is connected
297344 const isPortConnected = edges . some ( edge =>
298345 edge . end . nodeId === node . id &&
299346 edge . end . index === i &&
@@ -306,12 +353,13 @@ class Renderer {
306353
307354 this . drawLabelArrow ( ctx , node . x + 15 , portY , isControl ) ;
308355 ctx . fillStyle = 'white' ;
309- ctx . fillText ( input . name , node . x + 35 , portY + 5 ) ;
356+ ctx . fillText ( input . name , node . x + 35 , portY + 4 ) ;
310357 } ) ;
311358
312- // Output ports
359+ // Output ports - removed the initial gap
313360 nodeType . outputs . forEach ( ( output , i ) => {
314- const portY = node . y + currentHeight + i * 20 ;
361+ // Calculate portY without the conditional gap
362+ const portY = node . y + currentHeight + ( i * 14 ) ;
315363 const isControl = output . type === 'control' ;
316364
317365 const isPortConnected = edges . some ( edge =>
@@ -326,31 +374,36 @@ class Renderer {
326374
327375 ctx . fillStyle = 'white' ;
328376 const textWidth = ctx . measureText ( output . name ) . width ;
329- ctx . fillText ( output . name , node . x + width - textWidth - 35 , portY + 5 ) ;
377+ ctx . fillText ( output . name , node . x + width - textWidth - 35 , portY + 4 ) ;
330378 this . drawLabelArrow ( ctx , node . x + width - 25 , portY , isControl ) ;
331379 } ) ;
332380
333- currentHeight += Math . max ( nodeType . inputs . length , nodeType . outputs . length ) * 15 ;
381+ // Add the gap after drawing all ports if needed
382+ currentHeight += Math . max ( nodeType . inputs . length , nodeType . outputs . length ) * 14 ;
383+ if ( nodeType . inputs . length > 0 && nodeType . outputs . length > 0 ) {
384+ currentHeight += 5 ; // Only add gap if both inputs and outputs exist
385+ }
334386
335- // Node properties
387+ // Node properties - only render non-array properties
336388 if ( nodeType . properties ) {
337389 ctx . fillStyle = 'white' ;
338- ctx . font = `500 13px ${ FONT_FAMILY } ` ;
390+ ctx . font = `500 12px ${ FONT_FAMILY } ` ; // Slightly smaller font for properties
339391
340- nodeType . properties . forEach ( ( prop , index ) => {
341- // Check if property should be visible
392+ nodeType . properties . forEach ( prop => {
393+ // Skip array type properties and check visibility
394+ if ( prop . type === 'array' ) return ;
395+
342396 const isVisible = prop . visible === undefined ||
343397 ( typeof prop . visible === 'function' ?
344398 prop . visible ( node . properties ) :
345399 prop . visible ) ;
346400
347- if ( isVisible && prop . type !== 'array' ) { // Skip array type properties
401+ if ( isVisible ) {
348402 let displayValue = node . properties [ prop . name ] !== undefined ? node . properties [ prop . name ] : prop . default ;
349- // Skip rendering if the value is an object
350403 if ( typeof displayValue === 'object' ) return ;
351404
352405 const text = `${ prop . name } : ${ displayValue } ` ;
353- currentHeight += 20 ;
406+ currentHeight += 16 ; // Reduced from 20
354407 ctx . fillText ( text , node . x + 10 , node . y + currentHeight ) ;
355408 }
356409 } ) ;
@@ -359,26 +412,54 @@ class Renderer {
359412 }
360413
361414 drawConnectionLine ( ctx , connecting , mousePosition , nodes ) {
362- const startNode = nodes . find ( n => n . id === connecting . nodeId ) ;
363- if ( startNode ) {
364- const { width } = this . getNodeDimensions ( startNode , ctx ) ;
365- const startX = connecting . isInput ? startNode . x : startNode . x + width ;
366- const startY = startNode . y + this . getNodeDimensions ( startNode , ctx ) . portStartY + connecting . index * 20 ;
367- const endX = mousePosition . x ;
368- const endY = mousePosition . y ;
415+ if ( ! connecting ) return ;
416+
417+ const node = nodes . find ( n => n . id === connecting . nodeId ) ;
418+ if ( ! node ) return ;
419+
420+ const { width } = this . getNodeDimensions ( node , ctx ) ;
421+ const portY = node . y + this . getNodeDimensions ( node , ctx ) . portStartY + ( connecting . index * 14 ) + 8 ;
422+
423+ // Calculate X position to start from middle of port
424+ const portOffset = 5 ;
425+ let portX ;
426+
427+ if ( connecting . isInput ) {
428+ if ( nodeTypes [ node . type ] . inputs [ connecting . index ] . type === 'control' ) {
429+ // For control input ports: start from middle of triangle
430+ const triangleWidth = 6 ;
431+ portX = node . x - portOffset - ( triangleWidth / 2 ) ;
432+ } else {
433+ // For data input ports: start from middle of circle
434+ portX = node . x - portOffset ;
435+ }
436+ } else {
437+ if ( nodeTypes [ node . type ] . outputs [ connecting . index ] . type === 'control' ) {
438+ // For control output ports: start from middle of triangle
439+ const triangleWidth = 6 ;
440+ portX = node . x + width + portOffset + ( triangleWidth / 2 ) ;
441+ } else {
442+ // For data output ports: start from middle of circle
443+ portX = node . x + width + portOffset + 5 ; // +5 to match the circle x position in drawLabelArrow
444+ }
445+ }
369446
370- // Calculate control points for the Bezier curve
371- const dx = endX - startX ;
372- const controlPoint1 = { x : startX + dx * 0.5 , y : startY } ;
373- const controlPoint2 = { x : endX - dx * 0.5 , y : endY } ;
447+ const startX = portX ;
448+ const startY = portY ;
449+ const endX = mousePosition . x ;
450+ const endY = mousePosition . y ;
374451
375- ctx . beginPath ( ) ;
376- ctx . moveTo ( startX , startY ) ;
377- ctx . bezierCurveTo ( controlPoint1 . x , controlPoint1 . y , controlPoint2 . x , controlPoint2 . y , endX , endY ) ;
378- ctx . strokeStyle = '#FFFF00' ;
379- ctx . lineWidth = 2 ;
380- ctx . stroke ( ) ;
381- }
452+ // Calculate control points for the Bezier curve
453+ const dx = endX - startX ;
454+ const controlPoint1 = { x : startX + dx * 0.5 , y : startY } ;
455+ const controlPoint2 = { x : endX - dx * 0.5 , y : endY } ;
456+
457+ ctx . beginPath ( ) ;
458+ ctx . moveTo ( startX , startY ) ;
459+ ctx . bezierCurveTo ( controlPoint1 . x , controlPoint1 . y , controlPoint2 . x , controlPoint2 . y , endX , endY ) ;
460+ ctx . strokeStyle = '#999999' ;
461+ ctx . lineWidth = 2 ;
462+ ctx . stroke ( ) ;
382463 }
383464
384465 setDarkTheme ( isDarkTheme ) {
0 commit comments