@@ -35,6 +35,10 @@ export class Editor {
3535 private aspectCorrection = 1 ;
3636 private canvasAspect :number ;
3737
38+ /**
39+ * Used to be able to identify when a user just clicks ( a mouse up woth no mouse movement )
40+ */
41+ private mouseMoved = false ;
3842 private handIcon : HandIcon ;
3943
4044 /**
@@ -175,6 +179,9 @@ export class Editor {
175179
176180 //#region MOUSE MOVE
177181 canvas . addEventListener ( 'mousemove' , ( event ) => {
182+
183+ this . mouseMoved = true ;
184+
178185 let scale = this . ctx . getTransform ( ) . a ; // Get the current scale (assuming uniform scaling)
179186 const mousePos = this . getMousePos ( event ) ;
180187 const canvasPos = this . getCanvasMousePosition ( mousePos ) ;
@@ -228,6 +235,8 @@ export class Editor {
228235
229236 //#region MOUSE DOWN
230237 canvas . addEventListener ( "mousedown" , ev => {
238+
239+ this . mouseMoved = false ;
231240 this . mouse = this . getMousePos ( ev ) ;
232241
233242 // middle mouse button to pan the workspace
@@ -277,10 +286,10 @@ export class Editor {
277286
278287 if ( Math . abs ( this . mouse . x - outlet . globalX ) <= hitAreaRatio && Math . abs ( this . mouse . y - outlet . globalY ) <= hitAreaRatio )
279288 {
280- //
281- // destroy any connectionusing this outlet...
282- //
283- this . destroyConnectionsUsing ( outlet ) ;
289+ // //
290+ // // destroy any connectionusing this outlet...
291+ // //
292+ // this.destroyConnectionsUsing( outlet );
284293
285294 //
286295 // create a new "open" connection
@@ -336,7 +345,24 @@ export class Editor {
336345 // if we clicked an outlet, we need to know which of the available outlets are valid to be connected to...
337346 //
338347 if ( this . selectedOutlet )
339- {
348+ {
349+
350+ //@ts -ignore
351+ if ( this . selectedOutlet . isInput )
352+ {
353+ //
354+ // in this case we will pretend that the connection was made by the other end of the connection if it was connected, to allow
355+ // for the visual impression of changing the endpoint of the connection that lead to us.
356+ //
357+ const oldOutlet = this . selectedOutlet ;
358+
359+ if ( this . disolveSelectedOutlet ( ) )
360+ {
361+ outlets . push ( oldOutlet ) ;
362+ outlets . splice ( outlets . indexOf ( this . selectedOutlet ) , 1 ) ;
363+ }
364+ }
365+
340366 //
341367 // filter only outlet that we can connect to...
342368 //
@@ -403,18 +429,8 @@ export class Editor {
403429 }
404430 else
405431 {
406-
407- if ( this . chosenOutlet . length )
408- {
409- if ( this . chosenOutlet . length > 1 )
410- this . chosenOutlet . sort ( ( a , b ) => b . alignmentScore - a . alignmentScore ) ;
411-
412-
413- this . destroyConnectionsUsing ( this . chosenOutlet [ 0 ] . outlet ) ;
414-
415- this . connections . setOrphansTarget ( this . chosenOutlet [ 0 ] . outlet ) ;
416-
417- }
432+ if ( this . mouseMoved )
433+ this . createChosenConnections ( ) ;
418434
419435 this . clearOutletSelection ( ) ;
420436 }
@@ -604,15 +620,71 @@ export class Editor {
604620
605621 }
606622
607- protected destroyConnectionsUsing ( outlet :IOutlet )
623+ protected destroyConnectionsUsing ( outlet :IOutlet , onlyIfConnected = false )
608624 {
609- this . connections . purge ( connection => connection . from !== outlet && ( ! isOutlet ( connection . to ) || connection . to !== outlet ) )
610- // const clean = this.connections.filter( c=>( c.from!==outlet )
611- // && ( c.to !==outlet )
612- // );
625+ this . connections . purge ( connection => ( ( connection . from !== outlet ) || ( onlyIfConnected && ! isOutlet ( connection . to ) ) ) && ( ! isOutlet ( connection . to ) || connection . to !== outlet ) ) ;
626+ }
627+
628+ /**
629+ * An input can only recieve 1 connection. The connection array will never have "to" repeated referencing the same outlet.
630+ */
631+ protected disolveSelectedOutlet ( ) {
632+ if ( ! this . selectedOutlet || ! this . selectedOutlet . isInput ) return false ;
613633
614- // this.connections.length = 0;
615- // this.connections.push( ...clean );
634+ const other = this . selectedOutlet . connectedTo ;
635+ if ( other )
636+ {
637+ //
638+ // the first time we click an outlet a new connection if created with the "from" set to the clicked outlet and the "to" set to the mouse coordinates.
639+ //
640+ const openConnection = this . connections . find ( c => c . from == this . selectedOutlet && ! isOutlet ( c . to ) ) ;
641+
642+ let target :Vector2Like | undefined ;
643+
644+ if ( openConnection )
645+ {
646+ target = openConnection . to as Vector2Like ; //<--- mouse coordinates
647+ }
648+
649+ this . destroyConnectionsUsing ( this . selectedOutlet ) ;
650+
651+ this . selectedOutlet = other ;
652+
653+ if ( target )
654+ this . connections . push ( {
655+ from : other ,
656+ to : target
657+ } ) ;
658+
659+ return true ;
660+ }
661+
662+ return false ;
663+ }
664+
665+ /**
666+ * The user dragged the mouse out of an outlet aiming to create a new connection.
667+ */
668+ protected createChosenConnections ( ) {
669+
670+ if ( ! this . chosenOutlet . length || ! this . selectedOutlet ) return ;
671+
672+ //
673+ // pick the best one for the current one...
674+ //
675+ if ( this . chosenOutlet . length > 1 )
676+ this . chosenOutlet . sort ( ( a , b ) => b . alignmentScore - a . alignmentScore ) ;
677+
678+
679+ const chosenTarget = this . chosenOutlet [ 0 ] . outlet ;
680+
681+ if ( this . selectedOutlet . isInput )
682+ this . destroyConnectionsUsing ( this . selectedOutlet , true ) ;
683+
684+ //
685+ // all the connections that were following the mouse will not have this outlet as their endpoint connection.
686+ //
687+ this . connections . setOrphansTarget ( chosenTarget ) ;
616688 }
617689
618690 protected clearOutletSelection ( ) {
0 commit comments