feat: don't move graph on right click drag

This commit is contained in:
Felix Hungenberg
2026-01-22 23:26:26 +01:00
parent a58b19e935
commit 3e019e4e21
4 changed files with 74 additions and 61 deletions

View File

@@ -58,7 +58,9 @@ export class GraphState {
wrapper = $state<HTMLDivElement>(null!); wrapper = $state<HTMLDivElement>(null!);
rect: DOMRect = $derived( rect: DOMRect = $derived(
(this.wrapper && this.width && this.height) ? this.wrapper.getBoundingClientRect() : new DOMRect(0, 0, 0, 0) (this.wrapper && this.width && this.height)
? this.wrapper.getBoundingClientRect()
: new DOMRect(0, 0, 0, 0)
); );
camera = $state<OrthographicCamera>(null!); camera = $state<OrthographicCamera>(null!);
@@ -333,4 +335,8 @@ export class GraphState {
&& node.position[1] < this.cameraBounds[3] && node.position[1] < this.cameraBounds[3]
); );
} }
openNodePalette() {
this.addMenuPosition = [this.mousePosition[0], this.mousePosition[1]];
}
} }

View File

@@ -1,23 +1,23 @@
<script lang="ts"> <script lang="ts">
import type { Edge, NodeInstance } from "@nodarium/types"; import type { Edge, NodeInstance } from '@nodarium/types';
import { createKeyMap } from "../../helpers/createKeyMap"; import { Canvas } from '@threlte/core';
import AddMenu from "../components/AddMenu.svelte"; import { HTML } from '@threlte/extras';
import Background from "../background/Background.svelte"; import { createKeyMap } from '../../helpers/createKeyMap';
import BoxSelection from "../components/BoxSelection.svelte"; import Background from '../background/Background.svelte';
import EdgeEl from "../edges/Edge.svelte"; import AddMenu from '../components/AddMenu.svelte';
import NodeEl from "../node/Node.svelte"; import BoxSelection from '../components/BoxSelection.svelte';
import Camera from "../components/Camera.svelte"; import Camera from '../components/Camera.svelte';
import { Canvas } from "@threlte/core"; import HelpView from '../components/HelpView.svelte';
import HelpView from "../components/HelpView.svelte"; import Debug from '../debug/Debug.svelte';
import { getGraphManager, getGraphState } from "../graph-state.svelte"; import EdgeEl from '../edges/Edge.svelte';
import { HTML } from "@threlte/extras"; import { getGraphManager, getGraphState } from '../graph-state.svelte';
import { maxZoom, minZoom } from "./constants"; import NodeEl from '../node/Node.svelte';
import Debug from "../debug/Debug.svelte"; import { maxZoom, minZoom } from './constants';
import { FileDropEventManager } from "./drop.events"; import { FileDropEventManager } from './drop.events';
import { MouseEventManager } from "./mouse.events"; import { MouseEventManager } from './mouse.events';
const { const {
keymap, keymap
}: { }: {
keymap: ReturnType<typeof createKeyMap>; keymap: ReturnType<typeof createKeyMap>;
} = $props(); } = $props();
@@ -45,19 +45,18 @@
const newNode = graph.createNode({ const newNode = graph.createNode({
type: node.type, type: node.type,
position: node.position, position: node.position,
props: node.props, props: node.props
}); });
if (!newNode) return; if (!newNode) return;
if (graphState.activeSocket) { if (graphState.activeSocket) {
if (typeof graphState.activeSocket.index === "number") { if (typeof graphState.activeSocket.index === 'number') {
const socketType = const socketType = graphState.activeSocket.node.state?.type?.outputs?.[
graphState.activeSocket.node.state?.type?.outputs?.[
graphState.activeSocket.index graphState.activeSocket.index
]; ];
const input = Object.entries(newNode?.state?.type?.inputs || {}).find( const input = Object.entries(newNode?.state?.type?.inputs || {}).find(
(inp) => inp[1].type === socketType, (inp) => inp[1].type === socketType
); );
if (input) { if (input) {
@@ -65,12 +64,11 @@
graphState.activeSocket.node, graphState.activeSocket.node,
graphState.activeSocket.index, graphState.activeSocket.index,
newNode, newNode,
input[0], input[0]
); );
} }
} else { } else {
const socketType = const socketType = graphState.activeSocket.node.state?.type?.inputs?.[
graphState.activeSocket.node.state?.type?.inputs?.[
graphState.activeSocket.index graphState.activeSocket.index
]; ];
@@ -85,7 +83,7 @@
newNode, newNode,
output.indexOf(output), output.indexOf(output),
graphState.activeSocket.node, graphState.activeSocket.node,
graphState.activeSocket.index, graphState.activeSocket.index
); );
} }
} }
@@ -97,15 +95,15 @@
</script> </script>
<svelte:window <svelte:window
onmousemove={(ev) => mouseEvents.handleMouseMove(ev)} onmousemove={(ev) => mouseEvents.handleWindowMouseMove(ev)}
onmouseup={(ev) => mouseEvents.handleMouseUp(ev)} onmouseup={(ev) => mouseEvents.handleWindowMouseUp(ev)}
/> />
<div <div
onwheel={(ev) => mouseEvents.handleMouseScroll(ev)} onwheel={(ev) => mouseEvents.handleMouseScroll(ev)}
bind:this={graphState.wrapper} bind:this={graphState.wrapper}
class="graph-wrapper" class="graph-wrapper"
style="height: 100%;" style="height: 100%"
class:is-panning={graphState.isPanning} class:is-panning={graphState.isPanning}
class:is-hovering={graphState.hoveredNodeId !== -1} class:is-hovering={graphState.hoveredNodeId !== -1}
aria-label="Graph" aria-label="Graph"
@@ -115,6 +113,7 @@
bind:clientHeight={graphState.height} bind:clientHeight={graphState.height}
onkeydown={(ev) => keymap.handleKeyboardEvent(ev)} onkeydown={(ev) => keymap.handleKeyboardEvent(ev)}
onmousedown={(ev) => mouseEvents.handleMouseDown(ev)} onmousedown={(ev) => mouseEvents.handleMouseDown(ev)}
oncontextmenu={(ev) => mouseEvents.handleContextMenu(ev)}
{...fileDropEvents.getEventListenerProps()} {...fileDropEvents.getEventListenerProps()}
> >
<input <input
@@ -147,20 +146,18 @@
<BoxSelection <BoxSelection
cameraPosition={graphState.cameraPosition} cameraPosition={graphState.cameraPosition}
p1={{ p1={{
x: x: graphState.cameraPosition[0]
graphState.cameraPosition[0] + + (graphState.mouseDown[0] - graphState.width / 2)
(graphState.mouseDown[0] - graphState.width / 2) / / graphState.cameraPosition[2],
graphState.cameraPosition[2], y: graphState.cameraPosition[1]
y: + (graphState.mouseDown[1] - graphState.height / 2)
graphState.cameraPosition[1] + / graphState.cameraPosition[2]
(graphState.mouseDown[1] - graphState.height / 2) /
graphState.cameraPosition[2],
}} }}
p2={{ x: graphState.mousePosition[0], y: graphState.mousePosition[1] }} p2={{ x: graphState.mousePosition[0], y: graphState.mousePosition[1] }}
/> />
{/if} {/if}
{#if graph.status === "idle"} {#if graph.status === 'idle'}
{#if graphState.addMenuPosition} {#if graphState.addMenuPosition}
<AddMenu onnode={handleNodeCreation} /> <AddMenu onnode={handleNodeCreation} />
{/if} {/if}
@@ -207,9 +204,9 @@
{/each} {/each}
</div> </div>
</HTML> </HTML>
{:else if graph.status === "loading"} {:else if graph.status === 'loading'}
<span>Loading</span> <span>Loading</span>
{:else if graph.status === "error"} {:else if graph.status === 'error'}
<span>Error</span> <span>Error</span>
{/if} {/if}
</Canvas> </Canvas>

View File

@@ -1,7 +1,7 @@
import { animate, lerp } from '$lib/helpers'; import { animate, lerp } from '$lib/helpers';
import { type NodeInstance } from '@nodarium/types'; import { type NodeInstance } from '@nodarium/types';
import type { GraphManager } from '../graph-manager.svelte'; import type { GraphManager } from '../graph-manager.svelte';
import type { GraphState } from '../graph-state.svelte'; import { type GraphState } from '../graph-state.svelte';
import { snapToGrid as snapPointToGrid } from '../helpers'; import { snapToGrid as snapPointToGrid } from '../helpers';
import { maxZoom, minZoom, zoomSpeed } from './constants'; import { maxZoom, minZoom, zoomSpeed } from './constants';
import { EdgeInteractionManager } from './edge.events'; import { EdgeInteractionManager } from './edge.events';
@@ -16,7 +16,7 @@ export class MouseEventManager {
this.edgeInteractionManager = new EdgeInteractionManager(graph, state); this.edgeInteractionManager = new EdgeInteractionManager(graph, state);
} }
handleMouseUp(event: MouseEvent) { handleWindowMouseUp(event: MouseEvent) {
this.edgeInteractionManager.handleMouseUp(); this.edgeInteractionManager.handleMouseUp();
this.state.isPanning = false; this.state.isPanning = false;
if (!this.state.mouseDown) return; if (!this.state.mouseDown) return;
@@ -151,7 +151,19 @@ export class MouseEventManager {
this.state.addMenuPosition = null; this.state.addMenuPosition = null;
} }
handleContextMenu(event: MouseEvent) {
if (!this.state.addMenuPosition) {
event.preventDefault();
this.state.openNodePalette();
}
}
handleMouseDown(event: MouseEvent) { handleMouseDown(event: MouseEvent) {
// Right click
if (event.button === 2) {
return;
}
if (this.state.mouseDown) return; if (this.state.mouseDown) return;
this.state.edgeEndPosition = null; this.state.edgeEndPosition = null;
@@ -229,7 +241,7 @@ export class MouseEventManager {
this.state.edgeEndPosition = null; this.state.edgeEndPosition = null;
} }
handleMouseMove(event: MouseEvent) { handleWindowMouseMove(event: MouseEvent) {
let mx = event.clientX - this.state.rect.x; let mx = event.clientX - this.state.rect.x;
let my = event.clientY - this.state.rect.y; let my = event.clientY - this.state.rect.y;

View File

@@ -59,9 +59,7 @@ export function setupKeymaps(keymap: Keymap, graph: GraphManager, graphState: Gr
key: 'A', key: 'A',
shift: true, shift: true,
description: 'Add new Node', description: 'Add new Node',
callback: () => { callback: () => graphState.openNodePalette()
graphState.addMenuPosition = [graphState.mousePosition[0], graphState.mousePosition[1]];
}
}); });
keymap.addShortcut({ keymap.addShortcut({