Graph component
This commit is contained in:
@@ -20,6 +20,7 @@
|
|||||||
import ComfyProperties from "./ComfyProperties.svelte";
|
import ComfyProperties from "./ComfyProperties.svelte";
|
||||||
import queueState from "$lib/stores/queueState";
|
import queueState from "$lib/stores/queueState";
|
||||||
import ComfyUnlockUIButton from "./ComfyUnlockUIButton.svelte";
|
import ComfyUnlockUIButton from "./ComfyUnlockUIButton.svelte";
|
||||||
|
import ComfyGraphView from "./ComfyGraphView.svelte";
|
||||||
|
|
||||||
export let app: ComfyApp = undefined;
|
export let app: ComfyApp = undefined;
|
||||||
let imageViewer: ImageViewer;
|
let imageViewer: ImageViewer;
|
||||||
@@ -59,6 +60,7 @@
|
|||||||
$layoutState.currentSelection = []
|
$layoutState.currentSelection = []
|
||||||
|
|
||||||
let graphSize = 0;
|
let graphSize = 0;
|
||||||
|
let graphTransitioning = false;
|
||||||
|
|
||||||
function toggleGraph() {
|
function toggleGraph() {
|
||||||
if (graphSize == 0) {
|
if (graphSize == 0) {
|
||||||
@@ -121,10 +123,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function doRecenter(): void {
|
|
||||||
app.lCanvas.recenter();
|
|
||||||
}
|
|
||||||
|
|
||||||
$: if ($uiState.uiUnlocked && !hasShownUIHelpToast) {
|
$: if ($uiState.uiUnlocked && !hasShownUIHelpToast) {
|
||||||
hasShownUIHelpToast = true;
|
hasShownUIHelpToast = true;
|
||||||
toast.push("Right-click to open context menu.")
|
toast.push("Right-click to open context menu.")
|
||||||
@@ -145,11 +143,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$: if (containerElem) {
|
$: if (containerElem) {
|
||||||
let wrappers = containerElem.querySelectorAll<HTMLDivElement>(".pane-wrapper")
|
const canvas = containerElem.querySelector<HTMLDivElement>("#graph-canvas")
|
||||||
for (const wrapper of wrappers) {
|
if (canvas) {
|
||||||
const paneNode = wrapper.parentNode as HTMLElement; // get the node inside the <Pane/>
|
console.warn("reg!");
|
||||||
paneNode.ontransitionend = () => {
|
const paneNode = canvas.closest(".splitpanes__pane")
|
||||||
app.resizeCanvas()
|
if (paneNode) {
|
||||||
|
(paneNode as HTMLElement).ontransitionstart = () => {
|
||||||
|
graphTransitioning = true
|
||||||
|
}
|
||||||
|
(paneNode as HTMLElement).ontransitionend = () => {
|
||||||
|
graphTransitioning = false
|
||||||
|
app.resizeCanvas()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -190,9 +195,7 @@
|
|||||||
<ComfyUIPane bind:this={uiPane} {app} />
|
<ComfyUIPane bind:this={uiPane} {app} />
|
||||||
</Pane>
|
</Pane>
|
||||||
<Pane bind:size={graphSize}>
|
<Pane bind:size={graphSize}>
|
||||||
<div class="canvas-wrapper pane-wrapper">
|
<ComfyGraphView {app} transitioning={graphTransitioning} />
|
||||||
<canvas id="graph-canvas" />
|
|
||||||
</div>
|
|
||||||
</Pane>
|
</Pane>
|
||||||
</Splitpanes>
|
</Splitpanes>
|
||||||
</Pane>
|
</Pane>
|
||||||
@@ -226,9 +229,6 @@
|
|||||||
<Button variant="secondary" on:click={doLoadDefault}>
|
<Button variant="secondary" on:click={doLoadDefault}>
|
||||||
Load Default
|
Load Default
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="secondary" on:click={doRecenter}>
|
|
||||||
Recenter
|
|
||||||
</Button>
|
|
||||||
<Button variant="secondary" on:click={doRefreshCombos}>
|
<Button variant="secondary" on:click={doRefreshCombos}>
|
||||||
🔄
|
🔄
|
||||||
</Button>
|
</Button>
|
||||||
@@ -273,15 +273,6 @@
|
|||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
#comfy-ui {
|
|
||||||
}
|
|
||||||
|
|
||||||
#comfy-graph {
|
|
||||||
}
|
|
||||||
|
|
||||||
#graph-canvas {
|
|
||||||
}
|
|
||||||
|
|
||||||
#bottombar {
|
#bottombar {
|
||||||
padding-top: 0.5em;
|
padding-top: 0.5em;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -302,12 +293,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.canvas-wrapper {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-wrapper {
|
.sidebar-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|||||||
@@ -106,6 +106,8 @@ export default class ComfyApp {
|
|||||||
LiteGraph.release_link_on_empty_shows_menu = true;
|
LiteGraph.release_link_on_empty_shows_menu = true;
|
||||||
LiteGraph.alt_drag_do_clone_nodes = true;
|
LiteGraph.alt_drag_do_clone_nodes = true;
|
||||||
|
|
||||||
|
(window as any).LiteGraph = LiteGraph;
|
||||||
|
|
||||||
// await this.#invokeExtensionsAsync("init");
|
// await this.#invokeExtensionsAsync("init");
|
||||||
await this.registerNodes();
|
await this.registerNodes();
|
||||||
|
|
||||||
|
|||||||
76
src/lib/components/ComfyGraphView.svelte
Normal file
76
src/lib/components/ComfyGraphView.svelte
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Button } from "@gradio/button";
|
||||||
|
import type ComfyApp from "./ComfyApp";
|
||||||
|
|
||||||
|
export let app: ComfyApp;
|
||||||
|
export let transitioning: boolean = false;
|
||||||
|
|
||||||
|
function doRecenter(): void {
|
||||||
|
app?.lCanvas?.recenter();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="wrapper">
|
||||||
|
<div class="canvas-wrapper pane-wrapper">
|
||||||
|
<canvas id="graph-canvas" />
|
||||||
|
</div>
|
||||||
|
<div class="bar">
|
||||||
|
{#if !transitioning}
|
||||||
|
<span class="left">
|
||||||
|
<button on:click={doRecenter}>Recenter</button>
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
$bar-height: 3em;
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.canvas-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - $bar-height);
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar {
|
||||||
|
padding: 0.2em 0.5em;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: $bar-height;
|
||||||
|
background-color: #3A3A3A;
|
||||||
|
border: 2px solid #2A2A2A;
|
||||||
|
gap: var(--layout-gap);
|
||||||
|
margin-top: auto;
|
||||||
|
overflow-x: auto;
|
||||||
|
|
||||||
|
> .left {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .right {
|
||||||
|
margin-left: auto
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
color: #EEE;
|
||||||
|
border: 1px solid #888;
|
||||||
|
padding: 2px 5px;
|
||||||
|
background-color: #666;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #999;
|
||||||
|
border-color: #AAA;
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
background-color: #555;
|
||||||
|
border-color: #777;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function validNodeProperty(spec: AttributesSpec, node: LGraphNode | null): boolean {
|
function validNodeProperty(spec: AttributesSpec, node: LGraphNode | null): boolean {
|
||||||
if (node == null)
|
if (node == null || spec.location !== "nodeProps")
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (spec.canShow && !spec.canShow(node))
|
if (spec.canShow && !spec.canShow(node))
|
||||||
@@ -77,8 +77,21 @@
|
|||||||
return spec.name in node.properties
|
return spec.name in node.properties
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validNodeVar(spec: AttributesSpec, node: LGraphNode | null): boolean {
|
||||||
|
if (node == null || spec.location !== "nodeVars")
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (spec.canShow && !spec.canShow(node))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (spec.validNodeTypes) {
|
||||||
|
return spec.validNodeTypes.indexOf(node.type) !== -1;
|
||||||
|
}
|
||||||
|
return spec.name in node
|
||||||
|
}
|
||||||
|
|
||||||
function validWidgetAttribute(spec: AttributesSpec, widget: IDragItem | null): boolean {
|
function validWidgetAttribute(spec: AttributesSpec, widget: IDragItem | null): boolean {
|
||||||
if (widget == null)
|
if (widget == null || spec.location !== "widget")
|
||||||
return false;
|
return false;
|
||||||
if (spec.canShow)
|
if (spec.canShow)
|
||||||
return spec.canShow(widget);
|
return spec.canShow(widget);
|
||||||
@@ -86,6 +99,13 @@
|
|||||||
return spec.name in widget.attrs
|
return spec.name in widget.attrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validWorkflowAttribute(spec: AttributesSpec): boolean {
|
||||||
|
if (spec.location !== "workflow")
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return spec.name in $layoutState.attrs
|
||||||
|
}
|
||||||
|
|
||||||
function getAttribute(target: IDragItem, spec: AttributesSpec): any {
|
function getAttribute(target: IDragItem, spec: AttributesSpec): any {
|
||||||
let value = target.attrs[spec.name]
|
let value = target.attrs[spec.name]
|
||||||
if (value == null)
|
if (value == null)
|
||||||
@@ -200,7 +220,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{#each category.specs as spec(spec.id)}
|
{#each category.specs as spec(spec.id)}
|
||||||
{#if spec.location === "widget" && validWidgetAttribute(spec, target)}
|
{#if validWidgetAttribute(spec, target)}
|
||||||
<div class="props-entry">
|
<div class="props-entry">
|
||||||
{#if spec.type === "string"}
|
{#if spec.type === "string"}
|
||||||
<TextBox
|
<TextBox
|
||||||
@@ -237,7 +257,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{:else if node}
|
{:else if node}
|
||||||
{#if spec.location === "nodeProps" && validNodeProperty(spec, node)}
|
{#if validNodeProperty(spec, node)}
|
||||||
<div class="props-entry">
|
<div class="props-entry">
|
||||||
{#if spec.type === "string"}
|
{#if spec.type === "string"}
|
||||||
<TextBox
|
<TextBox
|
||||||
@@ -273,7 +293,7 @@
|
|||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{:else if spec.location === "nodeVars" && spec.name in node}
|
{:else if validNodeVar(spec, node)}
|
||||||
<div class="props-entry">
|
<div class="props-entry">
|
||||||
{#if spec.type === "string"}
|
{#if spec.type === "string"}
|
||||||
<TextBox
|
<TextBox
|
||||||
@@ -310,7 +330,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{:else if spec.location === "workflow" && spec.name in $layoutState.attrs}
|
{:else if !node && !target && validWorkflowAttribute(spec)}
|
||||||
<div class="props-entry">
|
<div class="props-entry">
|
||||||
{#if spec.type === "string"}
|
{#if spec.type === "string"}
|
||||||
<TextBox
|
<TextBox
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="wrapper button lg" class:toggled>
|
<div class="unlock-button" class:toggled>
|
||||||
<Button on:click={toggle} variant={toggled ? "primary" : "secondary"}>
|
<Button on:click={toggle} variant={toggled ? "primary" : "secondary"}>
|
||||||
{#if toggled}
|
{#if toggled}
|
||||||
<LockOpen2 />
|
<LockOpen2 />
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.wrapper {
|
.unlock-button {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
width: var(--size-12);
|
width: var(--size-12);
|
||||||
height: var(--size-12);
|
height: var(--size-12);
|
||||||
|
|||||||
@@ -856,3 +856,23 @@ input[type=range]::-ms-fill-upper {
|
|||||||
color: var(--ae-input-color) !important;
|
color: var(--ae-input-color) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.unlock-button {
|
||||||
|
> .lg {
|
||||||
|
border-color: var(--ae-subpanel-border-color) !important;
|
||||||
|
}
|
||||||
|
&:hover svg {
|
||||||
|
color: var(--ae-main-bg-color) !important;
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
color: var(--ae-input-color) !important;
|
||||||
|
}
|
||||||
|
&.toggled {
|
||||||
|
svg {
|
||||||
|
color: var(--ae-icon-color) !important;
|
||||||
|
}
|
||||||
|
&:hover svg {
|
||||||
|
color: var(--ae-main-bg-color) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user