@@ -81,12 +81,50 @@ class CoreGraph {
8181 this . cy . nodeEditing ( {
8282 resizeToContentCueEnabled : ( ) => false ,
8383 setWidth : ( node , width ) => {
84- // Allow smooth resizing - don't snap during drag
85- node . data ( 'style' , { ...node . data ( 'style' ) , width } ) ;
84+ // HARD ENFORCEMENT: Snap width every frame during resize
85+ const snappedWidth = this . snapDimensionToGrid ( width ) ;
86+ node . data ( 'style' , { ...node . data ( 'style' ) , width : snappedWidth } ) ;
87+
88+ // Adjust position to maintain edge alignment based on resize handle
89+ const resizeType = node . scratch ( 'resizeType' ) ;
90+ if ( resizeType && ( resizeType . includes ( 'left' ) || resizeType . includes ( 'right' ) ) ) {
91+ const currentPos = node . position ( ) ;
92+ const initialPos = node . scratch ( 'resizeInitialPos' ) ;
93+ const initialWidth = node . scratch ( 'width' ) ;
94+ const widthDelta = snappedWidth - initialWidth ;
95+
96+ let newX = currentPos . x ;
97+ if ( resizeType . includes ( 'left' ) ) {
98+ newX = initialPos . x - widthDelta / 2 ;
99+ } else if ( resizeType . includes ( 'right' ) ) {
100+ newX = initialPos . x + widthDelta / 2 ;
101+ }
102+ node . position ( { x : this . snapToGrid ( newX ) , y : currentPos . y } ) ;
103+ }
104+ return snappedWidth ;
86105 } ,
87106 setHeight : ( node , height ) => {
88- // Allow smooth resizing - don't snap during drag
89- node . data ( 'style' , { ...node . data ( 'style' ) , height } ) ;
107+ // HARD ENFORCEMENT: Snap height every frame during resize
108+ const snappedHeight = this . snapDimensionToGrid ( height ) ;
109+ node . data ( 'style' , { ...node . data ( 'style' ) , height : snappedHeight } ) ;
110+
111+ // Adjust position to maintain edge alignment based on resize handle
112+ const resizeType = node . scratch ( 'resizeType' ) ;
113+ if ( resizeType && ( resizeType . includes ( 'top' ) || resizeType . includes ( 'bottom' ) ) ) {
114+ const currentPos = node . position ( ) ;
115+ const initialPos = node . scratch ( 'resizeInitialPos' ) ;
116+ const initialHeight = node . scratch ( 'height' ) ;
117+ const heightDelta = snappedHeight - initialHeight ;
118+
119+ let newY = currentPos . y ;
120+ if ( resizeType . includes ( 'top' ) ) {
121+ newY = initialPos . y - heightDelta / 2 ;
122+ } else if ( resizeType . includes ( 'bottom' ) ) {
123+ newY = initialPos . y + heightDelta / 2 ;
124+ }
125+ node . position ( { x : currentPos . x , y : this . snapToGrid ( newY ) } ) ;
126+ }
127+ return snappedHeight ;
90128 } ,
91129 isNoResizeMode ( node ) { return node . data ( 'type' ) !== 'ordin' ; } ,
92130 isNoControlsMode ( node ) { return node . data ( 'type' ) !== 'ordin' ; } ,
@@ -199,26 +237,36 @@ class CoreGraph {
199237
200238 this . cy . on ( 'free' , 'node[type = "ordin"]' , ( e ) => {
201239 e . target . forEach ( ( node ) => {
240+ const initialPos = node . scratch ( 'position' ) ;
202241 const currentPos = node . position ( ) ;
203- const snappedPos = this . snapPositionToGrid ( currentPos ) ;
204- node . position ( snappedPos ) ;
242+ // Only snap if the node actually moved
243+ const moved = ! initialPos || initialPos . x !== currentPos . x || initialPos . y !== currentPos . y ;
244+ if ( moved ) {
245+ const snappedPos = this . snapPositionToGrid ( currentPos ) ;
246+ node . position ( snappedPos ) ;
247+ }
205248 } ) ;
206249 } ) ;
207250
208251 this . cy . on ( 'nodeediting.resizestart' , ( e , type , node ) => {
252+ // Store initial state for resize operation
209253 node . scratch ( 'height' , node . data ( 'style' ) . height ) ;
210254 node . scratch ( 'width' , node . data ( 'style' ) . width ) ;
211- node . scratch ( 'position' , { ...node . position ( ) } ) ;
255+ node . scratch ( 'resizeInitialPos' , { ...node . position ( ) } ) ;
256+ node . scratch ( 'resizeType' , type ) ;
212257 } ) ;
213258
214259 this . cy . on ( 'nodeediting.resizeend' , ( e , type , node ) => {
215- // Snap dimensions to grid multiples
260+ // Clean up scratch data
261+ node . removeScratch ( 'resizeType' ) ;
262+ node . removeScratch ( 'resizeInitialPos' ) ;
263+
264+ // Final enforcement: ensure position and dimensions are grid-aligned
216265 const style = node . data ( 'style' ) || { } ;
217266 const snappedWidth = this . snapDimensionToGrid ( style . width || 100 ) ;
218267 const snappedHeight = this . snapDimensionToGrid ( style . height || 50 ) ;
219268 node . data ( 'style' , { ...style , width : snappedWidth , height : snappedHeight } ) ;
220-
221- // Snap position to ensure all corners align to grid
269+
222270 const snappedPos = this . snapPositionToGrid ( node . position ( ) ) ;
223271 node . position ( snappedPos ) ;
224272 } ) ;
0 commit comments