feat: node store interface

This commit is contained in:
2024-04-20 02:41:18 +02:00
parent 1d203c687c
commit 78c88e4d66
51 changed files with 772 additions and 552 deletions

View File

@ -36,7 +36,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any, "
history: HistoryManager = new HistoryManager();
constructor(private nodeRegistry: NodeRegistry) {
constructor(public registry: NodeRegistry) {
super();
this.nodes.subscribe((nodes) => {
this._nodes = nodes;
@ -82,7 +82,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any, "
}
getNodeTypes() {
return this.nodeRegistry.getAllNodes();
return this.registry.getAllNodes();
}
getLinkedNodes(node: Node) {
@ -122,7 +122,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any, "
private _init(graph: Graph) {
const nodes = new Map(graph.nodes.map(node => {
const nodeType = this.nodeRegistry.getNode(node.type);
const nodeType = this.registry.getNode(node.type);
if (nodeType) {
node.tmp = {
random: (Math.random() - 0.5) * 2,
@ -164,10 +164,10 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any, "
this.id.set(graph.id);
const nodeIds = Array.from(new Set([...graph.nodes.map(n => n.type)]));
await this.nodeRegistry.load(nodeIds);
await this.registry.load(nodeIds);
for (const node of this.graph.nodes) {
const nodeType = this.nodeRegistry.getNode(node.type);
const nodeType = this.registry.getNode(node.type);
if (!nodeType) {
logger.error(`Node type not found: ${node.type}`);
this.status.set("error");
@ -222,7 +222,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any, "
}
getNodeType(id: string) {
return this.nodeRegistry.getNode(id);
return this.registry.getNode(id);
}
getChildrenOfNode(node: Node) {
@ -303,7 +303,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any, "
nodes = nodes.map((node, i) => {
const id = startId + i;
idMap.set(node.id, id);
const type = this.nodeRegistry.getNode(node.type);
const type = this.registry.getNode(node.type);
if (!type) {
throw new Error(`Node type not found: ${node.type}`);
}
@ -343,7 +343,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any, "
createNode({ type, position, props = {} }: { type: Node["type"], position: Node["position"], props: Node["props"] }) {
const nodeType = this.nodeRegistry.getNode(type);
const nodeType = this.registry.getNode(type);
if (!nodeType) {
logger.error(`Node type not found: ${type}`);
return;

View File

@ -20,6 +20,7 @@
import { createKeyMap } from "../../helpers/createKeyMap";
import BoxSelection from "../BoxSelection.svelte";
import AddMenu from "../AddMenu.svelte";
import { get } from "svelte/store";
export let graph: GraphManager;
@ -78,7 +79,7 @@
}
function updateNodePosition(node: NodeType) {
if (node?.tmp?.ref) {
if (node?.tmp?.ref && node?.tmp?.mesh) {
if (node.tmp["x"] !== undefined && node.tmp["y"] !== undefined) {
node.tmp.ref.style.setProperty("--nx", `${node.tmp.x * 10}px`);
node.tmp.ref.style.setProperty("--ny", `${node.tmp.y * 10}px`);
@ -758,6 +759,34 @@
addMenuPosition = null;
}
function handleDrop(event: DragEvent) {
if (!event.dataTransfer) return;
const nodeId = event.dataTransfer.getData("data/node-id");
let mx = event.clientX - rect.x;
let my = event.clientY - rect.y;
let nodeOffsetX = event.dataTransfer.getData("data/node-offset-x");
let nodeOffsetY = event.dataTransfer.getData("data/node-offset-y");
if (nodeOffsetX && nodeOffsetY) {
mx += parseInt(nodeOffsetX);
my += parseInt(nodeOffsetY);
}
const pos = projectScreenToWorld(mx, my);
graph.registry.load([nodeId]).then(() => {
graph.createNode({
type: nodeId,
props: {},
position: pos,
});
});
console.log({ nodeId });
}
function handlerDragOver(e: DragEvent) {
e.preventDefault();
}
onMount(() => {
if (localStorage.getItem("cameraPosition")) {
const cPosition = JSON.parse(localStorage.getItem("cameraPosition")!);
@ -779,6 +808,8 @@
tabindex="0"
bind:clientWidth={width}
bind:clientHeight={height}
on:dragover={handlerDragOver}
on:drop={handleDrop}
on:keydown={keymap.handleKeyboardEvent}
on:mousedown={handleMouseDown}
>

View File

@ -11,7 +11,7 @@
export let graph: Graph;
export let settings: Writable<Record<string, any>> | undefined;
const manager = new GraphManager(registry);
export const manager = new GraphManager(registry);
export const status = manager.status;

View File

@ -9,6 +9,7 @@
import { Color, type Mesh } from "three";
import NodeFrag from "./Node.frag";
import NodeVert from "./Node.vert";
import NodeHtml from "./NodeHTML.svelte";
export let node: Node;
export let inView = true;
@ -22,32 +23,20 @@
const getNodeHeight = getContext<(n: string) => number>("getNodeHeight");
const type = node?.tmp?.type;
const zOffset = (node.tmp?.random || 0) * 0.5;
const zLimit = 2 - zOffset;
const parameters = Object.entries(type?.inputs || {})
.filter((p) => p[1].type !== "seed")
.filter((p) => !("setting" in p[1]));
let ref: HTMLDivElement;
let meshRef: Mesh;
const height = getNodeHeight(node.type);
const height = getNodeHeight?.(node.type);
$: if (node && ref && meshRef) {
$: if (node && meshRef) {
node.tmp = node.tmp || {};
node.tmp.ref = ref;
node.tmp.mesh = meshRef;
updateNodePosition(node);
updateNodePosition?.(node);
}
onMount(() => {
node.tmp = node.tmp || {};
node.tmp.ref = ref;
node.tmp.mesh = meshRef;
updateNodePosition(node);
updateNodePosition?.(node);
});
</script>
@ -83,51 +72,4 @@
/>
</T.Mesh>
<div
class="node"
class:active={isActive}
style:--cz={z + zOffset}
style:display={inView && z > zLimit ? "block" : "none"}
class:selected={isSelected}
class:out-of-view={!inView}
data-node-id={node.id}
bind:this={ref}
>
<NodeHeader {node} />
{#each parameters as [key, value], i}
<NodeParameter
bind:node
id={key}
input={value}
isLast={i == parameters.length - 1}
/>
{/each}
</div>
<style>
.node {
position: absolute;
box-sizing: border-box;
user-select: none !important;
cursor: pointer;
width: 200px;
color: var(--text-color);
transform: translate3d(var(--nx), var(--ny), 0);
z-index: 1;
opacity: calc((var(--cz) - 2.5) / 3.5);
font-weight: 300;
--stroke: var(--outline);
--stroke-width: 2px;
}
.node.active {
--stroke: var(--active);
--stroke-width: 2px;
}
.node.selected {
--stroke: var(--selected);
--stroke-width: 2px;
}
</style>
<NodeHtml {node} {inView} {isActive} {isSelected} {z} />

View File

@ -0,0 +1,86 @@
<script lang="ts">
import type { Node } from "@nodes/types";
import NodeHeader from "./NodeHeader.svelte";
import NodeParameter from "./NodeParameter.svelte";
import { getContext, onMount } from "svelte";
export let isActive = false;
export let isSelected = false;
export let inView = true;
export let z = 2;
let ref: HTMLDivElement;
export let node: Node;
export let position = "absolute";
const zOffset = (node.tmp?.random || 0) * 0.5;
const zLimit = 2 - zOffset;
const type = node?.tmp?.type;
const parameters = Object.entries(type?.inputs || {})
.filter((p) => p[1].type !== "seed")
.filter((p) => !("setting" in p[1]));
const updateNodePosition =
getContext<(n: Node) => void>("updateNodePosition");
$: if (node && ref) {
node.tmp = node.tmp || {};
node.tmp.ref = ref;
updateNodePosition?.(node);
}
onMount(() => {
node.tmp = node.tmp || {};
node.tmp.ref = ref;
updateNodePosition?.(node);
});
</script>
<div
class="node {position}"
class:active={isActive}
style:--cz={z + zOffset}
style:display={inView && z > zLimit ? "block" : "none"}
class:selected={isSelected}
class:out-of-view={!inView}
data-node-id={node.id}
bind:this={ref}
>
<NodeHeader {node} />
{#each parameters as [key, value], i}
<NodeParameter
bind:node
id={key}
input={value}
isLast={i == parameters.length - 1}
/>
{/each}
</div>
<style>
.node {
box-sizing: border-box;
user-select: none !important;
cursor: pointer;
width: 200px;
color: var(--text-color);
transform: translate3d(var(--nx), var(--ny), 0);
z-index: 1;
opacity: calc((var(--cz) - 2.5) / 3.5);
font-weight: 300;
--stroke: var(--outline);
--stroke-width: 2px;
}
.node.active {
--stroke: var(--active);
--stroke-width: 2px;
}
.node.selected {
--stroke: var(--selected);
--stroke-width: 2px;
}
</style>

View File

@ -14,10 +14,10 @@
function handleMouseDown(event: MouseEvent) {
event.stopPropagation();
event.preventDefault();
setDownSocket({
setDownSocket?.({
node,
index: 0,
position: getSocketPosition(node, 0),
position: getSocketPosition?.(node, 0),
});
}

View File

@ -15,8 +15,10 @@
$: if (node?.props?.[id] !== value) {
node.props = { ...node.props, [id]: value };
graph.save();
graph.execute();
if (graph) {
graph.save();
graph.execute();
}
}
</script>

View File

@ -20,8 +20,8 @@
const socketId = `${node.id}-${id}`;
const graph = getGraphManager();
const graphId = graph.id;
const inputSockets = graph.inputSockets;
const graphId = graph?.id;
const inputSockets = graph?.inputSockets;
const elementId = `input-${Math.random().toString(36).substring(7)}`;
@ -34,10 +34,10 @@
function handleMouseDown(ev: MouseEvent) {
ev.preventDefault();
ev.stopPropagation();
setDownSocket({
setDownSocket?.({
node,
index: id,
position: getSocketPosition(node, id),
position: getSocketPosition?.(node, id),
});
}
@ -76,7 +76,7 @@
class:disabled={$possibleSocketIds && !$possibleSocketIds.has(socketId)}
>
{#key id && graphId}
<div class="content" class:disabled={$inputSockets.has(socketId)}>
<div class="content" class:disabled={$inputSockets?.has(socketId)}>
{#if inputType.label !== false}
<label for={elementId}>{input.label || id}</label>
{/if}