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
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { boundsOf, type Box, boxesInBand, frameBoxes } from '../../src/editor/framing';
|
||||
import { boundsOf, type Box, boxesInBand, dragOffset, frameBoxes } from '../../src/editor/framing';
|
||||
|
||||
const LIMITS = { min: 0.25, max: 2.5 };
|
||||
|
||||
@@ -28,6 +28,39 @@ describe('rubber band', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('drag offset', () => {
|
||||
const STEP = 24;
|
||||
|
||||
it('rounds to whole pixels without snapping', () => {
|
||||
expect(dragOffset({ x: 10, y: 10 }, 12.4, -7.6, 0)).toEqual({ x: 12, y: -8 });
|
||||
});
|
||||
|
||||
it('puts a dragged node on the grid, wherever it started', () => {
|
||||
// Started off-grid at 10: the drop is a multiple of 24, not 10 plus a multiple.
|
||||
const off = dragOffset({ x: 10, y: 10 }, 50, 50, STEP);
|
||||
expect({ x: 10 + off.x, y: 10 + off.y }).toEqual({ x: 72, y: 72 });
|
||||
});
|
||||
|
||||
it('gives two differently placed nodes different offsets, so both land on the grid', () => {
|
||||
// The same gesture over a selection: 10 and 17 are 7 apart and both end up on a grid line.
|
||||
const a = dragOffset({ x: 10, y: 0 }, 50, 0, STEP);
|
||||
const b = dragOffset({ x: 17, y: 0 }, 50, 0, STEP);
|
||||
expect(a.x).not.toBe(b.x);
|
||||
expect(10 + a.x).toBe(72);
|
||||
expect(17 + b.x).toBe(72);
|
||||
});
|
||||
|
||||
it('takes the nearest grid line, in both directions', () => {
|
||||
expect(dragOffset({ x: 0, y: 0 }, 11, 13, STEP)).toEqual({ x: 0, y: 24 });
|
||||
expect(dragOffset({ x: 0, y: 0 }, -11, -13, STEP)).toEqual({ x: 0, y: -24 });
|
||||
});
|
||||
|
||||
it('still moves a node that starts on the grid', () => {
|
||||
// A snapped drag shorter than half a step is the one case that could deadlock into "no move".
|
||||
expect(dragOffset({ x: 48, y: 48 }, 20, 4, STEP)).toEqual({ x: 24, y: 0 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('fit', () => {
|
||||
/** Where a graph point lands on screen under a framing. */
|
||||
const toScreen = (f: { zoom: number; panX: number; panY: number }, x: number, y: number) => ({
|
||||
|
||||
Reference in new issue
Block a user