mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-14 06:43:25 +08:00
Merge pull request #252 from gibson042/sequenceDiagram-over
Support sequenceDiagram "over" notes
This commit is contained in:
commit
49c13f19ff
@ -74,7 +74,7 @@ There are six types of arrows currently supported:
|
||||
|
||||
## Notes
|
||||
It is possible to add notes to a sequence diagram. This is done by the notation
|
||||
Note [ right | left ] of [Actor]: Text in note content
|
||||
Note [ right of | left of | over ] [Actor]: Text in note content
|
||||
|
||||
See the example below:
|
||||
```
|
||||
@ -92,18 +92,17 @@ sequenceDiagram
|
||||
Note right of John: Text in note
|
||||
```
|
||||
|
||||
It is possible to break text into different rows by using <br/> as a line breaker.
|
||||
It is also possible to create notes spanning two participants:
|
||||
```
|
||||
%% Example of sequence diagram
|
||||
sequenceDiagram
|
||||
participant John
|
||||
Note left of John: Text in note spanning several rows.
|
||||
Alice->John: Hello John, how are you?
|
||||
Note over Alice,John: A typical interaction
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant John
|
||||
Note left of John: Text in note spanning several rows.
|
||||
Alice->John: Hello John, how are you?
|
||||
Note over Alice,John: A typical interaction
|
||||
```
|
||||
|
||||
## Loops
|
||||
@ -309,4 +308,4 @@ mermaid.sequenceConfig = {
|
||||
Param | Descriotion | Default value
|
||||
--- | --- | ---
|
||||
mirrorActor|Turns on/off the rendering of actors below the diagram as well as above it|false
|
||||
bottomMarginAdj|Adjusts how far down the graph ended. Wide borders styles with css could generate unwantewd clipping which is why this config param exists.|1
|
||||
bottomMarginAdj|Adjusts how far down the graph ended. Wide borders styles with css could generate unwantewd clipping which is why this config param exists.|1
|
||||
|
@ -103,8 +103,16 @@ statement
|
||||
;
|
||||
|
||||
note_statement
|
||||
: 'note' placement actor text2 {$$=[$3,{type:'addNote', placement:$2, actor:$3.actor, text:$4}];}
|
||||
| 'note' 'over' spaceList actor_pair actor
|
||||
: 'note' placement actor text2
|
||||
{
|
||||
$$ = [$3, {type:'addNote', placement:$2, actor:$3.actor, text:$4}];}
|
||||
| 'note' 'over' actor_pair text2
|
||||
{
|
||||
// Coerce actor_pair into a [to, from, ...] array
|
||||
$2 = [].concat($3, $3).slice(0, 2);
|
||||
$2[0] = $2[0].actor;
|
||||
$2[1] = $2[1].actor;
|
||||
$$ = [$3, {type:'addNote', placement:yy.PLACEMENT.OVER, actor:$2.slice(0, 2), text:$4}];}
|
||||
;
|
||||
|
||||
spaceList
|
||||
@ -112,8 +120,8 @@ spaceList
|
||||
| SPACE
|
||||
;
|
||||
actor_pair
|
||||
: actor { $$ = $1; }
|
||||
| actor ',' actor { $$ = [$1, $3]; }
|
||||
: actor ',' actor { $$ = [$1, $3]; }
|
||||
| actor { $$ = $1; }
|
||||
;
|
||||
|
||||
placement
|
||||
|
@ -77,8 +77,11 @@ exports.PLACEMENT = {
|
||||
exports.addNote = function (actor, placement, message){
|
||||
var note = {actor:actor, placement: placement, message:message};
|
||||
|
||||
// Coerce actor into a [to, from, ...] array
|
||||
var actors = [].concat(actor, actor);
|
||||
|
||||
notes.push(note);
|
||||
messages.push({from:actor, to:actor, message:message, type:exports.LINETYPE.NOTE, placement: placement});
|
||||
messages.push({from:actors[0], to:actors[1], message:message, type:exports.LINETYPE.NOTE, placement: placement});
|
||||
};
|
||||
|
||||
|
||||
@ -132,4 +135,4 @@ exports.apply = function(param){
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -231,6 +231,31 @@ describe('when parsing a sequenceDiagram',function() {
|
||||
expect(messages[0].from).toBe('Alice');
|
||||
expect(messages[2].from).toBe('John');
|
||||
});
|
||||
it('it should handle notes over a single actor', function () {
|
||||
var str = 'sequenceDiagram\n' +
|
||||
'Alice->Bob: Hello Bob, how are you?\n' +
|
||||
'Note over Bob: Bob thinks\n';
|
||||
|
||||
sq.parse(str);
|
||||
|
||||
var messages = sq.yy.getMessages();
|
||||
expect(messages[1].from).toBe('Bob');
|
||||
expect(messages[1].to).toBe('Bob');
|
||||
});
|
||||
it('it should handle notes over multiple actors', function () {
|
||||
var str = 'sequenceDiagram\n' +
|
||||
'Alice->Bob: Hello Bob, how are you?\n' +
|
||||
'Note over Alice,Bob: confusion\n' +
|
||||
'Note over Bob,Alice: resolution\n';
|
||||
|
||||
sq.parse(str);
|
||||
|
||||
var messages = sq.yy.getMessages();
|
||||
expect(messages[1].from).toBe('Alice');
|
||||
expect(messages[1].to).toBe('Bob');
|
||||
expect(messages[2].from).toBe('Bob');
|
||||
expect(messages[2].to).toBe('Alice');
|
||||
});
|
||||
it('it should handle loop statements a sequenceDiagram', function () {
|
||||
var str = 'sequenceDiagram\n' +
|
||||
'Alice->Bob: Hello Bob, how are you?\n\n' +
|
||||
@ -623,7 +648,23 @@ describe('when rendering a sequenceDiagram',function() {
|
||||
expect(bounds.stopy ).toBe(conf.height);
|
||||
|
||||
});
|
||||
it('it should handle one actor and a note', function () {
|
||||
it('it should handle one actor and a centered note', function () {
|
||||
sd.bounds.init();
|
||||
var str = 'sequenceDiagram\n' +
|
||||
'participant Alice\n' +
|
||||
'Note over Alice: Alice thinks\n';
|
||||
|
||||
sq.parse(str);
|
||||
sd.draw(str,'tst');
|
||||
|
||||
var bounds = sd.bounds.getBounds();
|
||||
expect(bounds.startx).toBe(0);
|
||||
expect(bounds.starty).toBe(0);
|
||||
expect(bounds.stopx ).toBe( conf.width);
|
||||
// 10 comes from mock of text height
|
||||
expect(bounds.stopy ).toBe( conf.height + conf.boxMargin + 2*conf.noteMargin +10);
|
||||
});
|
||||
it('it should handle one actor and a note to the left', function () {
|
||||
sd.bounds.init();
|
||||
var str = 'sequenceDiagram\n' +
|
||||
'participant Alice\n' +
|
||||
@ -668,7 +709,22 @@ describe('when rendering a sequenceDiagram',function() {
|
||||
expect(bounds.starty).toBe(0);
|
||||
expect(bounds.stopx ).toBe(conf.width*2 + conf.actorMargin);
|
||||
expect(bounds.stopy ).toBe(0 + conf.messageMargin + conf.height);
|
||||
});
|
||||
it('it should handle two actors and two centered shared notes', function () {
|
||||
sd.bounds.init();
|
||||
var str = 'sequenceDiagram\n' +
|
||||
'Alice->Bob: Hello Bob, how are you?\n'+
|
||||
'Note over Alice,Bob: Looks\n' +
|
||||
'Note over Bob,Alice: Looks back\n';
|
||||
|
||||
sq.parse(str);
|
||||
sd.draw(str,'tst');
|
||||
|
||||
var bounds = sd.bounds.getBounds();
|
||||
expect(bounds.startx).toBe(0);
|
||||
expect(bounds.starty).toBe(0);
|
||||
expect(bounds.stopx ).toBe(conf.width*2 + conf.actorMargin);
|
||||
expect(bounds.stopy ).toBe( conf.height + conf.messageMargin + 2*(conf.boxMargin + 2*conf.noteMargin + 10));
|
||||
});
|
||||
it('it should draw two actors and two messages', function () {
|
||||
sd.bounds.init();
|
||||
|
@ -129,11 +129,11 @@ exports.bounds = {
|
||||
* @param pos The position if the actor in the liost of actors
|
||||
* @param description The text in the box
|
||||
*/
|
||||
var drawNote = function(elem, startx, verticalPos, msg){
|
||||
var drawNote = function(elem, startx, verticalPos, msg, forceWidth){
|
||||
var rect = svgDraw.getNoteRect();
|
||||
rect.x = startx;
|
||||
rect.y = verticalPos;
|
||||
rect.width = conf.width;
|
||||
rect.width = forceWidth || conf.width;
|
||||
rect.class = 'note';
|
||||
|
||||
var g = elem.append('g');
|
||||
@ -147,21 +147,19 @@ var drawNote = function(elem, startx, verticalPos, msg){
|
||||
textObj.text = msg.message;
|
||||
textObj.class = 'noteText';
|
||||
|
||||
var textElem = svgDraw.drawText(g,textObj, conf.width-conf.noteMargin);
|
||||
var textElem = svgDraw.drawText(g,textObj, rect.width-conf.noteMargin);
|
||||
|
||||
var textHeight = textElem[0][0].getBBox().height;
|
||||
if(textHeight > conf.width){
|
||||
if(!forceWidth && textHeight > conf.width){
|
||||
textElem.remove();
|
||||
g = elem.append('g');
|
||||
|
||||
//textObj.x = textObj.x - conf.width;
|
||||
//textElem = svgDraw.drawText(g,textObj, 2*conf.noteMargin);
|
||||
textElem = svgDraw.drawText(g,textObj, 2*conf.width-conf.noteMargin);
|
||||
textElem = svgDraw.drawText(g,textObj, 2*rect.width-conf.noteMargin);
|
||||
textHeight = textElem[0][0].getBBox().height;
|
||||
rectElem.attr('width',2*conf.width);
|
||||
exports.bounds.insert(startx, verticalPos, startx + 2*conf.width, verticalPos + 2*conf.noteMargin + textHeight);
|
||||
rectElem.attr('width',2*rect.width);
|
||||
exports.bounds.insert(startx, verticalPos, startx + 2*rect.width, verticalPos + 2*conf.noteMargin + textHeight);
|
||||
}else{
|
||||
exports.bounds.insert(startx, verticalPos, startx + conf.width, verticalPos + 2*conf.noteMargin + textHeight);
|
||||
exports.bounds.insert(startx, verticalPos, startx + rect.width, verticalPos + 2*conf.noteMargin + textHeight);
|
||||
}
|
||||
|
||||
rectElem.attr('height',textHeight+ 2*conf.noteMargin);
|
||||
@ -290,6 +288,7 @@ module.exports.draw = function (text, id) {
|
||||
|
||||
var startx;
|
||||
var stopx;
|
||||
var forceWidth;
|
||||
|
||||
// Fetch data from the parsing
|
||||
var actors = sq.yy.getActors();
|
||||
@ -312,13 +311,19 @@ module.exports.draw = function (text, id) {
|
||||
startx = actors[msg.from].x;
|
||||
stopx = actors[msg.to].x;
|
||||
|
||||
if(msg.placement !== 0){
|
||||
// Right of
|
||||
if(msg.placement === sq.yy.PLACEMENT.RIGHTOF){
|
||||
drawNote(diagram, startx + (conf.width + conf.actorMargin)/2, exports.bounds.getVerticalPos(), msg);
|
||||
|
||||
}else{
|
||||
// Left of
|
||||
}else if(msg.placement === sq.yy.PLACEMENT.LEFTOF){
|
||||
drawNote(diagram, startx - (conf.width + conf.actorMargin)/2, exports.bounds.getVerticalPos(), msg);
|
||||
}else if(msg.to === msg.from) {
|
||||
// Single-actor over
|
||||
drawNote(diagram, startx, exports.bounds.getVerticalPos(), msg);
|
||||
}else{
|
||||
// Multi-actor over
|
||||
forceWidth = Math.abs(startx - stopx) + conf.actorMargin;
|
||||
drawNote(diagram, (startx + stopx + conf.width - forceWidth)/2, exports.bounds.getVerticalPos(), msg,
|
||||
forceWidth);
|
||||
}
|
||||
break;
|
||||
case sq.yy.LINETYPE.LOOP_START:
|
||||
|
Loading…
x
Reference in New Issue
Block a user