mirror of
https://github.com/DayuanJiang/next-ai-draw-io.git
synced 2026-09-01 17:10:24 +08:00
feat(diagram-engine): connection vocabulary — arrowheads, parallel edges, edge ids
Arrowheads carry meaning: a crow's foot IS one-to-many, a hollow diamond IS aggregation. The engine allowed exactly one arrowhead; this opens the vocabulary the same way shapes were opened: - LinkSpec gains head/tail (pass-through to endArrow/startArrow, charset- gated against style injection) and headFill/tailFill — fill is written explicitly whenever a head is declared, because UML composition and aggregation differ ONLY by fill and draw.io's per-head default would flip the meaning. bold (4px amber, for THE key relationship) included. - Parallel edges: a second link between the same pair is allowed when it carries an id (ER's 'places' and 'cancels' between the same two entities); without one it stays an error, since two identical overlapping lines is a mistake. Edge ids are also what later operations address. - Sequence messages respect a declared head (an async message's open arrow is UML notation) while defaulting to the solid block as before. - draw_graph's edge schema extended to match; GraphEdge passes the new fields through to the link operations it generates. 5 new tests: crow's foot style emission, hollow-vs-filled round trip, injection rejection, parallel-edge gating, bold round trip. 561 unit tests green. ER+UML acceptance diagram (crow's foot, zero-to-one, hollow inheritance triangle, filled composition diamond) verified in the real editor.
This commit is contained in:
@@ -590,6 +590,18 @@ function edgeXml(
|
||||
let style = l.style ?? EDGE_STYLE
|
||||
if (!l.style) {
|
||||
if (l.dashed) style += "dashed=1;"
|
||||
// A bold link is a visual element, not a connector: thick amber with a filled
|
||||
// block head — the "this becomes that" arrow of a comparison.
|
||||
if (l.bold)
|
||||
style +=
|
||||
"strokeWidth=4;strokeColor=#D79B00;endArrow=block;endFill=1;endSize=6;"
|
||||
// Arrowhead vocabulary, passed through to draw.io. Fill is written whenever
|
||||
// the head is: UML composition vs aggregation differ ONLY by fill, so leaving
|
||||
// it to draw.io's per-head default would flip the meaning.
|
||||
if (l.head !== undefined)
|
||||
style += `endArrow=${l.head};endFill=${l.headFill ? 1 : 0};`
|
||||
if (l.tail !== undefined)
|
||||
style += `startArrow=${l.tail};startFill=${l.tailFill ? 1 : 0};`
|
||||
if (label) style += "labelBackgroundColor=light-dark(#FFFFFF,#0B0F14);"
|
||||
}
|
||||
if (route)
|
||||
@@ -646,7 +658,14 @@ function messageXml(
|
||||
const self = l.source === l.target
|
||||
let style = l.style ?? EDGE_STYLE
|
||||
if (!l.style) {
|
||||
style += "endArrow=block;endFill=1;html=1;"
|
||||
// The declared head wins over the sequence default: an async message drawn
|
||||
// with an open arrow is UML notation, not decoration.
|
||||
style +=
|
||||
l.head !== undefined
|
||||
? `endArrow=${l.head};endFill=${l.headFill ? 1 : 0};html=1;`
|
||||
: "endArrow=block;endFill=1;html=1;"
|
||||
if (l.tail !== undefined)
|
||||
style += `startArrow=${l.tail};startFill=${l.tailFill ? 1 : 0};`
|
||||
if (l.dashed) style += "dashed=1;"
|
||||
style += "labelBackgroundColor=light-dark(#FFFFFF,#0B0F14);"
|
||||
style += self ? "edgeStyle=orthogonalEdgeStyle;" : "edgeStyle=none;"
|
||||
|
||||
Reference in New Issue
Block a user