feat: improve loading times

This commit is contained in:
max_richter 2024-03-20 17:39:52 +01:00
parent 92a7e62d6a
commit 84bcfa61d8
12 changed files with 62 additions and 51 deletions

View File

@ -24,7 +24,7 @@
.selection { .selection {
width: 40px; width: 40px;
height: 20px; height: 20px;
border: solid 0.2px white; border: solid 0.2px rgba(200, 200, 200, 0.8);
border-style: dashed; border-style: dashed;
border-radius: 2px; border-radius: 2px;
} }

View File

@ -19,17 +19,11 @@
import { CubicBezierCurve } from "three/src/extras/curves/CubicBezierCurve.js"; import { CubicBezierCurve } from "three/src/extras/curves/CubicBezierCurve.js";
import { Vector3 } from "three/src/math/Vector3.js"; import { Vector3 } from "three/src/math/Vector3.js";
import { Vector2 } from "three/src/math/Vector2.js"; import { Vector2 } from "three/src/math/Vector2.js";
import { LineMaterial } from "three/examples/jsm/Addons.js";
export let from: { x: number; y: number }; export let from: { x: number; y: number };
export let to: { x: number; y: number }; export let to: { x: number; y: number };
const samples = Math.max( let samples = 5;
5,
Math.floor(
Math.sqrt(Math.pow(to.x - from.x, 2) + Math.pow(to.y - from.y, 2)) / 2,
),
);
const curve = new CubicBezierCurve( const curve = new CubicBezierCurve(
new Vector2(from.x, from.y), new Vector2(from.x, from.y),
@ -45,8 +39,6 @@
let mesh: Mesh; let mesh: Mesh;
const color = new Color(32 / 255, 32 / 255, 32 / 255);
export const update = function (force = false) { export const update = function (force = false) {
if (!force) { if (!force) {
const new_x = from.x + to.x; const new_x = from.x + to.x;
@ -60,18 +52,17 @@
const mid = new Vector2((from.x + to.x) / 2, (from.y + to.y) / 2); const mid = new Vector2((from.x + to.x) / 2, (from.y + to.y) / 2);
// const length = Math.sqrt( const length = Math.floor(
// Math.pow(to.x - from.x, 2) + Math.pow(to.y - from.y, 2), Math.sqrt(Math.pow(to.x - from.x, 2) + Math.pow(to.y - from.y, 2)) / 4,
// ); );
// samples = Math.min(Math.max(10, length), 100);
curve.v0.set(from.x, from.y); curve.v0.set(from.x, from.y);
curve.v1.set(mid.x, from.y); curve.v1.set(mid.x, from.y);
curve.v2.set(mid.x, to.y); curve.v2.set(mid.x, to.y);
curve.v3.set(to.x, to.y); curve.v3.set(to.x, to.y);
points = curve.getPoints(samples).map((p) => new Vector3(p.x, 0, p.y)); points = curve.getPoints(samples).map((p) => new Vector3(p.x, 0, p.y));
// mesh.setGeometry(points);
// mesh.needsUpdate = true;
}; };
update(); update();
@ -101,7 +92,9 @@
</T.Mesh> </T.Mesh>
<T.Mesh position.y={0.5} bind:ref={mesh}> <T.Mesh position.y={0.5} bind:ref={mesh}>
{#key samples}
<MeshLineGeometry {points} /> <MeshLineGeometry {points} />
{/key}
<MeshLineMaterial <MeshLineMaterial
width={4} width={4}
attenuate={false} attenuate={false}

View File

@ -24,6 +24,7 @@
const status = graph.status; const status = graph.status;
const nodes = graph.nodes; const nodes = graph.nodes;
const edges = graph.edges; const edges = graph.edges;
const graphId = graph.id;
let camera: OrthographicCamera; let camera: OrthographicCamera;
const minZoom = 1; const minZoom = 1;
@ -523,8 +524,6 @@
const clickedNodeId = getNodeIdFromEvent(event); const clickedNodeId = getNodeIdFromEvent(event);
console.log({ clickedNodeId });
if (clickedNodeId !== -1) { if (clickedNodeId !== -1) {
if (activeNode) { if (activeNode) {
if (!activeNode?.tmp?.isMoving && !event.ctrlKey && !event.shiftKey) { if (!activeNode?.tmp?.isMoving && !event.ctrlKey && !event.shiftKey) {
@ -676,7 +675,9 @@
to={{ x: mousePosition[0], y: mousePosition[1] }} to={{ x: mousePosition[0], y: mousePosition[1] }}
/> />
{/if} {/if}
{#key $graphId}
<GraphView {nodes} {edges} {cameraPosition} /> <GraphView {nodes} {edges} {cameraPosition} />
{/key}
{:else if $status === "loading"} {:else if $status === "loading"}
<span>Loading</span> <span>Loading</span>
{:else if $status === "error"} {:else if $status === "error"}

View File

@ -78,6 +78,7 @@
width: 0px; width: 0px;
height: 0px; height: 0px;
transform: scale(calc(var(--cz) * 0.1)); transform: scale(calc(var(--cz) * 0.1));
--input-opacity: calc((var(--cz) - 2) / 5); display: var(--node-display, block);
opacity: calc((var(--cz) - 2) / 5);
} }
</style> </style>

View File

@ -4,7 +4,7 @@ import { writable, type Writable } from "svelte/store";
import { Color } from "three/src/math/Color.js"; import { Color } from "three/src/math/Color.js";
export const activeNodeId: Writable<number> = writable(-1); export const activeNodeId: Writable<number> = writable(-1);
export const selectedNodes: Writable<Set<number> | null> = writable(null); export const selectedNodes: Writable<Set<number> | null> = writable(new Set());
export const activeSocket: Writable<Socket | null> = writable(null); export const activeSocket: Writable<Socket | null> = writable(null);
export const hoveredSocket: Writable<Socket | null> = writable(null); export const hoveredSocket: Writable<Socket | null> = writable(null);

View File

@ -68,7 +68,7 @@
uniforms={{ uniforms={{
uColorBright: { value: colorBright }, uColorBright: { value: colorBright },
uColorDark: { value: colorDark }, uColorDark: { value: colorDark },
uSelectedColor: { value: new Color("#f2be90") }, uSelectedColor: { value: new Color("#9d5f28") },
uActiveColor: { value: new Color("white") }, uActiveColor: { value: new Color("white") },
uSelected: { value: false }, uSelected: { value: false },
uActive: { value: false }, uActive: { value: false },
@ -113,10 +113,8 @@
transform: translate3d(var(--nx), var(--ny), 0); transform: translate3d(var(--nx), var(--ny), 0);
z-index: 1; z-index: 1;
font-weight: 300; font-weight: 300;
display: var(--node-display, block);
--stroke: var(--background-color-lighter); --stroke: var(--background-color-lighter);
--stroke-width: 2px; --stroke-width: 2px;
opacity: var(--input-opacity);
} }
.node.active { .node.active {
@ -125,7 +123,7 @@
} }
.node.selected { .node.selected {
--stroke: #f2be90; --stroke: #9d5f28;
--stroke-width: 1px; --stroke-width: 1px;
} }

View File

@ -3,12 +3,15 @@ import { type Graph, type Node, type Edge, type Socket, type NodeRegistry, type
import { HistoryManager } from "./history-manager"; import { HistoryManager } from "./history-manager";
import * as templates from "./graphs"; import * as templates from "./graphs";
import EventEmitter from "./helpers/EventEmitter"; import EventEmitter from "./helpers/EventEmitter";
import throttle from "./helpers/throttle";
export class GraphManager extends EventEmitter<{ "save": Graph }> { export class GraphManager extends EventEmitter<{ "save": Graph }> {
status: Writable<"loading" | "idle" | "error"> = writable("loading"); status: Writable<"loading" | "idle" | "error"> = writable("loading");
loaded = false;
graph: Graph = { nodes: [], edges: [] }; graph: Graph = { id: 0, nodes: [], edges: [] };
id = writable(0);
private _nodes: Map<number, Node> = new Map(); private _nodes: Map<number, Node> = new Map();
nodes: Writable<Map<number, Node>> = writable(new Map()); nodes: Writable<Map<number, Node>> = writable(new Map());
@ -32,6 +35,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph }> {
} }
this.inputSockets.set(s); this.inputSockets.set(s);
}); });
this.execute = throttle(() => this._execute(), 100);
} }
serialize(): Graph { serialize(): Graph {
@ -42,11 +46,12 @@ export class GraphManager extends EventEmitter<{ "save": Graph }> {
props: node.props, props: node.props,
})); }));
const edges = this._edges.map(edge => [edge[0].id, edge[1], edge[2].id, edge[3]]) as Graph["edges"]; const edges = this._edges.map(edge => [edge[0].id, edge[1], edge[2].id, edge[3]]) as Graph["edges"];
return { nodes, edges }; return { id: this.graph.id, nodes, edges };
} }
execute() { execute() { }
if (!this.runtime["loaded"]) return; _execute() {
if (this.loaded === false) return;
const start = performance.now(); const start = performance.now();
const result = this.runtime.execute(this.serialize()); const result = this.runtime.execute(this.serialize());
const end = performance.now(); const end = performance.now();
@ -64,12 +69,11 @@ export class GraphManager extends EventEmitter<{ "save": Graph }> {
return [node.id, node] return [node.id, node]
})); }));
this.edges.set(graph.edges.map((edge) => { const edges = graph.edges.map((edge) => {
const from = nodes.get(edge[0]); const from = nodes.get(edge[0]);
const to = nodes.get(edge[2]); const to = nodes.get(edge[2]);
if (!from || !to) { if (!from || !to) {
console.error("Edge references non-existing node"); throw new Error("Edge references non-existing node");
return;
}; };
from.tmp = from.tmp || {}; from.tmp = from.tmp || {};
from.tmp.children = from.tmp.children || []; from.tmp.children = from.tmp.children || [];
@ -77,19 +81,22 @@ export class GraphManager extends EventEmitter<{ "save": Graph }> {
to.tmp = to.tmp || {}; to.tmp = to.tmp || {};
to.tmp.parents = to.tmp.parents || []; to.tmp.parents = to.tmp.parents || [];
to.tmp.parents.push(from); to.tmp.parents.push(from);
return [from, edge[1], to, edge[3]] as const; return [from, edge[1], to, edge[3]] as Edge;
}) })
.filter(Boolean) as unknown as [Node, number, Node, string][]
);
this.edges.set(edges);
this.nodes.set(nodes); this.nodes.set(nodes);
} }
async load(graph: Graph) { async load(graph: Graph) {
this.loaded = false;
this.graph = graph; this.graph = graph;
const a = performance.now();
this.status.set("loading"); this.status.set("loading");
this.id.set(graph.id);
const b = performance.now();
for (const node of this.graph.nodes) { for (const node of this.graph.nodes) {
const nodeType = this.nodeRegistry.getNode(node.type); const nodeType = this.nodeRegistry.getNode(node.type);
if (!nodeType) { if (!nodeType) {
@ -100,13 +107,24 @@ export class GraphManager extends EventEmitter<{ "save": Graph }> {
node.tmp = node.tmp || {}; node.tmp = node.tmp || {};
node.tmp.type = nodeType; node.tmp.type = nodeType;
} }
const c = performance.now();
this._init(this.graph); this._init(this.graph);
setTimeout(() => { const d = performance.now();
this.status.set("idle");
this.save(); this.save();
}, 100)
const e = performance.now();
this.status.set("idle");
this.loaded = true;
const f = performance.now();
requestAnimationFrame(() => {
console.log(`Loading took ${f - a}ms; a-b: ${b - a}ms; b-c: ${c - b}ms; c-d: ${d - c}ms; d-e: ${e - d}ms; e-f: ${f - e}ms`);
this.execute();
});
} }

View File

@ -3,6 +3,7 @@ import type { Graph } from "$lib/types";
export function grid(width: number, height: number) { export function grid(width: number, height: number) {
const graph: Graph = { const graph: Graph = {
id: Math.floor(Math.random() * 100000),
edges: [], edges: [],
nodes: [], nodes: [],
}; };

View File

@ -47,6 +47,10 @@ export function tree(depth: number): Graph {
} }
return { nodes, edges }; return {
id: Math.floor(Math.random() * 100000),
nodes,
edges
};
} }

View File

@ -1,14 +1,8 @@
import type { Graph, Node, NodeRegistry, NodeType, RuntimeExecutor } from "./types"; import type { Graph, NodeRegistry, NodeType, RuntimeExecutor } from "./types";
export class MemoryRuntimeExecutor implements RuntimeExecutor { export class MemoryRuntimeExecutor implements RuntimeExecutor {
loaded = false; constructor(private registry: NodeRegistry) { }
constructor(private registry: NodeRegistry) {
setTimeout(() => {
this.loaded = true;
}, 500);
}
private getNodeTypes(graph: Graph) { private getNodeTypes(graph: Graph) {
@ -92,7 +86,6 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
} }
execute(graph: Graph) { execute(graph: Graph) {
if (!this.loaded) return;
// Then we add some metadata to the graph // Then we add some metadata to the graph
const [outputNode, nodes] = this.addMetaData(graph); const [outputNode, nodes] = this.addMetaData(graph);

View File

@ -7,6 +7,7 @@ export type Node = {
props?: Record<string, any>, props?: Record<string, any>,
tmp?: { tmp?: {
depth?: number; depth?: number;
mesh?: any;
parents?: Node[], parents?: Node[],
children?: Node[], children?: Node[],
inputNodes?: Record<string, Node> inputNodes?: Record<string, Node>
@ -58,6 +59,7 @@ export interface RuntimeExecutor {
export type Edge = [Node, number, Node, string]; export type Edge = [Node, number, Node, string];
export type Graph = { export type Graph = {
id: number;
meta?: { meta?: {
title?: string; title?: string;
lastModified?: string; lastModified?: string;

View File

@ -37,7 +37,7 @@
<br /> <br />
<button <button
on:click={() => on:click={() =>
graphManager.load(graphManager.createTemplate("grid", 5, 5))} graphManager.load(graphManager.createTemplate("grid", 10, 10))}
>load grid</button >load grid</button
> >
<br /> <br />