Skip to content

Commit

Permalink
Merge pull request #252 from gibson042/sequenceDiagram-over
Browse files Browse the repository at this point in the history
Support sequenceDiagram "over" notes
  • Loading branch information
knsv committed Nov 6, 2015
2 parents 76130bc + a59a5a2 commit 49c13f1
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 29 deletions.
15 changes: 7 additions & 8 deletions docs/content/sequenceDiagram.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
```
Expand All @@ -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
Expand Down Expand Up @@ -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
16 changes: 12 additions & 4 deletions src/diagrams/sequenceDiagram/parser/sequenceDiagram.jison
Original file line number Diff line number Diff line change
Expand Up @@ -103,17 +103,25 @@ 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
: SPACE spaceList
| SPACE
;
actor_pair
: actor { $$ = $1; }
| actor ',' actor { $$ = [$1, $3]; }
: actor ',' actor { $$ = [$1, $3]; }
| actor { $$ = $1; }
;

placement
Expand Down
7 changes: 5 additions & 2 deletions src/diagrams/sequenceDiagram/sequenceDb.js
Original file line number Diff line number Diff line change
Expand Up @@ -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});
};


Expand Down Expand Up @@ -132,4 +135,4 @@ exports.apply = function(param){
break;
}
}
};
};
58 changes: 57 additions & 1 deletion src/diagrams/sequenceDiagram/sequenceDiagram.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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' +
Expand Down Expand Up @@ -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' +
Expand Down Expand Up @@ -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();
Expand Down
33 changes: 19 additions & 14 deletions src/diagrams/sequenceDiagram/sequenceRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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);
Expand Down Expand Up @@ -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();
Expand All @@ -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:
Expand Down

0 comments on commit 49c13f1

Please sign in to comment.