A state can transition to itself: make transition and a second click on the same state connects a self transition, taking it fires On state exited and then On state entered every time, for local and global machines, while Set state into the current state stays silent as before; only states may connect to themselves, every other node is still refused, one self transition per state; the loop is drawn over the middle of the top edge with its arrow pointing down and its name at the apex, the preview already shows it while armed, and the inspector lists it once under Transitions out; new test hook transitionLabelAt, e2e 26e5 (#163)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
cc285af10a
commit
010b6a7f6c
12 files changed
+355
-33
No files matched your search
@@ -67,6 +67,44 @@ export function transitionEnds(from: Rect, to: Rect, offset = 0): { start: Point
|
||||
};
|
||||
}
|
||||
|
||||
/** How far apart a self-loop's two ends sit on the node's top edge, and how high it rises. */
|
||||
const LOOP_SPREAD = 14;
|
||||
const LOOP_RISE = 44;
|
||||
|
||||
/** A transition from a state back into itself: one cubic curve over the node's top edge. */
|
||||
export interface Loop {
|
||||
start: Point;
|
||||
c1: Point;
|
||||
c2: Point;
|
||||
end: Point;
|
||||
}
|
||||
|
||||
/**
|
||||
* The loop over the middle of the box, left end out and right end in, both `BORDER_GAP` clear of
|
||||
* the border like every other transition. The control points lean outwards, so the curve bulges
|
||||
* wider than its feet and reads as a loop rather than a hump.
|
||||
*/
|
||||
export function selfLoop(box: Rect): Loop {
|
||||
const x = box.x + box.w / 2;
|
||||
const y = box.y - BORDER_GAP;
|
||||
return {
|
||||
start: { x: x - LOOP_SPREAD, y },
|
||||
c1: { x: x - LOOP_SPREAD * 2.5, y: y - LOOP_RISE },
|
||||
c2: { x: x + LOOP_SPREAD * 2.5, y: y - LOOP_RISE },
|
||||
end: { x: x + LOOP_SPREAD, y },
|
||||
};
|
||||
}
|
||||
|
||||
/** The point at `t` along the loop, 0 at its start and 1 at the arrow's tip. */
|
||||
export function loopPoint(loop: Loop, t: number): Point {
|
||||
const u = 1 - t;
|
||||
const [a, b, c, d] = [u * u * u, 3 * u * u * t, 3 * u * t * t, t * t * t];
|
||||
return {
|
||||
x: a * loop.start.x + b * loop.c1.x + c * loop.c2.x + d * loop.end.x,
|
||||
y: a * loop.start.y + b * loop.c1.y + c * loop.c2.y + d * loop.end.y,
|
||||
};
|
||||
}
|
||||
|
||||
/** One transition as the offsets care about it: which states it joins, under which edge id. */
|
||||
export interface TransitionLink {
|
||||
id: string;
|
||||
|
||||
Reference in new issue
Block a user