diff --git a/cypress/integration/rendering/sequencediagram-v2.spec.js b/cypress/integration/rendering/sequencediagram-v2.spec.js index 42db4001d..9fe3dd8c0 100644 --- a/cypress/integration/rendering/sequencediagram-v2.spec.js +++ b/cypress/integration/rendering/sequencediagram-v2.spec.js @@ -776,5 +776,834 @@ describe('Sequence Diagram Special Cases', () => { ); }); }); + describe('Sequence Diagram Rendering with Autonumber and All Arrow Types', () => { + describe('Autonumber with All Arrow Types', () => { + it('should render all arrow types with autonumbering', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + Alice->>Bob: Solid arrow (->>) + Bob-->>Alice: Dotted arrow (-->>) + Alice->Charlie: Solid open arrow (->) + Charlie-->Dave: Dotted open arrow (-->) + Alice-xBob: Solid cross (-x) + Bob--xAlice: Dotted cross (--x) + Alice-)Charlie: Solid point async (-) + Charlie--)Dave: Dotted point async (--) + Alice<<->>Bob: Bidirectional solid (<<->>) + Charlie<<-->>Dave: Bidirectional dotted (<<-->>) + Alice-|\\Bob: Solid top half (-|\\) + Bob-|/Alice: Solid bottom half (-|/) + Alice-\\\\Charlie: Stick top half (-\\\\) + Charlie-//Dave: Stick bottom half (-//) + Dave/|-Charlie: Solid top reverse (/|-) + Charlie\\|-Bob: Solid bottom reverse (\\|-) + Bob//-Alice: Stick top reverse (//-) + Alice\\\\-Bob: Stick bottom reverse (\\\\-) + Alice--|\\Bob: Dotted solid top (--|\\) + Bob--|/Alice: Dotted solid bottom (--|/) + Alice--\\\\Charlie: Dotted stick top (--\\\\) + Charlie--//Dave: Dotted stick bottom (--//) + Dave/|--Charlie: Dotted solid top reverse (/|--) + Charlie\\|--Bob: Dotted solid bottom reverse (\\|--) + Bob//--Alice: Dotted stick top reverse (//--) + Alice\\\\--Bob: Dotted stick bottom reverse (\\\\--) + Alice->>()Bob: Solid with central connection + Bob()-->>Alice: Dotted with reverse central + Alice()->>()Charlie: Dual central connections`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render all arrow types with autonumbering - left to right only', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + Alice->>Bob: Solid arrow (->>) + Alice-->>Bob: Dotted arrow (-->>) + Alice->Bob: Solid open arrow (->) + Alice-->Bob: Dotted open arrow (-->) + Alice-xBob: Solid cross (-x) + Alice--xBob: Dotted cross (--x) + Alice-)Bob: Solid point async (-) + Alice--)Bob: Dotted point async (--) + Alice<<->>Bob: Bidirectional solid (<<->>) + Alice<<-->>Bob: Bidirectional dotted (<<-->>) + Alice-|\\Bob: Solid top half (-|\\) + Alice-|/Bob: Solid bottom half (-|/) + Alice-\\\\Bob: Stick top half (-\\\\) + Alice-//Bob: Stick bottom half (-//) + Bob/|-Alice: Solid top reverse (/|-) + Bob\\|-Alice: Solid bottom reverse (\\|-) + Bob//-Alice: Stick top reverse (//-) + Bob\\\\-Alice: Stick bottom reverse (\\\\-) + Alice--|\\Bob: Dotted solid top (--|\\) + Alice--|/Bob: Dotted solid bottom (--|/) + Alice--\\\\Bob: Dotted stick top (--\\\\) + Alice--//Bob: Dotted stick bottom (--//) + Bob/|--Alice: Dotted solid top reverse (/|--) + Bob\\|--Alice: Dotted solid bottom reverse (\\|--) + Bob//--Alice: Dotted stick top reverse (//--) + Bob\\\\--Alice: Dotted stick bottom reverse (\\\\--) + Alice->>()Bob: Solid with central connection + Alice()-->>Bob: Dotted with reverse central + Alice()->>()Bob: Dual central connections`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render central connections with autonumbering', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Alice->>()Bob: Central connection at destination + Bob()->>Alice: Reverse central at source + Alice()->>()Bob: Dual central connections + Bob->>()Charlie: Another central connection + Charlie()-->>Alice: Reverse central dotted + Alice()<<-->>()Bob: Dual central bidirectional`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render bidirectional arrows with autonumbering', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Alice<<->>Bob: Bidirectional solid left to right + Bob<<->>Alice: Bidirectional solid right to left + Alice<<-->>Charlie: Bidirectional dotted left to right + Charlie<<-->>Alice: Bidirectional dotted right to left + Bob<<->>Charlie: Bidirectional solid + Charlie<<-->>Bob: Bidirectional dotted`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render reverse arrows with autonumbering', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Bob/|-Alice: Solid top reverse left to right + Alice/|-Bob: Solid top reverse right to left + Bob\\|-Alice: Solid bottom reverse left to right + Alice\\|-Bob: Solid bottom reverse right to left + Bob//-Alice: Stick top reverse left to right + Alice//-Bob: Stick top reverse right to left + Bob\\\\-Alice: Stick bottom reverse left to right + Alice\\\\-Bob: Stick bottom reverse right to left + Bob/|--Alice: Dotted solid top reverse + Alice\\|--Bob: Dotted solid bottom reverse + Bob//--Alice: Dotted stick top reverse + Alice\\\\--Bob: Dotted stick bottom reverse`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + }); + + describe('Central Connections with Autonumber - Comprehensive Coverage', () => { + it('should render CENTRAL_CONNECTION with normal arrows - left to right', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Alice->>()Bob: Solid arrow with circle at destination + Alice-->>()Bob: Dotted arrow with circle at destination + Alice->()Bob: Open arrow with circle at destination + Alice--x()Bob: Cross arrow with circle at destination + Alice--)()Bob: Close arrow with circle at destination`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render CENTRAL_CONNECTION with normal arrows - right to left', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Bob->>()Alice: Solid arrow with circle at destination (RTL) + Charlie-->>()Bob: Dotted arrow with circle at destination (RTL) + Bob->()Alice: Open arrow with circle at destination (RTL) + Charlie--x()Alice: Cross arrow with circle at destination (RTL) + Bob--)()Alice: Close arrow with circle at destination (RTL)`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render CENTRAL_CONNECTION with reverse arrows - left to right', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Bob/|-()Alice: Solid top reverse with circle (LTR) + Bob\\|-()Alice: Solid bottom reverse with circle (LTR) + Bob//-()Alice: Stick top reverse with circle (LTR) + Bob\\\\-()Alice: Stick bottom reverse with circle (LTR) + Bob/|--()Alice: Dotted solid top reverse with circle (LTR) + Bob\\|--()Alice: Dotted solid bottom reverse with circle (LTR) + Bob//--()Alice: Dotted stick top reverse with circle (LTR) + Bob\\\\--()Alice: Dotted stick bottom reverse with circle (LTR)`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render CENTRAL_CONNECTION with reverse arrows - right to left', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Alice/|-()Bob: Solid top reverse with circle (RTL) + Alice\\|-()Bob: Solid bottom reverse with circle (RTL) + Alice//-()Bob: Stick top reverse with circle (RTL) + Alice\\\\-()Bob: Stick bottom reverse with circle (RTL) + Alice/|--()Bob: Dotted solid top reverse with circle (RTL) + Alice\\|--()Bob: Dotted solid bottom reverse with circle (RTL) + Alice//--()Bob: Dotted stick top reverse with circle (RTL) + Alice\\\\--()Bob: Dotted stick bottom reverse with circle (RTL)`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render Central_Connection_REVERSE ()->> normal LTR', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Alice()->>Bob: Circle at source with solid arrow + Alice()-->>Bob: Circle at source with dotted arrow + Alice()->Bob: Circle at source with open arrow + Alice()--xBob: Circle at source with cross arrow + Alice()--)Bob: Circle at source with close arrow`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render Central_Connection_REVERSE ()->> normal RTL', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Bob()->>Alice: Circle at source with solid arrow (RTL) + Charlie()-->>Bob: Circle at source with dotted arrow (RTL) + Bob()->Alice: Circle at source with open arrow (RTL) + Charlie()--xAlice: Circle at source with cross arrow (RTL) + Bob()--)Alice: Circle at source with close arrow (RTL)`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render Central_Connection_REVERSE ()->> reverse LTR', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Bob()/|-Alice: Circle at source with solid top reverse (LTR) + Bob()\\|-Alice: Circle at source with solid bottom reverse (LTR) + Bob()//-Alice: Circle at source with stick top reverse (LTR) + Bob()\\\\-Alice: Circle at source with stick bottom reverse (LTR) + Bob()/|--Alice: Circle at source with dotted solid top reverse (LTR) + Bob()\\|--Alice: Circle at source with dotted solid bottom reverse (LTR) + Bob()//--Alice: Circle at source with dotted stick top reverse (LTR) + Bob()\\\\--Alice: Circle at source with dotted stick bottom reverse (LTR)`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render Central_Connection_REVERSE ()->> reverse RTL', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Alice()/|-Bob: Circle at source with solid top reverse (RTL) + Alice()\\|-Bob: Circle at source with solid bottom reverse (RTL) + Alice()//-Bob: Circle at source with stick top reverse (RTL) + Alice()\\\\-Bob: Circle at source with stick bottom reverse (RTL) + Alice()/|--Bob: Circle at source with dotted solid top reverse (RTL) + Alice()\\|--Bob: Circle at source with dotted solid bottom reverse (RTL) + Alice()//--Bob: Circle at source with dotted stick top reverse (RTL) + Alice()\\\\--Bob: Circle at source with dotted stick bottom reverse (RTL)`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render Central_Connection_DUAL ()->>() normal LTR', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Alice()->>()Bob: Circles at both ends with solid arrow + Alice()-->>()Bob: Circles at both ends with dotted arrow + Alice()->()Bob: Circles at both ends with open arrow + Alice()--x()Bob: Circles at both ends with cross arrow + Alice()--)()Bob: Circles at both ends with close arrow`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render Central_Connection_DUAL ()->>() normal RTL', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Bob()->>()Alice: Circles at both ends with solid arrow (RTL) + Charlie()-->>()Bob: Circles at both ends with dotted arrow (RTL) + Bob()->()Alice: Circles at both ends with open arrow (RTL) + Charlie()--x()Alice: Circles at both ends with cross arrow (RTL) + Bob()--)()Alice: Circles at both ends with close arrow (RTL)`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render Central_Connection_DUAL ()->>() reverse LTR', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Bob()/|-()Alice: Circles at both ends with solid top reverse (LTR) + Bob()\\|-()Alice: Circles at both ends with solid bottom reverse (LTR) + Bob()//-()Alice: Circles at both ends with stick top reverse (LTR) + Bob()\\\\-()Alice: Circles at both ends with stick bottom reverse (LTR) + Bob()/|--()Alice: Circles at both ends with dotted solid top reverse (LTR) + Bob()\\|--()Alice: Circles at both ends with dotted solid bottom reverse (LTR) + Bob()//--()Alice: Circles at both ends with dotted stick top reverse (LTR) + Bob()\\\\--()Alice: Circles at both ends with dotted stick bottom reverse (LTR)`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render Central_Connection_DUAL ()->>() reverse RTL', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Alice()/|-()Bob: Circles at both ends with solid top reverse (RTL) + Alice()\\|-()Bob: Circles at both ends with solid bottom reverse (RTL) + Alice()//-()Bob: Circles at both ends with stick top reverse (RTL) + Alice()\\\\-()Bob: Circles at both ends with stick bottom reverse (RTL) + Alice()/|--()Bob: Circles at both ends with dotted solid top reverse (RTL) + Alice()\\|--()Bob: Circles at both ends with dotted solid bottom reverse (RTL) + Alice()//--()Bob: Circles at both ends with dotted stick top reverse (RTL) + Alice()\\\\--()Bob: Circles at both ends with dotted stick bottom reverse (RTL)`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render mixed central connections with autonumber', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + participant David + + Note over Alice,David: Normal arrows with central connections + Alice->>()Bob: CENTRAL_CONNECTION LTR + Bob->>()Alice: CENTRAL_CONNECTION RTL + Alice()->>Bob: CENTRAL_CONNECTION_REVERSE LTR + Bob()->>Alice: CENTRAL_CONNECTION_REVERSE RTL + Alice()->>()Bob: CENTRAL_CONNECTION_DUAL LTR + Bob()->>()Alice: CENTRAL_CONNECTION_DUAL RTL + + Note over Alice,David: Reverse arrows with central connections + Bob/|-()Alice: Reverse with CENTRAL_CONNECTION LTR + Alice/|-()Bob: Reverse with CENTRAL_CONNECTION RTL + Bob()/|-Alice: Reverse with CENTRAL_CONNECTION_REVERSE LTR + Alice()/|-Bob: Reverse with CENTRAL_CONNECTION_REVERSE RTL + Bob()/|-()Alice: Reverse with CENTRAL_CONNECTION_DUAL LTR + Alice()/|-()Bob: Reverse with CENTRAL_CONNECTION_DUAL RTL + + Note over Alice,David: Mixed with different participants + Alice->>()Charlie: Skip participant + Charlie()->>Alice: Back skip + Bob()->>()David: Another skip + David()->>()Bob: Return skip`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render central connections with bidirectional arrows and autonumber', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Alice()<<->>()Bob: Dual central with bidirectional solid LTR + Bob()<<->>()Alice: Dual central with bidirectional solid RTL + Alice()<<-->>()Bob: Dual central with bidirectional dotted LTR + Bob()<<-->>()Alice: Dual central with bidirectional dotted RTL + Alice<<->>()Bob: Central at end with bidirectional LTR + Bob()<<->>Alice: Central at start with bidirectional RTL`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + }); + + describe('Self-Reference Arrows - Comprehensive Coverage', () => { + it('should render self-reference with normal arrows - without autonumber', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + participant Alice + participant Bob + participant Charlie + Alice->>Alice: Solid arrow self-reference + Bob-->>Bob: Dotted arrow self-reference + Charlie->Charlie: Open arrow self-reference + Alice-->Alice: Dotted open arrow self-reference + Bob-xBob: Cross arrow self-reference + Charlie--xCharlie: Dotted cross self-reference`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render self-reference with normal arrows - with autonumber', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Alice->>Alice: Solid arrow self-reference + Bob-->>Bob: Dotted arrow self-reference + Charlie->Charlie: Open arrow self-reference + Alice-->Alice: Dotted open arrow self-reference + Bob-xBob: Cross arrow self-reference + Charlie--xCharlie: Dotted cross self-reference`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render self-reference with reverse arrows - without autonumber', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + participant Alice + participant Bob + participant Charlie + Alice/|-Alice: Solid top reverse self-reference + Bob\\|-Bob: Solid bottom reverse self-reference + Charlie//-Charlie: Stick top reverse self-reference + Alice\\\\-Alice: Stick bottom reverse self-reference + Bob/|--Bob: Dotted solid top reverse self-reference + Charlie\\|--Charlie: Dotted solid bottom reverse self-reference + Alice//--Alice: Dotted stick top reverse self-reference + Bob\\\\--Bob: Dotted stick bottom reverse self-reference`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render self-reference with reverse arrows - with autonumber', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Alice/|-Alice: Solid top reverse self-reference + Bob\\|-Bob: Solid bottom reverse self-reference + Charlie//-Charlie: Stick top reverse self-reference + Alice\\\\-Alice: Stick bottom reverse self-reference + Bob/|--Bob: Dotted solid top reverse self-reference + Charlie\\|--Charlie: Dotted solid bottom reverse self-reference + Alice//--Alice: Dotted stick top reverse self-reference + Bob\\\\--Bob: Dotted stick bottom reverse self-reference`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render self-reference with bidirectional arrows - without autonumber', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + participant Alice + participant Bob + participant Charlie + Alice<<->>Alice: Bidirectional solid self-reference + Bob<<-->>Bob: Bidirectional dotted self-reference + Charlie<<->>Charlie: Another bidirectional solid + Alice<<-->>Alice: Another bidirectional dotted`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render self-reference with bidirectional arrows - with autonumber', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Alice<<->>Alice: Bidirectional solid self-reference + Bob<<-->>Bob: Bidirectional dotted self-reference + Charlie<<->>Charlie: Another bidirectional solid + Alice<<-->>Alice: Another bidirectional dotted`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render self-reference with CENTRAL_CONNECTION - without autonumber', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + participant Alice + participant Bob + participant Charlie + Alice->>()Alice: Solid arrow with circle at destination + Bob-->>()Bob: Dotted arrow with circle at destination + Charlie->()Charlie: Open arrow with circle at destination + Alice--x()Alice: Cross arrow with circle at destination + Bob--)()Bob: Close arrow with circle at destination`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render self-reference with CENTRAL_CONNECTION - with autonumber', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Alice->>()Alice: Solid arrow with circle at destination + Bob-->>()Bob: Dotted arrow with circle at destination + Charlie->()Charlie: Open arrow with circle at destination + Alice--x()Alice: Cross arrow with circle at destination + Bob--)()Bob: Close arrow with circle at destination`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render self-reference with CENTRAL_CONNECTION_REVERSE - without autonumber', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + participant Alice + participant Bob + participant Charlie + Alice()->>Alice: Circle at source with solid arrow + Bob()-->>Bob: Circle at source with dotted arrow + Charlie()->Charlie: Circle at source with open arrow + Alice()--xAlice: Circle at source with cross arrow + Bob()--)Bob: Circle at source with close arrow`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render self-reference with CENTRAL_CONNECTION_REVERSE - with autonumber', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Alice()->>Alice: Circle at source with solid arrow + Bob()-->>Bob: Circle at source with dotted arrow + Charlie()->Charlie: Circle at source with open arrow + Alice()--xAlice: Circle at source with cross arrow + Bob()--)Bob: Circle at source with close arrow`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render self-reference with CENTRAL_CONNECTION_DUAL - without autonumber', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + participant Alice + participant Bob + participant Charlie + Alice()->>()Alice: Circles at both ends with solid arrow + Bob()-->>()Bob: Circles at both ends with dotted arrow + Charlie()->()Charlie: Circles at both ends with open arrow + Alice()--x()Alice: Circles at both ends with cross arrow + Bob()--)()Bob: Circles at both ends with close arrow`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render self-reference with CENTRAL_CONNECTION_DUAL - with autonumber', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Alice()->>()Alice: Circles at both ends with solid arrow + Bob()-->>()Bob: Circles at both ends with dotted arrow + Charlie()->()Charlie: Circles at both ends with open arrow + Alice()--x()Alice: Circles at both ends with cross arrow + Bob()--)()Bob: Circles at both ends with close arrow`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render self-reference with reverse arrows and CENTRAL_CONNECTION', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + participant Alice + participant Bob + participant Charlie + Alice/|-()Alice: Solid top reverse with circle at destination + Bob\\|-()Bob: Solid bottom reverse with circle at destination + Charlie//-()Charlie: Stick top reverse with circle at destination + Alice\\\\-()Alice: Stick bottom reverse with circle at destination + Bob/|--()Bob: Dotted solid top reverse with circle at destination + Charlie\\|--()Charlie: Dotted solid bottom reverse with circle at destination + Alice//--()Alice: Dotted stick top reverse with circle at destination + Bob\\\\--()Bob: Dotted stick bottom reverse with circle at destination`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render self-reference with reverse arrows and CENTRAL_CONNECTION - with autonumber', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Alice/|-()Alice: Solid top reverse with circle at destination + Bob\\|-()Bob: Solid bottom reverse with circle at destination + Charlie//-()Charlie: Stick top reverse with circle at destination + Alice\\\\-()Alice: Stick bottom reverse with circle at destination + Bob/|--()Bob: Dotted solid top reverse with circle at destination + Charlie\\|--()Charlie: Dotted solid bottom reverse with circle at destination + Alice//--()Alice: Dotted stick top reverse with circle at destination + Bob\\\\--()Bob: Dotted stick bottom reverse with circle at destination`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render self-ref reverse Central_Connection_REVERSE no-autonumber', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + participant Alice + participant Bob + participant Charlie + Alice()/|-Alice: Circle at source with solid top reverse + Bob()\\|-Bob: Circle at source with solid bottom reverse + Charlie()//-Charlie: Circle at source with stick top reverse + Alice()\\\\-Alice: Circle at source with stick bottom reverse + Bob()/|--Bob: Circle at source with dotted solid top reverse + Charlie()\\|--Charlie: Circle at source with dotted solid bottom reverse + Alice()//--Alice: Circle at source with dotted stick top reverse + Bob()\\\\--Bob: Circle at source with dotted stick bottom reverse`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render self-ref reverse Central_Connection_REVERSE autonumber', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Alice()/|-Alice: Circle at source with solid top reverse + Bob()\\|-Bob: Circle at source with solid bottom reverse + Charlie()//-Charlie: Circle at source with stick top reverse + Alice()\\\\-Alice: Circle at source with stick bottom reverse + Bob()/|--Bob: Circle at source with dotted solid top reverse + Charlie()\\|--Charlie: Circle at source with dotted solid bottom reverse + Alice()//--Alice: Circle at source with dotted stick top reverse + Bob()\\\\--Bob: Circle at source with dotted stick bottom reverse`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render self-ref reverse Central_Connection_DUAL no-autonumber', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + participant Alice + participant Bob + participant Charlie + Alice()/|-()Alice: Circles at both ends with solid top reverse + Bob()\\|-()Bob: Circles at both ends with solid bottom reverse + Charlie()//-()Charlie: Circles at both ends with stick top reverse + Alice()\\\\-()Alice: Circles at both ends with stick bottom reverse + Bob()/|--()Bob: Circles at both ends with dotted solid top reverse + Charlie()\\|--()Charlie: Circles at both ends with dotted solid bottom reverse + Alice()//--()Alice: Circles at both ends with dotted stick top reverse + Bob()\\\\--()Bob: Circles at both ends with dotted stick bottom reverse`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render self-references, reverse arrows & dual central connection (autonumber).', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Alice()/|-()Alice: Circles at both ends with solid top reverse + Bob()\\|-()Bob: Circles at both ends with solid bottom reverse + Charlie()//-()Charlie: Circles at both ends with stick top reverse + Alice()\\\\-()Alice: Circles at both ends with stick bottom reverse + Bob()/|--()Bob: Circles at both ends with dotted solid top reverse + Charlie()\\|--()Charlie: Circles at both ends with dotted solid bottom reverse + Alice()//--()Alice: Circles at both ends with dotted stick top reverse + Bob()\\\\--()Bob: Circles at both ends with dotted stick bottom reverse`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('Render self-references with bidirectional central connections (no autonumber).', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + participant Alice + participant Bob + participant Charlie + Alice()<<->>()Alice: Dual central with bidirectional solid + Bob()<<-->>()Bob: Dual central with bidirectional dotted + Charlie<<->>()Alice: Central at end with bidirectional + Bob()<<->>Bob: Central at start with bidirectional`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render self-reference with bidirectional and central connections - with autonumber', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + Alice()<<->>()Alice: Dual central with bidirectional solid + Bob()<<-->>()Bob: Dual central with bidirectional dotted + Charlie<<->>()Charlie: Central at end with bidirectional + Bob()<<->>Bob: Central at start with bidirectional`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render comprehensive self-reference scenario - all arrow types mixed', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + + Note over Alice,Charlie: Normal arrows + Alice->>Alice: Normal solid + Bob-->>Bob: Normal dotted + Charlie->Charlie: Normal open + + Note over Alice,Charlie: Reverse arrows + Alice/|-Alice: Reverse solid top + Bob\\|-Bob: Reverse solid bottom + + Note over Alice,Charlie: Bidirectional arrows + Charlie<<->>Charlie: Bidirectional solid + Alice<<-->>Alice: Bidirectional dotted + + Note over Alice,Charlie: Central connections + Bob->>()Bob: Central at destination + Charlie()->>Charlie: Central at source + Alice()->>()Alice: Dual central + + Note over Alice,Charlie: Reverse with central + Bob()/|-()Bob: Reverse with dual central + Charlie/|-()Charlie: Reverse with central at destination + + Note over Alice,Charlie: Bidirectional with central + Alice()<<->>()Alice: Bidirectional with dual central`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + + it('should render self-reference mixed with regular messages and autonumber', () => { + imgSnapshotTest( + `%%{init: {'theme':'base'}}%% +sequenceDiagram + autonumber + participant Alice + participant Bob + participant Charlie + + Alice->>Bob: Regular message + Bob->>Bob: Self-reference solid + Bob-->>Charlie: Regular dotted + Charlie()->>()Charlie: Self-ref dual central + Charlie->>Alice: Regular back + Alice<<->>Alice: Self-ref bidirectional + Alice()->>Bob: Regular with central + Bob()/|-()Bob: Self-ref reverse dual central + Bob-->>Alice: Regular dotted back`, + { sequence: { diagramMarginX: 50, diagramMarginY: 10 } } + ); + }); + }); + }); }); }); diff --git a/packages/mermaid/src/diagrams/sequence/sequenceRenderer.ts b/packages/mermaid/src/diagrams/sequence/sequenceRenderer.ts index 04d5607ad..b29c221ce 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceRenderer.ts +++ b/packages/mermaid/src/diagrams/sequence/sequenceRenderer.ts @@ -294,11 +294,25 @@ const drawCentralConnection = function ( const actors = diagObj.db.getActors(); const fromActor = actors.get(msg.from); const toActor = actors.get(msg.to); - const fromCenter = fromActor.x + fromActor.width / 2; - const toCenter = toActor.x + toActor.width / 2; + const isAutoNumberOn = msgModel.sequenceVisible; + let fromCenter = fromActor.x + fromActor.width / 2; + let toCenter = toActor.x + toActor.width / 2; + + // Determine arrow direction: left-to-right or right-to-left + const isLeftToRight = fromCenter <= toCenter; + const isReverse = isReverseArrowType(msg, diagObj); const g = elem.append('g'); + const CENTRAL_CONNECTION_CIRCLE_OFFSET = 16.5; + + const getCircleOffset = (isLeftToRight: boolean, isReverse: boolean) => { + const baseOffset = isLeftToRight + ? CENTRAL_CONNECTION_CIRCLE_OFFSET + : -CENTRAL_CONNECTION_CIRCLE_OFFSET; + return isReverse ? -baseOffset : baseOffset; + }; + const drawCircle = (cx: number) => { g.append('circle') .attr('cx', cx) @@ -311,6 +325,37 @@ const drawCentralConnection = function ( const { CENTRAL_CONNECTION, CENTRAL_CONNECTION_REVERSE, CENTRAL_CONNECTION_DUAL } = diagObj.db.LINETYPE; + // Calculate circle position adjustments when autonumber is enabled + if (isAutoNumberOn) { + switch (msg.centralConnection) { + case CENTRAL_CONNECTION: + // Pattern: actor ->>() actor - circle at destination + if (isReverse) { + toCenter += getCircleOffset(isLeftToRight, true); + } + // No adjustment for normal arrows + break; + + case CENTRAL_CONNECTION_REVERSE: + // Pattern: actor ()->> actor - circle at source + if (!isReverse) { + fromCenter += getCircleOffset(isLeftToRight, false); + } + // No adjustment for reverse arrows + break; + + case CENTRAL_CONNECTION_DUAL: + // Pattern: actor ()->>() actor - circles at both ends + if (isReverse) { + toCenter += getCircleOffset(isLeftToRight, true); + } else { + fromCenter += getCircleOffset(isLeftToRight, false); + } + break; + } + } + + // Draw circles based on central connection type switch (msg.centralConnection) { case CENTRAL_CONNECTION: drawCircle(toCenter); @@ -438,12 +483,17 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO let line; if (startx === stopx) { + const isAutoNumberOn = sequenceVisible || conf.showSequenceNumbers; + const isReverse = isReverseArrowType(msg, diagObj); + const isBidirectional = isBidirectionalArrowType(msg, diagObj); + const lineStartX = startx + (isAutoNumberOn && (isReverse || isBidirectional) ? 10 : 0); + if (conf.rightAngles) { line = diagram .append('path') .attr( 'd', - `M ${startx},${lineStartY} H ${ + `M ${lineStartX},${lineStartY} H ${ startx + common.getMax(conf.width / 2, textWidth / 2) } V ${lineStartY + 25} H ${startx}` ); @@ -453,11 +503,11 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO .attr( 'd', 'M ' + - startx + + lineStartX + ',' + lineStartY + ' C ' + - (startx + 60) + + (lineStartX + 60) + ',' + (lineStartY - 10) + ' ' + @@ -590,38 +640,70 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO type === diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE || type === diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE_DOTTED; - let x = 0; - if (isBidirectional || isReverseArrowType) { - const SEQUENCE_NUMBER_RADIUS = 6; + const SEQUENCE_NUMBER_RADIUS = 6; + const hasCentralConn = hasCentralConnection(msg, diagObj); + let lineStartX = startx; + let lineStopX = stopx; + if (isBidirectional) { + // For bidirectional arrows, adjust the start position if (startx < stopx) { - line.attr('x1', startx + 2 * SEQUENCE_NUMBER_RADIUS); + lineStartX = startx + SEQUENCE_NUMBER_RADIUS + (hasCentralConn ? 5 : 0); } else { - line.attr('x1', startx + SEQUENCE_NUMBER_RADIUS); + lineStartX = startx - SEQUENCE_NUMBER_RADIUS + (hasCentralConn ? -5 : 0); } - x = 3.5; + line.attr('x1', lineStartX); + } else if (isReverseArrowType) { + // For reverse arrows, adjust the stop position (where the arrowhead is) + if (stopx > startx) { + lineStopX = stopx - 2 * SEQUENCE_NUMBER_RADIUS; + } else { + lineStopX = stopx - SEQUENCE_NUMBER_RADIUS; + lineStartX += + msg?.centralConnection === diagObj.db.LINETYPE.CENTRAL_CONNECTION_DUAL || + msg?.centralConnection === diagObj.db.LINETYPE.CENTRAL_CONNECTION_REVERSE + ? -7.5 + : 0; + } + lineStopX += hasCentralConn ? 15 : 0; + + line.attr('x2', lineStopX); + line.attr('x1', lineStartX); + } else { + line.attr('x1', startx + SEQUENCE_NUMBER_RADIUS); + } + + // Calculate autonumber X position + let autonumberX = 0; + const isSelfMessage = startx === stopx; + const isLeftToRight = startx <= stopx; + + if (isSelfMessage) { + autonumberX = msgModel.fromBounds + 1; + } else if (isReverseArrowType) { + autonumberX = isLeftToRight ? msgModel.toBounds - 1 : msgModel.fromBounds + 1; + } else { + autonumberX = isLeftToRight ? msgModel.fromBounds + 1 : msgModel.toBounds - 1; } diagram .append('line') - .attr('x1', startx) + .attr('x1', autonumberX) .attr('y1', lineStartY) - .attr('x2', startx) + .attr('x2', autonumberX) .attr('y2', lineStartY) .attr('stroke-width', 0) - .attr('marker-start', 'url(' + url + '#sequencenumber)') - .attr('transform', `translate(-${x}, 0)`); + .attr('marker-start', 'url(' + url + '#sequencenumber)'); diagram .append('text') - .attr('x', startx) + .attr('x', autonumberX) .attr('y', lineStartY + 4) .attr('font-family', 'sans-serif') .attr('font-size', '12px') .attr('text-anchor', 'middle') .attr('class', 'sequenceNumber') - .text(sequenceIndex) - .attr('transform', `translate(-${x}, 0)`); + .text(sequenceIndex); } }; @@ -1657,6 +1739,47 @@ const calculateCentralConnectionOffset = function (msg, diagObj, isArrowToRight) return offset; }; +/** + * Check if a message is a reverse arrow type + * @param msg - The message object + * @param diagObj - The diagram object containing LINETYPE constants + * @returns True if the message is a reverse arrow type + */ +const isReverseArrowType = function (msg, diagObj) { + const { + SOLID_ARROW_TOP_REVERSE, + SOLID_ARROW_TOP_REVERSE_DOTTED, + SOLID_ARROW_BOTTOM_REVERSE, + SOLID_ARROW_BOTTOM_REVERSE_DOTTED, + STICK_ARROW_TOP_REVERSE, + STICK_ARROW_TOP_REVERSE_DOTTED, + STICK_ARROW_BOTTOM_REVERSE, + STICK_ARROW_BOTTOM_REVERSE_DOTTED, + } = diagObj.db.LINETYPE; + + return [ + SOLID_ARROW_TOP_REVERSE, + SOLID_ARROW_TOP_REVERSE_DOTTED, + SOLID_ARROW_BOTTOM_REVERSE, + SOLID_ARROW_BOTTOM_REVERSE_DOTTED, + STICK_ARROW_TOP_REVERSE, + STICK_ARROW_TOP_REVERSE_DOTTED, + STICK_ARROW_BOTTOM_REVERSE, + STICK_ARROW_BOTTOM_REVERSE_DOTTED, + ].includes(msg.type); +}; + +/** + * Check if a message is a bidirectional arrow type + * @param msg - The message object + * @param diagObj - The diagram object containing LINETYPE constants + * @returns True if the message is a bidirectional arrow type + */ +const isBidirectionalArrowType = function (msg, diagObj) { + const { BIDIRECTIONAL_SOLID, BIDIRECTIONAL_DOTTED } = diagObj.db.LINETYPE; + return [BIDIRECTIONAL_SOLID, BIDIRECTIONAL_DOTTED].includes(msg.type); +}; + const buildMessageModel = function (msg, actors, diagObj) { if ( ![ diff --git a/packages/mermaid/src/diagrams/sequence/svgDraw.js b/packages/mermaid/src/diagrams/sequence/svgDraw.js index 7db661930..6d7d4cb95 100644 --- a/packages/mermaid/src/diagrams/sequence/svgDraw.js +++ b/packages/mermaid/src/diagrams/sequence/svgDraw.js @@ -681,8 +681,8 @@ const drawActorTypeControl = function (elem, actor, conf, isFooter) { rect.class = 'actor'; const cx = actor.x + actor.width / 2; - const cy = actorY + 30; - const r = 18; + const cy = actorY + 32; + const r = 22; actElem .append('defs') @@ -719,7 +719,7 @@ const drawActorTypeControl = function (elem, actor, conf, isFooter) { actor.description, actElem, rect.x, - rect.y + r + (isFooter ? 5 : 10), + rect.y + r + (!isFooter ? 12 : 5), rect.width, rect.height, { class: `actor ${ACTOR_MAN_FIGURE_CLASS}` }, @@ -737,7 +737,7 @@ const drawActorTypeEntity = function (elem, actor, conf, isFooter) { const line = elem.append('g').lower(); const actElem = elem.append('g'); - let cssClass = ACTOR_MAN_FIGURE_CLASS; + let cssClass = 'actor'; if (isFooter) { cssClass += ` ${BOTTOM_ACTOR_CLASS}`; } else { @@ -756,7 +756,7 @@ const drawActorTypeEntity = function (elem, actor, conf, isFooter) { const cx = actor.x + actor.width / 2; const cy = actorY + (!isFooter ? 25 : 10); - const r = 18; + const r = 22; actElem .append('circle') @@ -772,7 +772,6 @@ const drawActorTypeEntity = function (elem, actor, conf, isFooter) { .attr('x2', cx + r) .attr('y1', cy + r) .attr('y2', cy + r) - .attr('stroke', '#333') .attr('stroke-width', 2); const bounds = actElem.node().getBBox(); @@ -799,7 +798,7 @@ const drawActorTypeEntity = function (elem, actor, conf, isFooter) { actor.description, actElem, rect.x, - rect.y + (!isFooter ? (cy + r - actorY) / 2 : (cy - actorY + r - 5) / 2), + rect.y + (!isFooter ? 30 : 15), rect.width, rect.height, { class: `actor ${ACTOR_MAN_FIGURE_CLASS}` }, @@ -807,9 +806,9 @@ const drawActorTypeEntity = function (elem, actor, conf, isFooter) { ); if (!isFooter) { - actElem.attr('transform', `translate(${0}, ${r / 2})`); + actElem.attr('transform', `translate(${0}, ${r / 2 - 5})`); } else { - actElem.attr('transform', `translate(${0}, ${r / 2})`); + actElem.attr('transform', `translate(${0}, ${r})`); } return actor.height; @@ -872,8 +871,8 @@ const drawActorTypeDatabase = function (elem, actor, conf, isFooter) { // Cylinder dimensions rect.x = actor.x; rect.y = actorY; - const w = rect.width / 4; - const h = rect.width / 4; + const w = rect.width / 3; + const h = rect.width / 3; const rx = w / 2; const ry = rx / (2.5 + w / 50); @@ -897,17 +896,14 @@ const drawActorTypeDatabase = function (elem, actor, conf, isFooter) { .attr('stroke-width', 1) .attr('class', cssclass); - if (!isFooter) { - cylinderGroup.attr('transform', `translate(${w * 1.5}, ${(rect.height + ry) / 4})`); - } else { - cylinderGroup.attr('transform', `translate(${w * 1.5}, ${rect.height / 4 - 2 * ry})`); - } + cylinderGroup.attr('transform', `translate(${w}, ${ry})`); + actor.rectData = rect; _drawTextCandidateFunc(conf, hasKatex(actor.description))( actor.description, g, rect.x, - rect.y + (!isFooter ? (rect.height + ry) / 2 : (rect.height + h) / 4), + rect.y + 35, rect.width, rect.height, { class: `actor ${ACTOR_BOX_CLASS}` }, @@ -927,7 +923,7 @@ const drawActorTypeBoundary = function (elem, actor, conf, isFooter) { const actorY = isFooter ? actor.stopy : actor.starty; const center = actor.x + actor.width / 2; const centerY = actorY + 80; - const radius = 30; + const radius = 22; const line = elem.append('g').lower(); if (!isFooter) { @@ -968,22 +964,22 @@ const drawActorTypeBoundary = function (elem, actor, conf, isFooter) { .append('line') .attr('id', 'actor-man-torso' + actorCnt) .attr('x1', actor.x + actor.width / 2 - radius * 2.5) - .attr('y1', actorY + 10) + .attr('y1', actorY + 12) .attr('x2', actor.x + actor.width / 2 - 15) - .attr('y2', actorY + 10); + .attr('y2', actorY + 12); actElem .append('line') .attr('id', 'actor-man-arms' + actorCnt) .attr('x1', actor.x + actor.width / 2 - radius * 2.5) - .attr('y1', actorY + 0) // starting Y + .attr('y1', actorY + 2) // starting Y .attr('x2', actor.x + actor.width / 2 - radius * 2.5) - .attr('y2', actorY + 20); // ending Y (26px long, adjust as needed) + .attr('y2', actorY + 22); // ending Y (26px long, adjust as needed) actElem .append('circle') .attr('cx', actor.x + actor.width / 2) - .attr('cy', actorY + 10) + .attr('cy', actorY + 12) .attr('r', radius); const bounds = actElem.node().getBBox(); @@ -993,7 +989,7 @@ const drawActorTypeBoundary = function (elem, actor, conf, isFooter) { actor.description, actElem, rect.x, - rect.y + (!isFooter ? radius / 2 + 3 : radius / 2 - 4), + rect.y + 15, rect.width, rect.height, { class: `actor ${ACTOR_MAN_FIGURE_CLASS}` }, @@ -1001,9 +997,9 @@ const drawActorTypeBoundary = function (elem, actor, conf, isFooter) { ); if (!isFooter) { - actElem.attr('transform', `translate(0,${radius / 2 + 7})`); + actElem.attr('transform', `translate(0,${radius / 2 + 10})`); } else { - actElem.attr('transform', `translate(0,${radius / 2 + 7})`); + actElem.attr('transform', `translate(0,${radius / 2 + 10})`); } return actor.height;