Graph: optionales Grid-Snapping beim Ziehen von Nodes
Ein Toggle in der Graph-Kopfzeile lässt gezogene Nodes auf dem 24er-Raster einrasten – derselben Größe, die den Hintergrund zeichnet. Einschalten bewegt nichts; die Regel greift erst beim nächsten Zug. Bei Mehrfachauswahl richtet sich jeder Node für sich aus, statt einem gemeinsamen Versatz zu folgen, der die alten krummen Abstände mitschleppen würde. Die Entscheidung liegt als reine Funktion in framing.ts, wo die übrige Graph-Geometrie schon wohnt, und ist dort wie im Browser gepinnt.
This commit is contained in:
1 parent
10d030376a
commit
4b47741fac
9 files changed
+187
-14
No files matched your search
@@ -60,11 +60,12 @@ import {
|
||||
foldMarkLabel,
|
||||
foldMarkRadius,
|
||||
} from './folding';
|
||||
import { type Box, boxesInBand, frameBoxes } from '../framing';
|
||||
import { type Box, boxesInBand, dragOffset, frameBoxes } from '../framing';
|
||||
import { NodePalette } from './NodePalette';
|
||||
import { type PaletteEntry, paletteEntries } from './paletteEntries';
|
||||
import { NODE_WIDTH, NodeView, portColor, TITLE_HEIGHT } from './NodeView';
|
||||
|
||||
/** Spacing of the background grid – and, with snapping on, of the positions a drag can leave. */
|
||||
const GRID_STEP = 24;
|
||||
/** Below this on-screen spacing the grid is noise rather than orientation, so it is dropped. */
|
||||
const MIN_GRID_STEP = 8;
|
||||
@@ -126,6 +127,7 @@ export class GraphCanvas extends Widget {
|
||||
pointer: { x: number; y: number };
|
||||
moved: boolean;
|
||||
} | null = null;
|
||||
private snapping = false;
|
||||
/** A rubber-band selection in progress, in graph coordinates. */
|
||||
private marquee: {
|
||||
start: { x: number; y: number };
|
||||
@@ -199,6 +201,15 @@ export class GraphCanvas extends Widget {
|
||||
this.fitView();
|
||||
}
|
||||
|
||||
/** Takes effect on the next drag only – turning it on must not shuffle the graph. */
|
||||
setSnapping(on: boolean): void {
|
||||
this.snapping = on;
|
||||
}
|
||||
|
||||
get snapEnabled(): boolean {
|
||||
return this.snapping;
|
||||
}
|
||||
|
||||
/** Drops the node in the middle of the view, since a button press names no position. */
|
||||
addNodeFrom(anchor: Widget): void {
|
||||
if (!this.assetId || this.state.mode !== 'edit') return;
|
||||
@@ -416,11 +427,13 @@ export class GraphCanvas extends Widget {
|
||||
this.dragging.moved = true;
|
||||
const graph = this.asset()?.graph;
|
||||
if (!graph) return;
|
||||
const step = this.snapping ? GRID_STEP : 0;
|
||||
for (const item of this.dragging.items) {
|
||||
const node = graph.nodes.find((n) => n.id === item.nodeId);
|
||||
if (!node) continue;
|
||||
node.x = Math.round(item.start.x + dx);
|
||||
node.y = Math.round(item.start.y + dy);
|
||||
const offset = dragOffset(item.start, dx, dy, step);
|
||||
node.x = item.start.x + offset.x;
|
||||
node.y = item.start.y + offset.y;
|
||||
}
|
||||
this.state.preview();
|
||||
} else if (this.connecting) {
|
||||
|
||||
Reference in new issue
Block a user