Skip to content

Commit e698e96

Browse files
committed
limit connection candidates to only 1 at a time + gradient con connection pipe to visually see diferent endpoint types were a conversion will occur
1 parent d8d5cb1 commit e698e96

13 files changed

+128
-51
lines changed

src/Editor.ts

Lines changed: 91 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -443,23 +443,29 @@ export class Editor {
443443
return screenPoint;
444444
}
445445

446-
protected drawConnectionPipes( ctx:CanvasRenderingContext2D )
446+
/**
447+
* Draw the connection pipes
448+
* @param ctx
449+
* @param theConnectedOnes which ones? the ones with both ends connected or the ones following the mouse?
450+
*/
451+
protected drawConnectionPipes( ctx:CanvasRenderingContext2D, theConnectedOnes = true )
447452
{
448453
let connectioDirStrength = 50;
449454

450455
//#region draw connections
451-
this.connections.forEach( connection=>{
456+
this.connections.forEach( connection=>{
452457

453458
const from = this.global2canvas({x:connection.from.globalX, y:connection.from.globalY });
454-
455-
ctx.beginPath();
456-
ctx.moveTo( from.x , from.y );
457-
458459

459460
let outDir = connection.from.isInput? -1 : 1;
460461

461462
if( isOutlet(connection.to) )
462463
{
464+
if( !theConnectedOnes ) return;
465+
466+
ctx.beginPath();
467+
ctx.moveTo( from.x , from.y );
468+
463469
let to = this.global2canvas({x:connection.to.globalX, y:connection.to.globalY });
464470

465471
ctx.bezierCurveTo(
@@ -472,21 +478,46 @@ export class Editor {
472478
to.x,
473479
to.y ,
474480
);
481+
482+
if( connection.from.size!=connection.to.size )
483+
{
484+
const gradient = ctx.createLinearGradient(
485+
from.x, from.y,
486+
to.x, to.y
487+
);
488+
gradient.addColorStop(0, connection.from.color as string);
489+
gradient.addColorStop(1, connection.to.color as string );
490+
ctx.strokeStyle = gradient;
491+
}
492+
else
493+
{
494+
ctx.strokeStyle = connection.from.color;
495+
}
496+
475497
}
476498
else
477-
{
499+
{
500+
if( theConnectedOnes ) return;
501+
502+
ctx.beginPath();
503+
ctx.moveTo( from.x , from.y );
504+
478505
let to = this.global2canvas( connection.to );
479506

480507
ctx.lineTo(
481508
to.x,
482509
to.y
483510
);
511+
512+
ctx.setLineDash([5, 5]);
513+
ctx.strokeStyle = connection.from.color;
484514
}
485515

486516

487-
ctx.strokeStyle = '#63c763';
517+
488518
ctx.lineWidth = 3;
489519
ctx.stroke();
520+
ctx.setLineDash([]);
490521

491522
})
492523

@@ -499,7 +530,9 @@ export class Editor {
499530
*/
500531
protected drawAvailableConnectionPipes( ctx:CanvasRenderingContext2D )
501532
{
502-
if(!this.selectedOutlet) return;
533+
if(!this.selectedOutlet) return;
534+
535+
this.drawConnectionPipes( ctx, false )
503536

504537
this.chosenOutlet.length = 0;
505538

@@ -522,6 +555,8 @@ export class Editor {
522555

523556

524557
const v:Vector2 = new Vector2();
558+
559+
const options : { outlet:IOutlet, score:number, origin:Vector2Like, dir:Vector2Like, grab:boolean }[] = []
525560

526561

527562
//
@@ -545,8 +580,7 @@ export class Editor {
545580
// if cursor is at reach....
546581
//
547582
if( distanceToCursor < maxReachDistance )
548-
{
549-
const dir2cursor = v.normalize();
583+
{
550584

551585
// 3. Calculate the dot product
552586
const alignment = calculateDirectionAlignment(-dir.x, -dir.y, origin.x, origin.y, position.x, position.y);
@@ -559,43 +593,67 @@ export class Editor {
559593
const alignmentScore = ( alignment-alignmentThreshold ) / (1-alignmentThreshold) ;
560594

561595
// not cut the length based on the distance...
562-
v.setLength( Math.min( distanceToCursor, (maxReachDistance-distanceToCursor) ) * alignmentScore )
596+
v.setLength( Math.min( distanceToCursor, (maxReachDistance-distanceToCursor) ) * alignmentScore );
597+
563598

599+
const outletGrabbed = v.clone().set(cursor.x - (position.x+v.x), cursor.y - (position.y+v.y)).length()<distToPlug;
564600

565-
ctx.beginPath();
566-
ctx.moveTo( position.x, position.y );
567-
ctx.lineTo( position.x + v.x, position.y + v.y)
601+
options.push({
602+
outlet,
603+
origin: position,
604+
dir: v.clone(),
605+
score: alignmentScore,
606+
grab: outletGrabbed
607+
});
608+
609+
}
610+
611+
612+
});
613+
614+
//
615+
// sort based on score : Higher score wins...
616+
//
617+
options.sort((a,b)=>b.score-a.score);
618+
619+
//
620+
// only draw 1...
621+
// as suggested by : https://x.com/KennedyRichard/status/1904915424866681301
622+
// makes sense... to reduce visual noise. Just draw the most likely connection candidate.
623+
//
624+
if( options.length )
625+
{
626+
options.length=1;
627+
628+
options.forEach( candidate => {
568629

630+
ctx.beginPath();
631+
//ctx.setLineDash([5, 5]);
632+
ctx.moveTo( candidate.origin.x, candidate.origin.y );
633+
ctx.lineTo( candidate.origin.x + candidate.dir.x, candidate.origin.y + candidate.dir.y);
634+
ctx.strokeStyle = candidate.outlet.color;
569635
ctx.stroke();
570-
636+
//ctx.setLineDash([]);
637+
571638
//
572639
// Draw the hand icon
573640
//
574641

575642
ctx.save();
576-
ctx.translate( position.x+ v.x, position.y + v.y);
577-
ctx.rotate( Math.atan2(v.y, v.x)+Math.PI/2 );
643+
ctx.translate( candidate.origin.x + candidate.dir.x, candidate.origin.y + candidate.dir.y );
644+
ctx.rotate( Math.atan2(candidate.dir.y, candidate.dir.x)+Math.PI/2 );
578645

579-
// distance from cursor to the current icon...
580-
v.set(
581-
cursor.x - (position.x+v.x),
582-
cursor.y - (position.y+v.y),
583-
);
584-
585-
const outletGrabbed = v.length()<distToPlug;
586-
587-
if( outletGrabbed )
646+
if( candidate.grab )
588647
{
589-
this.chosenOutlet.push( { outlet, alignmentScore } );
648+
this.chosenOutlet.push( { outlet:candidate.outlet, alignmentScore: candidate.score } );
590649
}
591650

592-
this.handIcon.drawSprite(ctx, outletGrabbed ?"grab" : "reach");
651+
this.handIcon.drawSprite(ctx, candidate.grab ?"grab" : "reach");
593652
ctx.restore();
594-
595-
}
596-
597653

598-
});
654+
});
655+
}
656+
599657

600658

601659
}

src/core/IOutlet.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import { FillStyle } from "../colors/Theme";
12
import { Node } from "../nodes/Node"
23

4+
export type OutletSize = 1|2|3|4|5;
5+
36
export interface IOutlet {
47
isInput:boolean
58

@@ -8,4 +11,6 @@ export interface IOutlet {
811

912
connectedTo?:IOutlet
1013
get owner():Node
14+
get size():OutletSize; // the output will be vec1 to 4 always... or in case of materials, we can say 5.
15+
get color():FillStyle
1116
}

src/properties/BaseColorProperty.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export class BaseColorProperty extends Input {
88

99

1010
constructor() {
11-
super(Theme.config.vec3);
11+
super(3);
1212

1313
this.layout = new Layout([
1414
new TextLabel("Base Color"),

src/properties/Input.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { FillStyle } from "../colors/Theme";
2+
import { OutletSize } from "../core/IOutlet";
23
import { OutletProperty } from "./OutletProperty";
34

45
export class Input extends OutletProperty {
5-
constructor(dotColor:FillStyle) {
6-
super(true, dotColor);
6+
constructor( size:OutletSize) {
7+
super(true, size);
78
}
89
}

src/properties/MaterialOutput.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { Theme } from "../colors/Theme";
1+
22
import { Output } from "./Output";
33

44
export class MaterialOutput extends Output {
55
constructor() {
6-
super( "Material", Theme.config.materialOutputSocketColor )
6+
super( "Material", 5 )
77
}
88
}

src/properties/OutletProperty.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { FillStyle, Theme } from "../colors/Theme";
2-
import { IOutlet } from "../core/IOutlet";
2+
import { IOutlet, OutletSize } from "../core/IOutlet";
33
import { LayoutElement } from "../layout/LayoutElement";
44
import { Node } from "../nodes/Node";
55

@@ -11,15 +11,27 @@ export class OutletProperty extends LayoutElement implements IOutlet
1111
private _globalX = 0;
1212
private _globalY = 0;
1313
private _isInput = true;
14+
private _size = 1;
1415

1516
get isInput() { return this._isInput; }
1617
get globalX() { return this._globalX; }
17-
get globalY() { return this._globalY; }
18+
get globalY() { return this._globalY; }
1819

19-
constructor( inputType:boolean, protected dotColor:FillStyle )
20+
readonly color:FillStyle;
21+
22+
constructor( inputType:boolean, readonly size:OutletSize )
2023
{
2124
super();
2225
this._isInput = inputType;
26+
27+
this.color = [
28+
"black",
29+
Theme.config.vec1,
30+
Theme.config.vec2,
31+
Theme.config.vec3,
32+
Theme.config.vec4,
33+
Theme.config.materialOutputSocketColor,
34+
][ size ]
2335
}
2436

2537
connectedTo?: IOutlet | undefined;
@@ -33,7 +45,7 @@ export class OutletProperty extends LayoutElement implements IOutlet
3345
//render circle...
3446
ctx.save()
3547
ctx.translate( this.isInput? 0 : maxWidth, maxHeight/2);
36-
this.drawCircle(ctx, 0, 0, 5, this.dotColor, Theme.config.borderColor, 1);
48+
this.drawCircle(ctx, 0, 0, 5, this.color, Theme.config.borderColor, 1);
3749

3850
//
3951
// obtain the global position of the outlet

src/properties/Output.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import { FillStyle, Theme } from "../colors/Theme";
1+
2+
import { OutletSize } from "../core/IOutlet";
23
import { OutletProperty } from "./OutletProperty";
34

45
export class Output extends OutletProperty {
56

6-
constructor( protected label:string, dotColor:FillStyle )
7+
constructor( protected label:string, size:OutletSize )
78
{
8-
super( false, dotColor );
9+
super( false, size );
910
}
1011

1112
override renderContents(ctx: CanvasRenderingContext2D, maxWidth: number, maxHeight: number): void {

src/properties/TextureProperty.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export class TextureProperty extends Input {
1717

1818

1919
constructor() {
20-
super( Theme.config.vec4 )
20+
super( 4 )
2121

2222
//"row", "start", "stretch",
2323
this.initial = new Layout( [

src/properties/UVAttributeProperty.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ import { Output } from "./Output";
33

44
export class UVAttributeProperty extends Output {
55
constructor() {
6-
super("UV", Theme.config.vec2);
6+
super("UV", 2);
77
}
88
}

src/properties/UVChannelProperty.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Input } from "./Input";
66
export class UVChannelProperty extends Input
77
{
88
constructor() {
9-
super( Theme.config.vec1 )
9+
super( 1 )
1010

1111
//"column","space-around","stretch",
1212
this.layout = new Layout([

0 commit comments

Comments
 (0)