mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-02-04 07:13:25 +08:00
Merge pull request #5209 from Ronid1/feature/4051_sequence_diagram-multi-directional-arrow
Feature/4051 sequence diagram multi directional arrow
This commit is contained in:
commit
cda41a1cdf
@ -1,4 +1,4 @@
|
|||||||
/// <reference types="Cypress" />
|
// <reference types="Cypress" />
|
||||||
|
|
||||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
|
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
|
||||||
|
|
||||||
@ -68,6 +68,19 @@ context('Sequence diagram', () => {
|
|||||||
{ sequence: { actorFontFamily: 'courier' } }
|
{ sequence: { actorFontFamily: 'courier' } }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('should render bidirectional arrows', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
sequenceDiagram
|
||||||
|
Alice<<->>John: Hello John, how are you?
|
||||||
|
Alice<<-->>John: Hi Alice, I can hear you!
|
||||||
|
John<<->>Alice: This also works the other way
|
||||||
|
John<<-->>Alice: Yes
|
||||||
|
Alice->John: Test
|
||||||
|
John->>Alice: Still works
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
it('should handle different line breaks', () => {
|
it('should handle different line breaks', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
|
@ -206,14 +206,16 @@ Messages can be of two displayed either solid or with a dotted line.
|
|||||||
[Actor][Arrow][Actor]:Message text
|
[Actor][Arrow][Actor]:Message text
|
||||||
```
|
```
|
||||||
|
|
||||||
There are six types of arrows currently supported:
|
There are ten types of arrows currently supported:
|
||||||
|
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
| ------ | ------------------------------------------------ |
|
| -------- | ------------------------------------------------------------------------ |
|
||||||
| `->` | Solid line without arrow |
|
| `->` | Solid line without arrow |
|
||||||
| `-->` | Dotted line without arrow |
|
| `-->` | Dotted line without arrow |
|
||||||
| `->>` | Solid line with arrowhead |
|
| `->>` | Solid line with arrowhead |
|
||||||
| `-->>` | Dotted line with arrowhead |
|
| `-->>` | Dotted line with arrowhead |
|
||||||
|
| `<<->>` | Solid line with bidirectional arrowheads (v\<MERMAID_RELEASE_VERSION>+) |
|
||||||
|
| `<<-->>` | Dotted line with bidirectional arrowheads (v\<MERMAID_RELEASE_VERSION>+) |
|
||||||
| `-x` | Solid line with a cross at the end |
|
| `-x` | Solid line with a cross at the end |
|
||||||
| `--x` | Dotted line with a cross at the end. |
|
| `--x` | Dotted line with a cross at the end. |
|
||||||
| `-)` | Solid line with an open arrow at the end (async) |
|
| `-)` | Solid line with an open arrow at the end (async) |
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
"actor" { this.begin('ID'); return 'participant_actor'; }
|
"actor" { this.begin('ID'); return 'participant_actor'; }
|
||||||
"create" return 'create';
|
"create" return 'create';
|
||||||
"destroy" { this.begin('ID'); return 'destroy'; }
|
"destroy" { this.begin('ID'); return 'destroy'; }
|
||||||
<ID>[^\->:\n,;]+?([\-]*[^\->:\n,;]+?)*?(?=((?!\n)\s)+"as"(?!\n)\s|[#\n;]|$) { yytext = yytext.trim(); this.begin('ALIAS'); return 'ACTOR'; }
|
<ID>[^\<->\->:\n,;]+?([\-]*[^\<->\->:\n,;]+?)*?(?=((?!\n)\s)+"as"(?!\n)\s|[#\n;]|$) { yytext = yytext.trim(); this.begin('ALIAS'); return 'ACTOR'; }
|
||||||
<ALIAS>"as" { this.popState(); this.popState(); this.begin('LINE'); return 'AS'; }
|
<ALIAS>"as" { this.popState(); this.popState(); this.begin('LINE'); return 'AS'; }
|
||||||
<ALIAS>(?:) { this.popState(); this.popState(); return 'NEWLINE'; }
|
<ALIAS>(?:) { this.popState(); this.popState(); return 'NEWLINE'; }
|
||||||
"loop" { this.begin('LINE'); return 'loop'; }
|
"loop" { this.begin('LINE'); return 'loop'; }
|
||||||
@ -73,9 +73,11 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
|||||||
"off" return 'off';
|
"off" return 'off';
|
||||||
"," return ',';
|
"," return ',';
|
||||||
";" return 'NEWLINE';
|
";" return 'NEWLINE';
|
||||||
[^\+\->:\n,;]+((?!(\-x|\-\-x|\-\)|\-\-\)))[\-]*[^\+\->:\n,;]+)* { yytext = yytext.trim(); return 'ACTOR'; }
|
[^\+\<->\->:\n,;]+((?!(\-x|\-\-x|\-\)|\-\-\)))[\-]*[^\+\<->\->:\n,;]+)* { yytext = yytext.trim(); return 'ACTOR'; }
|
||||||
"->>" return 'SOLID_ARROW';
|
"->>" return 'SOLID_ARROW';
|
||||||
|
"<<->>" return 'BIDIRECTIONAL_SOLID_ARROW';
|
||||||
"-->>" return 'DOTTED_ARROW';
|
"-->>" return 'DOTTED_ARROW';
|
||||||
|
"<<-->>" return 'BIDIRECTIONAL_DOTTED_ARROW';
|
||||||
"->" return 'SOLID_OPEN_ARROW';
|
"->" return 'SOLID_OPEN_ARROW';
|
||||||
"-->" return 'DOTTED_OPEN_ARROW';
|
"-->" return 'DOTTED_OPEN_ARROW';
|
||||||
\-[x] return 'SOLID_CROSS';
|
\-[x] return 'SOLID_CROSS';
|
||||||
@ -310,7 +312,9 @@ signaltype
|
|||||||
: SOLID_OPEN_ARROW { $$ = yy.LINETYPE.SOLID_OPEN; }
|
: SOLID_OPEN_ARROW { $$ = yy.LINETYPE.SOLID_OPEN; }
|
||||||
| DOTTED_OPEN_ARROW { $$ = yy.LINETYPE.DOTTED_OPEN; }
|
| DOTTED_OPEN_ARROW { $$ = yy.LINETYPE.DOTTED_OPEN; }
|
||||||
| SOLID_ARROW { $$ = yy.LINETYPE.SOLID; }
|
| SOLID_ARROW { $$ = yy.LINETYPE.SOLID; }
|
||||||
|
| BIDIRECTIONAL_SOLID_ARROW { $$ = yy.LINETYPE.BIDIRECTIONAL_SOLID; }
|
||||||
| DOTTED_ARROW { $$ = yy.LINETYPE.DOTTED; }
|
| DOTTED_ARROW { $$ = yy.LINETYPE.DOTTED; }
|
||||||
|
| BIDIRECTIONAL_DOTTED_ARROW { $$ = yy.LINETYPE.BIDIRECTIONAL_DOTTED; }
|
||||||
| SOLID_CROSS { $$ = yy.LINETYPE.SOLID_CROSS; }
|
| SOLID_CROSS { $$ = yy.LINETYPE.SOLID_CROSS; }
|
||||||
| DOTTED_CROSS { $$ = yy.LINETYPE.DOTTED_CROSS; }
|
| DOTTED_CROSS { $$ = yy.LINETYPE.DOTTED_CROSS; }
|
||||||
| SOLID_POINT { $$ = yy.LINETYPE.SOLID_POINT; }
|
| SOLID_POINT { $$ = yy.LINETYPE.SOLID_POINT; }
|
||||||
|
@ -328,6 +328,8 @@ export const LINETYPE = {
|
|||||||
BREAK_START: 30,
|
BREAK_START: 30,
|
||||||
BREAK_END: 31,
|
BREAK_END: 31,
|
||||||
PAR_OVER_START: 32,
|
PAR_OVER_START: 32,
|
||||||
|
BIDIRECTIONAL_SOLID: 33,
|
||||||
|
BIDIRECTIONAL_DOTTED: 34,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ARROWTYPE = {
|
export const ARROWTYPE = {
|
||||||
|
@ -516,6 +516,36 @@ Alice->>Bob:Hello Bob, how are you?`;
|
|||||||
expect(messages.length).toBe(1);
|
expect(messages.length).toBe(1);
|
||||||
expect(messages[0].type).toBe(diagram.db.LINETYPE.DOTTED);
|
expect(messages[0].type).toBe(diagram.db.LINETYPE.DOTTED);
|
||||||
});
|
});
|
||||||
|
it('should handle bidirectional arrow messages', async () => {
|
||||||
|
const str = `
|
||||||
|
sequenceDiagram
|
||||||
|
Alice<<->>Bob:Hello Bob, how are you?`;
|
||||||
|
|
||||||
|
await mermaidAPI.parse(str);
|
||||||
|
const actors = diagram.db.getActors();
|
||||||
|
expect(actors.get('Alice').description).toBe('Alice');
|
||||||
|
expect(actors.get('Bob').description).toBe('Bob');
|
||||||
|
|
||||||
|
const messages = diagram.db.getMessages();
|
||||||
|
|
||||||
|
expect(messages.length).toBe(1);
|
||||||
|
expect(messages[0].type).toBe(diagram.db.LINETYPE.BIDIRECTIONAL_SOLID);
|
||||||
|
});
|
||||||
|
it('should handle bidirectional dotted arrow messages', async () => {
|
||||||
|
const str = `
|
||||||
|
sequenceDiagram
|
||||||
|
Alice<<-->>Bob:Hello Bob, how are you?`;
|
||||||
|
|
||||||
|
await mermaidAPI.parse(str);
|
||||||
|
const actors = diagram.db.getActors();
|
||||||
|
expect(actors.get('Alice').description).toBe('Alice');
|
||||||
|
expect(actors.get('Bob').description).toBe('Bob');
|
||||||
|
|
||||||
|
const messages = diagram.db.getMessages();
|
||||||
|
|
||||||
|
expect(messages.length).toBe(1);
|
||||||
|
expect(messages[0].type).toBe(diagram.db.LINETYPE.BIDIRECTIONAL_DOTTED);
|
||||||
|
});
|
||||||
it('should handle actor activation', async () => {
|
it('should handle actor activation', async () => {
|
||||||
const str = `
|
const str = `
|
||||||
sequenceDiagram
|
sequenceDiagram
|
||||||
|
@ -436,7 +436,8 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
|||||||
type === diagObj.db.LINETYPE.DOTTED ||
|
type === diagObj.db.LINETYPE.DOTTED ||
|
||||||
type === diagObj.db.LINETYPE.DOTTED_CROSS ||
|
type === diagObj.db.LINETYPE.DOTTED_CROSS ||
|
||||||
type === diagObj.db.LINETYPE.DOTTED_POINT ||
|
type === diagObj.db.LINETYPE.DOTTED_POINT ||
|
||||||
type === diagObj.db.LINETYPE.DOTTED_OPEN
|
type === diagObj.db.LINETYPE.DOTTED_OPEN ||
|
||||||
|
type === diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED
|
||||||
) {
|
) {
|
||||||
line.style('stroke-dasharray', '3, 3');
|
line.style('stroke-dasharray', '3, 3');
|
||||||
line.attr('class', 'messageLine1');
|
line.attr('class', 'messageLine1');
|
||||||
@ -462,6 +463,13 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
|||||||
if (type === diagObj.db.LINETYPE.SOLID || type === diagObj.db.LINETYPE.DOTTED) {
|
if (type === diagObj.db.LINETYPE.SOLID || type === diagObj.db.LINETYPE.DOTTED) {
|
||||||
line.attr('marker-end', 'url(' + url + '#arrowhead)');
|
line.attr('marker-end', 'url(' + url + '#arrowhead)');
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
type === diagObj.db.LINETYPE.BIDIRECTIONAL_SOLID ||
|
||||||
|
type === diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED
|
||||||
|
) {
|
||||||
|
line.attr('marker-start', 'url(' + url + '#arrowhead)');
|
||||||
|
line.attr('marker-end', 'url(' + url + '#arrowhead)');
|
||||||
|
}
|
||||||
if (type === diagObj.db.LINETYPE.SOLID_POINT || type === diagObj.db.LINETYPE.DOTTED_POINT) {
|
if (type === diagObj.db.LINETYPE.SOLID_POINT || type === diagObj.db.LINETYPE.DOTTED_POINT) {
|
||||||
line.attr('marker-end', 'url(' + url + '#filled-head)');
|
line.attr('marker-end', 'url(' + url + '#filled-head)');
|
||||||
}
|
}
|
||||||
@ -1036,6 +1044,8 @@ export const draw = async function (_text: string, id: string, _version: string,
|
|||||||
diagObj.db.LINETYPE.DOTTED_CROSS,
|
diagObj.db.LINETYPE.DOTTED_CROSS,
|
||||||
diagObj.db.LINETYPE.SOLID_POINT,
|
diagObj.db.LINETYPE.SOLID_POINT,
|
||||||
diagObj.db.LINETYPE.DOTTED_POINT,
|
diagObj.db.LINETYPE.DOTTED_POINT,
|
||||||
|
diagObj.db.LINETYPE.BIDIRECTIONAL_SOLID,
|
||||||
|
diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED,
|
||||||
].includes(msg.type)
|
].includes(msg.type)
|
||||||
) {
|
) {
|
||||||
sequenceIndex = sequenceIndex + sequenceIndexStep;
|
sequenceIndex = sequenceIndex + sequenceIndexStep;
|
||||||
@ -1416,6 +1426,8 @@ const buildMessageModel = function (msg, actors, diagObj) {
|
|||||||
diagObj.db.LINETYPE.DOTTED_CROSS,
|
diagObj.db.LINETYPE.DOTTED_CROSS,
|
||||||
diagObj.db.LINETYPE.SOLID_POINT,
|
diagObj.db.LINETYPE.SOLID_POINT,
|
||||||
diagObj.db.LINETYPE.DOTTED_POINT,
|
diagObj.db.LINETYPE.DOTTED_POINT,
|
||||||
|
diagObj.db.LINETYPE.BIDIRECTIONAL_SOLID,
|
||||||
|
diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED,
|
||||||
].includes(msg.type)
|
].includes(msg.type)
|
||||||
) {
|
) {
|
||||||
return {};
|
return {};
|
||||||
@ -1423,7 +1435,7 @@ const buildMessageModel = function (msg, actors, diagObj) {
|
|||||||
const [fromLeft, fromRight] = activationBounds(msg.from, actors);
|
const [fromLeft, fromRight] = activationBounds(msg.from, actors);
|
||||||
const [toLeft, toRight] = activationBounds(msg.to, actors);
|
const [toLeft, toRight] = activationBounds(msg.to, actors);
|
||||||
const isArrowToRight = fromLeft <= toLeft;
|
const isArrowToRight = fromLeft <= toLeft;
|
||||||
const startx = isArrowToRight ? fromRight : fromLeft;
|
let startx = isArrowToRight ? fromRight : fromLeft;
|
||||||
let stopx = isArrowToRight ? toLeft : toRight;
|
let stopx = isArrowToRight ? toLeft : toRight;
|
||||||
|
|
||||||
// As the line width is considered, the left and right values will be off by 2.
|
// As the line width is considered, the left and right values will be off by 2.
|
||||||
@ -1462,6 +1474,17 @@ const buildMessageModel = function (msg, actors, diagObj) {
|
|||||||
if (![diagObj.db.LINETYPE.SOLID_OPEN, diagObj.db.LINETYPE.DOTTED_OPEN].includes(msg.type)) {
|
if (![diagObj.db.LINETYPE.SOLID_OPEN, diagObj.db.LINETYPE.DOTTED_OPEN].includes(msg.type)) {
|
||||||
stopx += adjustValue(3);
|
stopx += adjustValue(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shorten start position of bidirectional arrow to accommodate for second arrowhead
|
||||||
|
*/
|
||||||
|
if (
|
||||||
|
[diagObj.db.LINETYPE.BIDIRECTIONAL_SOLID, diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED].includes(
|
||||||
|
msg.type
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
startx -= adjustValue(3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const allBounds = [fromLeft, fromRight, toLeft, toRight];
|
const allBounds = [fromLeft, fromRight, toLeft, toRight];
|
||||||
|
@ -735,7 +735,7 @@ export const insertArrowHead = function (elem) {
|
|||||||
.attr('markerUnits', 'userSpaceOnUse')
|
.attr('markerUnits', 'userSpaceOnUse')
|
||||||
.attr('markerWidth', 12)
|
.attr('markerWidth', 12)
|
||||||
.attr('markerHeight', 12)
|
.attr('markerHeight', 12)
|
||||||
.attr('orient', 'auto')
|
.attr('orient', 'auto-start-reverse')
|
||||||
.append('path')
|
.append('path')
|
||||||
.attr('d', 'M -1 0 L 10 5 L 0 10 z'); // this is actual shape for arrowhead
|
.attr('d', 'M -1 0 L 10 5 L 0 10 z'); // this is actual shape for arrowhead
|
||||||
};
|
};
|
||||||
|
@ -141,14 +141,16 @@ Messages can be of two displayed either solid or with a dotted line.
|
|||||||
[Actor][Arrow][Actor]:Message text
|
[Actor][Arrow][Actor]:Message text
|
||||||
```
|
```
|
||||||
|
|
||||||
There are six types of arrows currently supported:
|
There are ten types of arrows currently supported:
|
||||||
|
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
| ------ | ------------------------------------------------ |
|
| -------- | ----------------------------------------------------------------------- |
|
||||||
| `->` | Solid line without arrow |
|
| `->` | Solid line without arrow |
|
||||||
| `-->` | Dotted line without arrow |
|
| `-->` | Dotted line without arrow |
|
||||||
| `->>` | Solid line with arrowhead |
|
| `->>` | Solid line with arrowhead |
|
||||||
| `-->>` | Dotted line with arrowhead |
|
| `-->>` | Dotted line with arrowhead |
|
||||||
|
| `<<->>` | Solid line with bidirectional arrowheads (v<MERMAID_RELEASE_VERSION>+) |
|
||||||
|
| `<<-->>` | Dotted line with bidirectional arrowheads (v<MERMAID_RELEASE_VERSION>+) |
|
||||||
| `-x` | Solid line with a cross at the end |
|
| `-x` | Solid line with a cross at the end |
|
||||||
| `--x` | Dotted line with a cross at the end. |
|
| `--x` | Dotted line with a cross at the end. |
|
||||||
| `-)` | Solid line with an open arrow at the end (async) |
|
| `-)` | Solid line with an open arrow at the end (async) |
|
||||||
|
@ -207,7 +207,7 @@ describe('when using mermaid and ', () => {
|
|||||||
[Error: Parse error on line 2:
|
[Error: Parse error on line 2:
|
||||||
...equenceDiagramAlice:->Bob: Hello Bob, h...
|
...equenceDiagramAlice:->Bob: Hello Bob, h...
|
||||||
----------------------^
|
----------------------^
|
||||||
Expecting 'SOLID_OPEN_ARROW', 'DOTTED_OPEN_ARROW', 'SOLID_ARROW', 'DOTTED_ARROW', 'SOLID_CROSS', 'DOTTED_CROSS', 'SOLID_POINT', 'DOTTED_POINT', got 'TXT']
|
Expecting 'SOLID_OPEN_ARROW', 'DOTTED_OPEN_ARROW', 'SOLID_ARROW', 'BIDIRECTIONAL_SOLID_ARROW', 'DOTTED_ARROW', 'BIDIRECTIONAL_DOTTED_ARROW', 'SOLID_CROSS', 'DOTTED_CROSS', 'SOLID_POINT', 'DOTTED_POINT', got 'TXT']
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user