Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support sequenceDiagram "over" notes #252

Merged
merged 2 commits into from
Nov 6, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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