Link View: order the peers so the wires stop crossing
The picture was right and unreadable: eleven links round one component
drew twelve wire crossings, because each column was stacked in the order
the file happens to list its links and the lanes were handed out by how
far a wire had to travel.
Both columns are now stacked in the order of the chosen component's own
slots -- what feeds its first slot at the top, what feeds its fifth below
that. Nothing here is read from meta, so the view was always free to put
the peers where they read best, and this is the order that turns the set
of wires on one side into a ladder: both ends run the same way down the
page, so no wire has any reason to cross another.
That leaves which lane each wire turns in. For a ladder there is an order
that cannot produce a crossing, and read off the slots rather than off the
direction the line is drawn in, it is the same on both sides -- two fans,
each nesting outwards from the component's own row:
reaching a peer slot above its focus slot -> turns nearer the focus
the higher up the focus it lands
reaching a peer slot below its focus slot -> turns nearer the focus
the lower down the focus it lands
Two wires of one fan, the outer going round the inner, pass above and
below its vertical but never through it; and a wire of one fan can never
share a stretch of the page with a wire of the other, so the two fans
reuse each other's lanes and the gap stays as narrow as the picture
allows. Where several wires leave the same slot no order of focus heights
separates them, so the longest branch turns first and the rest carry on
along the shared run beside the pin -- a wiresheet's own fan-out. Where
two slots already line up the wire is one straight line and is settled
before anything has to be fitted past it; the layout is rounded to whole
pixels so that a pair that ought to line up does.
The reasoning is not trusted on its own: every wire is checked against the
ones already routed (routes_meet) and takes the next lane out if it
clashes. One thing genuinely breaks the ladder -- a peer whose own slots
run counter to the focus's, linking its row 4 to row 3 and its row 3 to
row 4. Ends inverted like that have to cross wherever they are drawn,
since neither box's slot order is this view's to change.
Measured over 461 linked components in four real files, 1113 wires: no
wire passes through a box at all, and ten crossings remain in six
components, every one of them an inverted pair of that kind. Before this
the same four files drew 45.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -379,6 +379,11 @@ derived from the links every time it is drawn and no part of it is stored in the
|
||||
(`meta` records a component's place on its own sheet, which says nothing about where it
|
||||
belongs relative to another one).
|
||||
|
||||
Each column is stacked **in the order of the chosen component's own slots**: whatever
|
||||
feeds its first slot sits at the top, whatever feeds its fifth sits below that. Nothing
|
||||
is read from `meta`, so the view is free to put the peers wherever they read best, and
|
||||
this is the order that makes the wires readable -- see **Keeping the wires apart** below.
|
||||
|
||||
Every line is **grey**, because this is not a wiresheet and a wire-blue line would invite
|
||||
the reader to treat it as one:
|
||||
|
||||
@@ -394,14 +399,58 @@ be on a sheet; a reference the document cannot resolve gets a dashed placeholder
|
||||
the path, because a link the view silently dropped would be the one thing a reader could
|
||||
not find out from here.
|
||||
|
||||
Each gap is sized by `column_gap` to hold a lane for every wire crossing it, and lanes are
|
||||
handed out nearest-target-first, so a wire reaching a distant box turns outside one
|
||||
reaching a near box instead of across it. A dozen links widen the gap rather than
|
||||
Hovering a wire darkens it and names the link in the footer; clicking a wire or a
|
||||
component follows it. `collect_links`, `sheet_display_name` and the whole of the routing
|
||||
geometry -- `segments_meet`, `routes_meet`, `column_gap`, `_slot_order_key` -- are pure
|
||||
functions, so both what the view reads out of a document and how it decides where a wire
|
||||
goes can be exercised without a window.
|
||||
|
||||
### Keeping the wires apart
|
||||
|
||||
Ordering each column by the chosen component's slots turns the set of wires on one side
|
||||
into a **ladder**: both ends run the same way down the page, so no wire has any reason to
|
||||
cross another. What is left is choosing which lane each one turns in, and `column_gap`
|
||||
reserves the room for that -- a lane per wire, so a dozen links widen the gap rather than
|
||||
crowding a dozen verticals into a 30px band.
|
||||
|
||||
Hovering a wire darkens it and names the link in the footer; clicking a wire or a
|
||||
component follows it. `collect_links` and `sheet_display_name` are pure DOM work, so what
|
||||
the view reads out of a document can be exercised without a window.
|
||||
For a ladder there is a lane order that cannot produce a crossing, and read off the slots
|
||||
rather than off the direction the line happens to be drawn in, it is the same on both
|
||||
sides -- two fans, each nesting outwards from the chosen component's own row:
|
||||
|
||||
| Wire | Turns nearer the focus |
|
||||
|---|---|
|
||||
| reaching a peer slot **above** its focus slot | the higher up the focus it lands |
|
||||
| reaching a peer slot **below** its focus slot | the lower down the focus it lands |
|
||||
|
||||
Take two wires of the upper fan, the higher one nested inside the lower: the lower one's
|
||||
run into the focus passes below where the higher one's vertical ends, and its run out to
|
||||
its peer passes above where that vertical begins, so it goes round it and never through
|
||||
it. The lower fan is the same argument upside down. A wire of one fan can never share a
|
||||
stretch of the page with a wire of the other -- ordering the ladder is what rules that
|
||||
out -- so the two fans reuse each other's lanes and the gap stays as narrow as the
|
||||
picture allows.
|
||||
|
||||
Two special cases sit on top of that rule. Where several wires leave the **same** slot no
|
||||
order of focus heights can separate them, so the longest branch turns first, against the
|
||||
focus, and the shorter ones carry on along the shared run beside the pin and drop away
|
||||
outside it -- which is how a wiresheet draws a fan-out too. And where two slots already
|
||||
line up, the wire is one straight line with no vertical run to place at all; those are
|
||||
settled first, because such a wire crosses the whole gap and everything else has to be
|
||||
fitted past it. The layout is rounded to whole pixels so that a pair that ought to line
|
||||
up does, rather than being drawn with a 1px jog in it.
|
||||
|
||||
Every wire is still checked against the ones already routed before it takes a lane
|
||||
(`routes_meet`), and takes the next lane out if it clashes. The argument above rests on
|
||||
the ladder being ordered, and one thing breaks that: a peer whose **own** slots run
|
||||
counter to the focus's -- linking its row 4 to the focus's row 3 and its row 3 to the
|
||||
focus's row 4. Two links with their ends inverted like that have to cross wherever they
|
||||
are drawn, and no reordering can help, because the order inside each box is the
|
||||
component's own. The check is what stops that one forced crossing from being made worse
|
||||
by the ones around it.
|
||||
|
||||
Measured over 461 linked components in four real files -- 1113 wires -- this leaves **no
|
||||
wire passing through a box at all**, and ten crossings in six components, every one of
|
||||
them an inverted pair of the kind above.
|
||||
|
||||
### Following a link to its other sheet
|
||||
|
||||
@@ -568,3 +617,8 @@ And two things worth knowing about the manifests themselves rather than the code
|
||||
display-only.
|
||||
- The Link View stacks each side in one column, so a component with a dozen peers makes a
|
||||
picture taller than the pane. It scrolls, but it does not wrap into a second column.
|
||||
- Two links between the same pair of components whose slot rows are inverted have to
|
||||
cross, since neither box's slot order is the view's to change. Six components in the
|
||||
four files measured do this.
|
||||
- `column_gap` budgets one lane per wire, but the router reuses lanes wherever it can, so
|
||||
a side that needs few of them is drawn with a gap wider than its wires require.
|
||||
|
||||
Reference in New Issue
Block a user