feat: implement imposters at large zoom scales
This commit is contained in:
parent
70d7c57e46
commit
05e13733e2
@ -1,10 +1,25 @@
|
|||||||
|
<script context="module">
|
||||||
|
const color = new Color(0x202020);
|
||||||
|
color.convertLinearToSRGB();
|
||||||
|
|
||||||
|
const color2 = color.clone();
|
||||||
|
color2.convertSRGBToLinear();
|
||||||
|
|
||||||
|
const circleMaterial = new MeshBasicMaterial({
|
||||||
|
color,
|
||||||
|
toneMapped: false,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { T, extend } from "@threlte/core";
|
import { T } from "@threlte/core";
|
||||||
import { MeshLineGeometry, MeshLineMaterial } from "@threlte/extras";
|
import { MeshLineGeometry, MeshLineMaterial } from "@threlte/extras";
|
||||||
import { Color, type Mesh } from "three";
|
import { MeshBasicMaterial, type Mesh, LineBasicMaterial } from "three";
|
||||||
|
import { Color } from "three/src/math/Color.js";
|
||||||
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 };
|
||||||
@ -70,9 +85,9 @@
|
|||||||
position.z={from.y}
|
position.z={from.y}
|
||||||
position.y={0.8}
|
position.y={0.8}
|
||||||
rotation.x={-Math.PI / 2}
|
rotation.x={-Math.PI / 2}
|
||||||
|
material={circleMaterial}
|
||||||
>
|
>
|
||||||
<T.CircleGeometry args={[0.3, 16]} />
|
<T.CircleGeometry args={[0.3, 16]} />
|
||||||
<T.MeshBasicMaterial {color} />
|
|
||||||
</T.Mesh>
|
</T.Mesh>
|
||||||
|
|
||||||
<T.Mesh
|
<T.Mesh
|
||||||
@ -80,12 +95,17 @@
|
|||||||
position.z={to.y}
|
position.z={to.y}
|
||||||
position.y={0.8}
|
position.y={0.8}
|
||||||
rotation.x={-Math.PI / 2}
|
rotation.x={-Math.PI / 2}
|
||||||
|
material={circleMaterial}
|
||||||
>
|
>
|
||||||
<T.CircleGeometry args={[0.3, 16]} />
|
<T.CircleGeometry args={[0.3, 16]} />
|
||||||
<T.MeshBasicMaterial {color} />
|
|
||||||
</T.Mesh>
|
</T.Mesh>
|
||||||
|
|
||||||
<T.Mesh position.y={0.5} bind:ref={mesh}>
|
<T.Mesh position.y={0.5} bind:ref={mesh}>
|
||||||
<MeshLineGeometry {points} />
|
<MeshLineGeometry {points} />
|
||||||
<MeshLineMaterial width={2} attenuate={false} {color} />
|
<MeshLineMaterial
|
||||||
|
width={4}
|
||||||
|
attenuate={false}
|
||||||
|
color={color2}
|
||||||
|
toneMapped={false}
|
||||||
|
/>
|
||||||
</T.Mesh>
|
</T.Mesh>
|
||||||
|
@ -103,7 +103,6 @@
|
|||||||
}
|
}
|
||||||
const height = 5 + 10 * Object.keys(node.inputs).length;
|
const height = 5 + 10 * Object.keys(node.inputs).length;
|
||||||
nodeHeightCache[nodeTypeId] = height;
|
nodeHeightCache[nodeTypeId] = height;
|
||||||
console.log(node, height);
|
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
setContext("getNodeHeight", getNodeHeight);
|
setContext("getNodeHeight", getNodeHeight);
|
||||||
@ -310,7 +309,9 @@
|
|||||||
|
|
||||||
const zoomSpeed = 2;
|
const zoomSpeed = 2;
|
||||||
function handleMouseScroll(event: WheelEvent) {
|
function handleMouseScroll(event: WheelEvent) {
|
||||||
const bodyIsFocused = document.activeElement === document.body;
|
const bodyIsFocused =
|
||||||
|
document.activeElement === document.body ||
|
||||||
|
document?.activeElement?.id === "graph";
|
||||||
if (!bodyIsFocused) return;
|
if (!bodyIsFocused) return;
|
||||||
|
|
||||||
// Define zoom speed and clamp it between -1 and 1
|
// Define zoom speed and clamp it between -1 and 1
|
||||||
@ -344,47 +345,71 @@
|
|||||||
cameraDown[0] = cameraPosition[0];
|
cameraDown[0] = cameraPosition[0];
|
||||||
cameraDown[1] = cameraPosition[1];
|
cameraDown[1] = cameraPosition[1];
|
||||||
|
|
||||||
if (event.target instanceof HTMLElement && event.buttons === 1) {
|
let clickedNodeId: number | undefined;
|
||||||
const nodeElement = event.target.closest(".node");
|
|
||||||
const _activeNodeId = nodeElement?.getAttribute?.("data-node-id");
|
if (event.buttons === 1) {
|
||||||
if (_activeNodeId) {
|
// check if the clicked element is a node
|
||||||
const nodeId = parseInt(_activeNodeId, 10);
|
if (event.target instanceof HTMLElement) {
|
||||||
if ($activeNodeId !== -1) {
|
const nodeElement = event.target.closest(".node");
|
||||||
// if the selected node is the same as the clicked node
|
const nodeId = nodeElement?.getAttribute?.("data-node-id");
|
||||||
if ($activeNodeId === nodeId) {
|
if (nodeId) {
|
||||||
//$activeNodeId = -1;
|
clickedNodeId = parseInt(nodeId, 10);
|
||||||
// if the clicked node is different from the selected node and secondary
|
|
||||||
} else if (event.ctrlKey) {
|
|
||||||
$selectedNodes = $selectedNodes || new Set();
|
|
||||||
$selectedNodes.add($activeNodeId);
|
|
||||||
$selectedNodes.delete(nodeId);
|
|
||||||
$activeNodeId = nodeId;
|
|
||||||
// select the node
|
|
||||||
} else if (event.shiftKey) {
|
|
||||||
const activeNode = graph.getNode($activeNodeId);
|
|
||||||
const newNode = graph.getNode(nodeId);
|
|
||||||
if (activeNode && newNode) {
|
|
||||||
const edge = graph.getNodesBetween(activeNode, newNode);
|
|
||||||
if (edge) {
|
|
||||||
const selected = new Set(edge.map((n) => n.id));
|
|
||||||
selected.delete(nodeId);
|
|
||||||
$selectedNodes = selected;
|
|
||||||
}
|
|
||||||
$activeNodeId = nodeId;
|
|
||||||
}
|
|
||||||
} else if (!$selectedNodes?.has(nodeId)) {
|
|
||||||
$activeNodeId = nodeId;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$activeNodeId = nodeId;
|
|
||||||
}
|
}
|
||||||
} else if (event.ctrlKey) {
|
|
||||||
boxSelection = true;
|
|
||||||
} else {
|
|
||||||
$activeNodeId = -1;
|
|
||||||
$selectedNodes?.clear();
|
|
||||||
$selectedNodes = $selectedNodes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we do not have an active node,
|
||||||
|
// we are going to check if we clicked on a node by coordinates
|
||||||
|
if (clickedNodeId === undefined) {
|
||||||
|
const [downX, downY] = projectScreenToWorld(
|
||||||
|
event.clientX,
|
||||||
|
event.clientY,
|
||||||
|
);
|
||||||
|
for (const node of $nodes.values()) {
|
||||||
|
const x = node.position.x;
|
||||||
|
const y = node.position.y;
|
||||||
|
const height = getNodeHeight(node.type);
|
||||||
|
if (downX > x && downX < x + 20 && downY > y && downY < y + height) {
|
||||||
|
clickedNodeId = node.id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we clicked on a node
|
||||||
|
if (clickedNodeId !== undefined) {
|
||||||
|
if ($activeNodeId === -1) {
|
||||||
|
$activeNodeId = clickedNodeId;
|
||||||
|
// if the selected node is the same as the clicked node
|
||||||
|
} else if ($activeNodeId === clickedNodeId) {
|
||||||
|
//$activeNodeId = -1;
|
||||||
|
// if the clicked node is different from the selected node and secondary
|
||||||
|
} else if (event.ctrlKey) {
|
||||||
|
$selectedNodes = $selectedNodes || new Set();
|
||||||
|
$selectedNodes.add($activeNodeId);
|
||||||
|
$selectedNodes.delete(clickedNodeId);
|
||||||
|
$activeNodeId = clickedNodeId;
|
||||||
|
// select the node
|
||||||
|
} else if (event.shiftKey) {
|
||||||
|
const activeNode = graph.getNode($activeNodeId);
|
||||||
|
const newNode = graph.getNode(clickedNodeId);
|
||||||
|
if (activeNode && newNode) {
|
||||||
|
const edge = graph.getNodesBetween(activeNode, newNode);
|
||||||
|
if (edge) {
|
||||||
|
const selected = new Set(edge.map((n) => n.id));
|
||||||
|
selected.add(clickedNodeId);
|
||||||
|
$selectedNodes = selected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!$selectedNodes?.has(clickedNodeId)) {
|
||||||
|
$activeNodeId = clickedNodeId;
|
||||||
|
}
|
||||||
|
} else if (event.ctrlKey) {
|
||||||
|
boxSelection = true;
|
||||||
|
} else {
|
||||||
|
$activeNodeId = -1;
|
||||||
|
$selectedNodes?.clear();
|
||||||
|
$selectedNodes = $selectedNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
const node = graph.getNode($activeNodeId);
|
const node = graph.getNode($activeNodeId);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import type { Edge as EdgeType, Node as NodeType } from "$lib/types";
|
import type { Edge as EdgeType, Node as NodeType } from "$lib/types";
|
||||||
import { HTML } from "@threlte/extras";
|
import { HTML } from "@threlte/extras";
|
||||||
import Edge from "../edges/Edge.svelte";
|
import Edge from "../edges/Edge.svelte";
|
||||||
import Node from "../Node.svelte";
|
import Node from "../node/Node.svelte";
|
||||||
import { getContext, onMount } from "svelte";
|
import { getContext, onMount } from "svelte";
|
||||||
import type { Writable } from "svelte/store";
|
import type { Writable } from "svelte/store";
|
||||||
import { activeSocket } from "./stores";
|
import { activeSocket } from "./stores";
|
||||||
@ -10,7 +10,8 @@
|
|||||||
export let nodes: Writable<Map<number, NodeType>>;
|
export let nodes: Writable<Map<number, NodeType>>;
|
||||||
export let edges: Writable<EdgeType[]>;
|
export let edges: Writable<EdgeType[]>;
|
||||||
|
|
||||||
export let cameraPosition = [0, 1, 0];
|
export let cameraPosition = [0, 0, 4];
|
||||||
|
$: console.log(cameraPosition[2]);
|
||||||
|
|
||||||
const isNodeInView = getContext<(n: NodeType) => boolean>("isNodeInView");
|
const isNodeInView = getContext<(n: NodeType) => boolean>("isNodeInView");
|
||||||
|
|
||||||
@ -54,6 +55,7 @@
|
|||||||
<HTML transform={false}>
|
<HTML transform={false}>
|
||||||
<div
|
<div
|
||||||
role="tree"
|
role="tree"
|
||||||
|
id="graph"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
class="wrapper"
|
class="wrapper"
|
||||||
class:zoom-small={cameraPosition[2] < 2}
|
class:zoom-small={cameraPosition[2] < 2}
|
||||||
|
67
frontend/src/lib/components/node/Node.frag
Normal file
67
frontend/src/lib/components/node/Node.frag
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
varying vec2 vUv;
|
||||||
|
|
||||||
|
uniform float uWidth;
|
||||||
|
uniform float uHeight;
|
||||||
|
|
||||||
|
uniform vec3 uColorDark;
|
||||||
|
uniform vec3 uColorBright;
|
||||||
|
uniform vec3 uSelectedColor;
|
||||||
|
uniform vec3 uActiveColor;
|
||||||
|
|
||||||
|
uniform bool uSelected;
|
||||||
|
uniform bool uActive;
|
||||||
|
|
||||||
|
uniform float uStrokeWidth;
|
||||||
|
|
||||||
|
float msign(in float x) { return (x < 0.0) ? -1.0 : 1.0; }
|
||||||
|
|
||||||
|
vec4 roundedBoxSDF( in vec2 p, in vec2 b, in float r, in float s) {
|
||||||
|
vec2 q = abs(p) - b + r;
|
||||||
|
float l = b.x + b.y + 1.570796 * r;
|
||||||
|
|
||||||
|
float k1 = min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;
|
||||||
|
float k2 = ((q.x > 0.0) ? atan(q.y, q.x) : 1.570796);
|
||||||
|
float k3 = 3.0 + 2.0 * msign(min(p.x, -p.y)) - msign(p.x);
|
||||||
|
float k4 = msign(p.x * p.y);
|
||||||
|
float k5 = r * k2 + max(-q.x, 0.0);
|
||||||
|
|
||||||
|
float ra = s * round(k1 / s);
|
||||||
|
float l2 = l + 1.570796 * ra;
|
||||||
|
|
||||||
|
return vec4(k1 - ra, k3 * l2 + k4 * (b.y + ((q.y > 0.0) ? k5 + k2 * ra : q.y)), 4.0 * l2, k1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
|
||||||
|
float y = (1.0-vUv.y) * uHeight;
|
||||||
|
float x = vUv.x * uWidth;
|
||||||
|
|
||||||
|
vec2 size = vec2(uWidth, uHeight);
|
||||||
|
vec2 uv = (vUv - 0.5) * 2.0;
|
||||||
|
|
||||||
|
float u_border_radius = 1.5;
|
||||||
|
vec4 distance = roundedBoxSDF(uv * size, size, u_border_radius*2.0, 0.0);
|
||||||
|
|
||||||
|
if (distance.w > 0.0 ) {
|
||||||
|
// outside
|
||||||
|
gl_FragColor = vec4(0.0,0.0,0.0, 0.0);
|
||||||
|
}else{
|
||||||
|
|
||||||
|
if (distance.w > -uStrokeWidth || mod(y+5.0, 10.0) < uStrokeWidth/2.0) {
|
||||||
|
// draw the outer stroke
|
||||||
|
if (uSelected) {
|
||||||
|
gl_FragColor = vec4(uSelectedColor, 1.0);
|
||||||
|
} else if (uActive) {
|
||||||
|
gl_FragColor = vec4(uActiveColor, 1.0);
|
||||||
|
} else {
|
||||||
|
gl_FragColor = vec4(uColorBright, 1.0);
|
||||||
|
}
|
||||||
|
}else if (y<5.0){
|
||||||
|
// draw the header
|
||||||
|
gl_FragColor = vec4(uColorBright, 1.0);
|
||||||
|
}else{
|
||||||
|
gl_FragColor = vec4(uColorDark, 1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,18 +3,23 @@
|
|||||||
import { getContext, onMount } from "svelte";
|
import { getContext, onMount } from "svelte";
|
||||||
import NodeHeader from "./NodeHeader.svelte";
|
import NodeHeader from "./NodeHeader.svelte";
|
||||||
import NodeParameter from "./NodeParameter.svelte";
|
import NodeParameter from "./NodeParameter.svelte";
|
||||||
import { activeNodeId, selectedNodes } from "./graph/stores";
|
import { activeNodeId, selectedNodes } from "../graph/stores";
|
||||||
import { T } from "@threlte/core";
|
import { T } from "@threlte/core";
|
||||||
import type { Mesh } from "three";
|
import { Color, type Mesh } from "three";
|
||||||
|
import NodeFrag from "./Node.frag";
|
||||||
|
import NodeVert from "./Node.vert";
|
||||||
|
|
||||||
export let node: Node;
|
export let node: Node;
|
||||||
export let inView = true;
|
export let inView = true;
|
||||||
export let z = 2;
|
export let z = 2;
|
||||||
|
|
||||||
|
$: isActive = $activeNodeId === node.id;
|
||||||
|
$: isSelected = !!$selectedNodes?.has(node.id);
|
||||||
|
|
||||||
const updateNodePosition =
|
const updateNodePosition =
|
||||||
getContext<(n: Node) => void>("updateNodePosition");
|
getContext<(n: Node) => void>("updateNodePosition");
|
||||||
|
|
||||||
const getNodeHeight = getContext<(n: Node) => number>("getNodeHeight");
|
const getNodeHeight = getContext<(n: string) => number>("getNodeHeight");
|
||||||
|
|
||||||
const type = node?.tmp?.type;
|
const type = node?.tmp?.type;
|
||||||
|
|
||||||
@ -24,7 +29,6 @@
|
|||||||
let meshRef: Mesh;
|
let meshRef: Mesh;
|
||||||
|
|
||||||
const height = getNodeHeight(node.type);
|
const height = getNodeHeight(node.type);
|
||||||
console.log(node.type, height);
|
|
||||||
|
|
||||||
$: if (node && ref && meshRef) {
|
$: if (node && ref && meshRef) {
|
||||||
node.tmp = node.tmp || {};
|
node.tmp = node.tmp || {};
|
||||||
@ -39,6 +43,13 @@
|
|||||||
node.tmp.mesh = meshRef;
|
node.tmp.mesh = meshRef;
|
||||||
updateNodePosition(node);
|
updateNodePosition(node);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const colorDark = new Color();
|
||||||
|
colorDark.setStyle("#151515");
|
||||||
|
//colorDark.();
|
||||||
|
|
||||||
|
const colorBright = new Color("#202020");
|
||||||
|
//colorBright.convertLinearToSRGB();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<T.Mesh
|
<T.Mesh
|
||||||
@ -47,16 +58,34 @@
|
|||||||
position.y={0.8}
|
position.y={0.8}
|
||||||
rotation.x={-Math.PI / 2}
|
rotation.x={-Math.PI / 2}
|
||||||
bind:ref={meshRef}
|
bind:ref={meshRef}
|
||||||
visible={true}
|
visible={z < 7}
|
||||||
>
|
>
|
||||||
<T.PlaneGeometry args={[20, height]} />
|
<T.PlaneGeometry args={[20, height]} radius={1} />
|
||||||
<T.MeshBasicMaterial color="#151515" />
|
<T.ShaderMaterial
|
||||||
|
vertexShader={NodeVert}
|
||||||
|
fragmentShader={NodeFrag}
|
||||||
|
transparent
|
||||||
|
uniforms={{
|
||||||
|
uColorBright: { value: colorBright },
|
||||||
|
uColorDark: { value: colorDark },
|
||||||
|
uSelectedColor: { value: new Color("#f2be90") },
|
||||||
|
uActiveColor: { value: new Color("white") },
|
||||||
|
uSelected: { value: false },
|
||||||
|
uActive: { value: false },
|
||||||
|
uStrokeWidth: { value: 1.0 },
|
||||||
|
uWidth: { value: 20 },
|
||||||
|
uHeight: { value: height },
|
||||||
|
}}
|
||||||
|
uniforms.uSelected.value={isSelected}
|
||||||
|
uniforms.uActive.value={isActive}
|
||||||
|
uniforms.uStrokeWidth.value={(7 - z) / 3}
|
||||||
|
/>
|
||||||
</T.Mesh>
|
</T.Mesh>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="node"
|
class="node"
|
||||||
class:active={$activeNodeId === node.id}
|
class:active={isActive}
|
||||||
class:selected={!!$selectedNodes?.has(node.id)}
|
class:selected={isSelected}
|
||||||
class:out-of-view={!inView}
|
class:out-of-view={!inView}
|
||||||
data-node-id={node.id}
|
data-node-id={node.id}
|
||||||
bind:this={ref}
|
bind:this={ref}
|
||||||
@ -84,7 +113,7 @@
|
|||||||
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");
|
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);
|
opacity: var(--input-opacity);
|
15
frontend/src/lib/components/node/Node.vert
Normal file
15
frontend/src/lib/components/node/Node.vert
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
varying vec2 vUv;
|
||||||
|
varying vec3 vPosition;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
|
||||||
|
vUv = uv;
|
||||||
|
|
||||||
|
vec4 modelPosition = modelMatrix * vec4(position, 1.0);
|
||||||
|
|
||||||
|
vec4 viewPosition = viewMatrix * modelPosition;
|
||||||
|
vec4 projectedPosition = projectionMatrix * viewPosition;
|
||||||
|
|
||||||
|
gl_Position = projectedPosition;
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,7 @@
|
|||||||
import Integer from "$lib/elements/Integer.svelte";
|
import Integer from "$lib/elements/Integer.svelte";
|
||||||
import Select from "$lib/elements/Select.svelte";
|
import Select from "$lib/elements/Select.svelte";
|
||||||
import type { Node, NodeInput } from "$lib/types";
|
import type { Node, NodeInput } from "$lib/types";
|
||||||
import { getGraphManager } from "./graph/context";
|
import { getGraphManager } from "../graph/context";
|
||||||
|
|
||||||
export let node: Node;
|
export let node: Node;
|
||||||
export let input: NodeInput;
|
export let input: NodeInput;
|
@ -3,9 +3,9 @@
|
|||||||
import type { Node } from "$lib/types";
|
import type { Node } from "$lib/types";
|
||||||
import { getContext } from "svelte";
|
import { getContext } from "svelte";
|
||||||
import { createNodePath } from "$lib/helpers";
|
import { createNodePath } from "$lib/helpers";
|
||||||
import { possibleSocketIds } from "./graph/stores";
|
import { possibleSocketIds } from "../graph/stores";
|
||||||
|
import { getGraphManager } from "../graph/context";
|
||||||
import NodeInput from "./NodeInput.svelte";
|
import NodeInput from "./NodeInput.svelte";
|
||||||
import { getGraphManager } from "./graph/context";
|
|
||||||
|
|
||||||
export let node: Node;
|
export let node: Node;
|
||||||
export let input: NodeInputType;
|
export let input: NodeInputType;
|
||||||
@ -143,7 +143,6 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
opacity: var(--input-opacity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.zoom-small) .content {
|
:global(.zoom-small) .content {
|
@ -140,9 +140,11 @@ export class GraphManager extends EventEmitter<{ "save": Graph }> {
|
|||||||
// < - - - - from - - - - to
|
// < - - - - from - - - - to
|
||||||
const fromParents = this.getParentsOfNode(from);
|
const fromParents = this.getParentsOfNode(from);
|
||||||
if (toParents.includes(from)) {
|
if (toParents.includes(from)) {
|
||||||
return toParents.splice(toParents.indexOf(from));
|
const fromChildren = this.getChildrenOfNode(from);
|
||||||
|
return toParents.filter(n => fromChildren.includes(n));
|
||||||
} else if (fromParents.includes(to)) {
|
} else if (fromParents.includes(to)) {
|
||||||
return [...fromParents.splice(fromParents.indexOf(to)), from];
|
const toChildren = this.getChildrenOfNode(to);
|
||||||
|
return fromParents.filter(n => toChildren.includes(n));
|
||||||
} else {
|
} else {
|
||||||
// these two nodes are not connected
|
// these two nodes are not connected
|
||||||
return;
|
return;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
import Graph from "$lib/components/graph/Graph.svelte";
|
import Graph from "$lib/components/graph/Graph.svelte";
|
||||||
import { MemoryRuntimeExecutor } from "$lib/runtime-executor";
|
import { MemoryRuntimeExecutor } from "$lib/runtime-executor";
|
||||||
import { MemoryNodeRegistry } from "$lib/node-registry";
|
import { MemoryNodeRegistry } from "$lib/node-registry";
|
||||||
|
import { LinearSRGBColorSpace } from "three";
|
||||||
|
|
||||||
const nodeRegistry = new MemoryNodeRegistry();
|
const nodeRegistry = new MemoryNodeRegistry();
|
||||||
const runtimeExecutor = new MemoryRuntimeExecutor(nodeRegistry);
|
const runtimeExecutor = new MemoryRuntimeExecutor(nodeRegistry);
|
||||||
@ -14,7 +15,7 @@
|
|||||||
if (graph) {
|
if (graph) {
|
||||||
graphManager.load(JSON.parse(graph));
|
graphManager.load(JSON.parse(graph));
|
||||||
} else {
|
} else {
|
||||||
graphManager.load(graphManager.createTemplate("grid", 10, 10));
|
graphManager.load(graphManager.createTemplate("tree", 5));
|
||||||
}
|
}
|
||||||
|
|
||||||
graphManager.on("save", (graph) => {
|
graphManager.on("save", (graph) => {
|
||||||
@ -47,7 +48,12 @@
|
|||||||
<!-- </div> -->
|
<!-- </div> -->
|
||||||
|
|
||||||
<div id="canvas-wrapper">
|
<div id="canvas-wrapper">
|
||||||
<Canvas shadows={false} renderMode="on-demand" colorManagementEnabled={false}>
|
<Canvas
|
||||||
|
shadows={false}
|
||||||
|
renderMode="on-demand"
|
||||||
|
colorManagementEnabled={false}
|
||||||
|
colorSpace={LinearSRGBColorSpace}
|
||||||
|
>
|
||||||
<!-- <PerfMonitor /> -->
|
<!-- <PerfMonitor /> -->
|
||||||
<Graph graph={graphManager} bind:debug />
|
<Graph graph={graphManager} bind:debug />
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
Loading…
Reference in New Issue
Block a user