playing with graphs
This commit is contained in:
parent
9289f78f4d
commit
326aedb3fd
|
@ -16,6 +16,7 @@
|
||||||
"@sveltejs/vite-plugin-svelte": "^2.4.2",
|
"@sveltejs/vite-plugin-svelte": "^2.4.2",
|
||||||
"svelte": "^4.0.5",
|
"svelte": "^4.0.5",
|
||||||
"svelte-dnd-action": "^0.9.25",
|
"svelte-dnd-action": "^0.9.25",
|
||||||
|
"svelvet": "^8.1.0",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"vite": "^4.4.5"
|
"vite": "^4.4.5"
|
||||||
}
|
}
|
||||||
|
@ -842,6 +843,15 @@
|
||||||
"svelte": "^3.19.0 || ^4.0.0"
|
"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": {
|
"node_modules/uuid": {
|
||||||
"version": "9.0.0",
|
"version": "9.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
"@sveltejs/vite-plugin-svelte": "^2.4.2",
|
"@sveltejs/vite-plugin-svelte": "^2.4.2",
|
||||||
"svelte": "^4.0.5",
|
"svelte": "^4.0.5",
|
||||||
"svelte-dnd-action": "^0.9.25",
|
"svelte-dnd-action": "^0.9.25",
|
||||||
|
"svelvet": "^8.1.0",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"vite": "^4.4.5"
|
"vite": "^4.4.5"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { inputs, output, filters } from "./stores.js";
|
import { inputs, addInput, output, filters } from "./stores.js";
|
||||||
import Input from "./Input.svelte";
|
import Input from "./Input.svelte";
|
||||||
import Output from "./Output.svelte";
|
import Output from "./Output.svelte";
|
||||||
import Filter from "./Filter.svelte";
|
import Filter from "./Filter.svelte";
|
||||||
import FilterPicker from "./FilterPicker.svelte";
|
import FilterPicker from "./FilterPicker.svelte";
|
||||||
|
import Graph from "./Graph.svelte";
|
||||||
import { FFmpeg } from "@ffmpeg/ffmpeg";
|
import { FFmpeg } from "@ffmpeg/ffmpeg";
|
||||||
import { fetchFile, toBlobURL } from "@ffmpeg/util";
|
import { fetchFile, toBlobURL } from "@ffmpeg/util";
|
||||||
import { dndzone } from "svelte-dnd-action";
|
import { dndzone } from "svelte-dnd-action";
|
||||||
|
@ -17,7 +18,7 @@
|
||||||
const ffmpeg = new FFmpeg();
|
const ffmpeg = new FFmpeg();
|
||||||
|
|
||||||
let command = "";
|
let command = "";
|
||||||
let videoValue = "/" + $inputs[0];
|
let videoValue = "/" + $inputs[0].name;
|
||||||
let ffmpegLoaded = false;
|
let ffmpegLoaded = false;
|
||||||
let rendering = false;
|
let rendering = false;
|
||||||
let log = "";
|
let log = "";
|
||||||
|
@ -25,7 +26,7 @@
|
||||||
let commandRef;
|
let commandRef;
|
||||||
|
|
||||||
function newInput() {
|
function newInput() {
|
||||||
$inputs = [...$inputs, "punch.mp4"];
|
addInput("punch.mp4");
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
|
@ -42,7 +43,7 @@
|
||||||
rendering = true;
|
rendering = true;
|
||||||
try {
|
try {
|
||||||
for (let vid of $inputs) {
|
for (let vid of $inputs) {
|
||||||
await ffmpeg.writeFile(vid, await fetchFile("/" + vid));
|
await ffmpeg.writeFile(vid.name, await fetchFile("/" + vid.name));
|
||||||
}
|
}
|
||||||
const clist = commandList();
|
const clist = commandList();
|
||||||
console.log(clist);
|
console.log(clist);
|
||||||
|
@ -81,7 +82,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateCommand() {
|
function updateCommand() {
|
||||||
const cInputs = $inputs.map((i) => `-i ${i}`).join(" ");
|
console.log($inputs);
|
||||||
|
const cInputs = $inputs.map((i) => `-i ${i.name}`).join(" ");
|
||||||
|
|
||||||
const cOutput = $output;
|
const cOutput = $output;
|
||||||
|
|
||||||
|
@ -116,7 +118,7 @@
|
||||||
let command = [];
|
let command = [];
|
||||||
for (let vid of $inputs) {
|
for (let vid of $inputs) {
|
||||||
command.push("-i");
|
command.push("-i");
|
||||||
command.push(vid);
|
command.push(vid.name);
|
||||||
}
|
}
|
||||||
// const audioFilters = $filters.filter(f => f.type[0] === "A").map(makeFilterArgs);
|
// const audioFilters = $filters.filter(f => f.type[0] === "A").map(makeFilterArgs);
|
||||||
// const videoFilters = $filters.filter(f => f.type[0] === "V").map(makeFilterArgs);
|
// const videoFilters = $filters.filter(f => f.type[0] === "V").map(makeFilterArgs);
|
||||||
|
@ -179,7 +181,7 @@
|
||||||
<button on:click={newInput}>Add Input</button>
|
<button on:click={newInput}>Add Input</button>
|
||||||
</div>
|
</div>
|
||||||
{#each $inputs as inp, index}
|
{#each $inputs as inp, index}
|
||||||
<Input bind:filename={inp} {index} />
|
<Input bind:filename={inp.name} id={inp.id} {index} />
|
||||||
{/each}
|
{/each}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -233,6 +235,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section class="graph">
|
||||||
|
<Graph />
|
||||||
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { filters } from "./stores.js";
|
import { filters, removeFilter } from "./stores.js";
|
||||||
|
|
||||||
export let filter = {
|
export let filter = {
|
||||||
name: "",
|
name: "",
|
||||||
|
@ -10,9 +10,7 @@
|
||||||
let show = false;
|
let show = false;
|
||||||
|
|
||||||
function remove() {
|
function remove() {
|
||||||
const index = $filters.findIndex((f) => f.id === filter.id);
|
removeFilter(filter.id);
|
||||||
$filters.splice(index, 1);
|
|
||||||
$filters = $filters;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function reset() {
|
function reset() {
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import uFuzzy from "@leeoniya/ufuzzy";
|
import uFuzzy from "@leeoniya/ufuzzy";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
|
||||||
import FILTERS from "./filters.json";
|
import FILTERS from "./filters.json";
|
||||||
import { filters } from "./stores.js";
|
import { addFilter } from "./stores.js";
|
||||||
|
|
||||||
export let select = "video";
|
export let select = "video";
|
||||||
$: selectedFilters = selectFilters(select);
|
$: selectedFilters = selectFilters(select);
|
||||||
|
@ -26,16 +25,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function add(f) {
|
function add(f) {
|
||||||
const newFilter = { ...f, filterId: f.id, id: uuidv4() };
|
addFilter(f);
|
||||||
if (f.params) {
|
|
||||||
newFilter.params = f.params.map((p) => {
|
|
||||||
p.value = null;
|
|
||||||
if (p.default != null) p.value = p.default;
|
|
||||||
return p;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
$filters = [...$filters, newFilter];
|
|
||||||
console.log(newFilter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function update() {
|
function update() {
|
||||||
|
|
|
@ -0,0 +1,164 @@
|
||||||
|
<script>
|
||||||
|
import { inputs, output, filters } from "./stores.js";
|
||||||
|
import { Anchor, Node, Svelvet, Minimap, Controls } from "svelvet";
|
||||||
|
import { generateInput, generateOutput } from "svelvet";
|
||||||
|
|
||||||
|
function countInputs(f) {
|
||||||
|
const [ins, outs] = f.type.split("->");
|
||||||
|
if (ins == "N") return 1;
|
||||||
|
return ins.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function countCons(f) {
|
||||||
|
const [ins, outs] = f.type.split("->");
|
||||||
|
return { in: ins.split(""), out: outs.split("") };
|
||||||
|
}
|
||||||
|
|
||||||
|
function countOutputs(f) {
|
||||||
|
const [ins, outs] = f.type.split("->");
|
||||||
|
if (outs == "N") return 1;
|
||||||
|
return outs.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onConnect(e) {
|
||||||
|
const sourceAnchor = e.detail.sourceAnchor;
|
||||||
|
const targetAnchor = e.detail.targetAnchor;
|
||||||
|
const sourceNode = e.detail.sourceNode;
|
||||||
|
const targetNode = e.detail.targetNode;
|
||||||
|
console.log(sourceNode.id, "->", targetNode.id)
|
||||||
|
console.log(sourceAnchor.id, "->", targetAnchor.id)
|
||||||
|
}
|
||||||
|
function onDisconnect(e) {
|
||||||
|
const sourceAnchor = e.detail.sourceAnchor;
|
||||||
|
const targetAnchor = e.detail.targetAnchor;
|
||||||
|
const sourceNode = e.detail.sourceNode;
|
||||||
|
const targetNode = e.detail.targetNode;
|
||||||
|
console.log(sourceNode.id, "-/>", targetNode.id)
|
||||||
|
console.log(sourceAnchor.id, "-/>", targetAnchor.id)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Svelvet
|
||||||
|
id="my-canvas"
|
||||||
|
width={800}
|
||||||
|
height={500}
|
||||||
|
snapTo={25}
|
||||||
|
on:disconnection={onDisconnect}
|
||||||
|
on:connection={onConnect}
|
||||||
|
>
|
||||||
|
{#each $inputs as inp, index}
|
||||||
|
<Node inputs={0} outputs={2}>
|
||||||
|
<div class="node">
|
||||||
|
<div class="header">
|
||||||
|
{inp}
|
||||||
|
</div>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
<div class="output-anchors">
|
||||||
|
<Anchor id={"v" + index} let:linked let:connecting let:hovering output>
|
||||||
|
<div class:linked class:hovering class:connecting class="anchor video">v</div>
|
||||||
|
</Anchor>
|
||||||
|
<Anchor id={"a" + index} let:linked let:connecting let:hovering output>
|
||||||
|
<div class:linked class:hovering class:connecting class="anchor audio">a</div>
|
||||||
|
</Anchor>
|
||||||
|
</div>
|
||||||
|
</Node>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
{#each $filters as f, index}
|
||||||
|
<Node inputs={countInputs(f)} outputs={countOutputs(f)}>
|
||||||
|
<div class="node">
|
||||||
|
<div class="header">
|
||||||
|
{f.name}
|
||||||
|
</div>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
<div class="input-anchors">
|
||||||
|
{#each countCons(f).in as inp}
|
||||||
|
<Anchor let:linked let:connecting let:hovering input>
|
||||||
|
<div class:linked class:hovering class:connecting class="anchor in {inp}">{inp}</div>
|
||||||
|
</Anchor>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<div class="output-anchors">
|
||||||
|
{#each countCons(f).out as out}
|
||||||
|
<Anchor let:linked let:connecting let:hovering output>
|
||||||
|
<div class:linked class:hovering class:connecting class="anchor in {out}">{out}</div>
|
||||||
|
</Anchor>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</Node>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
<Node inputs={2} outputs="0" position={{ x: 600, y: 250 }}>
|
||||||
|
<div class="node">
|
||||||
|
<div class="header">
|
||||||
|
{$output}
|
||||||
|
</div>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
<div class="input-anchors">
|
||||||
|
<Anchor id={"output_video"} let:linked let:connecting let:hovering input>
|
||||||
|
<div class:linked class:hovering class:connecting class="anchor video">v</div>
|
||||||
|
</Anchor>
|
||||||
|
<Anchor id={"output_audio"} let:linked let:connecting let:hovering input>
|
||||||
|
<div class:linked class:hovering class:connecting class="anchor audio">a</div>
|
||||||
|
</Anchor>
|
||||||
|
</div>
|
||||||
|
</Node>
|
||||||
|
<Controls />
|
||||||
|
</Svelvet>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.node {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: fit-content;
|
||||||
|
height: fit-content;
|
||||||
|
position: relative;
|
||||||
|
pointer-events: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 10px;
|
||||||
|
gap: 10px;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid var(--b1);
|
||||||
|
font: 12px Times, serif;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
.output-anchors {
|
||||||
|
position: absolute;
|
||||||
|
right: -16px;
|
||||||
|
top: 0px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
.input-anchors {
|
||||||
|
position: absolute;
|
||||||
|
left: -16px;
|
||||||
|
top: 0px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
.anchor {
|
||||||
|
background-color: #fff;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 12px;
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
font-family: Times, serif;
|
||||||
|
border: solid 1px white;
|
||||||
|
border-color: var(--b1);
|
||||||
|
}
|
||||||
|
.hovering {
|
||||||
|
scale: 1.2;
|
||||||
|
}
|
||||||
|
.linked {
|
||||||
|
background-color: rgb(17, 214, 17) !important;
|
||||||
|
}
|
||||||
|
.connecting {
|
||||||
|
background-color: goldenrod;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,11 +1,12 @@
|
||||||
<script>
|
<script>
|
||||||
import { inputs } from "./stores.js";
|
import { removeInput } from "./stores.js";
|
||||||
export let filename = "punch.mp4";
|
export let filename = "punch.mp4";
|
||||||
|
export let id;
|
||||||
export let index;
|
export let index;
|
||||||
|
|
||||||
function remove() {
|
function remove() {
|
||||||
$inputs.splice(index, 1);
|
console.log(id);
|
||||||
$inputs = $inputs;
|
removeInput(id);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,55 @@
|
||||||
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import { writable } from 'svelte/store';
|
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 output = writable("out.mp4");
|
||||||
export const filters = writable([]);
|
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;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue