feat: improve loading times
This commit is contained in:
parent
92a7e62d6a
commit
84bcfa61d8
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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}>
|
||||||
<MeshLineGeometry {points} />
|
{#key samples}
|
||||||
|
<MeshLineGeometry {points} />
|
||||||
|
{/key}
|
||||||
<MeshLineMaterial
|
<MeshLineMaterial
|
||||||
width={4}
|
width={4}
|
||||||
attenuate={false}
|
attenuate={false}
|
||||||
|
@ -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}
|
||||||
<GraphView {nodes} {edges} {cameraPosition} />
|
{#key $graphId}
|
||||||
|
<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"}
|
||||||
|
@ -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>
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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: [],
|
||||||
};
|
};
|
||||||
|
@ -47,6 +47,10 @@ export function tree(depth: number): Graph {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return { nodes, edges };
|
return {
|
||||||
|
id: Math.floor(Math.random() * 100000),
|
||||||
|
nodes,
|
||||||
|
edges
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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 />
|
||||||
|
Loading…
Reference in New Issue
Block a user