Speed up graph view frontend by removing a querySelectorAll hot path (#1475)

* Reduce query selector all that was slowing perf

* Speed up double iteration of filter map with flatMap

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
0HyperCube 2023-11-25 23:25:58 +00:00 committed by GitHub
parent 2515620a77
commit ee95dac74e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -40,6 +40,9 @@
let searchTerm = "";
let nodeListLocation: { x: number; y: number } | undefined = undefined;
let inputs: SVGSVGElement[][] = [];
let outputs: SVGSVGElement[][] = [];
$: watchNodes($nodeGraph.nodes);
$: gridSpacing = calculateGridSpacing(transform.scale);
@ -126,17 +129,21 @@
}
async function watchNodes(nodes: FrontendNode[]) {
nodes.forEach((_, index) => {
if (!inputs[index]) inputs[index] = [];
if (!outputs[index]) outputs[index] = [];
});
selected = selected.filter((id) => nodes.find((node) => node.id === id));
await refreshLinks();
}
function resolveLink(link: FrontendNodeLink, containerBounds: HTMLDivElement): { nodeOutput: SVGSVGElement | undefined; nodeInput: SVGSVGElement | undefined } {
function resolveLink(link: FrontendNodeLink): { nodeOutput: SVGSVGElement | undefined; nodeInput: SVGSVGElement | undefined } {
const outputIndex = Number(link.linkStartOutputIndex);
const inputIndex = Number(link.linkEndInputIndex);
const nodeOutputConnectors = containerBounds.querySelectorAll(`[data-node="${String(link.linkStart)}"] [data-port="output"]`) || undefined;
const nodeInputConnectors = containerBounds.querySelectorAll(`[data-node="${String(link.linkEnd)}"] [data-port="input"]`) || undefined;
const nodeOutputConnectors = outputs[$nodeGraph.nodes.findIndex((node) => node.id === link.linkStart)];
const nodeInputConnectors = inputs[$nodeGraph.nodes.findIndex((node) => node.id === link.linkEnd)] || undefined;
const nodeOutput = nodeOutputConnectors?.[outputIndex] as SVGSVGElement | undefined;
const nodeInput = nodeInputConnectors?.[inputIndex] as SVGSVGElement | undefined;
@ -146,12 +153,9 @@
async function refreshLinks() {
await tick();
if (!nodesContainer) return;
const theNodesContainer = nodesContainer;
const links = $nodeGraph.links;
nodeLinkPaths = links.flatMap((link, index) => {
const { nodeInput, nodeOutput } = resolveLink(link, theNodesContainer);
const { nodeInput, nodeOutput } = resolveLink(link);
if (!nodeInput || !nodeOutput) return [];
if (disconnecting?.linkIndex === index) return [];
const linkStart = $nodeGraph.nodes.find((node) => node.id === link.linkStart)?.displayName === "Layer";
@ -463,7 +467,7 @@
// Find the link that the node has been dragged on top of
const link = $nodeGraph.links.find((link): boolean => {
const { nodeInput, nodeOutput } = resolveLink(link, theNodesContainer);
const { nodeInput, nodeOutput } = resolveLink(link);
if (!nodeInput || !nodeOutput) return false;
const wireCurveLocations = buildWirePathLocations(nodeOutput.getBoundingClientRect(), nodeInput.getBoundingClientRect(), false, false);
@ -661,7 +665,7 @@
<!-- Layers and nodes -->
<div class="layers-and-nodes" style:transform={`scale(${transform.scale}) translate(${transform.x}px, ${transform.y}px)`} style:transform-origin={`0 0`} bind:this={nodesContainer}>
<!-- Layers -->
{#each $nodeGraph.nodes.filter((node) => node.displayName === "Layer") as node (String(node.id))}
{#each $nodeGraph.nodes.flatMap((node, nodeIndex) => (node.displayName === "Layer" ? [{ node, nodeIndex }] : [])) as { node, nodeIndex } (String(node.id))}
{@const clipPathId = `${Math.random()}`.substring(2)}
{@const stackDatainput = node.exposedInputs[0]}
<div
@ -687,6 +691,7 @@
data-datatype={node.primaryInput?.dataType}
style:--data-color={`var(--color-data-${node.primaryInput?.dataType})`}
style:--data-color-dim={`var(--color-data-${node.primaryInput?.dataType}-dim)`}
bind:this={inputs[nodeIndex][0]}
>
<title>{node.primaryInput} data</title>
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" />
@ -705,6 +710,7 @@
data-datatype={node.primaryOutput.dataType}
style:--data-color={`var(--color-data-${node.primaryOutput.dataType})`}
style:--data-color-dim={`var(--color-data-${node.primaryOutput.dataType}-dim)`}
bind:this={outputs[nodeIndex][0]}
>
<title>{node.primaryOutput.dataType} data</title>
<path d="M0,2.953,2.521,1.259a2.649,2.649,0,0,1,2.959,0L8,2.953V8H0Z" />
@ -718,6 +724,7 @@
data-datatype={stackDatainput.dataType}
style:--data-color={`var(--color-data-${stackDatainput.dataType})`}
style:--data-color-dim={`var(--color-data-${stackDatainput.dataType}-dim)`}
bind:this={inputs[nodeIndex][1]}
>
<title>{stackDatainput.dataType} data</title>
<path d="M0,0H8V8L5.479,6.319a2.666,2.666,0,0,0-2.959,0L0,8Z" />
@ -737,7 +744,7 @@
</div>
{/each}
<!-- Nodes -->
{#each $nodeGraph.nodes.filter((node) => node.displayName !== "Layer") as node (String(node.id))}
{#each $nodeGraph.nodes.flatMap((node, nodeIndex) => (node.displayName !== "Layer" ? [{ node, nodeIndex }] : [])) as { node, nodeIndex } (String(node.id))}
{@const exposedInputsOutputs = [...node.exposedInputs, ...node.exposedOutputs]}
{@const clipPathId = `${Math.random()}`.substring(2)}
<div
@ -780,6 +787,7 @@
data-datatype={node.primaryInput?.dataType}
style:--data-color={`var(--color-data-${node.primaryInput?.dataType})`}
style:--data-color-dim={`var(--color-data-${node.primaryInput?.dataType}-dim)`}
bind:this={inputs[nodeIndex][0]}
>
<title>{node.primaryInput} data</title>
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" />
@ -795,6 +803,7 @@
data-datatype={parameter.dataType}
style:--data-color={`var(--color-data-${parameter.dataType})`}
style:--data-color-dim={`var(--color-data-${parameter.dataType}-dim)`}
bind:this={inputs[nodeIndex][index + 1]}
>
<title>{parameter.dataType} data</title>
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" />
@ -813,12 +822,13 @@
data-datatype={node.primaryOutput.dataType}
style:--data-color={`var(--color-data-${node.primaryOutput.dataType})`}
style:--data-color-dim={`var(--color-data-${node.primaryOutput.dataType}-dim)`}
bind:this={outputs[nodeIndex][0]}
>
<title>{node.primaryOutput.dataType} data</title>
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" />
</svg>
{/if}
{#each node.exposedOutputs as parameter}
{#each node.exposedOutputs as parameter, outputIndex}
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 8 8"
@ -827,6 +837,7 @@
data-datatype={parameter.dataType}
style:--data-color={`var(--color-data-${parameter.dataType})`}
style:--data-color-dim={`var(--color-data-${parameter.dataType}-dim)`}
bind:this={outputs[nodeIndex][outputIndex + 1]}
>
<title>{parameter.dataType} data</title>
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" />