@elicdavis/node-flow 0.1.16 → 0.1.18
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 +674 -79
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +668 -78
- 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 +83 -1
- package/src/nodes/factory.ts +9 -5
- package/src/nodes/publisher.ts +39 -4
- package/src/nodes/subsystem.ts +214 -2
- package/src/notes/subsystem.ts +3 -0
- package/src/popup.ts +27 -6
- 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/src/widgets/number.ts +2 -1
- package/src/widgets/string.ts +3 -1
- package/src/widgets/toggle.ts +3 -1
- package/test/minimap.test.ts +103 -0
- package/test/node_menu_filter.test.ts +119 -0
- package/test/popup.test.ts +104 -0
- package/test/render_scheduler.test.ts +119 -0
- package/test/widget_click.test.ts +126 -0
- package/test/widget_construction.test.ts +48 -0
package/dist/index.mjs
CHANGED
|
@@ -60,6 +60,14 @@ var Theme = {
|
|
|
60
60
|
FontColor: "#afb9bb",
|
|
61
61
|
DisabledFontColor: "#4a585c"
|
|
62
62
|
},
|
|
63
|
+
Minimap: {
|
|
64
|
+
BackgroundColor: "rgba(10, 16, 18, 0.85)",
|
|
65
|
+
BorderColor: "#1c1c1c",
|
|
66
|
+
BorderRadius: 4,
|
|
67
|
+
Padding: 6,
|
|
68
|
+
NodeColor: "#6b7f85",
|
|
69
|
+
ViewportColor: "rgba(175, 185, 187, 0.25)"
|
|
70
|
+
},
|
|
63
71
|
Note: {
|
|
64
72
|
FontColor: "#afb9bb",
|
|
65
73
|
FontSize: 16,
|
|
@@ -601,6 +609,43 @@ var ContextMenu = class _ContextMenu {
|
|
|
601
609
|
}
|
|
602
610
|
};
|
|
603
611
|
|
|
612
|
+
// src/render_scheduler.ts
|
|
613
|
+
var subscribers = /* @__PURE__ */ new Set();
|
|
614
|
+
var frameQueued = false;
|
|
615
|
+
var continuous = 0;
|
|
616
|
+
var canSchedule = () => typeof requestAnimationFrame === "function";
|
|
617
|
+
function onRenderRequested(redraw) {
|
|
618
|
+
subscribers.add(redraw);
|
|
619
|
+
return () => {
|
|
620
|
+
subscribers.delete(redraw);
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
function requestRender() {
|
|
624
|
+
if (frameQueued || !canSchedule()) {
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
frameQueued = true;
|
|
628
|
+
requestAnimationFrame(() => {
|
|
629
|
+
frameQueued = false;
|
|
630
|
+
subscribers.forEach((redraw) => redraw());
|
|
631
|
+
if (continuous > 0) {
|
|
632
|
+
requestRender();
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
function renderContinuously() {
|
|
637
|
+
continuous++;
|
|
638
|
+
requestRender();
|
|
639
|
+
let released = false;
|
|
640
|
+
return () => {
|
|
641
|
+
if (released) {
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
released = true;
|
|
645
|
+
continuous--;
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
|
|
604
649
|
// src/input.ts
|
|
605
650
|
var LONG_PRESS_MS = 500;
|
|
606
651
|
var LONG_PRESS_SLOP = 12;
|
|
@@ -634,15 +679,19 @@ var MouseObserver = class {
|
|
|
634
679
|
this.#lastTouch = Zero();
|
|
635
680
|
this.#lastMousePosition = Zero();
|
|
636
681
|
ele.style.touchAction = "none";
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
ele.addEventListener("
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
682
|
+
const redraws = (handler) => (event) => {
|
|
683
|
+
handler(event);
|
|
684
|
+
requestRender();
|
|
685
|
+
};
|
|
686
|
+
ele.addEventListener("mousedown", redraws(this.#down.bind(this)), false);
|
|
687
|
+
ele.addEventListener("touchstart", redraws(this.#touchStart.bind(this)), { passive: false });
|
|
688
|
+
document.addEventListener("mouseup", redraws(this.#up.bind(this)), false);
|
|
689
|
+
document.addEventListener("touchend", redraws(this.#touchEnd.bind(this)), false);
|
|
690
|
+
document.addEventListener("touchcancel", redraws(this.#touchEnd.bind(this)), false);
|
|
691
|
+
ele.addEventListener("mousemove", redraws(this.#move.bind(this)), false);
|
|
692
|
+
ele.addEventListener("touchmove", redraws(this.#touchMove.bind(this)), { passive: false });
|
|
693
|
+
ele.addEventListener("wheel", redraws(this.#wheel.bind(this)), { passive: false });
|
|
694
|
+
ele.addEventListener("drop", redraws((ev) => {
|
|
646
695
|
ev.preventDefault();
|
|
647
696
|
if (ev.dataTransfer?.items) {
|
|
648
697
|
[...ev.dataTransfer.items].forEach((item, i) => {
|
|
@@ -654,18 +703,18 @@ var MouseObserver = class {
|
|
|
654
703
|
}
|
|
655
704
|
});
|
|
656
705
|
}
|
|
657
|
-
});
|
|
658
|
-
ele.addEventListener("dragover", (ev) => {
|
|
706
|
+
}));
|
|
707
|
+
ele.addEventListener("dragover", redraws((ev) => {
|
|
659
708
|
ev.preventDefault();
|
|
660
709
|
this.#moveCallback(this.#mousePos(ev));
|
|
661
|
-
});
|
|
662
|
-
ele.addEventListener("contextmenu", (evt) => {
|
|
710
|
+
}));
|
|
711
|
+
ele.addEventListener("contextmenu", redraws((evt) => {
|
|
663
712
|
evt.preventDefault();
|
|
664
713
|
if (Date.now() - this.#lastTouchAt < SUPPRESS_MOUSE_MS) {
|
|
665
714
|
return;
|
|
666
715
|
}
|
|
667
716
|
this.#contextMenu(this.#mousePos(evt));
|
|
668
|
-
}, false);
|
|
717
|
+
}), false);
|
|
669
718
|
}
|
|
670
719
|
#mousePos(event) {
|
|
671
720
|
const rect = this.#ele.getBoundingClientRect();
|
|
@@ -762,6 +811,7 @@ var MouseObserver = class {
|
|
|
762
811
|
this.#clicked = false;
|
|
763
812
|
this.#clickStop();
|
|
764
813
|
this.#contextMenu({ x, y });
|
|
814
|
+
requestRender();
|
|
765
815
|
}, LONG_PRESS_MS);
|
|
766
816
|
this.#clicked = true;
|
|
767
817
|
this.#moveCallback(pos);
|
|
@@ -1198,6 +1248,7 @@ var Text = class _Text {
|
|
|
1198
1248
|
if (!document.fonts.check(`16px "${this.#style.getFont()}"`)) {
|
|
1199
1249
|
document.fonts.addEventListener("loadingdone", () => {
|
|
1200
1250
|
this.#measured = false;
|
|
1251
|
+
requestRender();
|
|
1201
1252
|
});
|
|
1202
1253
|
}
|
|
1203
1254
|
}
|
|
@@ -1409,12 +1460,22 @@ function portsCompatible(a, b) {
|
|
|
1409
1460
|
if (!a || !b) {
|
|
1410
1461
|
return false;
|
|
1411
1462
|
}
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1463
|
+
return typeSetsCompatible(a.acceptedTypes(), b.acceptedTypes());
|
|
1464
|
+
}
|
|
1465
|
+
function typeSetsCompatible(a, b) {
|
|
1466
|
+
if (a.length === 0 || b.length === 0) {
|
|
1415
1467
|
return true;
|
|
1416
1468
|
}
|
|
1417
|
-
return
|
|
1469
|
+
return a.some((type) => b.includes(type));
|
|
1470
|
+
}
|
|
1471
|
+
function portConfigTypes(config) {
|
|
1472
|
+
if (config.anyType === true) {
|
|
1473
|
+
return [];
|
|
1474
|
+
}
|
|
1475
|
+
if (config.acceptedTypes !== void 0 && config.acceptedTypes.length > 0) {
|
|
1476
|
+
return config.acceptedTypes;
|
|
1477
|
+
}
|
|
1478
|
+
return [config.type === void 0 ? "" : config.type];
|
|
1418
1479
|
}
|
|
1419
1480
|
function fallbackColor(type, s) {
|
|
1420
1481
|
let value = 0;
|
|
@@ -1529,6 +1590,7 @@ var Port = class {
|
|
|
1529
1590
|
this.#filledStyle.fillColor = fallbackColor(this.#dataType, 1);
|
|
1530
1591
|
}
|
|
1531
1592
|
this.#dataTypePopupElement = this.#buildTooltip();
|
|
1593
|
+
requestRender();
|
|
1532
1594
|
}
|
|
1533
1595
|
setDataType(type) {
|
|
1534
1596
|
if (this.#dataType === type) {
|
|
@@ -1782,6 +1844,7 @@ var Popup = class {
|
|
|
1782
1844
|
#buttonCSS;
|
|
1783
1845
|
// Runtime ================================================================
|
|
1784
1846
|
#popup;
|
|
1847
|
+
#keyHandler;
|
|
1785
1848
|
constructor(config) {
|
|
1786
1849
|
this.#title = config.title;
|
|
1787
1850
|
this.#options = config.options;
|
|
@@ -1789,14 +1852,25 @@ var Popup = class {
|
|
|
1789
1852
|
this.#onClose = config.onClose;
|
|
1790
1853
|
this.#buttonCSS = config.buttonCSS === void 0 ? "flex-grow: 1; margin-right: 8px;" : config.buttonCSS;
|
|
1791
1854
|
this.#popup = null;
|
|
1855
|
+
this.#keyHandler = null;
|
|
1792
1856
|
}
|
|
1793
1857
|
Hide() {
|
|
1794
1858
|
if (this.#popup === null) {
|
|
1795
1859
|
return;
|
|
1796
1860
|
}
|
|
1861
|
+
if (this.#keyHandler !== null) {
|
|
1862
|
+
document.removeEventListener("keydown", this.#keyHandler, true);
|
|
1863
|
+
this.#keyHandler = null;
|
|
1864
|
+
}
|
|
1797
1865
|
document.body.removeChild(this.#popup);
|
|
1798
1866
|
this.#popup = null;
|
|
1799
1867
|
}
|
|
1868
|
+
#close(option) {
|
|
1869
|
+
this.Hide();
|
|
1870
|
+
if (this.#onClose !== void 0) {
|
|
1871
|
+
this.#onClose(option);
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1800
1874
|
Show() {
|
|
1801
1875
|
this.#popup = document.createElement("div");
|
|
1802
1876
|
this.#popup.style.cssText = "position:absolute;top:0;width:100%;display:flex;height:100%;justify-content:center;align-items:center;background-color:#00000070;";
|
|
@@ -1818,14 +1892,20 @@ var Popup = class {
|
|
|
1818
1892
|
const button = document.createElement("button");
|
|
1819
1893
|
button.style.cssText = this.#buttonCSS;
|
|
1820
1894
|
button.textContent = this.#options[i];
|
|
1821
|
-
button.onclick = () =>
|
|
1822
|
-
this.Hide();
|
|
1823
|
-
if (this.#onClose !== void 0) {
|
|
1824
|
-
this.#onClose(this.#options[i]);
|
|
1825
|
-
}
|
|
1826
|
-
};
|
|
1895
|
+
button.onclick = () => this.#close(this.#options[i]);
|
|
1827
1896
|
buttonContainer.appendChild(button);
|
|
1828
1897
|
}
|
|
1898
|
+
this.#keyHandler = (e) => {
|
|
1899
|
+
if (e.key === "Enter") {
|
|
1900
|
+
e.preventDefault();
|
|
1901
|
+
this.#close(this.#options.length > 0 ? this.#options[0] : null);
|
|
1902
|
+
} else if (e.key === "Escape") {
|
|
1903
|
+
e.preventDefault();
|
|
1904
|
+
this.#close(null);
|
|
1905
|
+
}
|
|
1906
|
+
e.stopPropagation();
|
|
1907
|
+
};
|
|
1908
|
+
document.addEventListener("keydown", this.#keyHandler, true);
|
|
1829
1909
|
}
|
|
1830
1910
|
};
|
|
1831
1911
|
|
|
@@ -1934,8 +2014,8 @@ var NumberWidget = class {
|
|
|
1934
2014
|
},
|
|
1935
2015
|
text: { color: Theme.Widget.FontColor }
|
|
1936
2016
|
}));
|
|
1937
|
-
this.#callback = config?.callback;
|
|
1938
2017
|
this.Set(startingWidgetValue(node, this.#nodeProperty, config?.value, 0));
|
|
2018
|
+
this.#callback = config?.callback;
|
|
1939
2019
|
if (this.#nodeProperty !== void 0) {
|
|
1940
2020
|
this.#node.addPropertyChangeListener(this.#nodeProperty, (oldVal, newVal) => {
|
|
1941
2021
|
this.Set(newVal);
|
|
@@ -2377,8 +2457,8 @@ var StringWidget = class {
|
|
|
2377
2457
|
},
|
|
2378
2458
|
text: { color: Theme.Widget.FontColor }
|
|
2379
2459
|
}));
|
|
2380
|
-
this.#callback = config?.callback;
|
|
2381
2460
|
this.Set(startingWidgetValue(node, this.#nodeProperty, config?.value, ""));
|
|
2461
|
+
this.#callback = config?.callback;
|
|
2382
2462
|
if (this.#nodeProperty !== void 0) {
|
|
2383
2463
|
this.#node.addPropertyChangeListener(this.#nodeProperty, (oldVal, newVal) => {
|
|
2384
2464
|
this.Set(newVal);
|
|
@@ -2543,8 +2623,8 @@ var ToggleWidget = class {
|
|
|
2543
2623
|
lightBorderColor: config?.disabledStyle?.lightBorderColor,
|
|
2544
2624
|
lightColor: config?.disabledStyle?.lightColor === void 0 ? "#004400" : config?.enabledStyle?.lightColor
|
|
2545
2625
|
});
|
|
2546
|
-
this.#callback = config?.callback;
|
|
2547
2626
|
this.Set(startingWidgetValue(node, this.#nodeProperty, config?.value, false));
|
|
2627
|
+
this.#callback = config?.callback;
|
|
2548
2628
|
if (this.#nodeProperty !== void 0) {
|
|
2549
2629
|
this.#node.addPropertyChangeListener(this.#nodeProperty, (oldVal, newVal) => {
|
|
2550
2630
|
this.Set(newVal);
|
|
@@ -2607,6 +2687,7 @@ var ImageWidget = class {
|
|
|
2607
2687
|
img.src = url;
|
|
2608
2688
|
img.onload = () => {
|
|
2609
2689
|
this.#image = img;
|
|
2690
|
+
requestRender();
|
|
2610
2691
|
};
|
|
2611
2692
|
img.onerror = (event) => {
|
|
2612
2693
|
console.log("error loading image:", url, event);
|
|
@@ -3187,6 +3268,13 @@ function TimeExecution(name, callback) {
|
|
|
3187
3268
|
}
|
|
3188
3269
|
|
|
3189
3270
|
// src/nodes/publisher.ts
|
|
3271
|
+
function offersMatchingPort(config, filter) {
|
|
3272
|
+
const ports = filter.needs === "INPUT" /* Input */ ? config.inputs : config.outputs;
|
|
3273
|
+
if (ports === void 0) {
|
|
3274
|
+
return false;
|
|
3275
|
+
}
|
|
3276
|
+
return ports.some((port) => typeSetsCompatible(portConfigTypes(port), filter.types));
|
|
3277
|
+
}
|
|
3190
3278
|
var Publisher = class {
|
|
3191
3279
|
#name;
|
|
3192
3280
|
#description;
|
|
@@ -3212,19 +3300,23 @@ var Publisher = class {
|
|
|
3212
3300
|
unregister(nodeType) {
|
|
3213
3301
|
return this.#registeredNodes.delete(nodeType);
|
|
3214
3302
|
}
|
|
3215
|
-
#recurseBuildMenu(graph, name, subMenu, position) {
|
|
3303
|
+
#recurseBuildMenu(graph, name, subMenu, position, filter) {
|
|
3216
3304
|
const items = [];
|
|
3217
3305
|
const subMenus = /* @__PURE__ */ new Map();
|
|
3218
3306
|
for (let [key, nodeConfig] of subMenu) {
|
|
3219
3307
|
const slashIndex = key.indexOf("/");
|
|
3220
3308
|
const bracketIndex = key.indexOf("[");
|
|
3221
3309
|
if (slashIndex === -1 || bracketIndex !== -1 && bracketIndex < slashIndex) {
|
|
3310
|
+
if (filter !== void 0 && !offersMatchingPort(nodeConfig, filter)) {
|
|
3311
|
+
continue;
|
|
3312
|
+
}
|
|
3222
3313
|
items.push({
|
|
3223
3314
|
name: key,
|
|
3224
3315
|
callback: () => {
|
|
3225
3316
|
const node = new FlowNode(nodeConfig);
|
|
3226
3317
|
node.setPosition(position);
|
|
3227
3318
|
graph.addNode(node);
|
|
3319
|
+
filter?.onCreated?.(node);
|
|
3228
3320
|
}
|
|
3229
3321
|
});
|
|
3230
3322
|
} else {
|
|
@@ -3239,7 +3331,11 @@ var Publisher = class {
|
|
|
3239
3331
|
}
|
|
3240
3332
|
const menus = [];
|
|
3241
3333
|
for (let [key, nodes] of subMenus) {
|
|
3242
|
-
|
|
3334
|
+
const built = this.#recurseBuildMenu(graph, key, nodes, position, filter);
|
|
3335
|
+
if (filter !== void 0 && built.items?.length === 0 && built.subMenus?.length === 0) {
|
|
3336
|
+
continue;
|
|
3337
|
+
}
|
|
3338
|
+
menus.push(built);
|
|
3243
3339
|
}
|
|
3244
3340
|
return {
|
|
3245
3341
|
name,
|
|
@@ -3247,8 +3343,8 @@ var Publisher = class {
|
|
|
3247
3343
|
subMenus: menus
|
|
3248
3344
|
};
|
|
3249
3345
|
}
|
|
3250
|
-
contextMenu(graph, position) {
|
|
3251
|
-
return this.#recurseBuildMenu(graph, this.#name, this.#registeredNodes, position);
|
|
3346
|
+
contextMenu(graph, position, filter) {
|
|
3347
|
+
return this.#recurseBuildMenu(graph, this.#name, this.#registeredNodes, position, filter);
|
|
3252
3348
|
}
|
|
3253
3349
|
create(nodeType) {
|
|
3254
3350
|
const config = this.#registeredNodes.get(nodeType);
|
|
@@ -3303,18 +3399,22 @@ var NodeFactory = class {
|
|
|
3303
3399
|
}
|
|
3304
3400
|
return node;
|
|
3305
3401
|
}
|
|
3306
|
-
newNodeSubmenus(graph, position) {
|
|
3402
|
+
newNodeSubmenus(graph, position, filter) {
|
|
3307
3403
|
const menus = [];
|
|
3308
3404
|
for (let [_, publisher] of this.#registeredPublishers) {
|
|
3309
|
-
|
|
3405
|
+
const built = publisher.contextMenu(graph, position, filter);
|
|
3406
|
+
if (filter !== void 0 && built.items?.length === 0 && built.subMenus?.length === 0) {
|
|
3407
|
+
continue;
|
|
3408
|
+
}
|
|
3409
|
+
menus.push(built);
|
|
3310
3410
|
}
|
|
3311
3411
|
return menus;
|
|
3312
3412
|
}
|
|
3313
|
-
openMenu(graph, position) {
|
|
3413
|
+
openMenu(graph, position, filter) {
|
|
3314
3414
|
return {
|
|
3315
3415
|
name: "New Node",
|
|
3316
3416
|
group: nodeFlowGroup,
|
|
3317
|
-
subMenus: this.newNodeSubmenus(graph, position)
|
|
3417
|
+
subMenus: this.newNodeSubmenus(graph, position, filter)
|
|
3318
3418
|
};
|
|
3319
3419
|
}
|
|
3320
3420
|
};
|
|
@@ -3453,6 +3553,9 @@ var NodeSubsystem2 = class {
|
|
|
3453
3553
|
CopyVector2(this.#boxSelectEnd_graphSpace, this.#boxSelectStart_graphSpace);
|
|
3454
3554
|
this.#boxSelect = true;
|
|
3455
3555
|
}
|
|
3556
|
+
if (!hoveringSomething && !ctrlKey) {
|
|
3557
|
+
this.unselectAllNodes();
|
|
3558
|
+
}
|
|
3456
3559
|
return hoveringSomething || ctrlKey;
|
|
3457
3560
|
}
|
|
3458
3561
|
if (this.#portHovering.InputPort) {
|
|
@@ -3512,6 +3615,102 @@ var NodeSubsystem2 = class {
|
|
|
3512
3615
|
}
|
|
3513
3616
|
}
|
|
3514
3617
|
}
|
|
3618
|
+
connectionsWithin(nodes) {
|
|
3619
|
+
const within = [];
|
|
3620
|
+
for (const connection of this.#connections) {
|
|
3621
|
+
const outNode = connection.outNode();
|
|
3622
|
+
const inNode = connection.inNode();
|
|
3623
|
+
if (outNode === null || inNode === null) {
|
|
3624
|
+
continue;
|
|
3625
|
+
}
|
|
3626
|
+
const from = nodes.indexOf(outNode);
|
|
3627
|
+
const to = nodes.indexOf(inNode);
|
|
3628
|
+
if (from === -1 || to === -1) {
|
|
3629
|
+
continue;
|
|
3630
|
+
}
|
|
3631
|
+
const outPort = connection.outPort();
|
|
3632
|
+
const inPort = connection.inPort();
|
|
3633
|
+
if (outPort === null || inPort === null) {
|
|
3634
|
+
continue;
|
|
3635
|
+
}
|
|
3636
|
+
within.push({
|
|
3637
|
+
fromNode: from,
|
|
3638
|
+
fromPort: this.#outputPortIndex(outNode, outPort),
|
|
3639
|
+
toNode: to,
|
|
3640
|
+
toPort: this.#inputPortIndex(inNode, inPort)
|
|
3641
|
+
});
|
|
3642
|
+
}
|
|
3643
|
+
return within;
|
|
3644
|
+
}
|
|
3645
|
+
#onConnectionReleased = null;
|
|
3646
|
+
setConnectionReleasedHandler(handler) {
|
|
3647
|
+
this.#onConnectionReleased = handler;
|
|
3648
|
+
}
|
|
3649
|
+
#describeDanglingConnection(conn) {
|
|
3650
|
+
const outNode = conn.outNode();
|
|
3651
|
+
const inNode = conn.inNode();
|
|
3652
|
+
if (outNode !== null && inNode === null) {
|
|
3653
|
+
const from = conn.outPort();
|
|
3654
|
+
if (from === null) {
|
|
3655
|
+
return null;
|
|
3656
|
+
}
|
|
3657
|
+
const fromIndex = this.#outputPortIndex(outNode, from);
|
|
3658
|
+
return {
|
|
3659
|
+
needs: "INPUT" /* Input */,
|
|
3660
|
+
types: from.acceptedTypes(),
|
|
3661
|
+
connectTo: (node) => {
|
|
3662
|
+
const to = this.#firstCompatiblePort(node, "INPUT" /* Input */, from);
|
|
3663
|
+
if (to !== -1 && fromIndex !== -1) {
|
|
3664
|
+
this.connectNodes(outNode, fromIndex, node, to);
|
|
3665
|
+
}
|
|
3666
|
+
}
|
|
3667
|
+
};
|
|
3668
|
+
}
|
|
3669
|
+
if (inNode !== null && outNode === null) {
|
|
3670
|
+
const to = conn.inPort();
|
|
3671
|
+
if (to === null) {
|
|
3672
|
+
return null;
|
|
3673
|
+
}
|
|
3674
|
+
const toIndex = this.#inputPortIndex(inNode, to);
|
|
3675
|
+
return {
|
|
3676
|
+
needs: "OUTPUT" /* Output */,
|
|
3677
|
+
types: to.acceptedTypes(),
|
|
3678
|
+
connectTo: (node) => {
|
|
3679
|
+
const from = this.#firstCompatiblePort(node, "OUTPUT" /* Output */, to);
|
|
3680
|
+
if (from !== -1 && toIndex !== -1) {
|
|
3681
|
+
this.connectNodes(node, from, inNode, toIndex);
|
|
3682
|
+
}
|
|
3683
|
+
}
|
|
3684
|
+
};
|
|
3685
|
+
}
|
|
3686
|
+
return null;
|
|
3687
|
+
}
|
|
3688
|
+
#outputPortIndex(node, port) {
|
|
3689
|
+
for (let i = 0; i < node.outputs(); i++) {
|
|
3690
|
+
if (node.outputPort(i) === port) {
|
|
3691
|
+
return i;
|
|
3692
|
+
}
|
|
3693
|
+
}
|
|
3694
|
+
return -1;
|
|
3695
|
+
}
|
|
3696
|
+
#inputPortIndex(node, port) {
|
|
3697
|
+
for (let i = 0; i < node.inputs(); i++) {
|
|
3698
|
+
if (node.inputPort(i) === port) {
|
|
3699
|
+
return i;
|
|
3700
|
+
}
|
|
3701
|
+
}
|
|
3702
|
+
return -1;
|
|
3703
|
+
}
|
|
3704
|
+
#firstCompatiblePort(node, side, against) {
|
|
3705
|
+
const count = side === "INPUT" /* Input */ ? node.inputs() : node.outputs();
|
|
3706
|
+
for (let i = 0; i < count; i++) {
|
|
3707
|
+
const port = side === "INPUT" /* Input */ ? node.inputPort(i) : node.outputPort(i);
|
|
3708
|
+
if (portsCompatible(port, against)) {
|
|
3709
|
+
return i;
|
|
3710
|
+
}
|
|
3711
|
+
}
|
|
3712
|
+
return -1;
|
|
3713
|
+
}
|
|
3515
3714
|
clickEnd() {
|
|
3516
3715
|
for (let i = 0; i < this.#nodesGrabbed.Count(); i++) {
|
|
3517
3716
|
const node = this.#nodes[this.#nodesGrabbed.At(i)];
|
|
@@ -3526,14 +3725,20 @@ var NodeSubsystem2 = class {
|
|
|
3526
3725
|
this.#boxSelect = false;
|
|
3527
3726
|
}
|
|
3528
3727
|
if (this.#widgetCurrentlyClicking !== null) {
|
|
3529
|
-
this.#widgetCurrentlyClicking
|
|
3728
|
+
if (this.#widgetHovering === this.#widgetCurrentlyClicking) {
|
|
3729
|
+
this.#widgetCurrentlyClicking.ClickEnd();
|
|
3730
|
+
}
|
|
3530
3731
|
this.#widgetCurrentlyClicking = null;
|
|
3531
3732
|
}
|
|
3532
3733
|
if (this.#connectionSelected === null) {
|
|
3533
3734
|
return;
|
|
3534
3735
|
}
|
|
3535
3736
|
if (this.#portHovering === null) {
|
|
3737
|
+
const dangling = this.#describeDanglingConnection(this.#connectionSelected);
|
|
3536
3738
|
this.#clearCurrentlySelectedConnection();
|
|
3739
|
+
if (dangling !== null) {
|
|
3740
|
+
this.#onConnectionReleased?.(dangling);
|
|
3741
|
+
}
|
|
3537
3742
|
return;
|
|
3538
3743
|
}
|
|
3539
3744
|
const port = this.#portHovering.Port;
|
|
@@ -3600,6 +3805,7 @@ var NodeSubsystem2 = class {
|
|
|
3600
3805
|
this.#idleConnectionRenderer
|
|
3601
3806
|
);
|
|
3602
3807
|
this.#connections.push(connection);
|
|
3808
|
+
requestRender();
|
|
3603
3809
|
return connection;
|
|
3604
3810
|
}
|
|
3605
3811
|
getNodes() {
|
|
@@ -3660,6 +3866,7 @@ var NodeSubsystem2 = class {
|
|
|
3660
3866
|
}
|
|
3661
3867
|
addNode(node) {
|
|
3662
3868
|
this.#nodes.push(node);
|
|
3869
|
+
requestRender();
|
|
3663
3870
|
for (let i = 0; i < this.#registeredNodeAddedCallbacks.length; i++) {
|
|
3664
3871
|
const callback = this.#registeredNodeAddedCallbacks[i];
|
|
3665
3872
|
if (!callback) {
|
|
@@ -3706,6 +3913,7 @@ var NodeSubsystem2 = class {
|
|
|
3706
3913
|
this.#removeNodeConnections(nodeIndex);
|
|
3707
3914
|
const node = this.#nodes[nodeIndex];
|
|
3708
3915
|
this.#nodes.splice(nodeIndex, 1);
|
|
3916
|
+
requestRender();
|
|
3709
3917
|
for (let i = 0; i < this.#nodeRemovedCallbacks.length; i++) {
|
|
3710
3918
|
this.#nodeRemovedCallbacks[i](node);
|
|
3711
3919
|
}
|
|
@@ -3715,6 +3923,7 @@ var NodeSubsystem2 = class {
|
|
|
3715
3923
|
this.#connections[index].clearPorts();
|
|
3716
3924
|
}
|
|
3717
3925
|
this.#connections.splice(index, 1);
|
|
3926
|
+
requestRender();
|
|
3718
3927
|
}
|
|
3719
3928
|
#removeConnection(connection, clearPorts) {
|
|
3720
3929
|
const index = this.#connections.indexOf(connection);
|
|
@@ -3760,7 +3969,8 @@ var NodeSubsystem2 = class {
|
|
|
3760
3969
|
this.#nodeFactory.openMenu(this, position)
|
|
3761
3970
|
]
|
|
3762
3971
|
};
|
|
3763
|
-
|
|
3972
|
+
const selectedCount = this.#nodesSelected().length;
|
|
3973
|
+
if (selectedCount > 0) {
|
|
3764
3974
|
organizeNodesSubMenu.items?.push({
|
|
3765
3975
|
name: "Selected Nodes",
|
|
3766
3976
|
group: nodeFlowGroup,
|
|
@@ -3768,6 +3978,13 @@ var NodeSubsystem2 = class {
|
|
|
3768
3978
|
this.#organizeSelected(ctx);
|
|
3769
3979
|
}
|
|
3770
3980
|
});
|
|
3981
|
+
config.items?.push({
|
|
3982
|
+
name: selectedCount === 1 ? "Delete Selected Node" : `Delete ${selectedCount} Selected Nodes`,
|
|
3983
|
+
group: nodeFlowGroup,
|
|
3984
|
+
callback: () => {
|
|
3985
|
+
this.removeSelectedNodes();
|
|
3986
|
+
}
|
|
3987
|
+
});
|
|
3771
3988
|
}
|
|
3772
3989
|
if (this.#nodeHovering > -1) {
|
|
3773
3990
|
const nodeToReview = this.#nodeHovering;
|
|
@@ -3841,6 +4058,29 @@ var NodeSubsystem2 = class {
|
|
|
3841
4058
|
this.#selectNode(inputs[i], false);
|
|
3842
4059
|
}
|
|
3843
4060
|
}
|
|
4061
|
+
/** Drops the selection entirely. */
|
|
4062
|
+
unselectAllNodes() {
|
|
4063
|
+
let changed = false;
|
|
4064
|
+
for (let i = 0; i < this.#nodes.length; i++) {
|
|
4065
|
+
if (this.#nodes[i].selected()) {
|
|
4066
|
+
this.#nodes[i].unselect();
|
|
4067
|
+
changed = true;
|
|
4068
|
+
}
|
|
4069
|
+
}
|
|
4070
|
+
if (changed) {
|
|
4071
|
+
requestRender();
|
|
4072
|
+
}
|
|
4073
|
+
}
|
|
4074
|
+
/**
|
|
4075
|
+
* Removes every selected node, and the connections that touched them.
|
|
4076
|
+
*/
|
|
4077
|
+
removeSelectedNodes() {
|
|
4078
|
+
const removed = this.getSelectedNodes();
|
|
4079
|
+
for (const node of removed) {
|
|
4080
|
+
this.removeNode(node);
|
|
4081
|
+
}
|
|
4082
|
+
return removed;
|
|
4083
|
+
}
|
|
3844
4084
|
#selectNodeByIndex(nodeIndex, unselectOthers) {
|
|
3845
4085
|
this.#selectNode(this.#nodes[nodeIndex], unselectOthers);
|
|
3846
4086
|
}
|
|
@@ -3878,8 +4118,16 @@ var NodeSubsystem2 = class {
|
|
|
3878
4118
|
this.#nodeHovering = -1;
|
|
3879
4119
|
this.#boxSelectionNodes.Clear();
|
|
3880
4120
|
const selectedBox_Screenspace = this.#boxSelectionScreenspaceBox(camera);
|
|
4121
|
+
const canvas = {
|
|
4122
|
+
Position: { x: 0, y: 0 },
|
|
4123
|
+
Size: { x: ctx.canvas.width, y: ctx.canvas.height }
|
|
4124
|
+
};
|
|
3881
4125
|
for (let i = 0; i < this.#nodes.length; i++) {
|
|
3882
4126
|
let state = 0 /* Idle */;
|
|
4127
|
+
const nodeBounds = this.#nodes[i].calculateBounds(ctx, camera);
|
|
4128
|
+
if (!BoxIntersection(nodeBounds, canvas) && this.#nodes[i].layoutPortsWithoutDrawing(nodeBounds, camera.zoom)) {
|
|
4129
|
+
continue;
|
|
4130
|
+
}
|
|
3883
4131
|
if (mousePosition !== void 0 && !this.#boxSelect) {
|
|
3884
4132
|
const intersection = this.#nodes[i].inBounds(ctx, camera, mousePosition);
|
|
3885
4133
|
if (intersection.Node !== void 0 && intersection.PortIndex === void 0 && intersection.Widget === void 0) {
|
|
@@ -3900,8 +4148,8 @@ var NodeSubsystem2 = class {
|
|
|
3900
4148
|
};
|
|
3901
4149
|
}
|
|
3902
4150
|
} else if (this.#boxSelect) {
|
|
3903
|
-
const
|
|
3904
|
-
if (BoxIntersection(selectedBox_Screenspace,
|
|
4151
|
+
const nodeBounds2 = this.#nodes[i].calculateBounds(ctx, camera);
|
|
4152
|
+
if (BoxIntersection(selectedBox_Screenspace, nodeBounds2)) {
|
|
3905
4153
|
state = 1 /* MouseOver */;
|
|
3906
4154
|
this.#boxSelectionNodes.Push(i);
|
|
3907
4155
|
}
|
|
@@ -3923,12 +4171,16 @@ var NodeSubsystem2 = class {
|
|
|
3923
4171
|
render(ctx, camera, mousePosition) {
|
|
3924
4172
|
this.#lastCtx = ctx;
|
|
3925
4173
|
this.#cursor = "default" /* Default */;
|
|
4174
|
+
const awaitingLayout = this.#nodes.some((node) => !node.hasBeenLaidOut());
|
|
3926
4175
|
TimeExecution("Render_Connections", () => {
|
|
3927
4176
|
this.#renderConnections(ctx, camera, mousePosition);
|
|
3928
4177
|
});
|
|
3929
4178
|
TimeExecution("Render_Nodes", () => {
|
|
3930
4179
|
this.#renderNodes(ctx, camera, mousePosition);
|
|
3931
4180
|
});
|
|
4181
|
+
if (awaitingLayout) {
|
|
4182
|
+
requestRender();
|
|
4183
|
+
}
|
|
3932
4184
|
if (this.#boxSelect) {
|
|
3933
4185
|
const box = this.#boxSelectionScreenspaceBox(camera);
|
|
3934
4186
|
ctx.setLineDash([Theme.BoxSelect.LineDashLength]);
|
|
@@ -4204,6 +4456,7 @@ var FlowNode = class {
|
|
|
4204
4456
|
return;
|
|
4205
4457
|
}
|
|
4206
4458
|
this.#selected = true;
|
|
4459
|
+
requestRender();
|
|
4207
4460
|
for (let i = 0; i < this.#onSelect.length; i++) {
|
|
4208
4461
|
this.#onSelect[i]();
|
|
4209
4462
|
}
|
|
@@ -4249,6 +4502,7 @@ var FlowNode = class {
|
|
|
4249
4502
|
return;
|
|
4250
4503
|
}
|
|
4251
4504
|
this.#data[name] = value;
|
|
4505
|
+
requestRender();
|
|
4252
4506
|
for (let i = 0; i < this.#registeredAnyPropertyChangeCallbacks.length; i++) {
|
|
4253
4507
|
this.#registeredAnyPropertyChangeCallbacks[i](name, oldValue, value);
|
|
4254
4508
|
}
|
|
@@ -4509,6 +4763,7 @@ var FlowNode = class {
|
|
|
4509
4763
|
return;
|
|
4510
4764
|
}
|
|
4511
4765
|
this.#selected = false;
|
|
4766
|
+
requestRender();
|
|
4512
4767
|
for (let i = 0; i < this.#onUnselect.length; i++) {
|
|
4513
4768
|
this.#onUnselect[i]();
|
|
4514
4769
|
}
|
|
@@ -4538,6 +4793,7 @@ var FlowNode = class {
|
|
|
4538
4793
|
}
|
|
4539
4794
|
setPosition(position) {
|
|
4540
4795
|
CopyVector2(this.#position, position);
|
|
4796
|
+
requestRender();
|
|
4541
4797
|
}
|
|
4542
4798
|
getPosition() {
|
|
4543
4799
|
return this.#position;
|
|
@@ -4600,10 +4856,12 @@ var FlowNode = class {
|
|
|
4600
4856
|
}
|
|
4601
4857
|
addWidget(widget) {
|
|
4602
4858
|
this.#widgets.push(widget);
|
|
4859
|
+
requestRender();
|
|
4603
4860
|
}
|
|
4604
4861
|
insertWidget(index, widget) {
|
|
4605
4862
|
const at = Math.max(0, Math.min(index, this.#widgets.length));
|
|
4606
4863
|
this.#widgets.splice(at, 0, widget);
|
|
4864
|
+
requestRender();
|
|
4607
4865
|
}
|
|
4608
4866
|
removeWidget(widget) {
|
|
4609
4867
|
const index = this.#widgets.indexOf(widget, 0);
|
|
@@ -4611,12 +4869,15 @@ var FlowNode = class {
|
|
|
4611
4869
|
throw new Error("node does not contain widget");
|
|
4612
4870
|
}
|
|
4613
4871
|
this.#widgets.splice(index, 1);
|
|
4872
|
+
requestRender();
|
|
4614
4873
|
}
|
|
4615
4874
|
removeWidgetAt(index) {
|
|
4616
4875
|
if (index < 0 || index >= this.#widgets.length) {
|
|
4617
4876
|
return void 0;
|
|
4618
4877
|
}
|
|
4619
|
-
|
|
4878
|
+
const removed = this.#widgets.splice(index, 1)[0];
|
|
4879
|
+
requestRender();
|
|
4880
|
+
return removed;
|
|
4620
4881
|
}
|
|
4621
4882
|
moveWidget(from, to) {
|
|
4622
4883
|
if (from < 0 || from >= this.#widgets.length) {
|
|
@@ -4627,9 +4888,11 @@ var FlowNode = class {
|
|
|
4627
4888
|
}
|
|
4628
4889
|
const [widget] = this.#widgets.splice(from, 1);
|
|
4629
4890
|
this.#widgets.splice(to, 0, widget);
|
|
4891
|
+
requestRender();
|
|
4630
4892
|
}
|
|
4631
4893
|
clearWidgets() {
|
|
4632
4894
|
this.#widgets.length = 0;
|
|
4895
|
+
requestRender();
|
|
4633
4896
|
}
|
|
4634
4897
|
getWidget(index) {
|
|
4635
4898
|
return this.#widgets[index];
|
|
@@ -4701,6 +4964,7 @@ var FlowNode = class {
|
|
|
4701
4964
|
return;
|
|
4702
4965
|
}
|
|
4703
4966
|
this.#title.set(cleaned);
|
|
4967
|
+
requestRender();
|
|
4704
4968
|
for (let i = 0; i < this.#titleChangeCallback.length; i++) {
|
|
4705
4969
|
const callback = this.#titleChangeCallback[i];
|
|
4706
4970
|
callback(this, old, cleaned);
|
|
@@ -4719,6 +4983,7 @@ var FlowNode = class {
|
|
|
4719
4983
|
}
|
|
4720
4984
|
const old = this.#infoText;
|
|
4721
4985
|
this.#infoText = cleaned;
|
|
4986
|
+
requestRender();
|
|
4722
4987
|
for (let i = 0; i < this.#infoChangeCallback.length; i++) {
|
|
4723
4988
|
const callback = this.#infoChangeCallback[i];
|
|
4724
4989
|
callback(this, old, cleaned);
|
|
@@ -4758,7 +5023,12 @@ var FlowNode = class {
|
|
|
4758
5023
|
clearMessages() {
|
|
4759
5024
|
this.#messages = [];
|
|
4760
5025
|
}
|
|
5026
|
+
hasBeenLaidOut() {
|
|
5027
|
+
return this.#laidOut;
|
|
5028
|
+
}
|
|
5029
|
+
#laidOut = false;
|
|
4761
5030
|
render(ctx, camera, state, mousePosition, postProcess) {
|
|
5031
|
+
this.#laidOut = true;
|
|
4762
5032
|
VectorPool.run(() => {
|
|
4763
5033
|
const tempMeasurement = VectorPool.get();
|
|
4764
5034
|
this.#inputPortPositions.Clear();
|
|
@@ -4894,8 +5164,58 @@ var FlowNode = class {
|
|
|
4894
5164
|
const message = this.#messages[i];
|
|
4895
5165
|
messageStart.y += message.render(ctx, camera.zoom, messageStart, !(state === 0 /* Idle */)) + 10 * camera.zoom;
|
|
4896
5166
|
}
|
|
5167
|
+
this.#rememberPortOffsets(nodeBounds, camera.zoom);
|
|
4897
5168
|
});
|
|
4898
5169
|
}
|
|
5170
|
+
#portOffsets = { input: [], output: [] };
|
|
5171
|
+
#rememberPortOffsets(bounds, zoom) {
|
|
5172
|
+
if (zoom <= 0) {
|
|
5173
|
+
return;
|
|
5174
|
+
}
|
|
5175
|
+
const record = (positions, into) => {
|
|
5176
|
+
into.length = 0;
|
|
5177
|
+
for (let i = 0; i < positions.Count(); i++) {
|
|
5178
|
+
const box = positions.At(i);
|
|
5179
|
+
into.push({
|
|
5180
|
+
Position: {
|
|
5181
|
+
x: (box.Position.x - bounds.Position.x) / zoom,
|
|
5182
|
+
y: (box.Position.y - bounds.Position.y) / zoom
|
|
5183
|
+
},
|
|
5184
|
+
Size: {
|
|
5185
|
+
x: box.Size.x / zoom,
|
|
5186
|
+
y: box.Size.y / zoom
|
|
5187
|
+
}
|
|
5188
|
+
});
|
|
5189
|
+
}
|
|
5190
|
+
};
|
|
5191
|
+
record(this.#inputPortPositions, this.#portOffsets.input);
|
|
5192
|
+
record(this.#outputPortPositions, this.#portOffsets.output);
|
|
5193
|
+
}
|
|
5194
|
+
layoutPortsWithoutDrawing(bounds, zoom) {
|
|
5195
|
+
if (this.#portOffsets.input.length === 0 && this.#portOffsets.output.length === 0) {
|
|
5196
|
+
return false;
|
|
5197
|
+
}
|
|
5198
|
+
const project = (offsets, into) => {
|
|
5199
|
+
into.Clear();
|
|
5200
|
+
for (let i = 0; i < offsets.length; i++) {
|
|
5201
|
+
const offset = offsets[i];
|
|
5202
|
+
into.Push({
|
|
5203
|
+
Position: {
|
|
5204
|
+
x: bounds.Position.x + offset.Position.x * zoom,
|
|
5205
|
+
y: bounds.Position.y + offset.Position.y * zoom
|
|
5206
|
+
},
|
|
5207
|
+
Size: {
|
|
5208
|
+
x: offset.Size.x * zoom,
|
|
5209
|
+
y: offset.Size.y * zoom
|
|
5210
|
+
}
|
|
5211
|
+
});
|
|
5212
|
+
}
|
|
5213
|
+
};
|
|
5214
|
+
project(this.#portOffsets.input, this.#inputPortPositions);
|
|
5215
|
+
project(this.#portOffsets.output, this.#outputPortPositions);
|
|
5216
|
+
this.#widgetPositions.Clear();
|
|
5217
|
+
return true;
|
|
5218
|
+
}
|
|
4899
5219
|
};
|
|
4900
5220
|
|
|
4901
5221
|
// src/markdown/token.ts
|
|
@@ -5036,7 +5356,10 @@ function onFontsLoaded(callback) {
|
|
|
5036
5356
|
if (typeof document === "undefined" || document.fonts === void 0) {
|
|
5037
5357
|
return;
|
|
5038
5358
|
}
|
|
5039
|
-
document.fonts.addEventListener("loadingdone", () =>
|
|
5359
|
+
document.fonts.addEventListener("loadingdone", () => {
|
|
5360
|
+
callback();
|
|
5361
|
+
requestRender();
|
|
5362
|
+
});
|
|
5040
5363
|
}
|
|
5041
5364
|
var CodeBlockEntry = class {
|
|
5042
5365
|
#text;
|
|
@@ -5786,6 +6109,7 @@ var NoteSubsystem = class {
|
|
|
5786
6109
|
return;
|
|
5787
6110
|
}
|
|
5788
6111
|
this.#notes.push(note);
|
|
6112
|
+
requestRender();
|
|
5789
6113
|
for (let i = 0; i < this.#onNoteAddedCallbacks.length; i++) {
|
|
5790
6114
|
this.#onNoteAddedCallbacks[i](note);
|
|
5791
6115
|
}
|
|
@@ -5908,6 +6232,7 @@ var NoteSubsystem = class {
|
|
|
5908
6232
|
if (index > -1) {
|
|
5909
6233
|
const noteRemoved = this.#notes[index];
|
|
5910
6234
|
this.#notes.splice(index, 1);
|
|
6235
|
+
requestRender();
|
|
5911
6236
|
for (let i = 0; i < this.#onNoteRemovedCallbacks.length; i++) {
|
|
5912
6237
|
this.#onNoteRemovedCallbacks[i](noteRemoved);
|
|
5913
6238
|
}
|
|
@@ -6244,6 +6569,124 @@ var QuickMenu = class {
|
|
|
6244
6569
|
}
|
|
6245
6570
|
};
|
|
6246
6571
|
|
|
6572
|
+
// src/minimap.ts
|
|
6573
|
+
var Minimap = class {
|
|
6574
|
+
#enabled;
|
|
6575
|
+
#width;
|
|
6576
|
+
#height;
|
|
6577
|
+
#margin;
|
|
6578
|
+
#backgroundColor;
|
|
6579
|
+
#borderColor;
|
|
6580
|
+
#nodeColor;
|
|
6581
|
+
#viewportColor;
|
|
6582
|
+
#box = { Position: { x: 0, y: 0 }, Size: { x: 0, y: 0 } };
|
|
6583
|
+
#scale = 1;
|
|
6584
|
+
#originX = 0;
|
|
6585
|
+
#originY = 0;
|
|
6586
|
+
// The padding the last frame was laid out with, so a click maps back
|
|
6587
|
+
// through the same geometry it was drawn with.
|
|
6588
|
+
#padding = Theme.Minimap.Padding;
|
|
6589
|
+
#drawn = false;
|
|
6590
|
+
constructor(config) {
|
|
6591
|
+
this.#enabled = config?.enabled === true;
|
|
6592
|
+
this.#width = config?.width === void 0 ? 200 : config.width;
|
|
6593
|
+
this.#height = config?.height === void 0 ? 150 : config.height;
|
|
6594
|
+
this.#margin = config?.margin === void 0 ? 16 : config.margin;
|
|
6595
|
+
this.#backgroundColor = config?.backgroundColor;
|
|
6596
|
+
this.#borderColor = config?.borderColor;
|
|
6597
|
+
this.#nodeColor = config?.nodeColor;
|
|
6598
|
+
this.#viewportColor = config?.viewportColor;
|
|
6599
|
+
}
|
|
6600
|
+
enabled() {
|
|
6601
|
+
return this.#enabled;
|
|
6602
|
+
}
|
|
6603
|
+
setEnabled(enabled) {
|
|
6604
|
+
this.#enabled = enabled;
|
|
6605
|
+
this.#drawn = false;
|
|
6606
|
+
}
|
|
6607
|
+
contains(position) {
|
|
6608
|
+
return this.#enabled && this.#drawn && InBox(this.#box, position);
|
|
6609
|
+
}
|
|
6610
|
+
graphPositionOf(position, out) {
|
|
6611
|
+
out.x = (position.x - this.#box.Position.x - this.#padding) / this.#scale + this.#originX;
|
|
6612
|
+
out.y = (position.y - this.#box.Position.y - this.#padding) / this.#scale + this.#originY;
|
|
6613
|
+
}
|
|
6614
|
+
render(ctx, canvas, camera, nodes) {
|
|
6615
|
+
if (!this.#enabled) {
|
|
6616
|
+
this.#drawn = false;
|
|
6617
|
+
return;
|
|
6618
|
+
}
|
|
6619
|
+
const flat = new Camera();
|
|
6620
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
6621
|
+
const boxes = [];
|
|
6622
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
6623
|
+
const bounds = nodes[i].calculateBounds(ctx, flat);
|
|
6624
|
+
boxes.push(bounds);
|
|
6625
|
+
minX = Math.min(minX, bounds.Position.x);
|
|
6626
|
+
minY = Math.min(minY, bounds.Position.y);
|
|
6627
|
+
maxX = Math.max(maxX, bounds.Position.x + bounds.Size.x);
|
|
6628
|
+
maxY = Math.max(maxY, bounds.Position.y + bounds.Size.y);
|
|
6629
|
+
}
|
|
6630
|
+
const topLeft = { x: 0, y: 0 };
|
|
6631
|
+
const bottomRight = { x: 0, y: 0 };
|
|
6632
|
+
camera.screenSpaceToGraphSpace({ x: 0, y: 0 }, topLeft);
|
|
6633
|
+
camera.screenSpaceToGraphSpace({ x: canvas.width, y: canvas.height }, bottomRight);
|
|
6634
|
+
minX = Math.min(minX, topLeft.x);
|
|
6635
|
+
minY = Math.min(minY, topLeft.y);
|
|
6636
|
+
maxX = Math.max(maxX, bottomRight.x);
|
|
6637
|
+
maxY = Math.max(maxY, bottomRight.y);
|
|
6638
|
+
if (!isFinite(minX) || maxX <= minX || maxY <= minY) {
|
|
6639
|
+
this.#drawn = false;
|
|
6640
|
+
return;
|
|
6641
|
+
}
|
|
6642
|
+
this.#box.Size.x = this.#width;
|
|
6643
|
+
this.#box.Size.y = this.#height;
|
|
6644
|
+
this.#box.Position.x = canvas.width - this.#width - this.#margin;
|
|
6645
|
+
this.#box.Position.y = canvas.height - this.#height - this.#margin;
|
|
6646
|
+
this.#padding = Theme.Minimap.Padding;
|
|
6647
|
+
const usableWidth = this.#width - this.#padding * 2;
|
|
6648
|
+
const usableHeight = this.#height - this.#padding * 2;
|
|
6649
|
+
this.#scale = Math.min(usableWidth / (maxX - minX), usableHeight / (maxY - minY));
|
|
6650
|
+
this.#originX = minX;
|
|
6651
|
+
this.#originY = minY;
|
|
6652
|
+
const left = this.#box.Position.x + this.#padding;
|
|
6653
|
+
const top = this.#box.Position.y + this.#padding;
|
|
6654
|
+
const toMapX = (x) => left + (x - minX) * this.#scale;
|
|
6655
|
+
const toMapY = (y) => top + (y - minY) * this.#scale;
|
|
6656
|
+
ctx.fillStyle = this.#backgroundColor ?? Theme.Minimap.BackgroundColor;
|
|
6657
|
+
ctx.strokeStyle = this.#borderColor ?? Theme.Minimap.BorderColor;
|
|
6658
|
+
ctx.lineWidth = 1;
|
|
6659
|
+
ctx.beginPath();
|
|
6660
|
+
ctx.roundRect(
|
|
6661
|
+
this.#box.Position.x,
|
|
6662
|
+
this.#box.Position.y,
|
|
6663
|
+
this.#width,
|
|
6664
|
+
this.#height,
|
|
6665
|
+
Theme.Minimap.BorderRadius
|
|
6666
|
+
);
|
|
6667
|
+
ctx.fill();
|
|
6668
|
+
ctx.stroke();
|
|
6669
|
+
ctx.fillStyle = this.#nodeColor ?? Theme.Minimap.NodeColor;
|
|
6670
|
+
for (let i = 0; i < boxes.length; i++) {
|
|
6671
|
+
const b = boxes[i];
|
|
6672
|
+
ctx.fillRect(
|
|
6673
|
+
toMapX(b.Position.x),
|
|
6674
|
+
toMapY(b.Position.y),
|
|
6675
|
+
Math.max(1, b.Size.x * this.#scale),
|
|
6676
|
+
Math.max(1, b.Size.y * this.#scale)
|
|
6677
|
+
);
|
|
6678
|
+
}
|
|
6679
|
+
ctx.fillStyle = this.#viewportColor ?? Theme.Minimap.ViewportColor;
|
|
6680
|
+
ctx.fillRect(
|
|
6681
|
+
toMapX(topLeft.x),
|
|
6682
|
+
toMapY(topLeft.y),
|
|
6683
|
+
Math.max(1, (bottomRight.x - topLeft.x) * this.#scale),
|
|
6684
|
+
Math.max(1, (bottomRight.y - topLeft.y) * this.#scale)
|
|
6685
|
+
);
|
|
6686
|
+
this.#drawn = true;
|
|
6687
|
+
}
|
|
6688
|
+
};
|
|
6689
|
+
|
|
6247
6690
|
// src/graph.ts
|
|
6248
6691
|
function BuildBackgroundRenderer(backgroundColor) {
|
|
6249
6692
|
return (canvas, context, position, scale) => {
|
|
@@ -6381,7 +6824,13 @@ var NodeFlowGraph = class {
|
|
|
6381
6824
|
const backgroundColor = config?.backgroundColor === void 0 ? Theme.Graph.BackgroundColor : config.backgroundColor;
|
|
6382
6825
|
this.#backgroundRenderer = BuildBackgroundRenderer(backgroundColor);
|
|
6383
6826
|
}
|
|
6384
|
-
|
|
6827
|
+
this.#minimap = new Minimap(config?.minimap);
|
|
6828
|
+
this.#mainNodeSubsystem.setConnectionReleasedHandler((dangling) => {
|
|
6829
|
+
this.#openScopedMenu(dangling);
|
|
6830
|
+
});
|
|
6831
|
+
this.#watchCanvasSize();
|
|
6832
|
+
this.#stopRendering = onRenderRequested(this.#render.bind(this));
|
|
6833
|
+
requestRender();
|
|
6385
6834
|
new MouseObserver(
|
|
6386
6835
|
this.#canvas,
|
|
6387
6836
|
this.#mouseDragEvent.bind(this),
|
|
@@ -6399,39 +6848,90 @@ var NodeFlowGraph = class {
|
|
|
6399
6848
|
document.addEventListener(
|
|
6400
6849
|
"keydown",
|
|
6401
6850
|
(e) => {
|
|
6402
|
-
|
|
6403
|
-
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
|
|
6407
|
-
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
|
|
6411
|
-
|
|
6412
|
-
|
|
6413
|
-
|
|
6414
|
-
|
|
6415
|
-
|
|
6851
|
+
this.#keyDown(e);
|
|
6852
|
+
requestRender();
|
|
6853
|
+
}
|
|
6854
|
+
);
|
|
6855
|
+
}
|
|
6856
|
+
#copyCallbacks = [];
|
|
6857
|
+
#pasteCallbacks = [];
|
|
6858
|
+
addCopyListener(callback) {
|
|
6859
|
+
this.#copyCallbacks.push(callback);
|
|
6860
|
+
}
|
|
6861
|
+
addPasteListener(callback) {
|
|
6862
|
+
this.#pasteCallbacks.push(callback);
|
|
6863
|
+
}
|
|
6864
|
+
#raiseCopy() {
|
|
6865
|
+
const nodes = this.#mainNodeSubsystem.getSelectedNodes();
|
|
6866
|
+
if (nodes.length === 0) {
|
|
6867
|
+
return;
|
|
6868
|
+
}
|
|
6869
|
+
const connections = this.#mainNodeSubsystem.connectionsWithin(nodes);
|
|
6870
|
+
this.#copyCallbacks.forEach((callback) => callback(nodes, connections));
|
|
6871
|
+
}
|
|
6872
|
+
#raisePaste() {
|
|
6873
|
+
const position = this.#mousePosition === void 0 ? { x: 0, y: 0 } : this.#sceenPositionToGraphPosition(this.#mousePosition);
|
|
6874
|
+
this.#pasteCallbacks.forEach((callback) => callback(position));
|
|
6875
|
+
}
|
|
6876
|
+
#deleteKey(e) {
|
|
6877
|
+
return e.code === "Delete" || e.code === "Backspace" || e.key === "Delete" || e.key === "Backspace";
|
|
6878
|
+
}
|
|
6879
|
+
#keyDown(e) {
|
|
6880
|
+
if (document.activeElement) {
|
|
6881
|
+
if (["INPUT", "TEXTAREA"].includes(document.activeElement.tagName)) return;
|
|
6882
|
+
}
|
|
6883
|
+
if (this.#deleteKey(e)) {
|
|
6884
|
+
if (this.#mainNodeSubsystem.getSelectedNodes().length > 0) {
|
|
6885
|
+
e.preventDefault();
|
|
6886
|
+
this.#mainNodeSubsystem.removeSelectedNodes();
|
|
6887
|
+
return;
|
|
6888
|
+
}
|
|
6889
|
+
}
|
|
6890
|
+
if (e.ctrlKey || e.metaKey) {
|
|
6891
|
+
const letter = e.code.startsWith("Key") ? e.code.substring(3).toLowerCase() : (e.key ?? "").toLowerCase();
|
|
6892
|
+
switch (letter) {
|
|
6893
|
+
case "c":
|
|
6894
|
+
this.#raiseCopy();
|
|
6416
6895
|
return;
|
|
6417
|
-
|
|
6418
|
-
|
|
6419
|
-
if (!spacePressed) {
|
|
6896
|
+
case "v":
|
|
6897
|
+
this.#raisePaste();
|
|
6420
6898
|
return;
|
|
6421
|
-
|
|
6422
|
-
|
|
6899
|
+
// duplicate
|
|
6900
|
+
case "d":
|
|
6901
|
+
e.preventDefault();
|
|
6902
|
+
this.#raiseCopy();
|
|
6903
|
+
this.#raisePaste();
|
|
6423
6904
|
return;
|
|
6424
|
-
}
|
|
6425
|
-
const contextMenuPosition = this.#sceenPositionToGraphPosition(this.#mousePosition);
|
|
6426
|
-
let items = this.#mainNodeSubsystem.nodeFactory().newNodeSubmenus(this.#mainNodeSubsystem, contextMenuPosition);
|
|
6427
|
-
this.#openQuickMenu = {
|
|
6428
|
-
Menu: new QuickMenu({
|
|
6429
|
-
subMenus: items
|
|
6430
|
-
}),
|
|
6431
|
-
Position: contextMenuPosition
|
|
6432
|
-
};
|
|
6433
6905
|
}
|
|
6434
|
-
|
|
6906
|
+
}
|
|
6907
|
+
if (this.#openQuickMenu) {
|
|
6908
|
+
if (e.code === "Escape") {
|
|
6909
|
+
this.#openQuickMenu = null;
|
|
6910
|
+
return;
|
|
6911
|
+
}
|
|
6912
|
+
if (e.code === "Enter") {
|
|
6913
|
+
this.#openQuickMenu.Menu.execute();
|
|
6914
|
+
this.#openQuickMenu = null;
|
|
6915
|
+
return;
|
|
6916
|
+
}
|
|
6917
|
+
this.#openQuickMenu.Menu.keyboardEvent(e);
|
|
6918
|
+
return;
|
|
6919
|
+
}
|
|
6920
|
+
const spacePressed = e.key == " " || e.code == "Space";
|
|
6921
|
+
if (!spacePressed) {
|
|
6922
|
+
return;
|
|
6923
|
+
}
|
|
6924
|
+
if (!this.#mousePosition) {
|
|
6925
|
+
return;
|
|
6926
|
+
}
|
|
6927
|
+
const contextMenuPosition = this.#sceenPositionToGraphPosition(this.#mousePosition);
|
|
6928
|
+
let items = this.#mainNodeSubsystem.nodeFactory().newNodeSubmenus(this.#mainNodeSubsystem, contextMenuPosition);
|
|
6929
|
+
this.#openQuickMenu = {
|
|
6930
|
+
Menu: new QuickMenu({
|
|
6931
|
+
subMenus: items
|
|
6932
|
+
}),
|
|
6933
|
+
Position: contextMenuPosition
|
|
6934
|
+
};
|
|
6435
6935
|
}
|
|
6436
6936
|
#fileDrop(file) {
|
|
6437
6937
|
if (this.currentView().fileDrop(file)) {
|
|
@@ -6497,8 +6997,25 @@ var NodeFlowGraph = class {
|
|
|
6497
6997
|
this.#openQuickMenu = null;
|
|
6498
6998
|
this.#contextMenuEntryHovering = null;
|
|
6499
6999
|
this.#mousePosition = mousePosition;
|
|
7000
|
+
if (this.#minimap.contains(mousePosition)) {
|
|
7001
|
+
this.#lookAtFromMinimap(mousePosition);
|
|
7002
|
+
this.#draggingMinimap = true;
|
|
7003
|
+
return;
|
|
7004
|
+
}
|
|
6500
7005
|
this.currentView().clickStart(mousePosition, this.#camera, ctrlKey);
|
|
6501
7006
|
}
|
|
7007
|
+
#draggingMinimap = false;
|
|
7008
|
+
#lookAtFromMinimap(mousePosition) {
|
|
7009
|
+
const target = { x: 0, y: 0 };
|
|
7010
|
+
this.#minimap.graphPositionOf(mousePosition, target);
|
|
7011
|
+
this.#camera.position.x = -(target.x * this.#camera.zoom) + this.#canvas.width / 2;
|
|
7012
|
+
this.#camera.position.y = -(target.y * this.#camera.zoom) + this.#canvas.height / 2;
|
|
7013
|
+
requestRender();
|
|
7014
|
+
}
|
|
7015
|
+
/** The minimap, so it can be turned on and sized by the host. */
|
|
7016
|
+
minimap() {
|
|
7017
|
+
return this.#minimap;
|
|
7018
|
+
}
|
|
6502
7019
|
currentView() {
|
|
6503
7020
|
return this.#views[this.#currentView];
|
|
6504
7021
|
}
|
|
@@ -6518,6 +7035,12 @@ var NodeFlowGraph = class {
|
|
|
6518
7035
|
getSelectedNodes() {
|
|
6519
7036
|
return this.#mainNodeSubsystem.getSelectedNodes();
|
|
6520
7037
|
}
|
|
7038
|
+
unselectAllNodes() {
|
|
7039
|
+
this.#mainNodeSubsystem.unselectAllNodes();
|
|
7040
|
+
}
|
|
7041
|
+
removeSelectedNodes() {
|
|
7042
|
+
return this.#mainNodeSubsystem.removeSelectedNodes();
|
|
7043
|
+
}
|
|
6521
7044
|
/**
|
|
6522
7045
|
* Returns a copy of the current camera orientation (screen-space pan + zoom).
|
|
6523
7046
|
*/
|
|
@@ -6633,10 +7156,37 @@ var NodeFlowGraph = class {
|
|
|
6633
7156
|
Position: contextMenuPosition
|
|
6634
7157
|
};
|
|
6635
7158
|
}
|
|
7159
|
+
#openScopedMenu(dangling) {
|
|
7160
|
+
if (this.#mousePosition === void 0) {
|
|
7161
|
+
return;
|
|
7162
|
+
}
|
|
7163
|
+
const position = this.#sceenPositionToGraphPosition(this.#mousePosition);
|
|
7164
|
+
const menu = this.#mainNodeSubsystem.nodeFactory().openMenu(
|
|
7165
|
+
this.#mainNodeSubsystem,
|
|
7166
|
+
position,
|
|
7167
|
+
{
|
|
7168
|
+
needs: dangling.needs,
|
|
7169
|
+
types: dangling.types,
|
|
7170
|
+
onCreated: dangling.connectTo
|
|
7171
|
+
}
|
|
7172
|
+
);
|
|
7173
|
+
this.#openedContextMenu = {
|
|
7174
|
+
Menu: new ContextMenu(menu),
|
|
7175
|
+
Position: position
|
|
7176
|
+
};
|
|
7177
|
+
requestRender();
|
|
7178
|
+
}
|
|
6636
7179
|
#clickEnd() {
|
|
7180
|
+
this.#draggingMinimap = false;
|
|
6637
7181
|
this.currentView().clickEnd();
|
|
6638
7182
|
}
|
|
6639
7183
|
#mouseDragEvent(delta) {
|
|
7184
|
+
if (this.#draggingMinimap) {
|
|
7185
|
+
if (this.#mousePosition !== void 0) {
|
|
7186
|
+
this.#lookAtFromMinimap(this.#mousePosition);
|
|
7187
|
+
}
|
|
7188
|
+
return;
|
|
7189
|
+
}
|
|
6640
7190
|
let draggingSomething = this.currentView().mouseDragEvent(delta, this.#camera.zoom);
|
|
6641
7191
|
if (!draggingSomething) {
|
|
6642
7192
|
this.#camera.position.x += delta.x;
|
|
@@ -6645,12 +7195,45 @@ var NodeFlowGraph = class {
|
|
|
6645
7195
|
}
|
|
6646
7196
|
#lastFrameCursor;
|
|
6647
7197
|
#cursor;
|
|
6648
|
-
#
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
7198
|
+
#minimap;
|
|
7199
|
+
#stopRendering;
|
|
7200
|
+
#sizeObserver;
|
|
7201
|
+
#matchCanvasToParent() {
|
|
7202
|
+
const parent = this.#canvas.parentNode;
|
|
7203
|
+
if (parent === null) {
|
|
7204
|
+
return;
|
|
7205
|
+
}
|
|
7206
|
+
const rect = parent.getBoundingClientRect();
|
|
7207
|
+
if (this.#canvas.width === rect.width && this.#canvas.height === rect.height) {
|
|
7208
|
+
return;
|
|
6653
7209
|
}
|
|
7210
|
+
this.#canvas.width = rect.width;
|
|
7211
|
+
this.#canvas.height = rect.height;
|
|
7212
|
+
}
|
|
7213
|
+
#watchCanvasSize() {
|
|
7214
|
+
this.#matchCanvasToParent();
|
|
7215
|
+
const parent = this.#canvas.parentNode;
|
|
7216
|
+
if (parent === null || typeof ResizeObserver === "undefined") {
|
|
7217
|
+
return;
|
|
7218
|
+
}
|
|
7219
|
+
this.#sizeObserver = new ResizeObserver(() => {
|
|
7220
|
+
this.#matchCanvasToParent();
|
|
7221
|
+
requestRender();
|
|
7222
|
+
});
|
|
7223
|
+
this.#sizeObserver.observe(parent);
|
|
7224
|
+
}
|
|
7225
|
+
requestRender() {
|
|
7226
|
+
requestRender();
|
|
7227
|
+
}
|
|
7228
|
+
renderContinuously() {
|
|
7229
|
+
return renderContinuously();
|
|
7230
|
+
}
|
|
7231
|
+
dispose() {
|
|
7232
|
+
this.#stopRendering();
|
|
7233
|
+
this.#sizeObserver?.disconnect();
|
|
7234
|
+
}
|
|
7235
|
+
#render() {
|
|
7236
|
+
this.#matchCanvasToParent();
|
|
6654
7237
|
this.#cursor = "default" /* Default */;
|
|
6655
7238
|
TimeExecution("Render_Background", this.#renderBackground.bind(this));
|
|
6656
7239
|
TimeExecution("Render_View_" + this.#currentView, () => {
|
|
@@ -6659,13 +7242,15 @@ var NodeFlowGraph = class {
|
|
|
6659
7242
|
this.#cursor = results?.cursorStyle;
|
|
6660
7243
|
}
|
|
6661
7244
|
});
|
|
7245
|
+
TimeExecution("Render_Minimap", () => {
|
|
7246
|
+
this.#minimap.render(this.#ctx, this.#canvas, this.#camera, this.#mainNodeSubsystem.getNodes());
|
|
7247
|
+
});
|
|
6662
7248
|
TimeExecution("Render_Context", this.#renderContextMenu.bind(this));
|
|
6663
7249
|
TimeExecution("Render_QuickMenu", this.#renderQuickMenu.bind(this));
|
|
6664
7250
|
if (this.#lastFrameCursor !== this.#cursor) {
|
|
6665
7251
|
this.#canvas.style.cursor = this.#cursor;
|
|
6666
7252
|
}
|
|
6667
7253
|
this.#lastFrameCursor = this.#cursor;
|
|
6668
|
-
window.requestAnimationFrame(this.#render.bind(this));
|
|
6669
7254
|
}
|
|
6670
7255
|
#renderBackground() {
|
|
6671
7256
|
this.#backgroundRenderer(this.#canvas, this.#ctx, this.#camera.position, this.#camera.zoom);
|
|
@@ -6706,6 +7291,7 @@ export {
|
|
|
6706
7291
|
GlobalWidgetFactory,
|
|
6707
7292
|
ImageWidget,
|
|
6708
7293
|
MessageType,
|
|
7294
|
+
Minimap,
|
|
6709
7295
|
NodeFactory,
|
|
6710
7296
|
NodeFlowGraph,
|
|
6711
7297
|
NodeState,
|
|
@@ -6719,6 +7305,10 @@ export {
|
|
|
6719
7305
|
Theme,
|
|
6720
7306
|
ToggleWidget,
|
|
6721
7307
|
WidgetFactory,
|
|
6722
|
-
|
|
7308
|
+
portConfigTypes,
|
|
7309
|
+
portsCompatible,
|
|
7310
|
+
renderContinuously,
|
|
7311
|
+
requestRender,
|
|
7312
|
+
typeSetsCompatible
|
|
6723
7313
|
};
|
|
6724
7314
|
//# sourceMappingURL=index.mjs.map
|