From 326aedb3fdde45a7e9fdde21a759f2a119c9fc37 Mon Sep 17 00:00:00 2001 From: Sam Lavigne Date: Tue, 22 Aug 2023 12:05:49 -0400 Subject: [PATCH 01/11] playing with graphs --- package-lock.json | 10 +++ package.json | 1 + src/App.svelte | 20 +++-- src/Filter.svelte | 6 +- src/FilterPicker.svelte | 14 +--- src/Graph.svelte | 164 ++++++++++++++++++++++++++++++++++++++++ src/Input.svelte | 7 +- src/stores.js | 52 ++++++++++++- 8 files changed, 247 insertions(+), 27 deletions(-) create mode 100644 src/Graph.svelte diff --git a/package-lock.json b/package-lock.json index 031025d..cf74935 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@sveltejs/vite-plugin-svelte": "^2.4.2", "svelte": "^4.0.5", "svelte-dnd-action": "^0.9.25", + "svelvet": "^8.1.0", "uuid": "^9.0.0", "vite": "^4.4.5" } @@ -842,6 +843,15 @@ "svelte": "^3.19.0 || ^4.0.0" } }, + "node_modules/svelvet": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/svelvet/-/svelvet-8.1.0.tgz", + "integrity": "sha512-rH67tgb7e2aTBQZBCW+V5hSvulLwvzBiOml9Dzdz2ATkgQr58mHi2WtlQFOOb+eZt6zH/J10a2MataC29Qdpuw==", + "dev": true, + "peerDependencies": { + "svelte": ">=3.59.2 || ^4.0.0" + } + }, "node_modules/uuid": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", diff --git a/package.json b/package.json index 5e9ed9f..64166c0 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "@sveltejs/vite-plugin-svelte": "^2.4.2", "svelte": "^4.0.5", "svelte-dnd-action": "^0.9.25", + "svelvet": "^8.1.0", "uuid": "^9.0.0", "vite": "^4.4.5" }, diff --git a/src/App.svelte b/src/App.svelte index cc0acf8..447d86a 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -1,10 +1,11 @@ + + + {#each $inputs as inp, index} + +
+
+ {inp} +
+ +
+
+ +
v
+
+ +
a
+
+
+
+ {/each} + + {#each $filters as f, index} + +
+
+ {f.name} +
+ +
+
+ {#each countCons(f).in as inp} + +
{inp}
+
+ {/each} +
+
+ {#each countCons(f).out as out} + +
{out}
+
+ {/each} +
+
+ {/each} + + +
+
+ {$output} +
+ +
+
+ +
v
+
+ +
a
+
+
+
+ +
+ + diff --git a/src/Input.svelte b/src/Input.svelte index 7d17220..cd3ca24 100644 --- a/src/Input.svelte +++ b/src/Input.svelte @@ -1,11 +1,12 @@ diff --git a/src/stores.js b/src/stores.js index c6e1556..f1538d1 100644 --- a/src/stores.js +++ b/src/stores.js @@ -1,5 +1,55 @@ +import { v4 as uuidv4 } from "uuid"; import { writable } from 'svelte/store'; -export const inputs = writable(["punch.mp4"]); +export const inputs = writable([{name: "punch.mp4", id: uuidv4()}]); export const output = writable("out.mp4"); export const filters = writable([]); + +export function addFilter(f) { + const newFilter = { ...f, filterId: f.id, id: uuidv4() }; + if (f.params) { + newFilter.params = f.params.map((p) => { + p.value = null; + if (p.default != null) p.value = p.default; + return p; + }); + } + filters.update((filts) => { + filts.push(newFilter) + return filts; + }) +} + +export function removeFilter(id) { + filters.update((filts) => { + const index = filts.findIndex((f) => f.id === id); + filts.splice(index, 1); + return filts; + }); +} + +export function addOutput(f) { + +} + +export function removeOutput(f) { + +} + +export function addInput(f) { + const newInput = {name: f, id: uuidv4()} + inputs.update((inps) => { + inps.push(newInput); + return inps; + }); + +} + +export function removeInput(id) { + inputs.update((inps) => { + const index = inps.findIndex((f) => f.id === id); + inps.splice(index, 1); + return inps; + }); + +} From 73f3c57690ece4859c655226cf7994478c36fa82 Mon Sep 17 00:00:00 2001 From: Sam Lavigne Date: Tue, 22 Aug 2023 13:12:24 -0400 Subject: [PATCH 02/11] ok --- src/Graph.svelte | 65 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/src/Graph.svelte b/src/Graph.svelte index a294d91..5c16521 100644 --- a/src/Graph.svelte +++ b/src/Graph.svelte @@ -1,7 +1,25 @@ @@ -47,18 +76,18 @@ on:connection={onConnect} > {#each $inputs as inp, index} - +
- {inp} + {inp.name}
- +
v
- +
a
@@ -66,7 +95,7 @@ {/each} {#each $filters as f, index} - +
{f.name} @@ -74,15 +103,15 @@
- {#each countCons(f).in as inp} - + {#each countCons(f).in as inp, index} +
{inp}
{/each}
{#each countCons(f).out as out} - +
{out}
{/each} @@ -90,7 +119,7 @@ {/each} - +
{$output} @@ -109,6 +138,14 @@ +
+ {#each edges as e} +

+ {e[0]} =======> {e[1]} +

+ {/each} +
+ +
+ {JSON.stringify(command)} +
diff --git a/src/Graph_old.svelte b/src/Graph_old.svelte new file mode 100644 index 0000000..5c16521 --- /dev/null +++ b/src/Graph_old.svelte @@ -0,0 +1,201 @@ + + + + {#each $inputs as inp, index} + +
+
+ {inp.name} +
+ +
+
+ +
v
+
+ +
a
+
+
+
+ {/each} + + {#each $filters as f, index} + +
+
+ {f.name} +
+ +
+
+ {#each countCons(f).in as inp, index} + +
{inp}
+
+ {/each} +
+
+ {#each countCons(f).out as out} + +
{out}
+
+ {/each} +
+
+ {/each} + + +
+
+ {$output} +
+ +
+
+ +
v
+
+ +
a
+
+
+
+ +
+ +
+ {#each edges as e} +

+ {e[0]} =======> {e[1]} +

+ {/each} +
+ + diff --git a/src/Input.svelte b/src/Input.svelte index cd3ca24..a355aa5 100644 --- a/src/Input.svelte +++ b/src/Input.svelte @@ -1,12 +1,11 @@ diff --git a/src/nodes/FilterNode.svelte b/src/nodes/FilterNode.svelte new file mode 100644 index 0000000..e69de29 diff --git a/src/nodes/InputNode.svelte b/src/nodes/InputNode.svelte new file mode 100644 index 0000000..e69de29 diff --git a/src/nodes/Node.svelte b/src/nodes/Node.svelte new file mode 100644 index 0000000..bdee8b1 --- /dev/null +++ b/src/nodes/Node.svelte @@ -0,0 +1,23 @@ + + +
+ {data.name} +
+{#each data.inputs as inp, index} + +{/each} +{#each data.outputs as out, index} + +{/each} + + + + + + + + diff --git a/src/nodes/OutputNode.svelte b/src/nodes/OutputNode.svelte new file mode 100644 index 0000000..e69de29 diff --git a/src/stores.js b/src/stores.js index f1538d1..da485e0 100644 --- a/src/stores.js +++ b/src/stores.js @@ -1,55 +1,148 @@ import { v4 as uuidv4 } from "uuid"; -import { writable } from 'svelte/store'; +import { writable, derived, get } from "svelte/store"; -export const inputs = writable([{name: "punch.mp4", id: uuidv4()}]); -export const output = writable("out.mp4"); -export const filters = writable([]); +// export const inputs = writable([]); +// export const output = writable("out.mp4"); +// export const filters = writable([]); +export const nodes = writable([]); +export const edges = writable([]); -export function addFilter(f) { - const newFilter = { ...f, filterId: f.id, id: uuidv4() }; - if (f.params) { - newFilter.params = f.params.map((p) => { - p.value = null; - if (p.default != null) p.value = p.default; - return p; - }); - } - filters.update((filts) => { - filts.push(newFilter) - return filts; - }) +addNode({ name: "punch.mp4" }, "input"); +addNode({ name: "out.mp4" }, "output"); + +function makeFilterArgs(f) { + let fCommand = f.name; + if (f.params && f.params.length > 0) { + let params = f.params + .map((p) => { + if (p.value === "" || p.value === null || p.value === p.default) return null; + return `${p.name}=${p.value}`; + }) + .filter((p) => p !== null) + .join(":"); + if (params) fCommand += "=" + params; + } + return fCommand; } -export function removeFilter(id) { - filters.update((filts) => { - const index = filts.findIndex((f) => f.id === id); - filts.splice(index, 1); - return filts; - }); +export const command = derived(edges, ($edges) => { + console.log($edges); + return $edges; +}); + +export const previewCommand = derived(nodes, ($nodes) => { + const cInputs = $nodes + .filter((n) => n.nodeType === "input") + .map((i) => `-i ${i.data.name}`) + .join(" "); + + const cOutput = $nodes + .filter((n) => n.nodeType === "output") + .map((i) => `${i.data.name}`) + .join(" "); + + const cFilters = $nodes + .filter((n) => n.nodeType === "filter") + .map((n) => n.data) + .map(makeFilterArgs) + .join(","); + + let out = `ffmpeg ${cInputs}`; + + if (cFilters) out += ` -filter_complex "${cFilters}"`; + + out += ` ${cOutput}`; + return out; +}); + +export const inputs = derived(nodes, ($nodes) => { + return $nodes.filter((n) => n.nodeType === "input").map((n) => n.data); +}); + +export const filters = derived(nodes, ($nodes) => { + return $nodes.filter((n) => n.nodeType === "filter").map((n) => n.data); +}); + +export const output = derived(nodes, ($nodes) => { + return $nodes.filter((n) => n.nodeType === "output").map((n) => n.data); +}); + +export function addNode(data, type) { + let ins = []; + let outs = []; + + if (type === "input") { + outs = ["v", "a"]; + } else if (type === "output") { + ins = ["v", "a"]; + } else if (type === "filter") { + const [_ins, _outs] = data.type.split("->"); + ins = _ins.toLowerCase().split(""); + outs = _outs.toLowerCase().split(""); + if (data.params) { + data.params = data.params.map((p) => { + p.value = null; + if (p.default != null) p.value = p.default; + return p; + }); + } + } + + let x = 0; + let y = 0; + + const w = 100; + const h = 50; + const margin = 10; + + const existing = get(nodes); + + if (type === "input") { + const inps = existing.filter((n) => n.nodeType === "input"); + y = inps.length * h; + } else if (type === "filter") { + const flts = existing.filter((n) => n.nodeType === "filter"); + x = (flts.length + 1) * w; + } else if (type === "output") { + x = 500; + } + + data.inputs = ins; + data.outputs = outs; + + let node = { + id: uuidv4(), + type: "ffmpeg", + data: data, + nodeType: type, + position: { x, y }, + }; + + nodes.update((n) => { + n.push(node); + return n; + }); + + edges.update((_edges) => { + console.log('EXISTING', existing); + const target = existing[existing.length -2]; + if (!target) return _edges; + const newEdge = { + id: uuidv4(), + type: "default", + source: node.id, + target: target.id, + }; + console.log("NEW EDGE", newEdge); + _edges.push(newEdge); + return _edges; + }); } -export function addOutput(f) { - -} - -export function removeOutput(f) { - -} - -export function addInput(f) { - const newInput = {name: f, id: uuidv4()} - inputs.update((inps) => { - inps.push(newInput); - return inps; - }); - -} - -export function removeInput(id) { - inputs.update((inps) => { - const index = inps.findIndex((f) => f.id === id); - inps.splice(index, 1); - return inps; - }); - +export function removeNode(id) { + nodes.update((_nodes) => { + const index = _nodes.findIndex((n) => n.id === id); + _nodes.splice(index, 1); + return _nodes; + }); } From 7c085cbba24e6fcbf1bbbe9bb18fac48dd7f6b8a Mon Sep 17 00:00:00 2001 From: Sam Lavigne Date: Wed, 23 Aug 2023 16:27:48 -0400 Subject: [PATCH 04/11] working graph --- src/App.svelte | 30 +++--------- src/Graph.svelte | 6 +-- src/stores.js | 118 +++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 107 insertions(+), 47 deletions(-) diff --git a/src/App.svelte b/src/App.svelte index caa3397..95b9d09 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -45,14 +45,18 @@ for (let vid of $inputs) { await ffmpeg.writeFile(vid.name, await fetchFile("/" + vid.name)); } - const clist = commandList(); - console.log(clist); + let clist = $previewCommand.replaceAll('"', '').replace("ffmpeg", "").split(" ").filter(i => i.trim() != ''); + console.log("command", clist); + // command.push("-pix_fmt"); + // command.push("yuv420p"); + // command.push("out.mp4"); await ffmpeg.exec(clist, TIMEOUT); // await ffmpeg.exec(["-f", "lavfi", "-i", "color=size=1280x720:rate=25:color=red", "-t", "5", "out.mp4"]) const data = await ffmpeg.readFile("out.mp4"); rendering = false; videoValue = URL.createObjectURL(new Blob([data.buffer], { type: "video/mp4" })); } catch (e) { + console.log(e); log += "Failed"; } rendering = false; @@ -60,7 +64,6 @@ async function loadFFmpeg() { ffmpeg.on("log", ({ message: msg }) => { - console.log(msg); log += msg + "\n"; logbox.scrollTop = logbox.scrollHeight; }); @@ -77,34 +80,13 @@ workerURL: await toBlobURL(`${baseURL}/ffmpeg-core.worker.js`, "text/javascript"), }); } - console.log(ffmpeg); ffmpegLoaded = true; } - function commandList() { - let command = []; - for (let vid of $inputs) { - command.push("-i"); - command.push(vid.name); - } - // const audioFilters = $filters.filter(f => f.type[0] === "A").map(makeFilterArgs); - // const videoFilters = $filters.filter(f => f.type[0] === "V").map(makeFilterArgs); - const cFilters = $filters.map(makeFilterArgs).join(","); - if (cFilters.length > 0) { - command.push("-filter_complex"); - command.push(cFilters); - } - - command.push("-pix_fmt"); - command.push("yuv420p"); - command.push("out.mp4"); - - return command; - } function handleFilterSort(e) { filters.set(e.detail.items); diff --git a/src/Graph.svelte b/src/Graph.svelte index e5c5e37..1070f96 100644 --- a/src/Graph.svelte +++ b/src/Graph.svelte @@ -1,5 +1,5 @@ + + + {#each $nodes as n, index} + +
+
+ {n.data.name} +
+ +
+
+ {#each n.data.inputs as inp, index} + +
{inp}
+
+ {/each} +
+
+ {#each n.data.outputs as out} + +
{out}
+
+ {/each} +
+
+ {/each} + +
+ +
+ {JSON.stringify($edges)} +
+ + diff --git a/src/Graph_old.svelte b/src/Graph_old.svelte deleted file mode 100644 index 5c16521..0000000 --- a/src/Graph_old.svelte +++ /dev/null @@ -1,201 +0,0 @@ - - - - {#each $inputs as inp, index} - -
-
- {inp.name} -
- -
-
- -
v
-
- -
a
-
-
-
- {/each} - - {#each $filters as f, index} - -
-
- {f.name} -
- -
-
- {#each countCons(f).in as inp, index} - -
{inp}
-
- {/each} -
-
- {#each countCons(f).out as out} - -
{out}
-
- {/each} -
-
- {/each} - - -
-
- {$output} -
- -
-
- -
v
-
- -
a
-
-
-
- -
- -
- {#each edges as e} -

- {e[0]} =======> {e[1]} -

- {/each} -
- - diff --git a/src/app.css b/src/app.css index f485d16..236873e 100644 --- a/src/app.css +++ b/src/app.css @@ -104,3 +104,7 @@ input[type="range"]::-moz-range-thumb { input[type="range"]:focus::-moz-range-thumb { } +.svelte-flow__node { + border-radius: 0px !important; + border: 1px solid var(--b1) !important; +} diff --git a/src/nodes/Node.svelte b/src/nodes/Node.svelte index bdee8b1..b4de612 100644 --- a/src/nodes/Node.svelte +++ b/src/nodes/Node.svelte @@ -4,14 +4,14 @@ export let data = { name: "", inputs: [], outputs: [], onChange: () => {} }; -
+
{data.name}
{#each data.inputs as inp, index} - + {/each} {#each data.outputs as out, index} - + {/each} @@ -21,3 +21,8 @@ + From 2ab5af02354cc9052851e2fba300f32b26e769b5 Mon Sep 17 00:00:00 2001 From: Sam Lavigne Date: Wed, 23 Aug 2023 19:30:04 -0400 Subject: [PATCH 06/11] ok --- src/App.svelte | 2 +- src/GraphOld.svelte | 64 +++++++++++++++++++------------- src/stores.js | 90 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 27 deletions(-) diff --git a/src/App.svelte b/src/App.svelte index 2ac9ccf..8fcdd1f 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -5,7 +5,7 @@ import Output from "./Output.svelte"; import Filter from "./Filter.svelte"; import FilterPicker from "./FilterPicker.svelte"; - import Graph from "./Graph.svelte"; + // import Graph from "./Graph.svelte"; import GraphOld from "./GraphOld.svelte"; import { FFmpeg } from "@ffmpeg/ffmpeg"; import { fetchFile, toBlobURL } from "@ffmpeg/util"; diff --git a/src/GraphOld.svelte b/src/GraphOld.svelte index 5ad78fe..a54befc 100644 --- a/src/GraphOld.svelte +++ b/src/GraphOld.svelte @@ -1,34 +1,45 @@ @@ -41,7 +52,12 @@ on:connection={onConnect} > {#each $nodes as n, index} - +
{n.data.name} @@ -67,10 +83,6 @@ -
- {JSON.stringify($edges)} -
- diff --git a/src/app.css b/src/app.css index 3eb3aa5..6e78712 100644 --- a/src/app.css +++ b/src/app.css @@ -2,12 +2,12 @@ box-sizing: border-box; } :root { - /* --b1: #004dff; */ - /* --b2: #f19696b3; */ - --b1: #004dff; - --b2: #ffdadab3; - /* --b1: #ff0000; */ - /* --b2: #b6e3f2b3; */ + /* --b1: #004dff; */ + /* --b2: #f19696b3; */ + --b1: #004dff; + --b2: #ffdadab3; + /* --b1: #ff0000; */ + /* --b2: #b6e3f2b3; */ } a { @@ -15,8 +15,8 @@ a { } a:hover { - background-color: var(--b1); - color: #fff; + background-color: var(--b1); + color: #fff; } body { @@ -24,6 +24,11 @@ body { font: 16px Times, serif; + margin: 0; +} + +input { + outline: none; } textrea, select, @@ -32,26 +37,26 @@ button { font: inherit; } -button, input:not([type="range"]) , select { - border: 1px solid var(--b1); - background-color: white; - box-shadow: 2px 2px 0px var(--b2); +button, +input:not([type="range"]), +select { + border: 1px solid var(--b1); + background-color: white; + box-shadow: 2px 2px 0px var(--b2); } button:active { - position: relative; - top: 2px; - left: 2px; - box-shadow: none; -} -video { - width: 100%; + position: relative; + top: 2px; + left: 2px; + box-shadow: none; } + input[type="range"] { - -webkit-appearance: none; - appearance: none; - background: transparent; - cursor: pointer; + -webkit-appearance: none; + appearance: none; + background: transparent; + cursor: pointer; } /* Removes default focus */ @@ -62,53 +67,53 @@ input[type="range"]:focus { /***** Chrome, Safari, Opera and Edge Chromium styles *****/ /* slider track */ input[type="range"]::-webkit-slider-runnable-track { - background-color: var(--b1); - border-radius: 0; - height: 0.3rem; + background-color: var(--b1); + border-radius: 0; + height: 0.3rem; } /* slider thumb */ input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; /* Override default look */ - appearance: none; - margin-top: -5px; /* Centers thumb on the track */ + appearance: none; + margin-top: -5px; /* Centers thumb on the track */ - /*custom styles*/ - background-color: var(--b1); - height: 15px; - width: 10px; + /*custom styles*/ + background-color: var(--b1); + height: 15px; + width: 10px; } -input[type="range"]:focus::-webkit-slider-thumb { +input[type="range"]:focus::-webkit-slider-thumb { /* border: 1px solid #053a5f; */ } /******** Firefox styles ********/ /* slider track */ input[type="range"]::-moz-range-track { - background-color: var(--b1); - border-radius: 0; - height: 0.3rem; + background-color: var(--b1); + border-radius: 0; + height: 0.3rem; } /* slider thumb */ input[type="range"]::-moz-range-thumb { - border: none; /*Removes extra border that FF applies*/ - border-radius: 0; /*Removes default border-radius that FF applies*/ + border: none; /*Removes extra border that FF applies*/ + border-radius: 0; /*Removes default border-radius that FF applies*/ - /*custom styles*/ - background-color: var(--b1); - height: 15px; - width: 10px; + /*custom styles*/ + background-color: var(--b1); + height: 15px; + width: 10px; } input[type="range"]:focus::-moz-range-thumb { } .svelte-flow__node { - border-radius: 0px !important; - border: 1px solid var(--b1) !important; + border-radius: 0px !important; + border: 1px solid var(--b1) !important; } .svelte-flow__attribution { - display: none !important; + display: none !important; } diff --git a/src/nodes/Node.svelte b/src/nodes/Node.svelte index b4de612..fb25537 100644 --- a/src/nodes/Node.svelte +++ b/src/nodes/Node.svelte @@ -1,28 +1,96 @@ -
- {data.name} +
+
+
{data.nodeType}
+ +
+
+ {#if data.nodeType == "input"} + + {:else} + {data.name} + {/if} +
{#each data.inputs as inp, index} - + {inp} {/each} {#each data.outputs as out, index} - + {out} {/each} - - - - - - - - + diff --git a/src/stores.js b/src/stores.js index 93a20ca..be462dd 100644 --- a/src/stores.js +++ b/src/stores.js @@ -7,6 +7,7 @@ import { writable, derived, get } from "svelte/store"; export const nodes = writable([]); export const edges = writable([]); export const auto = writable(true); +export const selectedFilter = writable(); const PREFIX = ""; @@ -146,19 +147,22 @@ export const previewCommand = derived([edges, nodes], ([$edges, $nodes]) => { const source = $nodes.find((n) => n.id === e.source); const target = $nodes.find((n) => n.id === e.target); - if (source.nodeType === "input") { - if (e.sourceHandle.includes("v")) { - edgeIds[e.id] = inputIds[source.id] + ":v"; - } - if (e.sourceHandle.includes("a")) { - edgeIds[e.id] = inputIds[source.id] + ":a"; - } - } + if (source && target) { - if (target.nodeType === "output") { - const outType = e.targetHandle.includes("a") ? "aud_out" : "vid_out"; - edgeIds[e.id] = outType; - } + if (source.nodeType === "input") { + if (e.sourceHandle.includes("v")) { + edgeIds[e.id] = inputIds[source.id] + ":v"; + } + if (e.sourceHandle.includes("a")) { + edgeIds[e.id] = inputIds[source.id] + ":a"; + } + } + + if (target.nodeType === "output") { + const outType = e.targetHandle.includes("a") ? "aud_out" : "vid_out"; + edgeIds[e.id] = outType; + } + } } for (let n of $nodes.filter((n) => n.nodeType == "filter")) { @@ -330,6 +334,7 @@ export function addNode(data, type) { } } + data.nodeType = type; data.inputs = ins; data.outputs = outs; @@ -347,9 +352,9 @@ export function addNode(data, type) { const isAuto = get(auto); if (isAuto) { - const w = 100; + const w = 120; const h = 50; - const margin = 10; + const margin = 50; let prev = null; for (let n of _nodes) { @@ -362,7 +367,7 @@ export function addNode(data, type) { for (let n of _nodes) { if (n.nodeType === "filter") { let _w = prev && prev.width ? prev.width : w; - n.position = { x: prev ? prev.position.x + _w + margin : 0, y: -30 }; + n.position = { x: prev ? prev.position.x + _w + margin : 0, y: -50 }; prev = n; } } @@ -374,8 +379,13 @@ export function addNode(data, type) { } } } + if (node.nodeType === "filter") { + selectedFilter.set(_nodes.length - 1); + } return _nodes; }); + + } export function removeNode(id) {