@elicdavis/node-flow 0.1.16 → 0.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +97 -4
- package/dist/index.d.ts +97 -4
- package/dist/index.js +643 -69
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +637 -68
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/graph.ts +234 -41
- package/src/index.ts +16 -0
- package/src/input.ts +22 -14
- package/src/markdown/entry.ts +6 -2
- package/src/minimap.ts +178 -0
- package/src/node.ts +80 -1
- package/src/nodes/factory.ts +9 -5
- package/src/nodes/publisher.ts +39 -4
- package/src/nodes/subsystem.ts +211 -1
- package/src/notes/subsystem.ts +3 -0
- package/src/port.ts +17 -4
- package/src/render_scheduler.ts +49 -0
- package/src/theme.ts +8 -0
- package/src/types/text.ts +2 -0
- package/src/widgets/image.ts +2 -0
- package/test/minimap.test.ts +103 -0
- package/test/node_menu_filter.test.ts +119 -0
- package/test/render_scheduler.test.ts +119 -0
package/dist/index.js
CHANGED
|
@@ -30,6 +30,7 @@ __export(index_exports, {
|
|
|
30
30
|
GlobalWidgetFactory: () => GlobalWidgetFactory,
|
|
31
31
|
ImageWidget: () => ImageWidget,
|
|
32
32
|
MessageType: () => MessageType,
|
|
33
|
+
Minimap: () => Minimap,
|
|
33
34
|
NodeFactory: () => NodeFactory,
|
|
34
35
|
NodeFlowGraph: () => NodeFlowGraph,
|
|
35
36
|
NodeState: () => NodeState,
|
|
@@ -43,7 +44,11 @@ __export(index_exports, {
|
|
|
43
44
|
Theme: () => Theme,
|
|
44
45
|
ToggleWidget: () => ToggleWidget,
|
|
45
46
|
WidgetFactory: () => WidgetFactory,
|
|
46
|
-
|
|
47
|
+
portConfigTypes: () => portConfigTypes,
|
|
48
|
+
portsCompatible: () => portsCompatible,
|
|
49
|
+
renderContinuously: () => renderContinuously,
|
|
50
|
+
requestRender: () => requestRender,
|
|
51
|
+
typeSetsCompatible: () => typeSetsCompatible
|
|
47
52
|
});
|
|
48
53
|
module.exports = __toCommonJS(index_exports);
|
|
49
54
|
|
|
@@ -109,6 +114,14 @@ var Theme = {
|
|
|
109
114
|
FontColor: "#afb9bb",
|
|
110
115
|
DisabledFontColor: "#4a585c"
|
|
111
116
|
},
|
|
117
|
+
Minimap: {
|
|
118
|
+
BackgroundColor: "rgba(7, 33, 42, 0.85)",
|
|
119
|
+
BorderColor: "#1c1c1c",
|
|
120
|
+
BorderRadius: 4,
|
|
121
|
+
Padding: 6,
|
|
122
|
+
NodeColor: "#6b7f85",
|
|
123
|
+
ViewportColor: "rgba(175, 185, 187, 0.25)"
|
|
124
|
+
},
|
|
112
125
|
Note: {
|
|
113
126
|
FontColor: "#afb9bb",
|
|
114
127
|
FontSize: 16,
|
|
@@ -650,6 +663,43 @@ var ContextMenu = class _ContextMenu {
|
|
|
650
663
|
}
|
|
651
664
|
};
|
|
652
665
|
|
|
666
|
+
// src/render_scheduler.ts
|
|
667
|
+
var subscribers = /* @__PURE__ */ new Set();
|
|
668
|
+
var frameQueued = false;
|
|
669
|
+
var continuous = 0;
|
|
670
|
+
var canSchedule = () => typeof requestAnimationFrame === "function";
|
|
671
|
+
function onRenderRequested(redraw) {
|
|
672
|
+
subscribers.add(redraw);
|
|
673
|
+
return () => {
|
|
674
|
+
subscribers.delete(redraw);
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
function requestRender() {
|
|
678
|
+
if (frameQueued || !canSchedule()) {
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
frameQueued = true;
|
|
682
|
+
requestAnimationFrame(() => {
|
|
683
|
+
frameQueued = false;
|
|
684
|
+
subscribers.forEach((redraw) => redraw());
|
|
685
|
+
if (continuous > 0) {
|
|
686
|
+
requestRender();
|
|
687
|
+
}
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
function renderContinuously() {
|
|
691
|
+
continuous++;
|
|
692
|
+
requestRender();
|
|
693
|
+
let released = false;
|
|
694
|
+
return () => {
|
|
695
|
+
if (released) {
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
released = true;
|
|
699
|
+
continuous--;
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
|
|
653
703
|
// src/input.ts
|
|
654
704
|
var LONG_PRESS_MS = 500;
|
|
655
705
|
var LONG_PRESS_SLOP = 12;
|
|
@@ -683,15 +733,19 @@ var MouseObserver = class {
|
|
|
683
733
|
this.#lastTouch = Zero();
|
|
684
734
|
this.#lastMousePosition = Zero();
|
|
685
735
|
ele.style.touchAction = "none";
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
ele.addEventListener("
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
736
|
+
const redraws = (handler) => (event) => {
|
|
737
|
+
handler(event);
|
|
738
|
+
requestRender();
|
|
739
|
+
};
|
|
740
|
+
ele.addEventListener("mousedown", redraws(this.#down.bind(this)), false);
|
|
741
|
+
ele.addEventListener("touchstart", redraws(this.#touchStart.bind(this)), { passive: false });
|
|
742
|
+
document.addEventListener("mouseup", redraws(this.#up.bind(this)), false);
|
|
743
|
+
document.addEventListener("touchend", redraws(this.#touchEnd.bind(this)), false);
|
|
744
|
+
document.addEventListener("touchcancel", redraws(this.#touchEnd.bind(this)), false);
|
|
745
|
+
ele.addEventListener("mousemove", redraws(this.#move.bind(this)), false);
|
|
746
|
+
ele.addEventListener("touchmove", redraws(this.#touchMove.bind(this)), { passive: false });
|
|
747
|
+
ele.addEventListener("wheel", redraws(this.#wheel.bind(this)), { passive: false });
|
|
748
|
+
ele.addEventListener("drop", redraws((ev) => {
|
|
695
749
|
ev.preventDefault();
|
|
696
750
|
if (ev.dataTransfer?.items) {
|
|
697
751
|
[...ev.dataTransfer.items].forEach((item, i) => {
|
|
@@ -703,18 +757,18 @@ var MouseObserver = class {
|
|
|
703
757
|
}
|
|
704
758
|
});
|
|
705
759
|
}
|
|
706
|
-
});
|
|
707
|
-
ele.addEventListener("dragover", (ev) => {
|
|
760
|
+
}));
|
|
761
|
+
ele.addEventListener("dragover", redraws((ev) => {
|
|
708
762
|
ev.preventDefault();
|
|
709
763
|
this.#moveCallback(this.#mousePos(ev));
|
|
710
|
-
});
|
|
711
|
-
ele.addEventListener("contextmenu", (evt) => {
|
|
764
|
+
}));
|
|
765
|
+
ele.addEventListener("contextmenu", redraws((evt) => {
|
|
712
766
|
evt.preventDefault();
|
|
713
767
|
if (Date.now() - this.#lastTouchAt < SUPPRESS_MOUSE_MS) {
|
|
714
768
|
return;
|
|
715
769
|
}
|
|
716
770
|
this.#contextMenu(this.#mousePos(evt));
|
|
717
|
-
}, false);
|
|
771
|
+
}), false);
|
|
718
772
|
}
|
|
719
773
|
#mousePos(event) {
|
|
720
774
|
const rect = this.#ele.getBoundingClientRect();
|
|
@@ -811,6 +865,7 @@ var MouseObserver = class {
|
|
|
811
865
|
this.#clicked = false;
|
|
812
866
|
this.#clickStop();
|
|
813
867
|
this.#contextMenu({ x, y });
|
|
868
|
+
requestRender();
|
|
814
869
|
}, LONG_PRESS_MS);
|
|
815
870
|
this.#clicked = true;
|
|
816
871
|
this.#moveCallback(pos);
|
|
@@ -1247,6 +1302,7 @@ var Text = class _Text {
|
|
|
1247
1302
|
if (!document.fonts.check(`16px "${this.#style.getFont()}"`)) {
|
|
1248
1303
|
document.fonts.addEventListener("loadingdone", () => {
|
|
1249
1304
|
this.#measured = false;
|
|
1305
|
+
requestRender();
|
|
1250
1306
|
});
|
|
1251
1307
|
}
|
|
1252
1308
|
}
|
|
@@ -1458,12 +1514,22 @@ function portsCompatible(a, b) {
|
|
|
1458
1514
|
if (!a || !b) {
|
|
1459
1515
|
return false;
|
|
1460
1516
|
}
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1517
|
+
return typeSetsCompatible(a.acceptedTypes(), b.acceptedTypes());
|
|
1518
|
+
}
|
|
1519
|
+
function typeSetsCompatible(a, b) {
|
|
1520
|
+
if (a.length === 0 || b.length === 0) {
|
|
1464
1521
|
return true;
|
|
1465
1522
|
}
|
|
1466
|
-
return
|
|
1523
|
+
return a.some((type) => b.includes(type));
|
|
1524
|
+
}
|
|
1525
|
+
function portConfigTypes(config) {
|
|
1526
|
+
if (config.anyType === true) {
|
|
1527
|
+
return [];
|
|
1528
|
+
}
|
|
1529
|
+
if (config.acceptedTypes !== void 0 && config.acceptedTypes.length > 0) {
|
|
1530
|
+
return config.acceptedTypes;
|
|
1531
|
+
}
|
|
1532
|
+
return [config.type === void 0 ? "" : config.type];
|
|
1467
1533
|
}
|
|
1468
1534
|
function fallbackColor(type, s) {
|
|
1469
1535
|
let value = 0;
|
|
@@ -1578,6 +1644,7 @@ var Port = class {
|
|
|
1578
1644
|
this.#filledStyle.fillColor = fallbackColor(this.#dataType, 1);
|
|
1579
1645
|
}
|
|
1580
1646
|
this.#dataTypePopupElement = this.#buildTooltip();
|
|
1647
|
+
requestRender();
|
|
1581
1648
|
}
|
|
1582
1649
|
setDataType(type) {
|
|
1583
1650
|
if (this.#dataType === type) {
|
|
@@ -2656,6 +2723,7 @@ var ImageWidget = class {
|
|
|
2656
2723
|
img.src = url;
|
|
2657
2724
|
img.onload = () => {
|
|
2658
2725
|
this.#image = img;
|
|
2726
|
+
requestRender();
|
|
2659
2727
|
};
|
|
2660
2728
|
img.onerror = (event) => {
|
|
2661
2729
|
console.log("error loading image:", url, event);
|
|
@@ -3236,6 +3304,13 @@ function TimeExecution(name, callback) {
|
|
|
3236
3304
|
}
|
|
3237
3305
|
|
|
3238
3306
|
// src/nodes/publisher.ts
|
|
3307
|
+
function offersMatchingPort(config, filter) {
|
|
3308
|
+
const ports = filter.needs === "INPUT" /* Input */ ? config.inputs : config.outputs;
|
|
3309
|
+
if (ports === void 0) {
|
|
3310
|
+
return false;
|
|
3311
|
+
}
|
|
3312
|
+
return ports.some((port) => typeSetsCompatible(portConfigTypes(port), filter.types));
|
|
3313
|
+
}
|
|
3239
3314
|
var Publisher = class {
|
|
3240
3315
|
#name;
|
|
3241
3316
|
#description;
|
|
@@ -3261,19 +3336,23 @@ var Publisher = class {
|
|
|
3261
3336
|
unregister(nodeType) {
|
|
3262
3337
|
return this.#registeredNodes.delete(nodeType);
|
|
3263
3338
|
}
|
|
3264
|
-
#recurseBuildMenu(graph, name, subMenu, position) {
|
|
3339
|
+
#recurseBuildMenu(graph, name, subMenu, position, filter) {
|
|
3265
3340
|
const items = [];
|
|
3266
3341
|
const subMenus = /* @__PURE__ */ new Map();
|
|
3267
3342
|
for (let [key, nodeConfig] of subMenu) {
|
|
3268
3343
|
const slashIndex = key.indexOf("/");
|
|
3269
3344
|
const bracketIndex = key.indexOf("[");
|
|
3270
3345
|
if (slashIndex === -1 || bracketIndex !== -1 && bracketIndex < slashIndex) {
|
|
3346
|
+
if (filter !== void 0 && !offersMatchingPort(nodeConfig, filter)) {
|
|
3347
|
+
continue;
|
|
3348
|
+
}
|
|
3271
3349
|
items.push({
|
|
3272
3350
|
name: key,
|
|
3273
3351
|
callback: () => {
|
|
3274
3352
|
const node = new FlowNode(nodeConfig);
|
|
3275
3353
|
node.setPosition(position);
|
|
3276
3354
|
graph.addNode(node);
|
|
3355
|
+
filter?.onCreated?.(node);
|
|
3277
3356
|
}
|
|
3278
3357
|
});
|
|
3279
3358
|
} else {
|
|
@@ -3288,7 +3367,11 @@ var Publisher = class {
|
|
|
3288
3367
|
}
|
|
3289
3368
|
const menus = [];
|
|
3290
3369
|
for (let [key, nodes] of subMenus) {
|
|
3291
|
-
|
|
3370
|
+
const built = this.#recurseBuildMenu(graph, key, nodes, position, filter);
|
|
3371
|
+
if (filter !== void 0 && built.items?.length === 0 && built.subMenus?.length === 0) {
|
|
3372
|
+
continue;
|
|
3373
|
+
}
|
|
3374
|
+
menus.push(built);
|
|
3292
3375
|
}
|
|
3293
3376
|
return {
|
|
3294
3377
|
name,
|
|
@@ -3296,8 +3379,8 @@ var Publisher = class {
|
|
|
3296
3379
|
subMenus: menus
|
|
3297
3380
|
};
|
|
3298
3381
|
}
|
|
3299
|
-
contextMenu(graph, position) {
|
|
3300
|
-
return this.#recurseBuildMenu(graph, this.#name, this.#registeredNodes, position);
|
|
3382
|
+
contextMenu(graph, position, filter) {
|
|
3383
|
+
return this.#recurseBuildMenu(graph, this.#name, this.#registeredNodes, position, filter);
|
|
3301
3384
|
}
|
|
3302
3385
|
create(nodeType) {
|
|
3303
3386
|
const config = this.#registeredNodes.get(nodeType);
|
|
@@ -3352,18 +3435,22 @@ var NodeFactory = class {
|
|
|
3352
3435
|
}
|
|
3353
3436
|
return node;
|
|
3354
3437
|
}
|
|
3355
|
-
newNodeSubmenus(graph, position) {
|
|
3438
|
+
newNodeSubmenus(graph, position, filter) {
|
|
3356
3439
|
const menus = [];
|
|
3357
3440
|
for (let [_, publisher] of this.#registeredPublishers) {
|
|
3358
|
-
|
|
3441
|
+
const built = publisher.contextMenu(graph, position, filter);
|
|
3442
|
+
if (filter !== void 0 && built.items?.length === 0 && built.subMenus?.length === 0) {
|
|
3443
|
+
continue;
|
|
3444
|
+
}
|
|
3445
|
+
menus.push(built);
|
|
3359
3446
|
}
|
|
3360
3447
|
return menus;
|
|
3361
3448
|
}
|
|
3362
|
-
openMenu(graph, position) {
|
|
3449
|
+
openMenu(graph, position, filter) {
|
|
3363
3450
|
return {
|
|
3364
3451
|
name: "New Node",
|
|
3365
3452
|
group: nodeFlowGroup,
|
|
3366
|
-
subMenus: this.newNodeSubmenus(graph, position)
|
|
3453
|
+
subMenus: this.newNodeSubmenus(graph, position, filter)
|
|
3367
3454
|
};
|
|
3368
3455
|
}
|
|
3369
3456
|
};
|
|
@@ -3502,6 +3589,9 @@ var NodeSubsystem2 = class {
|
|
|
3502
3589
|
CopyVector2(this.#boxSelectEnd_graphSpace, this.#boxSelectStart_graphSpace);
|
|
3503
3590
|
this.#boxSelect = true;
|
|
3504
3591
|
}
|
|
3592
|
+
if (!hoveringSomething && !ctrlKey) {
|
|
3593
|
+
this.unselectAllNodes();
|
|
3594
|
+
}
|
|
3505
3595
|
return hoveringSomething || ctrlKey;
|
|
3506
3596
|
}
|
|
3507
3597
|
if (this.#portHovering.InputPort) {
|
|
@@ -3561,6 +3651,102 @@ var NodeSubsystem2 = class {
|
|
|
3561
3651
|
}
|
|
3562
3652
|
}
|
|
3563
3653
|
}
|
|
3654
|
+
connectionsWithin(nodes) {
|
|
3655
|
+
const within = [];
|
|
3656
|
+
for (const connection of this.#connections) {
|
|
3657
|
+
const outNode = connection.outNode();
|
|
3658
|
+
const inNode = connection.inNode();
|
|
3659
|
+
if (outNode === null || inNode === null) {
|
|
3660
|
+
continue;
|
|
3661
|
+
}
|
|
3662
|
+
const from = nodes.indexOf(outNode);
|
|
3663
|
+
const to = nodes.indexOf(inNode);
|
|
3664
|
+
if (from === -1 || to === -1) {
|
|
3665
|
+
continue;
|
|
3666
|
+
}
|
|
3667
|
+
const outPort = connection.outPort();
|
|
3668
|
+
const inPort = connection.inPort();
|
|
3669
|
+
if (outPort === null || inPort === null) {
|
|
3670
|
+
continue;
|
|
3671
|
+
}
|
|
3672
|
+
within.push({
|
|
3673
|
+
fromNode: from,
|
|
3674
|
+
fromPort: this.#outputPortIndex(outNode, outPort),
|
|
3675
|
+
toNode: to,
|
|
3676
|
+
toPort: this.#inputPortIndex(inNode, inPort)
|
|
3677
|
+
});
|
|
3678
|
+
}
|
|
3679
|
+
return within;
|
|
3680
|
+
}
|
|
3681
|
+
#onConnectionReleased = null;
|
|
3682
|
+
setConnectionReleasedHandler(handler) {
|
|
3683
|
+
this.#onConnectionReleased = handler;
|
|
3684
|
+
}
|
|
3685
|
+
#describeDanglingConnection(conn) {
|
|
3686
|
+
const outNode = conn.outNode();
|
|
3687
|
+
const inNode = conn.inNode();
|
|
3688
|
+
if (outNode !== null && inNode === null) {
|
|
3689
|
+
const from = conn.outPort();
|
|
3690
|
+
if (from === null) {
|
|
3691
|
+
return null;
|
|
3692
|
+
}
|
|
3693
|
+
const fromIndex = this.#outputPortIndex(outNode, from);
|
|
3694
|
+
return {
|
|
3695
|
+
needs: "INPUT" /* Input */,
|
|
3696
|
+
types: from.acceptedTypes(),
|
|
3697
|
+
connectTo: (node) => {
|
|
3698
|
+
const to = this.#firstCompatiblePort(node, "INPUT" /* Input */, from);
|
|
3699
|
+
if (to !== -1 && fromIndex !== -1) {
|
|
3700
|
+
this.connectNodes(outNode, fromIndex, node, to);
|
|
3701
|
+
}
|
|
3702
|
+
}
|
|
3703
|
+
};
|
|
3704
|
+
}
|
|
3705
|
+
if (inNode !== null && outNode === null) {
|
|
3706
|
+
const to = conn.inPort();
|
|
3707
|
+
if (to === null) {
|
|
3708
|
+
return null;
|
|
3709
|
+
}
|
|
3710
|
+
const toIndex = this.#inputPortIndex(inNode, to);
|
|
3711
|
+
return {
|
|
3712
|
+
needs: "OUTPUT" /* Output */,
|
|
3713
|
+
types: to.acceptedTypes(),
|
|
3714
|
+
connectTo: (node) => {
|
|
3715
|
+
const from = this.#firstCompatiblePort(node, "OUTPUT" /* Output */, to);
|
|
3716
|
+
if (from !== -1 && toIndex !== -1) {
|
|
3717
|
+
this.connectNodes(node, from, inNode, toIndex);
|
|
3718
|
+
}
|
|
3719
|
+
}
|
|
3720
|
+
};
|
|
3721
|
+
}
|
|
3722
|
+
return null;
|
|
3723
|
+
}
|
|
3724
|
+
#outputPortIndex(node, port) {
|
|
3725
|
+
for (let i = 0; i < node.outputs(); i++) {
|
|
3726
|
+
if (node.outputPort(i) === port) {
|
|
3727
|
+
return i;
|
|
3728
|
+
}
|
|
3729
|
+
}
|
|
3730
|
+
return -1;
|
|
3731
|
+
}
|
|
3732
|
+
#inputPortIndex(node, port) {
|
|
3733
|
+
for (let i = 0; i < node.inputs(); i++) {
|
|
3734
|
+
if (node.inputPort(i) === port) {
|
|
3735
|
+
return i;
|
|
3736
|
+
}
|
|
3737
|
+
}
|
|
3738
|
+
return -1;
|
|
3739
|
+
}
|
|
3740
|
+
#firstCompatiblePort(node, side, against) {
|
|
3741
|
+
const count = side === "INPUT" /* Input */ ? node.inputs() : node.outputs();
|
|
3742
|
+
for (let i = 0; i < count; i++) {
|
|
3743
|
+
const port = side === "INPUT" /* Input */ ? node.inputPort(i) : node.outputPort(i);
|
|
3744
|
+
if (portsCompatible(port, against)) {
|
|
3745
|
+
return i;
|
|
3746
|
+
}
|
|
3747
|
+
}
|
|
3748
|
+
return -1;
|
|
3749
|
+
}
|
|
3564
3750
|
clickEnd() {
|
|
3565
3751
|
for (let i = 0; i < this.#nodesGrabbed.Count(); i++) {
|
|
3566
3752
|
const node = this.#nodes[this.#nodesGrabbed.At(i)];
|
|
@@ -3582,7 +3768,11 @@ var NodeSubsystem2 = class {
|
|
|
3582
3768
|
return;
|
|
3583
3769
|
}
|
|
3584
3770
|
if (this.#portHovering === null) {
|
|
3771
|
+
const dangling = this.#describeDanglingConnection(this.#connectionSelected);
|
|
3585
3772
|
this.#clearCurrentlySelectedConnection();
|
|
3773
|
+
if (dangling !== null) {
|
|
3774
|
+
this.#onConnectionReleased?.(dangling);
|
|
3775
|
+
}
|
|
3586
3776
|
return;
|
|
3587
3777
|
}
|
|
3588
3778
|
const port = this.#portHovering.Port;
|
|
@@ -3649,6 +3839,7 @@ var NodeSubsystem2 = class {
|
|
|
3649
3839
|
this.#idleConnectionRenderer
|
|
3650
3840
|
);
|
|
3651
3841
|
this.#connections.push(connection);
|
|
3842
|
+
requestRender();
|
|
3652
3843
|
return connection;
|
|
3653
3844
|
}
|
|
3654
3845
|
getNodes() {
|
|
@@ -3709,6 +3900,7 @@ var NodeSubsystem2 = class {
|
|
|
3709
3900
|
}
|
|
3710
3901
|
addNode(node) {
|
|
3711
3902
|
this.#nodes.push(node);
|
|
3903
|
+
requestRender();
|
|
3712
3904
|
for (let i = 0; i < this.#registeredNodeAddedCallbacks.length; i++) {
|
|
3713
3905
|
const callback = this.#registeredNodeAddedCallbacks[i];
|
|
3714
3906
|
if (!callback) {
|
|
@@ -3755,6 +3947,7 @@ var NodeSubsystem2 = class {
|
|
|
3755
3947
|
this.#removeNodeConnections(nodeIndex);
|
|
3756
3948
|
const node = this.#nodes[nodeIndex];
|
|
3757
3949
|
this.#nodes.splice(nodeIndex, 1);
|
|
3950
|
+
requestRender();
|
|
3758
3951
|
for (let i = 0; i < this.#nodeRemovedCallbacks.length; i++) {
|
|
3759
3952
|
this.#nodeRemovedCallbacks[i](node);
|
|
3760
3953
|
}
|
|
@@ -3764,6 +3957,7 @@ var NodeSubsystem2 = class {
|
|
|
3764
3957
|
this.#connections[index].clearPorts();
|
|
3765
3958
|
}
|
|
3766
3959
|
this.#connections.splice(index, 1);
|
|
3960
|
+
requestRender();
|
|
3767
3961
|
}
|
|
3768
3962
|
#removeConnection(connection, clearPorts) {
|
|
3769
3963
|
const index = this.#connections.indexOf(connection);
|
|
@@ -3809,7 +4003,8 @@ var NodeSubsystem2 = class {
|
|
|
3809
4003
|
this.#nodeFactory.openMenu(this, position)
|
|
3810
4004
|
]
|
|
3811
4005
|
};
|
|
3812
|
-
|
|
4006
|
+
const selectedCount = this.#nodesSelected().length;
|
|
4007
|
+
if (selectedCount > 0) {
|
|
3813
4008
|
organizeNodesSubMenu.items?.push({
|
|
3814
4009
|
name: "Selected Nodes",
|
|
3815
4010
|
group: nodeFlowGroup,
|
|
@@ -3817,6 +4012,13 @@ var NodeSubsystem2 = class {
|
|
|
3817
4012
|
this.#organizeSelected(ctx);
|
|
3818
4013
|
}
|
|
3819
4014
|
});
|
|
4015
|
+
config.items?.push({
|
|
4016
|
+
name: selectedCount === 1 ? "Delete Selected Node" : `Delete ${selectedCount} Selected Nodes`,
|
|
4017
|
+
group: nodeFlowGroup,
|
|
4018
|
+
callback: () => {
|
|
4019
|
+
this.removeSelectedNodes();
|
|
4020
|
+
}
|
|
4021
|
+
});
|
|
3820
4022
|
}
|
|
3821
4023
|
if (this.#nodeHovering > -1) {
|
|
3822
4024
|
const nodeToReview = this.#nodeHovering;
|
|
@@ -3890,6 +4092,29 @@ var NodeSubsystem2 = class {
|
|
|
3890
4092
|
this.#selectNode(inputs[i], false);
|
|
3891
4093
|
}
|
|
3892
4094
|
}
|
|
4095
|
+
/** Drops the selection entirely. */
|
|
4096
|
+
unselectAllNodes() {
|
|
4097
|
+
let changed = false;
|
|
4098
|
+
for (let i = 0; i < this.#nodes.length; i++) {
|
|
4099
|
+
if (this.#nodes[i].selected()) {
|
|
4100
|
+
this.#nodes[i].unselect();
|
|
4101
|
+
changed = true;
|
|
4102
|
+
}
|
|
4103
|
+
}
|
|
4104
|
+
if (changed) {
|
|
4105
|
+
requestRender();
|
|
4106
|
+
}
|
|
4107
|
+
}
|
|
4108
|
+
/**
|
|
4109
|
+
* Removes every selected node, and the connections that touched them.
|
|
4110
|
+
*/
|
|
4111
|
+
removeSelectedNodes() {
|
|
4112
|
+
const removed = this.getSelectedNodes();
|
|
4113
|
+
for (const node of removed) {
|
|
4114
|
+
this.removeNode(node);
|
|
4115
|
+
}
|
|
4116
|
+
return removed;
|
|
4117
|
+
}
|
|
3893
4118
|
#selectNodeByIndex(nodeIndex, unselectOthers) {
|
|
3894
4119
|
this.#selectNode(this.#nodes[nodeIndex], unselectOthers);
|
|
3895
4120
|
}
|
|
@@ -3927,8 +4152,16 @@ var NodeSubsystem2 = class {
|
|
|
3927
4152
|
this.#nodeHovering = -1;
|
|
3928
4153
|
this.#boxSelectionNodes.Clear();
|
|
3929
4154
|
const selectedBox_Screenspace = this.#boxSelectionScreenspaceBox(camera);
|
|
4155
|
+
const canvas = {
|
|
4156
|
+
Position: { x: 0, y: 0 },
|
|
4157
|
+
Size: { x: ctx.canvas.width, y: ctx.canvas.height }
|
|
4158
|
+
};
|
|
3930
4159
|
for (let i = 0; i < this.#nodes.length; i++) {
|
|
3931
4160
|
let state = 0 /* Idle */;
|
|
4161
|
+
const nodeBounds = this.#nodes[i].calculateBounds(ctx, camera);
|
|
4162
|
+
if (!BoxIntersection(nodeBounds, canvas) && this.#nodes[i].layoutPortsWithoutDrawing(nodeBounds, camera.zoom)) {
|
|
4163
|
+
continue;
|
|
4164
|
+
}
|
|
3932
4165
|
if (mousePosition !== void 0 && !this.#boxSelect) {
|
|
3933
4166
|
const intersection = this.#nodes[i].inBounds(ctx, camera, mousePosition);
|
|
3934
4167
|
if (intersection.Node !== void 0 && intersection.PortIndex === void 0 && intersection.Widget === void 0) {
|
|
@@ -3949,8 +4182,8 @@ var NodeSubsystem2 = class {
|
|
|
3949
4182
|
};
|
|
3950
4183
|
}
|
|
3951
4184
|
} else if (this.#boxSelect) {
|
|
3952
|
-
const
|
|
3953
|
-
if (BoxIntersection(selectedBox_Screenspace,
|
|
4185
|
+
const nodeBounds2 = this.#nodes[i].calculateBounds(ctx, camera);
|
|
4186
|
+
if (BoxIntersection(selectedBox_Screenspace, nodeBounds2)) {
|
|
3954
4187
|
state = 1 /* MouseOver */;
|
|
3955
4188
|
this.#boxSelectionNodes.Push(i);
|
|
3956
4189
|
}
|
|
@@ -3972,12 +4205,16 @@ var NodeSubsystem2 = class {
|
|
|
3972
4205
|
render(ctx, camera, mousePosition) {
|
|
3973
4206
|
this.#lastCtx = ctx;
|
|
3974
4207
|
this.#cursor = "default" /* Default */;
|
|
4208
|
+
const awaitingLayout = this.#nodes.some((node) => !node.hasBeenLaidOut());
|
|
3975
4209
|
TimeExecution("Render_Connections", () => {
|
|
3976
4210
|
this.#renderConnections(ctx, camera, mousePosition);
|
|
3977
4211
|
});
|
|
3978
4212
|
TimeExecution("Render_Nodes", () => {
|
|
3979
4213
|
this.#renderNodes(ctx, camera, mousePosition);
|
|
3980
4214
|
});
|
|
4215
|
+
if (awaitingLayout) {
|
|
4216
|
+
requestRender();
|
|
4217
|
+
}
|
|
3981
4218
|
if (this.#boxSelect) {
|
|
3982
4219
|
const box = this.#boxSelectionScreenspaceBox(camera);
|
|
3983
4220
|
ctx.setLineDash([Theme.BoxSelect.LineDashLength]);
|
|
@@ -4253,6 +4490,7 @@ var FlowNode = class {
|
|
|
4253
4490
|
return;
|
|
4254
4491
|
}
|
|
4255
4492
|
this.#selected = true;
|
|
4493
|
+
requestRender();
|
|
4256
4494
|
for (let i = 0; i < this.#onSelect.length; i++) {
|
|
4257
4495
|
this.#onSelect[i]();
|
|
4258
4496
|
}
|
|
@@ -4298,6 +4536,7 @@ var FlowNode = class {
|
|
|
4298
4536
|
return;
|
|
4299
4537
|
}
|
|
4300
4538
|
this.#data[name] = value;
|
|
4539
|
+
requestRender();
|
|
4301
4540
|
for (let i = 0; i < this.#registeredAnyPropertyChangeCallbacks.length; i++) {
|
|
4302
4541
|
this.#registeredAnyPropertyChangeCallbacks[i](name, oldValue, value);
|
|
4303
4542
|
}
|
|
@@ -4558,6 +4797,7 @@ var FlowNode = class {
|
|
|
4558
4797
|
return;
|
|
4559
4798
|
}
|
|
4560
4799
|
this.#selected = false;
|
|
4800
|
+
requestRender();
|
|
4561
4801
|
for (let i = 0; i < this.#onUnselect.length; i++) {
|
|
4562
4802
|
this.#onUnselect[i]();
|
|
4563
4803
|
}
|
|
@@ -4587,6 +4827,7 @@ var FlowNode = class {
|
|
|
4587
4827
|
}
|
|
4588
4828
|
setPosition(position) {
|
|
4589
4829
|
CopyVector2(this.#position, position);
|
|
4830
|
+
requestRender();
|
|
4590
4831
|
}
|
|
4591
4832
|
getPosition() {
|
|
4592
4833
|
return this.#position;
|
|
@@ -4649,10 +4890,12 @@ var FlowNode = class {
|
|
|
4649
4890
|
}
|
|
4650
4891
|
addWidget(widget) {
|
|
4651
4892
|
this.#widgets.push(widget);
|
|
4893
|
+
requestRender();
|
|
4652
4894
|
}
|
|
4653
4895
|
insertWidget(index, widget) {
|
|
4654
4896
|
const at = Math.max(0, Math.min(index, this.#widgets.length));
|
|
4655
4897
|
this.#widgets.splice(at, 0, widget);
|
|
4898
|
+
requestRender();
|
|
4656
4899
|
}
|
|
4657
4900
|
removeWidget(widget) {
|
|
4658
4901
|
const index = this.#widgets.indexOf(widget, 0);
|
|
@@ -4660,12 +4903,15 @@ var FlowNode = class {
|
|
|
4660
4903
|
throw new Error("node does not contain widget");
|
|
4661
4904
|
}
|
|
4662
4905
|
this.#widgets.splice(index, 1);
|
|
4906
|
+
requestRender();
|
|
4663
4907
|
}
|
|
4664
4908
|
removeWidgetAt(index) {
|
|
4665
4909
|
if (index < 0 || index >= this.#widgets.length) {
|
|
4666
4910
|
return void 0;
|
|
4667
4911
|
}
|
|
4668
|
-
|
|
4912
|
+
const removed = this.#widgets.splice(index, 1)[0];
|
|
4913
|
+
requestRender();
|
|
4914
|
+
return removed;
|
|
4669
4915
|
}
|
|
4670
4916
|
moveWidget(from, to) {
|
|
4671
4917
|
if (from < 0 || from >= this.#widgets.length) {
|
|
@@ -4676,9 +4922,11 @@ var FlowNode = class {
|
|
|
4676
4922
|
}
|
|
4677
4923
|
const [widget] = this.#widgets.splice(from, 1);
|
|
4678
4924
|
this.#widgets.splice(to, 0, widget);
|
|
4925
|
+
requestRender();
|
|
4679
4926
|
}
|
|
4680
4927
|
clearWidgets() {
|
|
4681
4928
|
this.#widgets.length = 0;
|
|
4929
|
+
requestRender();
|
|
4682
4930
|
}
|
|
4683
4931
|
getWidget(index) {
|
|
4684
4932
|
return this.#widgets[index];
|
|
@@ -4750,6 +4998,7 @@ var FlowNode = class {
|
|
|
4750
4998
|
return;
|
|
4751
4999
|
}
|
|
4752
5000
|
this.#title.set(cleaned);
|
|
5001
|
+
requestRender();
|
|
4753
5002
|
for (let i = 0; i < this.#titleChangeCallback.length; i++) {
|
|
4754
5003
|
const callback = this.#titleChangeCallback[i];
|
|
4755
5004
|
callback(this, old, cleaned);
|
|
@@ -4768,6 +5017,7 @@ var FlowNode = class {
|
|
|
4768
5017
|
}
|
|
4769
5018
|
const old = this.#infoText;
|
|
4770
5019
|
this.#infoText = cleaned;
|
|
5020
|
+
requestRender();
|
|
4771
5021
|
for (let i = 0; i < this.#infoChangeCallback.length; i++) {
|
|
4772
5022
|
const callback = this.#infoChangeCallback[i];
|
|
4773
5023
|
callback(this, old, cleaned);
|
|
@@ -4807,7 +5057,12 @@ var FlowNode = class {
|
|
|
4807
5057
|
clearMessages() {
|
|
4808
5058
|
this.#messages = [];
|
|
4809
5059
|
}
|
|
5060
|
+
hasBeenLaidOut() {
|
|
5061
|
+
return this.#laidOut;
|
|
5062
|
+
}
|
|
5063
|
+
#laidOut = false;
|
|
4810
5064
|
render(ctx, camera, state, mousePosition, postProcess) {
|
|
5065
|
+
this.#laidOut = true;
|
|
4811
5066
|
VectorPool.run(() => {
|
|
4812
5067
|
const tempMeasurement = VectorPool.get();
|
|
4813
5068
|
this.#inputPortPositions.Clear();
|
|
@@ -4943,8 +5198,57 @@ var FlowNode = class {
|
|
|
4943
5198
|
const message = this.#messages[i];
|
|
4944
5199
|
messageStart.y += message.render(ctx, camera.zoom, messageStart, !(state === 0 /* Idle */)) + 10 * camera.zoom;
|
|
4945
5200
|
}
|
|
5201
|
+
this.#rememberPortOffsets(nodeBounds, camera.zoom);
|
|
4946
5202
|
});
|
|
4947
5203
|
}
|
|
5204
|
+
#portOffsets = { input: [], output: [] };
|
|
5205
|
+
#rememberPortOffsets(bounds, zoom) {
|
|
5206
|
+
if (zoom <= 0) {
|
|
5207
|
+
return;
|
|
5208
|
+
}
|
|
5209
|
+
const record = (positions, into) => {
|
|
5210
|
+
into.length = 0;
|
|
5211
|
+
for (let i = 0; i < positions.Count(); i++) {
|
|
5212
|
+
const box = positions.At(i);
|
|
5213
|
+
into.push({
|
|
5214
|
+
Position: {
|
|
5215
|
+
x: (box.Position.x - bounds.Position.x) / zoom,
|
|
5216
|
+
y: (box.Position.y - bounds.Position.y) / zoom
|
|
5217
|
+
},
|
|
5218
|
+
Size: {
|
|
5219
|
+
x: box.Size.x / zoom,
|
|
5220
|
+
y: box.Size.y / zoom
|
|
5221
|
+
}
|
|
5222
|
+
});
|
|
5223
|
+
}
|
|
5224
|
+
};
|
|
5225
|
+
record(this.#inputPortPositions, this.#portOffsets.input);
|
|
5226
|
+
record(this.#outputPortPositions, this.#portOffsets.output);
|
|
5227
|
+
}
|
|
5228
|
+
layoutPortsWithoutDrawing(bounds, zoom) {
|
|
5229
|
+
if (this.#portOffsets.input.length === 0 && this.#portOffsets.output.length === 0) {
|
|
5230
|
+
return false;
|
|
5231
|
+
}
|
|
5232
|
+
const project = (offsets, into) => {
|
|
5233
|
+
into.Clear();
|
|
5234
|
+
for (let i = 0; i < offsets.length; i++) {
|
|
5235
|
+
const offset = offsets[i];
|
|
5236
|
+
into.Push({
|
|
5237
|
+
Position: {
|
|
5238
|
+
x: bounds.Position.x + offset.Position.x * zoom,
|
|
5239
|
+
y: bounds.Position.y + offset.Position.y * zoom
|
|
5240
|
+
},
|
|
5241
|
+
Size: {
|
|
5242
|
+
x: offset.Size.x * zoom,
|
|
5243
|
+
y: offset.Size.y * zoom
|
|
5244
|
+
}
|
|
5245
|
+
});
|
|
5246
|
+
}
|
|
5247
|
+
};
|
|
5248
|
+
project(this.#portOffsets.input, this.#inputPortPositions);
|
|
5249
|
+
project(this.#portOffsets.output, this.#outputPortPositions);
|
|
5250
|
+
return true;
|
|
5251
|
+
}
|
|
4948
5252
|
};
|
|
4949
5253
|
|
|
4950
5254
|
// src/markdown/token.ts
|
|
@@ -5085,7 +5389,10 @@ function onFontsLoaded(callback) {
|
|
|
5085
5389
|
if (typeof document === "undefined" || document.fonts === void 0) {
|
|
5086
5390
|
return;
|
|
5087
5391
|
}
|
|
5088
|
-
document.fonts.addEventListener("loadingdone", () =>
|
|
5392
|
+
document.fonts.addEventListener("loadingdone", () => {
|
|
5393
|
+
callback();
|
|
5394
|
+
requestRender();
|
|
5395
|
+
});
|
|
5089
5396
|
}
|
|
5090
5397
|
var CodeBlockEntry = class {
|
|
5091
5398
|
#text;
|
|
@@ -5835,6 +6142,7 @@ var NoteSubsystem = class {
|
|
|
5835
6142
|
return;
|
|
5836
6143
|
}
|
|
5837
6144
|
this.#notes.push(note);
|
|
6145
|
+
requestRender();
|
|
5838
6146
|
for (let i = 0; i < this.#onNoteAddedCallbacks.length; i++) {
|
|
5839
6147
|
this.#onNoteAddedCallbacks[i](note);
|
|
5840
6148
|
}
|
|
@@ -5957,6 +6265,7 @@ var NoteSubsystem = class {
|
|
|
5957
6265
|
if (index > -1) {
|
|
5958
6266
|
const noteRemoved = this.#notes[index];
|
|
5959
6267
|
this.#notes.splice(index, 1);
|
|
6268
|
+
requestRender();
|
|
5960
6269
|
for (let i = 0; i < this.#onNoteRemovedCallbacks.length; i++) {
|
|
5961
6270
|
this.#onNoteRemovedCallbacks[i](noteRemoved);
|
|
5962
6271
|
}
|
|
@@ -6293,6 +6602,124 @@ var QuickMenu = class {
|
|
|
6293
6602
|
}
|
|
6294
6603
|
};
|
|
6295
6604
|
|
|
6605
|
+
// src/minimap.ts
|
|
6606
|
+
var Minimap = class {
|
|
6607
|
+
#enabled;
|
|
6608
|
+
#width;
|
|
6609
|
+
#height;
|
|
6610
|
+
#margin;
|
|
6611
|
+
#backgroundColor;
|
|
6612
|
+
#borderColor;
|
|
6613
|
+
#nodeColor;
|
|
6614
|
+
#viewportColor;
|
|
6615
|
+
#box = { Position: { x: 0, y: 0 }, Size: { x: 0, y: 0 } };
|
|
6616
|
+
#scale = 1;
|
|
6617
|
+
#originX = 0;
|
|
6618
|
+
#originY = 0;
|
|
6619
|
+
// The padding the last frame was laid out with, so a click maps back
|
|
6620
|
+
// through the same geometry it was drawn with.
|
|
6621
|
+
#padding = Theme.Minimap.Padding;
|
|
6622
|
+
#drawn = false;
|
|
6623
|
+
constructor(config) {
|
|
6624
|
+
this.#enabled = config?.enabled === true;
|
|
6625
|
+
this.#width = config?.width === void 0 ? 200 : config.width;
|
|
6626
|
+
this.#height = config?.height === void 0 ? 150 : config.height;
|
|
6627
|
+
this.#margin = config?.margin === void 0 ? 16 : config.margin;
|
|
6628
|
+
this.#backgroundColor = config?.backgroundColor;
|
|
6629
|
+
this.#borderColor = config?.borderColor;
|
|
6630
|
+
this.#nodeColor = config?.nodeColor;
|
|
6631
|
+
this.#viewportColor = config?.viewportColor;
|
|
6632
|
+
}
|
|
6633
|
+
enabled() {
|
|
6634
|
+
return this.#enabled;
|
|
6635
|
+
}
|
|
6636
|
+
setEnabled(enabled) {
|
|
6637
|
+
this.#enabled = enabled;
|
|
6638
|
+
this.#drawn = false;
|
|
6639
|
+
}
|
|
6640
|
+
contains(position) {
|
|
6641
|
+
return this.#enabled && this.#drawn && InBox(this.#box, position);
|
|
6642
|
+
}
|
|
6643
|
+
graphPositionOf(position, out) {
|
|
6644
|
+
out.x = (position.x - this.#box.Position.x - this.#padding) / this.#scale + this.#originX;
|
|
6645
|
+
out.y = (position.y - this.#box.Position.y - this.#padding) / this.#scale + this.#originY;
|
|
6646
|
+
}
|
|
6647
|
+
render(ctx, canvas, camera, nodes) {
|
|
6648
|
+
if (!this.#enabled) {
|
|
6649
|
+
this.#drawn = false;
|
|
6650
|
+
return;
|
|
6651
|
+
}
|
|
6652
|
+
const flat = new Camera();
|
|
6653
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
6654
|
+
const boxes = [];
|
|
6655
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
6656
|
+
const bounds = nodes[i].calculateBounds(ctx, flat);
|
|
6657
|
+
boxes.push(bounds);
|
|
6658
|
+
minX = Math.min(minX, bounds.Position.x);
|
|
6659
|
+
minY = Math.min(minY, bounds.Position.y);
|
|
6660
|
+
maxX = Math.max(maxX, bounds.Position.x + bounds.Size.x);
|
|
6661
|
+
maxY = Math.max(maxY, bounds.Position.y + bounds.Size.y);
|
|
6662
|
+
}
|
|
6663
|
+
const topLeft = { x: 0, y: 0 };
|
|
6664
|
+
const bottomRight = { x: 0, y: 0 };
|
|
6665
|
+
camera.screenSpaceToGraphSpace({ x: 0, y: 0 }, topLeft);
|
|
6666
|
+
camera.screenSpaceToGraphSpace({ x: canvas.width, y: canvas.height }, bottomRight);
|
|
6667
|
+
minX = Math.min(minX, topLeft.x);
|
|
6668
|
+
minY = Math.min(minY, topLeft.y);
|
|
6669
|
+
maxX = Math.max(maxX, bottomRight.x);
|
|
6670
|
+
maxY = Math.max(maxY, bottomRight.y);
|
|
6671
|
+
if (!isFinite(minX) || maxX <= minX || maxY <= minY) {
|
|
6672
|
+
this.#drawn = false;
|
|
6673
|
+
return;
|
|
6674
|
+
}
|
|
6675
|
+
this.#box.Size.x = this.#width;
|
|
6676
|
+
this.#box.Size.y = this.#height;
|
|
6677
|
+
this.#box.Position.x = canvas.width - this.#width - this.#margin;
|
|
6678
|
+
this.#box.Position.y = canvas.height - this.#height - this.#margin;
|
|
6679
|
+
this.#padding = Theme.Minimap.Padding;
|
|
6680
|
+
const usableWidth = this.#width - this.#padding * 2;
|
|
6681
|
+
const usableHeight = this.#height - this.#padding * 2;
|
|
6682
|
+
this.#scale = Math.min(usableWidth / (maxX - minX), usableHeight / (maxY - minY));
|
|
6683
|
+
this.#originX = minX;
|
|
6684
|
+
this.#originY = minY;
|
|
6685
|
+
const left = this.#box.Position.x + this.#padding;
|
|
6686
|
+
const top = this.#box.Position.y + this.#padding;
|
|
6687
|
+
const toMapX = (x) => left + (x - minX) * this.#scale;
|
|
6688
|
+
const toMapY = (y) => top + (y - minY) * this.#scale;
|
|
6689
|
+
ctx.fillStyle = this.#backgroundColor ?? Theme.Minimap.BackgroundColor;
|
|
6690
|
+
ctx.strokeStyle = this.#borderColor ?? Theme.Minimap.BorderColor;
|
|
6691
|
+
ctx.lineWidth = 1;
|
|
6692
|
+
ctx.beginPath();
|
|
6693
|
+
ctx.roundRect(
|
|
6694
|
+
this.#box.Position.x,
|
|
6695
|
+
this.#box.Position.y,
|
|
6696
|
+
this.#width,
|
|
6697
|
+
this.#height,
|
|
6698
|
+
Theme.Minimap.BorderRadius
|
|
6699
|
+
);
|
|
6700
|
+
ctx.fill();
|
|
6701
|
+
ctx.stroke();
|
|
6702
|
+
ctx.fillStyle = this.#nodeColor ?? Theme.Minimap.NodeColor;
|
|
6703
|
+
for (let i = 0; i < boxes.length; i++) {
|
|
6704
|
+
const b = boxes[i];
|
|
6705
|
+
ctx.fillRect(
|
|
6706
|
+
toMapX(b.Position.x),
|
|
6707
|
+
toMapY(b.Position.y),
|
|
6708
|
+
Math.max(1, b.Size.x * this.#scale),
|
|
6709
|
+
Math.max(1, b.Size.y * this.#scale)
|
|
6710
|
+
);
|
|
6711
|
+
}
|
|
6712
|
+
ctx.fillStyle = this.#viewportColor ?? Theme.Minimap.ViewportColor;
|
|
6713
|
+
ctx.fillRect(
|
|
6714
|
+
toMapX(topLeft.x),
|
|
6715
|
+
toMapY(topLeft.y),
|
|
6716
|
+
Math.max(1, (bottomRight.x - topLeft.x) * this.#scale),
|
|
6717
|
+
Math.max(1, (bottomRight.y - topLeft.y) * this.#scale)
|
|
6718
|
+
);
|
|
6719
|
+
this.#drawn = true;
|
|
6720
|
+
}
|
|
6721
|
+
};
|
|
6722
|
+
|
|
6296
6723
|
// src/graph.ts
|
|
6297
6724
|
function BuildBackgroundRenderer(backgroundColor) {
|
|
6298
6725
|
return (canvas, context, position, scale) => {
|
|
@@ -6430,7 +6857,13 @@ var NodeFlowGraph = class {
|
|
|
6430
6857
|
const backgroundColor = config?.backgroundColor === void 0 ? Theme.Graph.BackgroundColor : config.backgroundColor;
|
|
6431
6858
|
this.#backgroundRenderer = BuildBackgroundRenderer(backgroundColor);
|
|
6432
6859
|
}
|
|
6433
|
-
|
|
6860
|
+
this.#minimap = new Minimap(config?.minimap);
|
|
6861
|
+
this.#mainNodeSubsystem.setConnectionReleasedHandler((dangling) => {
|
|
6862
|
+
this.#openScopedMenu(dangling);
|
|
6863
|
+
});
|
|
6864
|
+
this.#watchCanvasSize();
|
|
6865
|
+
this.#stopRendering = onRenderRequested(this.#render.bind(this));
|
|
6866
|
+
requestRender();
|
|
6434
6867
|
new MouseObserver(
|
|
6435
6868
|
this.#canvas,
|
|
6436
6869
|
this.#mouseDragEvent.bind(this),
|
|
@@ -6448,39 +6881,90 @@ var NodeFlowGraph = class {
|
|
|
6448
6881
|
document.addEventListener(
|
|
6449
6882
|
"keydown",
|
|
6450
6883
|
(e) => {
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6884
|
+
this.#keyDown(e);
|
|
6885
|
+
requestRender();
|
|
6886
|
+
}
|
|
6887
|
+
);
|
|
6888
|
+
}
|
|
6889
|
+
#copyCallbacks = [];
|
|
6890
|
+
#pasteCallbacks = [];
|
|
6891
|
+
addCopyListener(callback) {
|
|
6892
|
+
this.#copyCallbacks.push(callback);
|
|
6893
|
+
}
|
|
6894
|
+
addPasteListener(callback) {
|
|
6895
|
+
this.#pasteCallbacks.push(callback);
|
|
6896
|
+
}
|
|
6897
|
+
#raiseCopy() {
|
|
6898
|
+
const nodes = this.#mainNodeSubsystem.getSelectedNodes();
|
|
6899
|
+
if (nodes.length === 0) {
|
|
6900
|
+
return;
|
|
6901
|
+
}
|
|
6902
|
+
const connections = this.#mainNodeSubsystem.connectionsWithin(nodes);
|
|
6903
|
+
this.#copyCallbacks.forEach((callback) => callback(nodes, connections));
|
|
6904
|
+
}
|
|
6905
|
+
#raisePaste() {
|
|
6906
|
+
const position = this.#mousePosition === void 0 ? { x: 0, y: 0 } : this.#sceenPositionToGraphPosition(this.#mousePosition);
|
|
6907
|
+
this.#pasteCallbacks.forEach((callback) => callback(position));
|
|
6908
|
+
}
|
|
6909
|
+
#deleteKey(e) {
|
|
6910
|
+
return e.code === "Delete" || e.code === "Backspace" || e.key === "Delete" || e.key === "Backspace";
|
|
6911
|
+
}
|
|
6912
|
+
#keyDown(e) {
|
|
6913
|
+
if (document.activeElement) {
|
|
6914
|
+
if (["INPUT", "TEXTAREA"].includes(document.activeElement.tagName)) return;
|
|
6915
|
+
}
|
|
6916
|
+
if (this.#deleteKey(e)) {
|
|
6917
|
+
if (this.#mainNodeSubsystem.getSelectedNodes().length > 0) {
|
|
6918
|
+
e.preventDefault();
|
|
6919
|
+
this.#mainNodeSubsystem.removeSelectedNodes();
|
|
6920
|
+
return;
|
|
6921
|
+
}
|
|
6922
|
+
}
|
|
6923
|
+
if (e.ctrlKey || e.metaKey) {
|
|
6924
|
+
const letter = e.code.startsWith("Key") ? e.code.substring(3).toLowerCase() : (e.key ?? "").toLowerCase();
|
|
6925
|
+
switch (letter) {
|
|
6926
|
+
case "c":
|
|
6927
|
+
this.#raiseCopy();
|
|
6465
6928
|
return;
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
if (!spacePressed) {
|
|
6929
|
+
case "v":
|
|
6930
|
+
this.#raisePaste();
|
|
6469
6931
|
return;
|
|
6470
|
-
|
|
6471
|
-
|
|
6932
|
+
// duplicate
|
|
6933
|
+
case "d":
|
|
6934
|
+
e.preventDefault();
|
|
6935
|
+
this.#raiseCopy();
|
|
6936
|
+
this.#raisePaste();
|
|
6472
6937
|
return;
|
|
6473
|
-
}
|
|
6474
|
-
const contextMenuPosition = this.#sceenPositionToGraphPosition(this.#mousePosition);
|
|
6475
|
-
let items = this.#mainNodeSubsystem.nodeFactory().newNodeSubmenus(this.#mainNodeSubsystem, contextMenuPosition);
|
|
6476
|
-
this.#openQuickMenu = {
|
|
6477
|
-
Menu: new QuickMenu({
|
|
6478
|
-
subMenus: items
|
|
6479
|
-
}),
|
|
6480
|
-
Position: contextMenuPosition
|
|
6481
|
-
};
|
|
6482
6938
|
}
|
|
6483
|
-
|
|
6939
|
+
}
|
|
6940
|
+
if (this.#openQuickMenu) {
|
|
6941
|
+
if (e.code === "Escape") {
|
|
6942
|
+
this.#openQuickMenu = null;
|
|
6943
|
+
return;
|
|
6944
|
+
}
|
|
6945
|
+
if (e.code === "Enter") {
|
|
6946
|
+
this.#openQuickMenu.Menu.execute();
|
|
6947
|
+
this.#openQuickMenu = null;
|
|
6948
|
+
return;
|
|
6949
|
+
}
|
|
6950
|
+
this.#openQuickMenu.Menu.keyboardEvent(e);
|
|
6951
|
+
return;
|
|
6952
|
+
}
|
|
6953
|
+
const spacePressed = e.key == " " || e.code == "Space";
|
|
6954
|
+
if (!spacePressed) {
|
|
6955
|
+
return;
|
|
6956
|
+
}
|
|
6957
|
+
if (!this.#mousePosition) {
|
|
6958
|
+
return;
|
|
6959
|
+
}
|
|
6960
|
+
const contextMenuPosition = this.#sceenPositionToGraphPosition(this.#mousePosition);
|
|
6961
|
+
let items = this.#mainNodeSubsystem.nodeFactory().newNodeSubmenus(this.#mainNodeSubsystem, contextMenuPosition);
|
|
6962
|
+
this.#openQuickMenu = {
|
|
6963
|
+
Menu: new QuickMenu({
|
|
6964
|
+
subMenus: items
|
|
6965
|
+
}),
|
|
6966
|
+
Position: contextMenuPosition
|
|
6967
|
+
};
|
|
6484
6968
|
}
|
|
6485
6969
|
#fileDrop(file) {
|
|
6486
6970
|
if (this.currentView().fileDrop(file)) {
|
|
@@ -6546,8 +7030,25 @@ var NodeFlowGraph = class {
|
|
|
6546
7030
|
this.#openQuickMenu = null;
|
|
6547
7031
|
this.#contextMenuEntryHovering = null;
|
|
6548
7032
|
this.#mousePosition = mousePosition;
|
|
7033
|
+
if (this.#minimap.contains(mousePosition)) {
|
|
7034
|
+
this.#lookAtFromMinimap(mousePosition);
|
|
7035
|
+
this.#draggingMinimap = true;
|
|
7036
|
+
return;
|
|
7037
|
+
}
|
|
6549
7038
|
this.currentView().clickStart(mousePosition, this.#camera, ctrlKey);
|
|
6550
7039
|
}
|
|
7040
|
+
#draggingMinimap = false;
|
|
7041
|
+
#lookAtFromMinimap(mousePosition) {
|
|
7042
|
+
const target = { x: 0, y: 0 };
|
|
7043
|
+
this.#minimap.graphPositionOf(mousePosition, target);
|
|
7044
|
+
this.#camera.position.x = -(target.x * this.#camera.zoom) + this.#canvas.width / 2;
|
|
7045
|
+
this.#camera.position.y = -(target.y * this.#camera.zoom) + this.#canvas.height / 2;
|
|
7046
|
+
requestRender();
|
|
7047
|
+
}
|
|
7048
|
+
/** The minimap, so it can be turned on and sized by the host. */
|
|
7049
|
+
minimap() {
|
|
7050
|
+
return this.#minimap;
|
|
7051
|
+
}
|
|
6551
7052
|
currentView() {
|
|
6552
7053
|
return this.#views[this.#currentView];
|
|
6553
7054
|
}
|
|
@@ -6567,6 +7068,12 @@ var NodeFlowGraph = class {
|
|
|
6567
7068
|
getSelectedNodes() {
|
|
6568
7069
|
return this.#mainNodeSubsystem.getSelectedNodes();
|
|
6569
7070
|
}
|
|
7071
|
+
unselectAllNodes() {
|
|
7072
|
+
this.#mainNodeSubsystem.unselectAllNodes();
|
|
7073
|
+
}
|
|
7074
|
+
removeSelectedNodes() {
|
|
7075
|
+
return this.#mainNodeSubsystem.removeSelectedNodes();
|
|
7076
|
+
}
|
|
6570
7077
|
/**
|
|
6571
7078
|
* Returns a copy of the current camera orientation (screen-space pan + zoom).
|
|
6572
7079
|
*/
|
|
@@ -6682,10 +7189,37 @@ var NodeFlowGraph = class {
|
|
|
6682
7189
|
Position: contextMenuPosition
|
|
6683
7190
|
};
|
|
6684
7191
|
}
|
|
7192
|
+
#openScopedMenu(dangling) {
|
|
7193
|
+
if (this.#mousePosition === void 0) {
|
|
7194
|
+
return;
|
|
7195
|
+
}
|
|
7196
|
+
const position = this.#sceenPositionToGraphPosition(this.#mousePosition);
|
|
7197
|
+
const menu = this.#mainNodeSubsystem.nodeFactory().openMenu(
|
|
7198
|
+
this.#mainNodeSubsystem,
|
|
7199
|
+
position,
|
|
7200
|
+
{
|
|
7201
|
+
needs: dangling.needs,
|
|
7202
|
+
types: dangling.types,
|
|
7203
|
+
onCreated: dangling.connectTo
|
|
7204
|
+
}
|
|
7205
|
+
);
|
|
7206
|
+
this.#openedContextMenu = {
|
|
7207
|
+
Menu: new ContextMenu(menu),
|
|
7208
|
+
Position: position
|
|
7209
|
+
};
|
|
7210
|
+
requestRender();
|
|
7211
|
+
}
|
|
6685
7212
|
#clickEnd() {
|
|
7213
|
+
this.#draggingMinimap = false;
|
|
6686
7214
|
this.currentView().clickEnd();
|
|
6687
7215
|
}
|
|
6688
7216
|
#mouseDragEvent(delta) {
|
|
7217
|
+
if (this.#draggingMinimap) {
|
|
7218
|
+
if (this.#mousePosition !== void 0) {
|
|
7219
|
+
this.#lookAtFromMinimap(this.#mousePosition);
|
|
7220
|
+
}
|
|
7221
|
+
return;
|
|
7222
|
+
}
|
|
6689
7223
|
let draggingSomething = this.currentView().mouseDragEvent(delta, this.#camera.zoom);
|
|
6690
7224
|
if (!draggingSomething) {
|
|
6691
7225
|
this.#camera.position.x += delta.x;
|
|
@@ -6694,12 +7228,45 @@ var NodeFlowGraph = class {
|
|
|
6694
7228
|
}
|
|
6695
7229
|
#lastFrameCursor;
|
|
6696
7230
|
#cursor;
|
|
6697
|
-
#
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
7231
|
+
#minimap;
|
|
7232
|
+
#stopRendering;
|
|
7233
|
+
#sizeObserver;
|
|
7234
|
+
#matchCanvasToParent() {
|
|
7235
|
+
const parent = this.#canvas.parentNode;
|
|
7236
|
+
if (parent === null) {
|
|
7237
|
+
return;
|
|
6702
7238
|
}
|
|
7239
|
+
const rect = parent.getBoundingClientRect();
|
|
7240
|
+
if (this.#canvas.width === rect.width && this.#canvas.height === rect.height) {
|
|
7241
|
+
return;
|
|
7242
|
+
}
|
|
7243
|
+
this.#canvas.width = rect.width;
|
|
7244
|
+
this.#canvas.height = rect.height;
|
|
7245
|
+
}
|
|
7246
|
+
#watchCanvasSize() {
|
|
7247
|
+
this.#matchCanvasToParent();
|
|
7248
|
+
const parent = this.#canvas.parentNode;
|
|
7249
|
+
if (parent === null || typeof ResizeObserver === "undefined") {
|
|
7250
|
+
return;
|
|
7251
|
+
}
|
|
7252
|
+
this.#sizeObserver = new ResizeObserver(() => {
|
|
7253
|
+
this.#matchCanvasToParent();
|
|
7254
|
+
requestRender();
|
|
7255
|
+
});
|
|
7256
|
+
this.#sizeObserver.observe(parent);
|
|
7257
|
+
}
|
|
7258
|
+
requestRender() {
|
|
7259
|
+
requestRender();
|
|
7260
|
+
}
|
|
7261
|
+
renderContinuously() {
|
|
7262
|
+
return renderContinuously();
|
|
7263
|
+
}
|
|
7264
|
+
dispose() {
|
|
7265
|
+
this.#stopRendering();
|
|
7266
|
+
this.#sizeObserver?.disconnect();
|
|
7267
|
+
}
|
|
7268
|
+
#render() {
|
|
7269
|
+
this.#matchCanvasToParent();
|
|
6703
7270
|
this.#cursor = "default" /* Default */;
|
|
6704
7271
|
TimeExecution("Render_Background", this.#renderBackground.bind(this));
|
|
6705
7272
|
TimeExecution("Render_View_" + this.#currentView, () => {
|
|
@@ -6708,13 +7275,15 @@ var NodeFlowGraph = class {
|
|
|
6708
7275
|
this.#cursor = results?.cursorStyle;
|
|
6709
7276
|
}
|
|
6710
7277
|
});
|
|
7278
|
+
TimeExecution("Render_Minimap", () => {
|
|
7279
|
+
this.#minimap.render(this.#ctx, this.#canvas, this.#camera, this.#mainNodeSubsystem.getNodes());
|
|
7280
|
+
});
|
|
6711
7281
|
TimeExecution("Render_Context", this.#renderContextMenu.bind(this));
|
|
6712
7282
|
TimeExecution("Render_QuickMenu", this.#renderQuickMenu.bind(this));
|
|
6713
7283
|
if (this.#lastFrameCursor !== this.#cursor) {
|
|
6714
7284
|
this.#canvas.style.cursor = this.#cursor;
|
|
6715
7285
|
}
|
|
6716
7286
|
this.#lastFrameCursor = this.#cursor;
|
|
6717
|
-
window.requestAnimationFrame(this.#render.bind(this));
|
|
6718
7287
|
}
|
|
6719
7288
|
#renderBackground() {
|
|
6720
7289
|
this.#backgroundRenderer(this.#canvas, this.#ctx, this.#camera.position, this.#camera.zoom);
|
|
@@ -6756,6 +7325,7 @@ var NodeFlowGraph = class {
|
|
|
6756
7325
|
GlobalWidgetFactory,
|
|
6757
7326
|
ImageWidget,
|
|
6758
7327
|
MessageType,
|
|
7328
|
+
Minimap,
|
|
6759
7329
|
NodeFactory,
|
|
6760
7330
|
NodeFlowGraph,
|
|
6761
7331
|
NodeState,
|
|
@@ -6769,6 +7339,10 @@ var NodeFlowGraph = class {
|
|
|
6769
7339
|
Theme,
|
|
6770
7340
|
ToggleWidget,
|
|
6771
7341
|
WidgetFactory,
|
|
6772
|
-
|
|
7342
|
+
portConfigTypes,
|
|
7343
|
+
portsCompatible,
|
|
7344
|
+
renderContinuously,
|
|
7345
|
+
requestRender,
|
|
7346
|
+
typeSetsCompatible
|
|
6773
7347
|
});
|
|
6774
7348
|
//# sourceMappingURL=index.js.map
|