Merge pull request #3 from knsv/master

Merge from master
This commit is contained in:
Björn Weström 2014-12-20 19:02:32 +01:00
commit 6a1550fbdf
19 changed files with 2366 additions and 1177 deletions

View File

@ -38,6 +38,17 @@ graph LR;
C-->|Two|E[Result two];
```
Below is the new declaration of the graph which since 0.2.16 also is valid along with the old declaration of the graph as described in the graph example on the home wiki page.
```
graph LR
A[Hard edge] -->|Link text| B(Round edge)
B --> C{Decision}
C -->|One| D[Result one]
C -->|Two| E[Result two]
```
![Example 2](http://www.sveido.com/mermaid/img/ex2.png)

View File

@ -1,6 +1,6 @@
{
"name": "mermaid",
"version": "0.2.15",
"version": "0.2.16",
"authors": [
"knsv <knut@sveido.com>"
],

890
dist/mermaid.full.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

890
dist/mermaid.slim.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{
"name": "mermaid",
"version": "0.2.15",
"version": "0.2.16",
"description": "Markdownish syntax for generating flowcharts",
"main": "src/main.js",
"scripts": {

View File

@ -26,6 +26,8 @@
"." return 'DOT';
"<" return 'TAGSTART';
">" return 'TAGEND';
"^" return 'UP'
"v" return 'DOWN'
\-\-[x] return 'ARROW_CROSS';
\-\-\> return 'ARROW_POINT';
\-\-[o] return 'ARROW_CIRCLE';
@ -120,17 +122,32 @@
expressions
: graphConfig statements EOF
| graphConfig statements
| graphConfig spaceListNewline statements EOF
{$$=$1;}
| graphConfig spaceListNewline statements
{$$=$1;}
;
graphConfig
: GRAPH SPACE DIR SEMI
: GRAPH SPACE DIR FirstStmtSeperator
{ yy.setDirection($3);$$ = $3;}
| GRAPH SPACE TAGEND FirstStmtSeperator
{ yy.setDirection("LR");$$ = $3;}
| GRAPH SPACE TAGSTART FirstStmtSeperator
{ yy.setDirection("RL");$$ = $3;}
| GRAPH SPACE UP FirstStmtSeperator
{ yy.setDirection("BT");$$ = $3;}
| GRAPH SPACE DOWN FirstStmtSeperator
{ yy.setDirection("TB");$$ = $3;}
;
FirstStmtSeperator
: SEMI | NEWLINE | spaceList NEWLINE ;
statements
: statement spaceListNewline statements
| statement statements
| statement
;
@ -150,15 +167,16 @@ spaceList
statement
: commentStatement NEWLINE
{$$='Comment';}
| verticeStatement SEMI
| styleStatement SEMI
| linkStyleStatement SEMI
| classDefStatement SEMI
| classStatement SEMI
| clickStatement SEMI
| verticeStatement separator
| styleStatement separator
| linkStyleStatement separator
| classDefStatement separator
| classStatement separator
| clickStatement separator
;
separator: NEWLINE | SEMI | EOF ;
verticeStatement:
vertex link vertex
{ yy.addLink($1,$3,$2);$$ = 'oy'}

File diff suppressed because one or more lines are too long

View File

@ -10,7 +10,7 @@ describe('when parsing ',function(){
flow.parser.yy = require('../graphDb');
flow.parser.yy.clear();
/*flow.parser.parse.parseError= function parseError(str, hash) {
console.log(str);
console.logconsole.log(str);
}*/
});
@ -30,6 +30,84 @@ describe('when parsing ',function(){
expect(edges[0].text).toBe('');
});
it('should handle angle bracket '>' as direction LR',function(){
var res = flow.parser.parse('graph >;A-->B;');
var vert = flow.parser.yy.getVertices();
var edges = flow.parser.yy.getEdges();
var direction = flow.parser.yy.getDirection();
expect(direction).toBe('LR');
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow');
expect(edges[0].text).toBe('');
});
it('should handle angle bracket '<' as direction RL',function(){
var res = flow.parser.parse('graph <;A-->B;');
var vert = flow.parser.yy.getVertices();
var edges = flow.parser.yy.getEdges();
var direction = flow.parser.yy.getDirection();
expect(direction).toBe('RL');
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow');
expect(edges[0].text).toBe('');
});
it('should handle caret '^' as direction BT',function(){
var res = flow.parser.parse('graph ^;A-->B;');
var vert = flow.parser.yy.getVertices();
var edges = flow.parser.yy.getEdges();
var direction = flow.parser.yy.getDirection();
expect(direction).toBe('BT');
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow');
expect(edges[0].text).toBe('');
});
it('should handle lower-case \'v\' as direction TB',function(){
var res = flow.parser.parse('graph v;A-->B;');
var vert = flow.parser.yy.getVertices();
var edges = flow.parser.yy.getEdges();
var direction = flow.parser.yy.getDirection();
expect(direction).toBe('TB');
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow');
expect(edges[0].text).toBe('');
});
it('should handle a nodes and edges and a space between link and node',function(){
var res = flow.parser.parse('graph TD;A --> B;');
@ -46,6 +124,37 @@ describe('when parsing ',function(){
expect(edges[0].text).toBe('');
});
it('should handle a nodes and edges, a space between link and node and each line ending without semicolon',function(){
var res = flow.parser.parse('graph TD\nA --> B\n style e red');
var vert = flow.parser.yy.getVertices();
var edges = flow.parser.yy.getEdges();
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(1);
expect(edges[0].start).toBe('A');
expect(edges[0].end).toBe('B');
expect(edges[0].type).toBe('arrow');
expect(edges[0].text).toBe('');
});
it('should handle statements ending without semicolon',function(){
var res = flow.parser.parse('graph TD\nA-->B\nB-->C');
var vert = flow.parser.yy.getVertices();
var edges = flow.parser.yy.getEdges();
expect(vert['A'].id).toBe('A');
expect(vert['B'].id).toBe('B');
expect(edges.length).toBe(2);
expect(edges[1].start).toBe('B');
expect(edges[1].end).toBe('C');
expect(edges[0].type).toBe('arrow');
expect(edges[0].text).toBe('');
});
it('should handle a comments',function(){
var res = flow.parser.parse('graph TD;\n%% CComment\n A-->B;');
@ -199,6 +308,18 @@ describe('when parsing ',function(){
expect(edges[0].type).toBe('arrow_cross');
expect(edges[0].text).toBe('text including URL space');
});
it('should handle text on edges with space dir',function(){
var res = flow.parser.parse('graph TD;A--x|text including R TD space|B;');
var vert = flow.parser.yy.getVertices();
var edges = flow.parser.yy.getEdges();
expect(edges[0].type).toBe('arrow_cross');
expect(edges[0].text).toBe('text including R TD space');
});
it('should handle text on edges with graph keyword',function(){
var res = flow.parser.parse('graph TD;A--x|text including graph space|B;');
@ -343,6 +464,15 @@ describe('when parsing ',function(){
expect(vert['C'].type).toBe('round');
expect(vert['C'].text).toBe('Chimpansen hoppar åäö <br> - ÅÄÖ');
});
xit('should handle text in vertices with åäö, minus and space and br',function(){
var res = flow.parser.parse('graph TD; A[Object&#40;foo,bar&#41;]-->B(Thing);');
var vert = flow.parser.yy.getVertices();
var edges = flow.parser.yy.getEdges();
expect(vert['C'].type).toBe('round');
expect(vert['C'].text).toBe(' A[Object&#40;foo,bar&#41;]-->B(Thing);');
});
it('should handle text in vertices with unicode chars',function(){
var res = flow.parser.parse('graph TD;A-->C(Начало);');

View File

@ -16,7 +16,10 @@
[\n]+ return 'NL';
\s+ /* skip whitespace */
\#[^\n]* /* skip comments */
\%%[^\n]* /* skip comments */
"participant" return 'participant';
"loop" return 'loop';
"end" return 'end';
"left of" return 'left_of';
"right of" return 'right_of';
"over" return 'over';
@ -30,6 +33,7 @@
">>" return 'OPENARROW';
">" return 'ARROW';
:[^#\n]+ return 'MESSAGE';
"%%" return 'CMT';
<<EOF>> return 'EOF';
. return 'INVALID';
@ -58,6 +62,10 @@ statement
| signal { $$='signal'; }
| note_statement { $$='note'; }
| 'title' message { yy.setTitle($2); }
| 'loop' ACTOR
{ yy.addSignal(undefined, undefined, $2, yy.LINETYPE.LOOP_START);$$='loop'; }
| 'end'
{ yy.addSignal(undefined, undefined, undefined, yy.LINETYPE.LOOP_END);$$='loop'; }
;
note_statement

View File

@ -72,12 +72,12 @@
}
*/
var parser = (function(){
var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[6,9,10,14,16,24],$V1=[1,14],$V2=[1,17],$V3=[24,29,30];
var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[6,9,10,14,16,17,18,19],$V1=[1,16],$V2=[1,19],$V3=[17,31,32];
var parser = {trace: function trace() { },
yy: {},
symbols_: {"error":2,"start":3,"SD":4,"document":5,"EOF":6,"line":7,"statement":8,"NL":9,"participant":10,"actor":11,"signal":12,"note_statement":13,"title":14,"message":15,"note":16,"placement":17,"over":18,"actor_pair":19,",":20,"left_of":21,"right_of":22,"signaltype":23,"ACTOR":24,"linetype":25,"arrowtype":26,"LINE":27,"DOTLINE":28,"ARROW":29,"OPENARROW":30,"MESSAGE":31,"$accept":0,"$end":1},
terminals_: {2:"error",4:"SD",6:"EOF",9:"NL",10:"participant",14:"title",16:"note",18:"over",20:",",21:"left_of",22:"right_of",24:"ACTOR",27:"LINE",28:"DOTLINE",29:"ARROW",30:"OPENARROW",31:"MESSAGE"},
productions_: [0,[3,3],[5,0],[5,2],[7,1],[7,1],[8,2],[8,1],[8,1],[8,2],[13,4],[13,4],[19,1],[19,3],[17,1],[17,1],[12,4],[11,1],[23,2],[23,1],[25,1],[25,1],[26,1],[26,1],[15,1]],
symbols_: {"error":2,"start":3,"SD":4,"document":5,"EOF":6,"line":7,"statement":8,"NL":9,"participant":10,"actor":11,"signal":12,"note_statement":13,"title":14,"message":15,"loop":16,"ACTOR":17,"end":18,"note":19,"placement":20,"over":21,"actor_pair":22,",":23,"left_of":24,"right_of":25,"signaltype":26,"linetype":27,"arrowtype":28,"LINE":29,"DOTLINE":30,"ARROW":31,"OPENARROW":32,"MESSAGE":33,"$accept":0,"$end":1},
terminals_: {2:"error",4:"SD",6:"EOF",9:"NL",10:"participant",14:"title",16:"loop",17:"ACTOR",18:"end",19:"note",21:"over",23:",",24:"left_of",25:"right_of",29:"LINE",30:"DOTLINE",31:"ARROW",32:"OPENARROW",33:"MESSAGE"},
productions_: [0,[3,3],[5,0],[5,2],[7,1],[7,1],[8,2],[8,1],[8,1],[8,2],[8,2],[8,1],[13,4],[13,4],[22,1],[22,3],[20,1],[20,1],[12,4],[11,1],[26,2],[26,1],[27,1],[27,1],[28,1],[28,1],[15,1]],
performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
/* this == yyval */
@ -102,51 +102,57 @@ case 9:
yy.setTitle($$[$0]);
break;
case 10:
this.$ = yy.addNote($$[$0-1], $$[$0-2], $$[$0]);
yy.addSignal(undefined, undefined, $$[$0], yy.LINETYPE.LOOP_START);this.$='loop';
break;
case 11:
this.$ = yy.addNote($$[$0-1], yy.PLACEMENT.OVER, $$[$0]);
yy.addSignal(undefined, undefined, undefined, yy.LINETYPE.LOOP_END);this.$='loop';
break;
case 12: case 19:
this.$ = $$[$0];
case 12:
this.$ = yy.addNote($$[$0-1], $$[$0-2], $$[$0]);
break;
case 13:
this.$ = [$$[$0-2], $$[$0]];
this.$ = yy.addNote($$[$0-1], yy.PLACEMENT.OVER, $$[$0]);
break;
case 14:
this.$ = yy.PLACEMENT.LEFTOF;
case 14: case 21:
this.$ = $$[$0];
break;
case 15:
this.$ = yy.PLACEMENT.RIGHTOF;
this.$ = [$$[$0-2], $$[$0]];
break;
case 16:
yy.addSignal($$[$0-3], $$[$0-1], $$[$0], $$[$0-2]);
this.$ = yy.PLACEMENT.LEFTOF;
break;
case 17:
yy.addActor($$[$0],$$[$0],$$[$0]);
this.$ = yy.PLACEMENT.RIGHTOF;
break;
case 18:
this.$ = $$[$0-1] | ($$[$0] << 2);
yy.addSignal($$[$0-3], $$[$0-1], $$[$0], $$[$0-2]);
break;
case 19:
yy.addActor($$[$0],$$[$0],$$[$0]);
break;
case 20:
this.$ = yy.LINETYPE.SOLID;
break;
case 21:
this.$ = yy.LINETYPE.DOTTED;
this.$ = $$[$0-1] | ($$[$0] << 2);
break;
case 22:
this.$ = yy.ARROWTYPE.FILLED;
this.$ = yy.LINETYPE.SOLID;
break;
case 23:
this.$ = yy.ARROWTYPE.OPEN;
this.$ = yy.LINETYPE.DOTTED;
break;
case 24:
this.$ = yy.ARROWTYPE.FILLED;
break;
case 25:
this.$ = yy.ARROWTYPE.OPEN;
break;
case 26:
this.$ = $$[$0].substring(1).trim().replace(/\\n/gm, "\n");
break;
}
},
table: [{3:1,4:[1,2]},{1:[3]},o($V0,[2,2],{5:3}),{6:[1,4],7:5,8:6,9:[1,7],10:[1,8],11:12,12:9,13:10,14:[1,11],16:[1,13],24:$V1},{1:[2,1]},o($V0,[2,3]),o($V0,[2,4]),o($V0,[2,5]),{11:15,24:$V1},o($V0,[2,7]),o($V0,[2,8]),{15:16,31:$V2},{23:18,25:19,27:[1,20],28:[1,21]},{17:22,18:[1,23],21:[1,24],22:[1,25]},o([6,9,10,14,16,20,24,27,28,31],[2,17]),o($V0,[2,6]),o($V0,[2,9]),o($V0,[2,24]),{11:26,24:$V1},{24:[2,19],26:27,29:[1,28],30:[1,29]},o($V3,[2,20]),o($V3,[2,21]),{11:30,24:$V1},{11:32,19:31,24:$V1},{24:[2,14]},{24:[2,15]},{15:33,31:$V2},{24:[2,18]},{24:[2,22]},{24:[2,23]},{15:34,31:$V2},{15:35,31:$V2},{20:[1,36],31:[2,12]},o($V0,[2,16]),o($V0,[2,10]),o($V0,[2,11]),{11:37,24:$V1},{31:[2,13]}],
defaultActions: {4:[2,1],24:[2,14],25:[2,15],27:[2,18],28:[2,22],29:[2,23],37:[2,13]},
table: [{3:1,4:[1,2]},{1:[3]},o($V0,[2,2],{5:3}),{6:[1,4],7:5,8:6,9:[1,7],10:[1,8],11:14,12:9,13:10,14:[1,11],16:[1,12],17:$V1,18:[1,13],19:[1,15]},{1:[2,1]},o($V0,[2,3]),o($V0,[2,4]),o($V0,[2,5]),{11:17,17:$V1},o($V0,[2,7]),o($V0,[2,8]),{15:18,33:$V2},{17:[1,20]},o($V0,[2,11]),{26:21,27:22,29:[1,23],30:[1,24]},{20:25,21:[1,26],24:[1,27],25:[1,28]},o([6,9,10,14,16,17,18,19,23,29,30,33],[2,19]),o($V0,[2,6]),o($V0,[2,9]),o($V0,[2,26]),o($V0,[2,10]),{11:29,17:$V1},{17:[2,21],28:30,31:[1,31],32:[1,32]},o($V3,[2,22]),o($V3,[2,23]),{11:33,17:$V1},{11:35,17:$V1,22:34},{17:[2,16]},{17:[2,17]},{15:36,33:$V2},{17:[2,20]},{17:[2,24]},{17:[2,25]},{15:37,33:$V2},{15:38,33:$V2},{23:[1,39],33:[2,14]},o($V0,[2,18]),o($V0,[2,12]),o($V0,[2,13]),{11:40,17:$V1},{33:[2,15]}],
defaultActions: {4:[2,1],27:[2,16],28:[2,17],30:[2,20],31:[2,24],32:[2,25],40:[2,15]},
parseError: function parseError(str, hash) {
if (hash.recoverable) {
this.trace(str);
@ -627,42 +633,50 @@ case 1:/* skip whitespace */
break;
case 2:/* skip comments */
break;
case 3:return 10;
case 3:/* skip comments */
break;
case 4:return 21;
case 4:return 10;
break;
case 5:return 22;
case 5:return 16;
break;
case 6:return 18;
break;
case 7:return 16;
case 7:return 24;
break;
case 8:return 14;
case 8:return 25;
break;
case 9:return 4;
case 9:return 21;
break;
case 10:return 20;
case 10:return 19;
break;
case 11:return 24;
case 11:return 14;
break;
case 12:return 28;
case 12:return 4;
break;
case 13:return 27;
case 13:return 23;
break;
case 14:return 30;
case 14:return 17;
break;
case 15:return 29;
case 15:return 30;
break;
case 16:return 31;
case 16:return 29;
break;
case 17:return 6;
case 17:return 32;
break;
case 18:return 'INVALID';
case 18:return 31;
break;
case 19:return 33;
break;
case 20:return 'CMT';
break;
case 21:return 6;
break;
case 22:return 'INVALID';
break;
}
},
rules: [/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:participant\b)/i,/^(?:left of\b)/i,/^(?:right of\b)/i,/^(?:over\b)/i,/^(?:note\b)/i,/^(?:title\b)/i,/^(?:sequenceDiagram\b)/i,/^(?:,)/i,/^(?:[^\->:\n,]+)/i,/^(?:--)/i,/^(?:-)/i,/^(?:>>)/i,/^(?:>)/i,/^(?:[^#\n]+)/i,/^(?:$)/i,/^(?:.)/i],
conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18],"inclusive":true}}
rules: [/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:participant\b)/i,/^(?:loop\b)/i,/^(?:end\b)/i,/^(?:left of\b)/i,/^(?:right of\b)/i,/^(?:over\b)/i,/^(?:note\b)/i,/^(?:title\b)/i,/^(?:sequenceDiagram\b)/i,/^(?:,)/i,/^(?:[^\->:\n,]+)/i,/^(?:--)/i,/^(?:-)/i,/^(?:>>)/i,/^(?:>)/i,/^(?:[^#\n]+)/i,/^(?:%%)/i,/^(?:$)/i,/^(?:.)/i],
conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22],"inclusive":true}}
});
return lexer;
})();

View File

@ -41,9 +41,11 @@ exports.clear = function(){
};
exports.LINETYPE = {
SOLID : 0,
DOTTED : 1,
NOTE : 2
SOLID : 0,
DOTTED : 1,
NOTE : 2,
LOOP_START: 10,
LOOP_END : 11,
};
exports.ARROWTYPE = {
@ -61,7 +63,7 @@ exports.addNote = function (actor, placement, message){
var note = {actor:actor, placement: placement, message:message};
notes.push(note);
messages.push({from:actor, to:actor, message:message, type:exports.LINETYPE.NOTE});
messages.push({from:actor, to:actor, message:message, type:exports.LINETYPE.NOTE, placement: placement});
};

View File

@ -2,28 +2,9 @@
* Created by knut on 14-11-18.
*/
var sq = require('./parser/sequenceDiagram').parser;
var sd = require('./sequenceRenderer');
//console.log(sq.parse('a12:d12\na24:d24'));
str = 'a12:d12\n\na24:d24';
//console.log(str);
//console.log(sq.parse(str));
//console.log(sq.parse('[]\n[]'));
str = 'bfs:queue\n\nbfs3:queue\n';
str = str + 'bfs:message=someNode.setLevel\n';
str = str + 'bfs:message2=someNode.setLevel2';
//console.log(str);
//console.log(sq.parse(str));
str = 'bfs:BFS\n';
str = str + 'someNode:SomeNode\n';
str = str + 'bfs:queue.new\n';
str = str + 'bfs:someNode.setLevel';
//console.log(str);
//console.log(sq.parse(str));
var str;
describe('when parsing a sequenceDiagram',function() {
var parseError;
beforeEach(function () {
@ -47,16 +28,451 @@ describe('when parsing a sequenceDiagram',function() {
expect(actors.Alice).ToBdescription = 'Alice';
actors.Bob.description = 'Bob';
//console.log('actors');
//console.log(actors);
var messages = sq.yy.getMessages();
expect(messages.length).toBe(3);
expect(messages[0].from).toBe('Alice');
expect(messages[2].from).toBe('Bob');
});
it('it should handle comments in a sequenceDiagram', function () {
str = 'sequenceDiagram\n' +
'Alice->Bob: Hello Bob, how are you?\n' +
'%% Comment\n' +
'Note right of Bob: Bob thinks\n' +
'Bob-->Alice: I am good thanks!\n';
sq.parse(str);
var actors = sq.yy.getActors();
expect(actors.Alice).ToBdescription = 'Alice';
actors.Bob.description = 'Bob';
var messages = sq.yy.getMessages();
expect(messages.length).toBe(3);
//console.log('messages');
//console.log(messages);
expect(messages[0].from).toBe('Alice');
expect(messages[2].from).toBe('Bob');
});
it('it should handle new lines in a sequenceDiagram', function () {
str = 'sequenceDiagram\n' +
'Alice->Bob: Hello Bob, how are you?\n\n' +
'%% Comment\n' +
'Note right of Bob: Bob thinks\n' +
'Bob-->Alice: I am good thanks!\n';
sq.parse(str);
var actors = sq.yy.getActors();
expect(actors.Alice).ToBdescription = 'Alice';
actors.Bob.description = 'Bob';
var messages = sq.yy.getMessages();
expect(messages.length).toBe(3);
expect(messages[0].from).toBe('Alice');
expect(messages[2].from).toBe('Bob');
});
it('it should handle loop statements a sequenceDiagram', function () {
var str = 'sequenceDiagram\n' +
'Alice->Bob: Hello Bob, how are you?\n\n' +
'%% Comment\n' +
'Note right of Bob: Bob thinks\n' +
'loop Multiple happy responses\n\n' +
'Bob-->Alice: I am good thanks!\n' +
'end';
sq.parse(str);
var actors = sq.yy.getActors();
expect(actors.Alice).ToBdescription = 'Alice';
actors.Bob.description = 'Bob';
var messages = sq.yy.getMessages();
expect(messages.length).toBe(5);
expect(messages[0].from).toBe('Alice');
expect(messages[3].from).toBe('Bob');
});
});
describe('when checking the bounds in a sequenceDiagram',function() {
var parseError, _d3, conf;
beforeEach(function () {
sq.yy = require('./sequenceDb');
sq.yy.clear();
parseError = function(err, hash) {
console.log('Syntax error:' + err);
console.log(hash);
};
sq.yy.parseError = parseError;
conf = {
diagramMarginX:50,
diagramMarginY:10,
actorMargin:50,
width:150,
// Height of actor boxes
height:65,
boxMargin:10,
messageMargin:40,
boxTextMargin:15,
noteMargin:25
};
sd.setConf(conf);
});
it('it should handle a simple bound call', function () {
sd.bounds.init();
sd.bounds.insert(100,100,200,200);
var bounds = sd.bounds.getBounds();
expect(bounds.startx).toBe(100);
expect(bounds.starty).toBe(100);
expect(bounds.stopx ).toBe(200);
expect(bounds.stopy ).toBe(200);
});
it('it should handle an expanding bound', function () {
sd.bounds.init();
sd.bounds.insert(100,100,200,200);
sd.bounds.insert(25,50,300,400);
var bounds = sd.bounds.getBounds();
expect(bounds.startx).toBe(25);
expect(bounds.starty).toBe(50);
expect(bounds.stopx ).toBe(300);
expect(bounds.stopy ).toBe(400);
});
it('it should handle inserts within the bound without changing the outer bounds', function () {
sd.bounds.init();
sd.bounds.insert(100,100,200,200);
sd.bounds.insert(25,50,300,400);
sd.bounds.insert(125,150,150,200);
var bounds = sd.bounds.getBounds();
expect(bounds.startx).toBe(25);
expect(bounds.starty).toBe(50);
expect(bounds.stopx ).toBe(300);
expect(bounds.stopy ).toBe(400);
});
it('it should handle a loop without expanding the area', function () {
sd.bounds.init();
sd.bounds.insert(25,50,300,400);
sd.bounds.verticalPos = 150;
sd.bounds.newLoop();
sd.bounds.insert(125,150,150,200);
var loop = sd.bounds.endLoop();
expect(loop.startx).toBe(125-conf.boxMargin);
expect(loop.starty).toBe(150-conf.boxMargin);
expect(loop.stopx ).toBe(150+conf.boxMargin);
expect(loop.stopy ).toBe(200+conf.boxMargin);
// Check bounds of first loop
var bounds = sd.bounds.getBounds();
expect(bounds.startx).toBe(25);
expect(bounds.starty).toBe(50);
expect(bounds.stopx ).toBe(300);
expect(bounds.stopy ).toBe(400);
});
it('it should handle multiple loops withtout expanding the bounds', function () {
sd.bounds.init();
sd.bounds.insert(100,100,1000,1000);
sd.bounds.verticalPos = 200;
sd.bounds.newLoop();
sd.bounds.newLoop();
sd.bounds.insert(200,200,300,300);
// Check bounds of first loop
var loop = sd.bounds.endLoop();
expect(loop.startx).toBe(200-conf.boxMargin);
expect(loop.starty).toBe(200-conf.boxMargin);
expect(loop.stopx ).toBe(300+conf.boxMargin);
expect(loop.stopy ).toBe(300+conf.boxMargin);
// Check bounds of second loop
loop = sd.bounds.endLoop();
expect(loop.startx).toBe(200-2*conf.boxMargin);
expect(loop.starty).toBe(200-2*conf.boxMargin);
expect(loop.stopx ).toBe(300+2*conf.boxMargin);
expect(loop.stopy ).toBe(300+2*conf.boxMargin);
// Check bounds of first loop
var bounds = sd.bounds.getBounds();
expect(bounds.startx).toBe(100);
expect(bounds.starty).toBe(100);
expect(bounds.stopx ).toBe(1000);
expect(bounds.stopy ).toBe(1000);
});
it('it should handle a loop that expands the area', function () {
sd.bounds.init();
sd.bounds.insert(100,100,200,200);
sd.bounds.verticalPos = 200;
sd.bounds.newLoop();
sd.bounds.insert(50,50,300,300);
var loop = sd.bounds.endLoop();
expect(loop.startx).toBe(50 - conf.boxMargin);
expect(loop.starty).toBe(50 - conf.boxMargin);
expect(loop.stopx ).toBe(300 + conf.boxMargin);
expect(loop.stopy ).toBe(300 + conf.boxMargin);
// Check bounds after the loop
var bounds = sd.bounds.getBounds();
expect(bounds.startx).toBe(loop.startx);
expect(bounds.starty).toBe(loop.starty);
expect(bounds.stopx ).toBe(loop.stopx);
expect(bounds.stopy ).toBe(loop.stopy);
});
xit('it should handle multiple loops that expands the area', function () {
sd.bounds.init();
sd.bounds.insert(100,100,200,200);
sd.bounds.newLoop();
sd.bounds.newLoop();
sd.bounds.insert(50,50,300,300);
var loop = sd.bounds.endLoop();
loop = sd.bounds.endLoop();
expect(loop.startx).toBe(50 - 2 * conf.boxMargin);
expect(loop.starty).toBe(50 - 2 * conf.boxMargin);
expect(loop.stopx ).toBe(300 + 2 * conf.boxMargin);
expect(loop.stopy ).toBe(300 + 2 * conf.boxMargin);
// Check bounds after the loop
var bounds = sd.bounds.getBounds();
expect(bounds.startx).toBe(loop.startx);
expect(bounds.starty).toBe(loop.starty);
expect(bounds.stopx ).toBe(loop.stopx);
expect(bounds.stopy ).toBe(loop.stopy);
});
});
describe('when rendering a sequenceDiagram',function() {
var parseError, _d3, conf;
beforeEach(function () {
sq.yy = require('./sequenceDb');
sq.yy.clear();
parseError = function(err, hash) {
console.log('Syntax error:' + err);
console.log(hash);
};
sq.yy.parseError = parseError;
function newD3() {
var o = {
append: function (type) {
return newD3();
},
attr: function (key, val) {
return this;
},
style: function (key, val) {
return this;
},
text: function (txt) {
return this;
},
0:{
0: {
getBBox: function () {
return {
height: 10,
width: 20
};
}
}
}
};
return o;
}
var _d3 = {
select:function(){
return new newD3();
}
};
d3 = _d3;
conf = {
diagramMarginX:50,
diagramMarginY:10,
actorMargin:50,
width:150,
// Height of actor boxes
height:65,
boxMargin:10,
messageMargin:40,
boxTextMargin:15,
noteMargin:25
};
sd.setConf(conf);
});
it('it should handle one actor', function () {
sd.bounds.init();
var str = 'sequenceDiagram\n' +
'participant Alice\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);
expect(bounds.stopy ).toBe(conf.height);
});
it('it should handle one actor and a note', function () {
sd.bounds.init();
var str = 'sequenceDiagram\n' +
'participant Alice\n' +
'Note left of Alice: Alice thinks\n';
sq.parse(str);
sd.draw(str,'tst');
var bounds = sd.bounds.getBounds();
expect(bounds.startx).toBe(-(conf.width/2)-(conf.actorMargin/2));
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 right', function () {
sd.bounds.init();
var str = 'sequenceDiagram\n' +
'participant Alice\n' +
'Note right of 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/2) + (conf.actorMargin/2) + 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 two actors', function () {
sd.bounds.init();
var str = 'sequenceDiagram\n' +
'Alice->Bob: Hello Bob, how are you?\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(0 + conf.messageMargin + conf.height);
});
it('it should draw two actors and two messages', function () {
sd.bounds.init();
var str = 'sequenceDiagram\n' +
'Alice->Bob: Hello Bob, how are you?\n'+
'Bob->Alice: Fine!\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(0 + conf.width*2 + conf.actorMargin);
expect(bounds.stopy ).toBe(0 + 2*conf.messageMargin + conf.height);
});
it('it should draw two actors notes to the right', function () {
sd.bounds.init();
var str = 'sequenceDiagram\n' +
'Alice->Bob: Hello Bob, how are you?\n'+
'Note right of Bob: Bob thinks\n' +
'Bob->Alice: Fine!\n';
sq.parse(str);
sd.draw(str,'tst');
var bounds = sd.bounds.getBounds();
expect(bounds.startx).toBe(0);
expect(bounds.starty).toBe(0);
var expStopX = conf.actorMargin +conf.width+ (conf.width/2) + conf.noteMargin + conf.width;
expect(bounds.stopx ).toBe(expStopX);
expect(bounds.stopy ).toBe(2*conf.messageMargin + conf.height + conf.boxMargin + 10+ 2*conf.noteMargin);
});
it('it should draw two actors notes to the left', function () {
sd.bounds.init();
var str = 'sequenceDiagram\n' +
'Alice->Bob: Hello Bob, how are you?\n'+
'Note left of Alice: Bob thinks\n' +
'Bob->Alice: Fine!\n';
sq.parse(str);
sd.draw(str,'tst');
var bounds = sd.bounds.getBounds();
expect(bounds.startx).toBe( -(conf.width/2)-(conf.actorMargin/2));
expect(bounds.starty).toBe(0);
expect(bounds.stopx ).toBe( conf.width*2 + conf.actorMargin);
expect(bounds.stopy ).toBe( 2*conf.messageMargin + conf.height + conf.boxMargin +10+ 2*conf.noteMargin);
});
it('it should draw two loops', function () {
sd.bounds.init();
var str = 'sequenceDiagram\n' +
'Alice->Bob: Hello Bob, how are you?\n'+
'loop Cheers\n' +
'Bob->Alice: Fine!\n' +
'end';
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(0 + conf.width*2 + conf.actorMargin);
expect(bounds.stopy ).toBe(0 + 2*conf.messageMargin + conf.height + 3*conf.boxMargin + conf.boxTextMargin);
});
});

View File

@ -5,6 +5,108 @@
var sq = require('./parser/sequenceDiagram').parser;
sq.yy = require('./sequenceDb');
var svgDraw = require('./svgDraw');
var conf = {
diagramMarginX:50,
diagramMarginY:10,
// Margin between actors
actorMargin:50,
// Width of actor moxes
width:150,
// Height of actor boxes
height:65,
// Margin around loop boxes
boxMargin:10,
boxTextMargin:15,
noteMargin:10,
// Space between messages
messageMargin:40
};
exports.bounds = {
data:{
startx:undefined,
stopx :undefined,
starty:undefined,
stopy :undefined,
},
verticalPos:0,
list: [],
init : function(){
this.list = [];
this.data = {
startx:undefined,
stopx :undefined,
starty:undefined,
stopy :undefined,
};
this.verticalPos =0;
},
updateVal : function (obj,key,val,fun){
if(typeof obj[key] === 'undefined'){
obj[key] = val;
}else{
obj[key] = fun(val,obj[key]);
}
},
updateLoops:function(startx,starty,stopx,stopy){
var _self = this;
var cnt = 0;
this.list.forEach(function(loop){
cnt++;
// The loop list is a stack so the biggest margins in the beginning of the list
var n = _self.list.length-cnt+1;
_self.updateVal(loop, 'startx',startx - n*conf.boxMargin, Math.min);
_self.updateVal(loop, 'starty',starty - n*conf.boxMargin, Math.min);
_self.updateVal(loop, 'stopx' ,stopx + n*conf.boxMargin, Math.max);
_self.updateVal(loop, 'stopy' ,stopy + n*conf.boxMargin, Math.max);
_self.updateVal(exports.bounds.data,'startx',startx - n*conf.boxMargin ,Math.min);
_self.updateVal(exports.bounds.data,'starty',starty - n*conf.boxMargin ,Math.min);
_self.updateVal(exports.bounds.data,'stopx' ,stopx + n*conf.boxMargin ,Math.max);
_self.updateVal(exports.bounds.data,'stopy' ,stopy + n*conf.boxMargin ,Math.max);
});
},
insert:function(startx,starty,stopx,stopy){
var _startx, _starty, _stopx, _stopy;
_startx = Math.min(startx,stopx);
_stopx = Math.max(startx,stopx);
_starty = Math.min(starty,stopy);
_stopy = Math.max(starty,stopy);
this.updateVal(exports.bounds.data,'startx',_startx,Math.min);
this.updateVal(exports.bounds.data,'starty',_starty,Math.min);
this.updateVal(exports.bounds.data,'stopx' ,_stopx ,Math.max);
this.updateVal(exports.bounds.data,'stopy' ,_stopy ,Math.max);
this.updateLoops(_startx,_starty,_stopx,_stopy);
},
newLoop:function(title){
this.list.push({startx:undefined,starty:this.verticalPos,stopx:undefined,stopy:undefined, title:title});
},
endLoop:function(){
var loop = this.list.pop();
//loop.stopy = exports.bounds.getVerticalPos();
return loop;
},
bumpVerticalPos:function(bump){
this.verticalPos = this.verticalPos + bump;
this.data.stopy = this.verticalPos;
},
getVerticalPos:function(){
return this.verticalPos;
},
getBounds:function(){
return this.data;
}
};
/**
* Draws an actor in the diagram with the attaced line
@ -12,51 +114,207 @@ sq.yy = require('./sequenceDb');
* @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 insertLinebreaks = function (d) {
var el = d3.select(this);
var words = d.split(' ');
el.text('');
for (var i = 0; i < words.length; i++) {
var tspan = el.append('tspan').text(words[i]);
if (i > 0)
tspan.attr('x', 0).attr('dy', '15');
}
};
var drawNote = function(elem, startx, verticalPos, msg){
var rect = svgDraw.getNoteRect();
rect.x = startx;
rect.y = verticalPos;
rect.width = conf.width;
var g = elem.append("g");
var rectElem = g.append("rect")
.attr("x", startX + 25)
.attr("y", verticalPos -25)
.attr("fill", '#EDF2AE')
.attr("stroke", '#666')
.attr("width", 150)
.attr("height", 100)
.attr("rx", 0)
.attr("ry", 0);
var textElem = g.append("text")
.attr("x", startX + 10)
.attr("y", verticalPos - 15)
.style("text-anchor", "start");
msg.message.split('<br>').forEach(function(rowText){
textElem.append("tspan")
.attr("x", startX + 35)
.attr("dy", '1em')
.text(rowText);
});
var rectElem = svgDraw.drawRect(g, rect);
console.log('textElem.height');
console.log(textElem[0][0].getBBox());
rectElem.attr('height',textElem[0][0].getBBox().height+20);
//console.log(textElem.getBBox().height);
var textObj = svgDraw.getTextObj();
textObj.x = startx;
textObj.y = verticalPos+conf.noteMargin;
textObj.textMargin = conf.noteMargin;
textObj.dy = '1em';
textObj.text = msg.message;
//.text(msg.message + '\n' + msg.message)
var textElem = svgDraw.drawText(g,textObj);
var textHeight = textElem[0][0].getBBox().height;
exports.bounds.insert(startx, verticalPos, startx + conf.width, verticalPos + 2*conf.noteMargin + textHeight);
return verticalPos + textElem[0][0].getBBox().height - 10;
rectElem.attr('height',textHeight+ 2*conf.noteMargin);
exports.bounds.bumpVerticalPos(textHeight+ 2*conf.noteMargin);
};
/**
* Draws an actor in the diagram with the attaced line
* @param center - The center of the the actor
* @param pos The position if the actor in the list of actors
* @param description The text in the box
*/
exports.drawLoop = function(elem,bounds){
var g = elem.append("g");
var drawLoopLine = function(startx,starty,stopx,stopy){
g.append("line")
.attr("x1", startx)
.attr("y1", starty)
.attr("x2", stopx )
.attr("y2", stopy )
.attr("stroke-width", 2)
.attr("stroke", "#339933");
};
drawLoopLine(bounds.startx, bounds.starty, bounds.stopx , bounds.starty);
drawLoopLine(bounds.stopx , bounds.starty, bounds.stopx , bounds.stopy );
drawLoopLine(bounds.startx, bounds.stopy , bounds.stopx , bounds.stopy );
drawLoopLine(bounds.startx, bounds.starty, bounds.startx, bounds.stopy );
var txt = svgDraw.getTextObj();
txt.text = "Loop";
txt.x = bounds.startx;
txt.y = bounds.starty;
txt.labelMargin = 1.5 * conf.boxMargin;
svgDraw.drawLabel(g,txt);
txt = svgDraw.getTextObj();
txt.text = bounds.title;
txt.x = bounds.startx + (bounds.stopx - bounds.startx)/2;
txt.y = bounds.starty + 1.5 * conf.boxMargin;
txt.anchor = 'middle';
svgDraw.drawText(g,txt);
};
/**
* Setup arrow head and define the marker. The result is appended to the svg.
*/
var insertArrowHead = function(elem){
elem.append("defs").append("marker")
.attr("id", "arrowhead")
.attr("refX", 5) /*must be smarter way to calculate shift*/
.attr("refY", 2)
.attr("markerWidth", 6)
.attr("markerHeight", 4)
.attr("orient", "auto")
.append("path")
.attr("d", "M 0,0 V 4 L6,2 Z"); //this is actual shape for arrowhead
};
/**
* Draws a message
* @param elem
* @param startx
* @param stopx
* @param verticalPos
* @param txtCenter
* @param msg
*/
var drawMessage = function(elem, startx, stopx, verticalPos, msg){
var g = elem.append("g");
var txtCenter = startx + (stopx-startx)/2;
//Make an SVG Container
//Draw the line
if(msg.type !== 2) {
if (msg.type === 1) {
g.append("line")
.attr("x1", startx)
.attr("y1", verticalPos)
.attr("x2", stopx)
.attr("y2", verticalPos)
.attr("stroke-width", 2)
.attr("stroke", "black")
.style("stroke-dasharray", ("3, 3"))
.attr("class", "link")
.attr("marker-end", "url(#arrowhead)");
//.attr("d", diagonal);
}
else {
g.append("line")
.attr("x1", startx)
.attr("y1", verticalPos)
.attr("x2", stopx)
.attr("y2", verticalPos)
.attr("stroke-width", 2)
.attr("stroke", "black")
.attr("class", "link")
.attr("marker-end", "url(#arrowhead)");
}
g.append("text") // text label for the x axis
.attr("x", txtCenter)
.attr("y", verticalPos - 10)
.style("text-anchor", "middle")
.text(msg.message);
exports.bounds.insert(startx, exports.bounds.getVerticalPos() -10, stopx, exports.bounds.getVerticalPos());
}
else{
var textElem = g.append("text")
.attr("x", txtCenter)
.attr("y", exports.bounds.getVerticalPos() - 10)
.style("text-anchor", "middle")
.text(msg.message);
var box = textElem[0][0].getBBox();
exports.bounds.insert(box.x, exports.bounds.getVerticalPos() -10, box.x+box.width, exports.bounds.getVerticalPos()-10 + box.height);
}
};
/**
* Draws an actor in the diagram with the attaced line
* @param center - The center of the the actor
* @param pos The position if the actor in the liost of actors
* @param description The text in the box
*/
var drawActor = function(elem, left,description){
var center = left + (conf.width/2);
var g = elem.append("g");
g.append("line")
.attr("x1", center)
.attr("y1", 5)
.attr("x2", center)
.attr("y2", 2000)
.attr("stroke-width", '0.5px')
.attr("stroke", '#999');
g.append("rect")
.attr("x", left)
.attr("y", 0)
.attr("fill", '#eaeaea')
.attr("stroke", '#666')
.attr("width", conf.width)
.attr("height", conf.height)
.attr("rx", 3)
.attr("ry", 3);
g.append("text") // text label for the x axis
.attr("x", center)
.attr("y", (conf.height/2)+5)
.style("text-anchor", "middle")
.text(description)
;
exports.bounds.insert(left, 0, left + conf.width, conf.height);
};
module.exports.drawActors = function(diagram, actors, actorKeys){
var i;
// Draw the actors
for(i=0;i<actorKeys.length;i++){
var key = actorKeys[i];
// Add some rendering data to the object
actors[key].x = i*conf.actorMargin +i*conf.width;
actors[key].y = 0;
actors[key].width = conf.diagramMarginY;
actors[key].height = conf.diagramMarginY;
// Draw the box with the attached line
drawActor(diagram, actors[key].x, actors[key].description);
}
// Add a margin between the actor boxes and the first arrow
//exports.bounds.bumpVerticalPos(conf.height+conf.messageMargin);
exports.bounds.bumpVerticalPos(conf.height);
};
module.exports.setConf = function(cnf){
conf = cnf;
};
/**
* Draws a flowchart in the tag with id: id based on the graph definition in text.
* @param text
@ -65,159 +323,68 @@ var drawNote = function(elem, startX, verticalPos, msg){
module.exports.draw = function (text, id) {
sq.yy.clear();
sq.parse(text);
// Intial config for margins etc
var startMargin = 50;
var margin = 50;
var width = 150;
var height = 65;
var yStartMargin = 10;
exports.bounds.init();
var diagram = d3.select('#'+id);
/**
* Draws an actor in the diagram with the attaced line
* @param center - The center of the the actor
* @param pos The position if the actor in the liost of actors
* @param description The text in the box
*/
var drawActor = function(elem, center, pos, description){
var g = elem.append("g");
g.append("line")
.attr("x1", center)
.attr("y1", yStartMargin)
.attr("x2", center)
.attr("y2", 2000)
.attr("stroke-width", '0.5px')
.attr("stroke", '#999');
g.append("rect")
.attr("x", startMargin + pos*margin +i*150)
.attr("y", yStartMargin)
.attr("fill", '#eaeaea')
.attr("stroke", '#666')
.attr("width", width)
.attr("height", height)
.attr("rx", 3)
.attr("ry", 3);
g.append("text") // text label for the x axis
.attr("x", startMargin + pos*margin +i*width + 75)
.attr("y", yStartMargin+37.5)
.style("text-anchor", "middle")
.text(description)
;
};
/**
* Setup arrow head and define the marker. The result is appended to the svg.
*/
var insertArrowHead = function(elem){
elem.append("defs").append("marker")
.attr("id", "arrowhead")
.attr("refX", 5) /*must be smarter way to calculate shift*/
.attr("refY", 2)
.attr("markerWidth", 6)
.attr("markerHeight", 4)
.attr("orient", "auto")
.append("path")
.attr("d", "M 0,0 V 4 L6,2 Z"); //this is actual shape for arrowhead
};
var drawMessage = function(elem, startx, stopx, verticalPos, txtCenter, msg){
var g = elem.append("g");
//Make an SVG Container
//Draw the line
if(msg.type !== 2) {
if (msg.type === 1) {
g.append("line")
.attr("x1", startx)
.attr("y1", verticalPos)
.attr("x2", stopx)
.attr("y2", verticalPos)
.attr("stroke-width", 2)
.attr("stroke", "black")
.style("stroke-dasharray", ("3, 3"))
.attr("class", "link")
.attr("marker-end", "url(#arrowhead)");
//.attr("d", diagonal);
}
else {
g.append("line")
.attr("x1", startx)
.attr("y1", verticalPos)
.attr("x2", stopx)
.attr("y2", verticalPos)
.attr("stroke-width", 2)
.attr("stroke", "black")
.attr("class", "link")
.attr("marker-end", "url(#arrowhead)");
//.attr("d", diagonal);
}
g.append("text") // text label for the x axis
.attr("x", txtCenter)
.attr("y", verticalPos - 10)
.style("text-anchor", "middle")
.text(msg.message);
}
else{
g.append("text") // text label for the x axis
.attr("x", txtCenter)
.attr("y", verticalPos - 10)
.style("text-anchor", "middle")
.text(msg.message);
}
};
// Fetch data from the parsing
var actors = sq.yy.getActors();
var actorKeys = sq.yy.getActorKeys();
var messages = sq.yy.getMessages();
var i, maxX = 0;
// Draw the actors
for(i=0;i<actorKeys.length;i++){
var key = actorKeys[i];
// Add some rendering data to the object
actors[key].x = startMargin + i*margin +i*150;
actors[key].y = yStartMargin;
actors[key].width = yStartMargin;
actors[key].height = yStartMargin;
var center = actors[key].x + (width/2);
// Keep track of width for with setting on the svg
maxX = Math.max(maxX,actors[key].x);
// Draw the box with the attached line
drawActor(diagram, center,i, actors[key].description);
}
maxX = maxX + width;
module.exports.drawActors(diagram, actors, actorKeys);
// The arrow head definition is attached to the svg once
insertArrowHead(diagram);
// Draw the messages/signals
var verticalPos = startMargin + 30;
messages.forEach(function(msg){
verticalPos = verticalPos + 40;
var startx = actors[msg.from].x + width/2;
var stopx = actors[msg.to].x + width/2;
var txtCenter = startx + (stopx-startx)/2;
if(msg.type === 2){
console.log('VP before:',verticalPos);
verticalPos = drawNote(diagram, startx, verticalPos, msg);
console.log('VP after:',verticalPos);
} else {
drawMessage(diagram, startx, stopx, verticalPos, txtCenter, msg);
// Keep track of width for with setting on the svg
maxX = Math.max(maxX,startx + 176);
}
var startx;
var stopx;
switch(msg.type){
case sq.yy.LINETYPE.NOTE:
exports.bounds.bumpVerticalPos(conf.boxMargin);
startx = actors[msg.from].x;
stopx = actors[msg.to].x;
if(msg.placement !== 0){
// Right of
drawNote(diagram, startx + (conf.width + conf.actorMargin)/2, exports.bounds.getVerticalPos(), msg);
}else{
// Left of
drawNote(diagram, startx - (conf.width + conf.actorMargin)/2, exports.bounds.getVerticalPos(), msg);
}
break;
case sq.yy.LINETYPE.LOOP_START:
exports.bounds.bumpVerticalPos(conf.boxMargin);
exports.bounds.newLoop(msg.message);
exports.bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin);
break;
case sq.yy.LINETYPE.LOOP_END:
var loopData = exports.bounds.endLoop();
exports.drawLoop(diagram, loopData);
exports.bounds.bumpVerticalPos(conf.boxMargin);
break;
default:
exports.bounds.bumpVerticalPos(conf.messageMargin);
startx = actors[msg.from].x + conf.width/2;
stopx = actors[msg.to].x + conf.width/2;
drawMessage(diagram, startx, stopx, exports.bounds.getVerticalPos(), msg);
}
});
diagram.attr("height", verticalPos + 40);
diagram.attr("width", maxX );
var box = exports.bounds.getBounds();
var height = box.stopy-box.starty+2*conf.diagramMarginY;
var width = box.stopx-box.startx+2*conf.diagramMarginX;
diagram.attr("height",height);
diagram.attr("width", width );
diagram.attr("viewBox", (box.startx-conf.diagramMarginX) + ' -' +conf.diagramMarginY + ' ' + width + ' ' + height);
};

View File

@ -0,0 +1,85 @@
/**
* Created by knut on 14-12-20.
*/
exports.drawRect = function(elem , rectData){
var rectElem = elem.append("rect");
rectElem.attr("x", rectData.x);
rectElem.attr("y", rectData.y);
rectElem.attr("fill", rectData.fill);
rectElem.attr("stroke", rectData.stroke);
rectElem.attr("width", rectData.width);
rectElem.attr("height", rectData.height);
rectElem.attr("rx", rectData.rx);
rectElem.attr("ry", rectData.ry);
return rectElem;
};
exports.drawText = function(elem , textData){
var textElem = elem.append('text');
textElem.attr('x', textData.x);
textElem.attr('y', textData.y);
textElem.style('text-anchor', textData.anchor);
textElem.style('fill', textData.fill);
textData.text.split('<br>').forEach(function(rowText){
var span = textElem.append('tspan');
span.attr('x', textData.x +textData.textMargin);
span.attr('dy', textData.dy);
span.text(rowText);
});
return textElem;
};
exports.drawLabel = function(elem , txtObject){
var rectData = exports.getNoteRect();
rectData.x = txtObject.x;
rectData.y = txtObject.y;
rectData.width = 50;
rectData.height = 20;
rectData.fill = '#339933';
rectData.stroke = 'none';
//rectData.color = 'white';
var label = exports.drawRect(elem, rectData);
txtObject.y = txtObject.y + txtObject.labelMargin;
txtObject.x = txtObject.x + 0.5*txtObject.labelMargin;
txtObject.fill = 'white';
exports.drawText(elem, txtObject);
//return textElem;
};
exports.getTextObj = function(){
var rect = {
x: 0,
y: 0,
'fill':'black',
'text-anchor': 'start',
style: '#666',
width: 100,
height: 100,
textMargin:0,
rx: 0,
ry: 0
};
return rect;
};
exports.getNoteRect = function(){
var rect = {
x: 0,
y: 0,
fill: '#EDF2AE',
stroke: '#666',
width: 100,
anchor:'start',
height: 100,
rx: 0,
ry: 0
};
return rect;
};

View File

@ -50,7 +50,6 @@ var init = function () {
switch(graphType){
case 'graph':
console.log('FC');
classes = flowRenderer.getClasses(txt, false);
flowRenderer.draw(txt, id, false);
utils.cloneCssStyles(element.firstChild, classes);

View File

@ -58,9 +58,10 @@
<div class="mermaid">
sequenceDiagram
Alice->Bob: Hello Bob, how are you?
Note right of Bob: Bob thinks about <br/> things <br/> to think about
Note left of Bob: Bob thinks about <br/> things <br/> to think about
Bob-->Alice: I am good thanks!
Bob-->John the Long: How about you John?
Bob-->Alice: Checking with John...
Alice->John the Long: Yes... John, how are you?
John the Long-->Alice: Better then you!
@ -68,9 +69,9 @@
<div class="mermaid">
graph LR;
A[Start]-->B{a = '1,2'};
B-->|True|C[test = 1];
B-->|False|Z[Store];
A[Start]-->B{a = '1,2'}
B-->|True|C[test = 1]
B-->|False|Z[Store]
C-->D{condition};
D-->|True|E[test = 2];
D-->|False|F[test = 3];

View File

@ -1,144 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="../dist/mermaid.full.js"></script>
<script>
var mermaid_config = {
startOnLoad:true
}
</script>
<script>
function apa(){
console.log('CLICKED');
}
</script>
<style>
.node-square {
stroke-width: 4px;
stroke: #339933;
fill: #999900;
font-weight: 300;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
font-size: 14px; }
.node-circle { stroke-width: 0.5px; stroke: #339999; fill: #009900; }
.node-odd-override { stroke-width: 3.5px; stroke: #339900; fill: #009999; }
.node-odd { stroke-width: 3.5px; stroke: #339900; fill: #009999; }
</style>
</head>
<body>
<h1>Style</h1>
Styling is applied in the following order:
<ol>
<li>Node default style (see wiki)</li>
<li>CSS on the page</li>
<li>Class definitions inside the graph definition</li>
<li>Inline styling inside the graph definition</li>
</ol>
and the last styling applied is the resulting styling. For instance, "Class definitions inside the graph definition" overrides styling from "CSS on the page".
<h3>CSS in the page head:</h3>
<pre>
&lt;style&gt;
.node-square {
stroke-width: 4px;
stroke: #339933;
fill: #999900;
font-weight: 300;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
font-size: 14px; }
.node-circle { stroke-width: 0.5px; stroke: #339999; fill: #009900; }
.node-odd-override { stroke-width: 3.5px; stroke: #339900; fill: #009999; }
.node-odd { stroke-width: 3.5px; stroke: #339900; fill: #009999; }
&lt;/style&gt;
</pre>
<h3>Graph definition</h3>
<pre>
graph TD;
noc[No class&lt;br />using default];
cyr2((Class node-cyr-undefined&lt;br /&gt;is undefined, using default));
class cyr2 node-cyr-undefined;
ndef[Default style];
noc-->ndef;
cyr2-->ndef;
sq[Class node-square&lt;br /&gt;defined in page CSS];
class sq node-square;
ncss[Page CSS style];
sq--&gt;ncss;
cyr[Class node-cyr&lt;br /&gt;defined by classDef];
od2&gt;Class node-odd-override&lt;br /&gt;defined in page CSS&lt;br /&gt;and defined by classDef];
ncdef[classDef style];
od2-->ncdef;
cyr-->ncdef;
class cyr node-cyr;
class od2 node-odd-override;
classDef node-odd-override fill:#BB00BB,stroke:#666622;
classDef node-cyr fill:#BB0099,stroke:#666622;
e1[Class node-cyr&lt;br /&gt;defined by classDef&lt;br /&gt;and inline style];
class e1 node-e1;
style e1 fill:#FF0000;
e2&gt;Class node-odd-override&lt;br /&gt;defined in page CSS&lt;br /&gt;and defined by classDef&lt;br /&gt;and inline style];
class e2 node-e2;
style e2 fill:#FF0000;
e((Inline style in&lt;br /&gt;graph definition));
style e fill:#FF0000;
ninl[Inline style];
e-->ninl;
e1-->ninl;
e2-->ninl;
classDef node-e1 fill:#990066,stroke:#666622;
classDef node-e2 fill:#990066,stroke:#666622;
</pre>
<div class="mermaid">
graph TD;
noc[No class<br />using default];
cyr2((Class node-cyr-undefined<br />is undefined, using default));
class cyr2 node-cyr-undefined;
ndef[Default style];
noc-->ndef;
cyr2-->ndef;
sq[Class node-square<br />defined in page CSS];
class sq node-square;
ncss[Page CSS style];
sq-->ncss;
cyr[Class node-cyr<br />defined by classDef];
od2>Class node-odd-override<br />defined in page CSS<br />and defined by classDef];
ncdef[classDef style];
od2-->ncdef;
cyr-->ncdef;
class cyr node-cyr;
class od2 node-odd-override;
classDef node-odd-override fill:#BB00BB,stroke:#666622;
classDef node-cyr fill:#BB0099,stroke:#666622;
e1[Class node-cyr<br />defined by classDef<br />and inline style];
class e1 node-e1;
style e1 fill:#FF0000;
e2>Class node-odd-override<br />defined in page CSS<br />and defined by classDef<br />and inline style];
class e2 node-e2;
style e2 fill:#FF0000;
e((Inline style in<br />graph definition));
style e fill:#FF0000;
ninl[Inline style];
e-->ninl;
e1-->ninl;
e2-->ninl;
classDef node-e1 fill:#990066,stroke:#666622;
classDef node-e2 fill:#990066,stroke:#666622;
</div>
</body>
</html>