> return 'EOF';
. return 'INVALID';
/lex
+%left '^'
+
%start start
%% /* language grammar */
start
- : SD document 'EOF' { return yy; }
+ : SD document 'EOF' { yy.apply($2);return $2; }
;
document
- : /* empty */
- | document line
+ : /* empty */ { $$ = [] }
+ | document line {$1.push($2);$$ = $1}
;
line
- : statement { }
- | 'NL'
+ : SPACE statement { $$ = $2 }
+ | statement { $$ = $1 }
+ | NL { $$=[];}
+ | EOF { $$=[];}
;
statement
- : 'participant' actor { $$='actor'; }
- | 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'; }
+ : 'participant' actor 'NL' {$$=$2;}
+ | signal 'NL'
+ | note_statement 'NL'
+ | 'title' SPACE text 'NL'
+ | 'loop' actor document end
+ {
+ $3.unshift({type: 'loopStart', loopText:$2.actor, signalType: yy.LINETYPE.LOOP_START});
+ $3.push({type: 'loopEnd', loopText:$2, signalType: yy.LINETYPE.LOOP_END});
+ $$=$3;}
+ | opt actor document end
+ {
+ $3.unshift({type: 'optStart', optText:$2.actor, signalType: yy.LINETYPE.OPT_START});
+ $3.push({type: 'optEnd', optText:$2.actor, signalType: yy.LINETYPE.OPT_END});
+ $$=$3;}
+ | alt actor document else actor document end
+ {
+ // Alt start
+ $3.unshift({type: 'altStart', altText:$2.actor, signalType: yy.LINETYPE.ALT_START});
+ // Content in alt is already in $3
+ // Else
+ $3.push({type: 'else', altText:$5.actor, signalType: yy.LINETYPE.ALT_ELSE});
+ // Content in other alt
+ $3 = $3.concat($6);
+ // End
+ $3.push({type: 'altEnd', signalType: yy.LINETYPE.ALT_END});
+
+ $$=$3;}
;
note_statement
- : 'note' placement actor message { $$ = yy.addNote($3, $2, $4); }
- | 'note' 'over' actor_pair message { $$ = yy.addNote($3, yy.PLACEMENT.OVER, $4); }
+ : 'note' placement actor text2 {$$=[$3,{type:'addNote', placement:$2, actor:$3.actor, text:$4}];}
+ | 'note' 'over' spaceList actor_pair actor
;
+spaceList
+ : SPACE spaceList
+ | SPACE
+ ;
actor_pair
: actor { $$ = $1; }
| actor ',' actor { $$ = [$1, $3]; }
@@ -84,32 +118,26 @@ placement
;
signal
- : actor signaltype actor message
- { yy.addSignal($1, $3, $4, $2); }
+ : actor signaltype actor text2
+ {$$ = [$1,$3,{type: 'addMessage', from:$1.actor, to:$3.actor, signalType:$2, msg:$4}]}
;
+actors: actors actor
+ | actor
+ ;
actor
- /*: ACTOR { $$ = yy.getActor($1); }*/
- : ACTOR { yy.addActor($1,$1,$1); }
+ : ACTOR {$$={type: 'addActor', actor:$1}}
;
signaltype
- : linetype arrowtype { $$ = $1 | ($2 << 2); }
- | linetype { $$ = $1; }
- ;
-
-linetype
- : LINE { $$ = yy.LINETYPE.SOLID; }
- | DOTLINE { $$ = yy.LINETYPE.DOTTED; }
+ : SOLID_OPEN_ARROW { $$ = yy.LINETYPE.SOLID_OPEN; }
+ | DOTTED_OPEN_ARROW { $$ = yy.LINETYPE.DOTTED_OPEN; }
+ | SOLID_ARROW { $$ = yy.LINETYPE.SOLID; }
+ | DOTTED_ARROW { $$ = yy.LINETYPE.DOTTED; }
+ | SOLID_CROSS { $$ = yy.LINETYPE.SOLID_CROSS; }
+ | DOTTED_CROSS { $$ = yy.LINETYPE.DOTTED_CROSS; }
;
-arrowtype
- : ARROW { $$ = yy.ARROWTYPE.FILLED; }
- | OPENARROW { $$ = yy.ARROWTYPE.OPEN; }
- ;
-
-message
- : MESSAGE { $$ = $1.substring(1).trim().replace(/\\n/gm, "\n"); }
- ;
+text2: TXT {$$ = $1.substring(1).trim().replace(/\\n/gm, "\n");} ;
%%
\ No newline at end of file
diff --git a/src/diagrams/sequenceDiagram/parser/sequenceDiagram.js b/src/diagrams/sequenceDiagram/parser/sequenceDiagram.js
index 3d3934d67c..2b858a80f7 100644
--- a/src/diagrams/sequenceDiagram/parser/sequenceDiagram.js
+++ b/src/diagrams/sequenceDiagram/parser/sequenceDiagram.js
@@ -72,87 +72,107 @@
}
*/
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,17,18,19],$V1=[1,16],$V2=[1,19],$V3=[17,31,32];
+var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[6,8,10,11,15,17,19,20,22,33],$V1=[2,2],$V2=[1,6],$V3=[1,8],$V4=[1,9],$V5=[1,12],$V6=[1,13],$V7=[1,14],$V8=[1,15],$V9=[1,17],$Va=[1,18],$Vb=[2,7],$Vc=[6,8,10,11,15,17,18,19,20,21,22,33],$Vd=[6,8,10,11,15,17,18,19,20,22,33],$Ve=[1,46],$Vf=[1,49],$Vg=[1,53];
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,"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]],
+symbols_: {"error":2,"start":3,"SD":4,"document":5,"EOF":6,"line":7,"SPACE":8,"statement":9,"NL":10,"participant":11,"actor":12,"signal":13,"note_statement":14,"title":15,"text":16,"loop":17,"end":18,"opt":19,"alt":20,"else":21,"note":22,"placement":23,"text2":24,"over":25,"spaceList":26,"actor_pair":27,",":28,"left_of":29,"right_of":30,"signaltype":31,"actors":32,"ACTOR":33,"SOLID_OPEN_ARROW":34,"DOTTED_OPEN_ARROW":35,"SOLID_ARROW":36,"DOTTED_ARROW":37,"SOLID_CROSS":38,"DOTTED_CROSS":39,"TXT":40,"$accept":0,"$end":1},
+terminals_: {2:"error",4:"SD",6:"EOF",8:"SPACE",10:"NL",11:"participant",15:"title",16:"text",17:"loop",18:"end",19:"opt",20:"alt",21:"else",22:"note",25:"over",28:",",29:"left_of",30:"right_of",33:"ACTOR",34:"SOLID_OPEN_ARROW",35:"DOTTED_OPEN_ARROW",36:"SOLID_ARROW",37:"DOTTED_ARROW",38:"SOLID_CROSS",39:"DOTTED_CROSS",40:"TXT"},
+productions_: [0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[9,3],[9,2],[9,2],[9,4],[9,4],[9,4],[9,7],[14,4],[14,5],[26,2],[26,1],[27,1],[27,3],[23,1],[23,1],[13,4],[32,2],[32,1],[12,1],[31,1],[31,1],[31,1],[31,1],[31,1],[31,1],[24,1]],
performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
/* this == yyval */
var $0 = $$.length - 1;
switch (yystate) {
case 1:
- return yy;
+ yy.apply($$[$0-1]);return $$[$0-1];
break;
-case 4:
-
+case 2:
+ this.$ = []
break;
-case 6:
- this.$='actor';
+case 3:
+$$[$0-1].push($$[$0]);this.$ = $$[$0-1]
break;
-case 7:
- this.$='signal';
+case 4: case 5:
+ this.$ = $$[$0]
break;
-case 8:
- this.$='note';
-break;
-case 9:
- yy.setTitle($$[$0]);
+case 6: case 7:
+ this.$=[];
break;
-case 10:
- yy.addSignal(undefined, undefined, $$[$0], yy.LINETYPE.LOOP_START);this.$='loop';
-break;
-case 11:
- yy.addSignal(undefined, undefined, undefined, yy.LINETYPE.LOOP_END);this.$='loop';
+case 8:
+this.$=$$[$0-1];
break;
case 12:
- this.$ = yy.addNote($$[$0-1], $$[$0-2], $$[$0]);
+
+ $$[$0-1].unshift({type: 'loopStart', loopText:$$[$0-2].actor, signalType: yy.LINETYPE.LOOP_START});
+ $$[$0-1].push({type: 'loopEnd', loopText:$$[$0-2], signalType: yy.LINETYPE.LOOP_END});
+ this.$=$$[$0-1];
break;
case 13:
- this.$ = yy.addNote($$[$0-1], yy.PLACEMENT.OVER, $$[$0]);
+
+ $$[$0-1].unshift({type: 'optStart', optText:$$[$0-2].actor, signalType: yy.LINETYPE.OPT_START});
+ $$[$0-1].push({type: 'optEnd', optText:$$[$0-2].actor, signalType: yy.LINETYPE.OPT_END});
+ this.$=$$[$0-1];
break;
-case 14: case 21:
- this.$ = $$[$0];
+case 14:
+
+ // Alt start
+ $$[$0-4].unshift({type: 'altStart', altText:$$[$0-5].actor, signalType: yy.LINETYPE.ALT_START});
+ // Content in alt is already in $$[$0-4]
+ // Else
+ $$[$0-4].push({type: 'else', altText:$$[$0-2].actor, signalType: yy.LINETYPE.ALT_ELSE});
+ // Content in other alt
+ $$[$0-4] = $$[$0-4].concat($$[$0-1]);
+ // End
+ $$[$0-4].push({type: 'altEnd', signalType: yy.LINETYPE.ALT_END});
+
+ this.$=$$[$0-4];
break;
case 15:
+this.$=[$$[$0-1],{type:'addNote', placement:$$[$0-2], actor:$$[$0-1].actor, text:$$[$0]}];
+break;
+case 19:
+ this.$ = $$[$0];
+break;
+case 20:
this.$ = [$$[$0-2], $$[$0]];
break;
-case 16:
+case 21:
this.$ = yy.PLACEMENT.LEFTOF;
break;
-case 17:
+case 22:
this.$ = yy.PLACEMENT.RIGHTOF;
break;
-case 18:
- yy.addSignal($$[$0-3], $$[$0-1], $$[$0], $$[$0-2]);
+case 23:
+this.$ = [$$[$0-3],$$[$0-1],{type: 'addMessage', from:$$[$0-3].actor, to:$$[$0-1].actor, signalType:$$[$0-2], msg:$$[$0]}]
break;
-case 19:
- yy.addActor($$[$0],$$[$0],$$[$0]);
+case 26:
+this.$={type: 'addActor', actor:$$[$0]}
break;
-case 20:
- this.$ = $$[$0-1] | ($$[$0] << 2);
+case 27:
+ this.$ = yy.LINETYPE.SOLID_OPEN;
break;
-case 22:
+case 28:
+ this.$ = yy.LINETYPE.DOTTED_OPEN;
+break;
+case 29:
this.$ = yy.LINETYPE.SOLID;
break;
-case 23:
+case 30:
this.$ = yy.LINETYPE.DOTTED;
break;
-case 24:
- this.$ = yy.ARROWTYPE.FILLED;
+case 31:
+ this.$ = yy.LINETYPE.SOLID_CROSS;
break;
-case 25:
- this.$ = yy.ARROWTYPE.OPEN;
+case 32:
+ this.$ = yy.LINETYPE.DOTTED_CROSS;
break;
-case 26:
- this.$ = $$[$0].substring(1).trim().replace(/\\n/gm, "\n");
+case 33:
+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: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]},
+table: [{3:1,4:[1,2]},{1:[3]},o($V0,$V1,{5:3}),{6:[1,4],7:5,8:$V2,9:7,10:$V3,11:$V4,12:16,13:10,14:11,15:$V5,17:$V6,19:$V7,20:$V8,22:$V9,33:$Va},o($V0,$Vb,{1:[2,1]}),o($Vc,[2,3]),{9:19,11:$V4,12:16,13:10,14:11,15:$V5,17:$V6,19:$V7,20:$V8,22:$V9,33:$Va},o($Vc,[2,5]),o($Vc,[2,6]),{12:20,33:$Va},{10:[1,21]},{10:[1,22]},{8:[1,23]},{12:24,33:$Va},{12:25,33:$Va},{12:26,33:$Va},{31:27,34:[1,28],35:[1,29],36:[1,30],37:[1,31],38:[1,32],39:[1,33]},{23:34,25:[1,35],29:[1,36],30:[1,37]},o([6,8,10,11,15,17,18,19,20,21,22,28,33,34,35,36,37,38,39,40],[2,26]),o($Vc,[2,4]),{10:[1,38]},o($Vc,[2,9]),o($Vc,[2,10]),{16:[1,39]},o($Vd,$V1,{5:40}),o($Vd,$V1,{5:41}),o([6,8,10,11,15,17,19,20,21,22,33],$V1,{5:42}),{12:43,33:$Va},{33:[2,27]},{33:[2,28]},{33:[2,29]},{33:[2,30]},{33:[2,31]},{33:[2,32]},{12:44,33:$Va},{8:$Ve,26:45},{33:[2,21]},{33:[2,22]},o($Vc,[2,8]),{10:[1,47]},{6:$Vf,7:5,8:$V2,9:7,10:$V3,11:$V4,12:16,13:10,14:11,15:$V5,17:$V6,18:[1,48],19:$V7,20:$V8,22:$V9,33:$Va},{6:$Vf,7:5,8:$V2,9:7,10:$V3,11:$V4,12:16,13:10,14:11,15:$V5,17:$V6,18:[1,50],19:$V7,20:$V8,22:$V9,33:$Va},{6:$Vf,7:5,8:$V2,9:7,10:$V3,11:$V4,12:16,13:10,14:11,15:$V5,17:$V6,19:$V7,20:$V8,21:[1,51],22:$V9,33:$Va},{24:52,40:$Vg},{24:54,40:$Vg},{12:56,27:55,33:$Va},{8:$Ve,26:57,33:[2,18]},o($Vc,[2,11]),o($Vc,[2,12]),o($Vc,$Vb),o($Vc,[2,13]),{12:58,33:$Va},{10:[2,23]},{10:[2,33]},{10:[2,15]},{12:59,33:$Va},{28:[1,60],33:[2,19]},{33:[2,17]},o($Vd,$V1,{5:61}),{10:[2,16]},{12:62,33:$Va},{6:$Vf,7:5,8:$V2,9:7,10:$V3,11:$V4,12:16,13:10,14:11,15:$V5,17:$V6,18:[1,63],19:$V7,20:$V8,22:$V9,33:$Va},{33:[2,20]},o($Vc,[2,14])],
+defaultActions: {28:[2,27],29:[2,28],30:[2,29],31:[2,30],32:[2,31],33:[2,32],36:[2,21],37:[2,22],52:[2,23],53:[2,33],54:[2,15],57:[2,17],59:[2,16],62:[2,20]},
parseError: function parseError(str, hash) {
if (hash.recoverable) {
this.trace(str);
@@ -627,56 +647,70 @@ performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
var YYSTATE=YY_START;
switch($avoiding_name_collisions) {
-case 0:return 9;
+case 0:return 10;
break;
-case 1:/* skip whitespace */
+case 1: return 38;
break;
-case 2:/* skip comments */
+case 2: return 39;
break;
-case 3:/* skip comments */
+case 3: return 36;
break;
-case 4:return 10;
+case 4: return 37;
break;
-case 5:return 16;
+case 5:/* skip whitespace */
break;
-case 6:return 18;
+case 6:/* skip comments */
break;
-case 7:return 24;
+case 7:/* skip comments */
break;
-case 8:return 25;
+case 8:return 11;
break;
-case 9:return 21;
+case 9:return 19;
break;
-case 10:return 19;
+case 10:return 17;
break;
-case 11:return 14;
+case 11:return 20;
break;
-case 12:return 4;
+case 12:return 21;
break;
-case 13:return 23;
+case 13:return 18;
break;
-case 14:return 17;
+case 14:return 29;
break;
case 15:return 30;
break;
-case 16:return 29;
+case 16:return 25;
+break;
+case 17:return 22;
+break;
+case 18:return 15;
+break;
+case 19:return 4;
+break;
+case 20:return 28;
+break;
+case 21:return 10;
+break;
+case 22:return 33;
+break;
+case 23:return 34;
break;
-case 17:return 32;
+case 24:return 35;
break;
-case 18:return 31;
+case 25:return 36;
break;
-case 19:return 33;
+case 26:return 37;
break;
-case 20:return 'CMT';
+case 27:return 40;
break;
-case 21:return 6;
+case 28:return 6;
break;
-case 22:return 'INVALID';
+case 29:return 'INVALID';
break;
}
},
-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}}
+rules: [/^(?:[\n]+)/i,/^(?:[\-][x])/i,/^(?:[\-][\-][x])/i,/^(?:[\-][>][>])/i,/^(?:[\-][\-][>][>])/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:participant\b)/i,/^(?:opt\b)/i,/^(?:loop\b)/i,/^(?:alt\b)/i,/^(?:else\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,/^(?:;)/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,19,20,21,22,23,24,25,26,27,28,29],"inclusive":true}}
});
return lexer;
})();
diff --git a/src/diagrams/sequenceDiagram/sequenceDb.js b/src/diagrams/sequenceDiagram/sequenceDb.js
index a34c862e49..c82aae964a 100644
--- a/src/diagrams/sequenceDiagram/sequenceDb.js
+++ b/src/diagrams/sequenceDiagram/sequenceDb.js
@@ -41,11 +41,21 @@ exports.clear = function(){
};
exports.LINETYPE = {
- SOLID : 0,
- DOTTED : 1,
- NOTE : 2,
- LOOP_START: 10,
- LOOP_END : 11,
+ SOLID : 0,
+ DOTTED : 1,
+ NOTE : 2,
+ SOLID_CROSS : 3,
+ DOTTED_CROSS: 4,
+ SOLID_OPEN : 5,
+ DOTTED_OPEN : 6,
+ LOOP_START : 10,
+ LOOP_END : 11,
+ ALT_START : 12,
+ ALT_ELSE : 13,
+ ALT_END : 14,
+ OPT_START : 15,
+ OPT_END : 16
+
};
exports.ARROWTYPE = {
@@ -69,4 +79,54 @@ exports.addNote = function (actor, placement, message){
exports.parseError = function(err, hash) {
console.log('Syntax error:' + err);
+};
+
+exports.apply = function(param){
+ if(param instanceof Array ){
+ param.forEach(function(item){
+ exports.apply(item);
+ });
+ } else {
+ // console.log(param);
+ switch(param.type){
+ case 'addActor':
+ exports.addActor(param.actor, param.actor, param.actor);
+ break;
+ case 'addNote':
+ exports.addNote(param.actor,param.placement, param.text);
+ break;
+ case 'addMessage':
+ exports.addSignal(param.from, param.to, param.msg, param.signalType);
+ break;
+ case 'loopStart':
+ //console.log('Loop text: ',param.loopText);
+ exports.addSignal(undefined, undefined, param.loopText, param.signalType);
+ //yy.addSignal(undefined, undefined, $2, yy.LINETYPE.LOOP_START);
+ break;
+ case 'loopEnd':
+ exports.addSignal(undefined, undefined, undefined, param.signalType);
+ break;
+ case 'optStart':
+ //console.log('Loop text: ',param.loopText);
+ exports.addSignal(undefined, undefined, param.optText, param.signalType);
+ //yy.addSignal(undefined, undefined, $2, yy.LINETYPE.LOOP_START);
+ break;
+ case 'optEnd':
+ exports.addSignal(undefined, undefined, undefined, param.signalType);
+ break;
+ case 'altStart':
+ //console.log('Loop text: ',param.loopText);
+ exports.addSignal(undefined, undefined, param.altText, param.signalType);
+ //yy.addSignal(undefined, undefined, $2, yy.LINETYPE.LOOP_START);
+ break;
+ case 'else':
+ exports.addSignal(undefined, undefined, param.altText, param.signalType);
+ break;
+ case 'altEnd':
+ exports.addSignal(undefined, undefined, undefined, param.signalType);
+ break;
+ }
+
+ // console.log('xxx',param);
+ }
};
\ No newline at end of file
diff --git a/src/diagrams/sequenceDiagram/sequenceDiagram.spec.js b/src/diagrams/sequenceDiagram/sequenceDiagram.spec.js
index b441287aaa..85847dffeb 100644
--- a/src/diagrams/sequenceDiagram/sequenceDiagram.spec.js
+++ b/src/diagrams/sequenceDiagram/sequenceDiagram.spec.js
@@ -19,13 +19,13 @@ describe('when parsing a sequenceDiagram',function() {
it('it should handle a sequenceDiagram defintion', function () {
str = 'sequenceDiagram\n' +
- 'Alice->Bob: Hello Bob, how are you?\n' +
+ 'Alice->Bob:Hello Bob, how are you?\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';
+ expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
var messages = sq.yy.getMessages();
@@ -35,16 +35,101 @@ describe('when parsing a sequenceDiagram',function() {
expect(messages[0].from).toBe('Alice');
expect(messages[2].from).toBe('Bob');
});
+ it('it should space in actor names', function () {
+ str = 'sequenceDiagram\n' +
+ 'Alice->Bob:Hello Bob, how are - you?\n' +
+ 'Bob-->Alice: I am good thanks!\n';
+
+ sq.parse(str);
+ var actors = sq.yy.getActors();
+ expect(actors.Alice.description).toBe('Alice');
+ actors.Bob.description = 'Bob';
+
+ var messages = sq.yy.getMessages();
+
+ expect(messages.length).toBe(2);
+
+ expect(messages[0].from).toBe('Alice');
+ expect(messages[1].from).toBe('Bob');
+ });
+ it('it should handle in async messages', function () {
+ var str = 'sequenceDiagram\n' +
+ 'Alice-xBob:Hello Bob, how are you?\n';
+
+ sq.parse(str);
+ var actors = sq.yy.getActors();
+ //console.log(actors);
+ expect(actors.Alice.description).toBe('Alice');
+ expect(actors.Bob.description).toBe('Bob');
+
+ var messages = sq.yy.getMessages();
+
+
+ expect(messages.length).toBe(1);
+
+ expect(messages[0].type).toBe(sq.yy.LINETYPE.SOLID_CROSS);
+ });
+ it('it should handle in async dotted messages', function () {
+ var str = 'sequenceDiagram\n' +
+ 'Alice--xBob:Hello Bob, how are you?\n';
+
+ sq.parse(str);
+ var actors = sq.yy.getActors();
+ //console.log(actors);
+ expect(actors.Alice.description).toBe('Alice');
+ expect(actors.Bob.description).toBe('Bob');
+
+ var messages = sq.yy.getMessages();
+
+
+ expect(messages.length).toBe(1);
+
+ expect(messages[0].type).toBe(sq.yy.LINETYPE.DOTTED_CROSS);
+ });
+ it('it should handle in arrow messages', function () {
+ var str = 'sequenceDiagram\n' +
+ 'Alice->>Bob:Hello Bob, how are you?\n';
+
+ sq.parse(str);
+ var actors = sq.yy.getActors();
+ expect(actors.Alice.description).toBe('Alice');
+ expect(actors.Bob.description).toBe('Bob');
+
+ var messages = sq.yy.getMessages();
+ //console.log(messages);
+
+
+ expect(messages.length).toBe(1);
+
+ expect(messages[0].type).toBe(sq.yy.LINETYPE.SOLID);
+ });
+ it('it should handle in arrow messages', function () {
+ var str = 'sequenceDiagram\n' +
+ 'Alice-->>Bob:Hello Bob, how are you?\n';
+
+ sq.parse(str);
+ var actors = sq.yy.getActors();
+ expect(actors.Alice.description).toBe('Alice');
+ expect(actors.Bob.description).toBe('Bob');
+
+ var messages = sq.yy.getMessages();
+ //console.log(messages);
+
+
+ expect(messages.length).toBe(1);
+
+ expect(messages[0].type).toBe(sq.yy.LINETYPE.DOTTED);
+ });
it('it should handle comments in a sequenceDiagram', function () {
str = 'sequenceDiagram\n' +
- 'Alice->Bob: Hello Bob, how are you?\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';
+ expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
var messages = sq.yy.getMessages();
@@ -64,7 +149,7 @@ describe('when parsing a sequenceDiagram',function() {
sq.parse(str);
var actors = sq.yy.getActors();
- expect(actors.Alice).ToBdescription = 'Alice';
+ expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
var messages = sq.yy.getMessages();
@@ -75,6 +160,70 @@ describe('when parsing a sequenceDiagram',function() {
expect(messages[2].from).toBe('Bob');
});
+ it('it should handle one leading space in 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.description).toBe('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 several leading spaces in 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.description).toBe('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 several leading spaces in lines in a sequenceDiagram', function () {
+ str = 'sequenceDiagram\n'+
+ 'participant Alice\n'+
+ 'participant Bob\n'+
+ 'Alice->John: Hello John, how are you?\n'+
+ ' loop Healthcheck\n'+
+ 'John->John: Fight against hypochondria\n'+
+ ' end\n'+
+ 'Note right of John: Rational thoughts prevail...\n'+
+ ' John-->Alice: Great!\n'+
+ ' John->Bob: How about you?\n'+
+ 'Bob-->John: Jolly good!\n';
+
+ sq.parse(str);
+ var actors = sq.yy.getActors();
+ expect(actors.Alice.description).toBe('Alice');
+ actors.Bob.description = 'Bob';
+
+ var messages = sq.yy.getMessages();
+
+ expect(messages.length).toBe(8);
+
+ expect(messages[0].from).toBe('Alice');
+ expect(messages[2].from).toBe('John');
+ });
+
it('it should handle loop statements a sequenceDiagram', function () {
var str = 'sequenceDiagram\n' +
'Alice->Bob: Hello Bob, how are you?\n\n' +
@@ -86,19 +235,90 @@ describe('when parsing a sequenceDiagram',function() {
sq.parse(str);
var actors = sq.yy.getActors();
- expect(actors.Alice).ToBdescription = 'Alice';
+ //console.log(actors);
+ expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
var messages = sq.yy.getMessages();
+ //console.log(messages);
expect(messages.length).toBe(5);
+ expect(messages[0].from).toBe('Alice');
+ expect(messages[1].from).toBe('Bob');
+
+
+ });
+ it('it should handle opt 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' +
+ 'opt Perhaps a happy response\n\n' +
+ 'Bob-->Alice: I am good thanks!\n' +
+ 'end';
+
+ sq.parse(str);
+ var actors = sq.yy.getActors();
+ //console.log(actors);
+ expect(actors.Alice.description).toBe('Alice');
+ actors.Bob.description = 'Bob';
+
+ var messages = sq.yy.getMessages();
+ //console.log(messages);
+
+ expect(messages.length).toBe(5);
expect(messages[0].from).toBe('Alice');
- expect(messages[3].from).toBe('Bob');
+ expect(messages[1].from).toBe('Bob');
});
-});
+ it('it should handle opt statements a sequenceDiagram', function () {
+ var str = 'sequenceDiagram;Alice->Bob: Hello Bob, how are you?;opt Perhaps a happy response;Bob-->Alice: I am good thanks!;end;';
+
+ sq.parse(str);
+ var actors = sq.yy.getActors();
+ //console.log(actors);
+ expect(actors.Alice.description).toBe('Alice');
+ actors.Bob.description = 'Bob';
+
+ var messages = sq.yy.getMessages();
+ //console.log(messages);
+
+ expect(messages.length).toBe(4);
+ expect(messages[0].from).toBe('Alice');
+ expect(messages[1].type).toBe(sq.yy.LINETYPE.OPT_START);
+ expect(messages[2].from).toBe('Bob');
+
+
+ });
+
+ it('it should handle alt 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' +
+ 'alt isWell\n\n' +
+ 'Bob-->Alice: I am good thanks!\n' +
+ 'else isSick\n' +
+ 'Bob-->Alice: Feel sick...\n' +
+ 'end';
+
+ sq.parse(str);
+ var actors = sq.yy.getActors();
+
+ expect(actors.Alice.description).toBe('Alice');
+ actors.Bob.description = 'Bob';
+
+ var messages = sq.yy.getMessages();
+ //console.log(messages);
+
+ expect(messages.length).toBe(7);
+ expect(messages[0].from).toBe('Alice');
+ expect(messages[1].from).toBe('Bob');
+
+
+ });});
describe('when checking the bounds in a sequenceDiagram',function() {
var parseError, _d3, conf;
@@ -248,31 +468,6 @@ describe('when checking the bounds in a sequenceDiagram',function() {
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;
@@ -463,7 +658,7 @@ describe('when rendering a sequenceDiagram',function() {
'Alice->Bob: Hello Bob, how are you?\n'+
'loop Cheers\n' +
'Bob->Alice: Fine!\n' +
- 'end';
+ 'end\n';
sq.parse(str);
sd.draw(str,'tst');
diff --git a/src/diagrams/sequenceDiagram/sequenceRenderer.js b/src/diagrams/sequenceDiagram/sequenceRenderer.js
index 079ee070ad..c991358db2 100644
--- a/src/diagrams/sequenceDiagram/sequenceRenderer.js
+++ b/src/diagrams/sequenceDiagram/sequenceRenderer.js
@@ -18,11 +18,11 @@ var conf = {
height:65,
// Margin around loop boxes
boxMargin:10,
- boxTextMargin:15,
+ boxTextMargin:5,
noteMargin:10,
// Space between messages
- messageMargin:40
+ messageMargin:35
};
exports.bounds = {
@@ -96,6 +96,12 @@ exports.bounds = {
//loop.stopy = exports.bounds.getVerticalPos();
return loop;
},
+ addElseToLoop:function(message){
+ var loop = this.list.pop();
+ loop.elsey = exports.bounds.getVerticalPos();
+ loop.elseText = message;
+ this.list.push(loop);
+ },
bumpVerticalPos:function(bump){
this.verticalPos = this.verticalPos + bump;
this.data.stopy = this.verticalPos;
@@ -119,6 +125,7 @@ var drawNote = function(elem, startx, verticalPos, msg){
rect.x = startx;
rect.y = verticalPos;
rect.width = conf.width;
+ rect.class = 'note';
var g = elem.append("g");
var rectElem = svgDraw.drawRect(g, rect);
@@ -129,6 +136,7 @@ var drawNote = function(elem, startx, verticalPos, msg){
textObj.textMargin = conf.noteMargin;
textObj.dy = '1em';
textObj.text = msg.message;
+ textObj.class = 'noteText';
var textElem = svgDraw.drawText(g,textObj);
@@ -139,60 +147,6 @@ var drawNote = function(elem, startx, verticalPos, msg){
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
@@ -207,87 +161,54 @@ var drawMessage = function(elem, startx, stopx, verticalPos, msg){
var g = elem.append("g");
var txtCenter = startx + (stopx-startx)/2;
+ var textElem = g.append("text") // text label for the x axis
+ .attr("x", txtCenter)
+ .attr("y", verticalPos - 7)
+ .style("text-anchor", "middle")
+ .attr("class", "messageText")
+ .text(msg.message);
+
+ var textWidth = textElem[0][0].getBBox().width;
+
+ var line;
+
+ if(startx===stopx){
+ line = g.append("path")
+ .attr('d', 'M ' +startx+ ','+verticalPos+' C ' +(startx+60)+ ','+(verticalPos-10)+' ' +(startx+60)+ ',' +
+ (verticalPos+30)+' ' +startx+ ','+(verticalPos+20));
+
+ exports.bounds.bumpVerticalPos(30);
+ var dx = Math.max(textWidth/2,100);
+ exports.bounds.insert(startx-dx, exports.bounds.getVerticalPos() -10, stopx+dx, exports.bounds.getVerticalPos());
+ }else{
+ line = g.append("line");
+ line.attr("x1", startx);
+ line.attr("y1", verticalPos);
+ line.attr("x2", stopx);
+ line.attr("y2", verticalPos);
+ exports.bounds.insert(startx, exports.bounds.getVerticalPos() -10, stopx, exports.bounds.getVerticalPos());
+ }
//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());
+ if (msg.type === sq.yy.LINETYPE.DOTTED || msg.type === sq.yy.LINETYPE.DOTTED_CROSS || msg.type === sq.yy.LINETYPE.DOTTED_OPEN) {
+ line.style("stroke-dasharray", ("3, 3"));
+ line.attr("class", "messageLine1");
}
- 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);
+ else {
+ line.attr("class", "messageLine0");
}
-};
-/**
- * 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)
- ;
+ line.attr("stroke-width", 2);
+ line.attr("stroke", "black");
+ line.style("fill", "none"); // remove any fill colour
+ if (msg.type === sq.yy.LINETYPE.SOLID || msg.type === sq.yy.LINETYPE.DOTTED){
+ line.attr("marker-end", "url(#arrowhead)");
+ }
+
+ if (msg.type === sq.yy.LINETYPE.SOLID_CROSS || msg.type === sq.yy.LINETYPE.DOTTED_CROSS){
+ line.attr("marker-end", "url(#crosshead)");
+ }
- exports.bounds.insert(left, 0, left + conf.width, conf.height);
};
module.exports.drawActors = function(diagram, actors, actorKeys){
@@ -303,7 +224,9 @@ module.exports.drawActors = function(diagram, actors, actorKeys){
actors[key].height = conf.diagramMarginY;
// Draw the box with the attached line
- drawActor(diagram, actors[key].x, actors[key].description);
+ svgDraw.drawActor(diagram, actors[key].x, actors[key].description, conf);
+ exports.bounds.insert(actors[key].x, 0, actors[key].x + conf.width, conf.height);
+
}
// Add a margin between the actor boxes and the first arrow
@@ -322,10 +245,14 @@ module.exports.setConf = function(cnf){
*/
module.exports.draw = function (text, id) {
sq.yy.clear();
- sq.parse(text);
+ //console.log(text);
+ sq.parse(text+'\n');
exports.bounds.init();
var diagram = d3.select('#'+id);
+ var startx;
+ var stopx;
+
// Fetch data from the parsing
var actors = sq.yy.getActors();
var actorKeys = sq.yy.getActorKeys();
@@ -334,14 +261,13 @@ module.exports.draw = function (text, id) {
module.exports.drawActors(diagram, actors, actorKeys);
// The arrow head definition is attached to the svg once
- insertArrowHead(diagram);
+ svgDraw.insertArrowHead(diagram);
+ svgDraw.insertArrowCrossHead(diagram);
// Draw the messages/signals
messages.forEach(function(msg){
+ var loopData;
-
- var startx;
- var stopx;
switch(msg.type){
case sq.yy.LINETYPE.NOTE:
exports.bounds.bumpVerticalPos(conf.boxMargin);
@@ -364,9 +290,38 @@ module.exports.draw = function (text, id) {
exports.bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin);
break;
case sq.yy.LINETYPE.LOOP_END:
- var loopData = exports.bounds.endLoop();
+ loopData = exports.bounds.endLoop();
+
+ svgDraw.drawLoop(diagram, loopData,'loop', conf);
+ exports.bounds.bumpVerticalPos(conf.boxMargin);
+ break;
+ case sq.yy.LINETYPE.OPT_START:
+ exports.bounds.bumpVerticalPos(conf.boxMargin);
+ exports.bounds.newLoop(msg.message);
+ exports.bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin);
+ break;
+ case sq.yy.LINETYPE.OPT_END:
+ loopData = exports.bounds.endLoop();
+
+ svgDraw.drawLoop(diagram, loopData, 'opt', conf);
+ exports.bounds.bumpVerticalPos(conf.boxMargin);
+ break;
+ case sq.yy.LINETYPE.ALT_START:
+ exports.bounds.bumpVerticalPos(conf.boxMargin);
+ exports.bounds.newLoop(msg.message);
+ exports.bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin);
+ break;
+ case sq.yy.LINETYPE.ALT_ELSE:
+
+ //exports.drawLoop(diagram, loopData);
+ exports.bounds.bumpVerticalPos(conf.boxMargin);
+ loopData = exports.bounds.addElseToLoop(msg.message);
+ exports.bounds.bumpVerticalPos(conf.boxMargin);
+ break;
+ case sq.yy.LINETYPE.ALT_END:
+ loopData = exports.bounds.endLoop();
- exports.drawLoop(diagram, loopData);
+ svgDraw.drawLoop(diagram, loopData,'alt', conf);
exports.bounds.bumpVerticalPos(conf.boxMargin);
break;
default:
diff --git a/src/diagrams/sequenceDiagram/svgDraw.js b/src/diagrams/sequenceDiagram/svgDraw.js
index 5453061437..17fa87e081 100644
--- a/src/diagrams/sequenceDiagram/svgDraw.js
+++ b/src/diagrams/sequenceDiagram/svgDraw.js
@@ -12,6 +12,10 @@ exports.drawRect = function(elem , rectData){
rectElem.attr("rx", rectData.rx);
rectElem.attr("ry", rectData.ry);
+ if(typeof rectData.class !== 'undefined'){
+ rectElem.attr("class", rectData.class);
+ }
+
return rectElem;
};
@@ -20,15 +24,19 @@ exports.drawText = function(elem , textData){
textElem.attr('x', textData.x);
textElem.attr('y', textData.y);
textElem.style('text-anchor', textData.anchor);
- textElem.style('fill', textData.fill);
+ textElem.attr('fill', textData.fill);
- textData.text.split(' ').forEach(function(rowText){
+ textData.text.split(/ /ig).forEach(function(rowText){
var span = textElem.append('tspan');
span.attr('x', textData.x +textData.textMargin);
span.attr('dy', textData.dy);
span.text(rowText);
});
+ if(typeof textData.class !== 'undefined'){
+ textElem.attr("class", textData.class);
+ }
+
return textElem;
};
@@ -38,11 +46,12 @@ exports.drawLabel = function(elem , txtObject){
rectData.y = txtObject.y;
rectData.width = 50;
rectData.height = 20;
- rectData.fill = '#339933';
+ rectData.fill = '#526e52';
rectData.stroke = 'none';
+ rectData.class = 'labelBox';
//rectData.color = 'white';
- var label = exports.drawRect(elem, rectData);
+ exports.drawRect(elem, rectData);
txtObject.y = txtObject.y + txtObject.labelMargin;
txtObject.x = txtObject.x + 0.5*txtObject.labelMargin;
@@ -52,9 +61,143 @@ exports.drawLabel = function(elem , txtObject){
//return textElem;
};
+/**
+ * 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
+ */
+exports.drawActor = function(elem, left,description,conf){
+ 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("class", 'actor-line')
+ .attr("stroke-width", '0.5px')
+ .attr("stroke", '#999');
+
+ var rect = exports.getNoteRect();
+ rect.x = left;
+ rect.fill = '#eaeaea';
+ rect.width = conf.width;
+ rect.height = conf.height;
+ rect.class = 'actor';
+ rect.rx = 3;
+ rect.ry = 3;
+ exports.drawRect(g, rect);
+
+ g.append("text") // text label for the x axis
+ .attr("x", center)
+ .attr("y", (conf.height/2)+5)
+ .attr('class','actor')
+ .style("text-anchor", "middle")
+ .text(description)
+ ;
+};
+
+/**
+ * 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,labelText, conf){
+ 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", "#526e52")
+ .attr('class','loopLine');
+ };
+ 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 );
+ if(typeof bounds.elsey !== 'undefined'){
+ drawLoopLine(bounds.startx, bounds.elsey, bounds.stopx, bounds.elsey );
+ }
+
+ var txt = exports.getTextObj();
+ txt.text = labelText;
+ txt.x = bounds.startx;
+ txt.y = bounds.starty;
+ txt.labelMargin = 1.5 * conf.boxMargin;
+ txt.class = 'labelText';
+ txt.fill = 'white';
+
+ exports.drawLabel(g,txt);
+
+ txt = exports.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';
+ txt.class = 'loopText';
+
+ exports.drawText(g,txt);
+
+ if(typeof bounds.elseText !== 'undefined') {
+ txt.text = '[ ' + bounds.elseText + ' ]';
+ txt.y = bounds.elsey + 1.5 * conf.boxMargin;
+ exports.drawText(g, txt);
+ }
+};
+
+/**
+ * Setup arrow head and define the marker. The result is appended to the svg.
+ */
+exports.insertArrowHead = function(elem){
+ elem.append("defs").append("marker")
+ .attr("id", "arrowhead")
+ .attr("refX", 5)
+ .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
+};
+/**
+ * Setup arrow head and define the marker. The result is appended to the svg.
+ */
+exports.insertArrowCrossHead = function(elem){
+ var defs = elem.append("defs");
+ var marker = defs.append("marker")
+ .attr("id", "crosshead")
+ .attr("markerWidth", 15)
+ .attr("markerHeight", 8)
+ .attr("orient", "auto")
+ .attr("refX", 16)
+ .attr("refY", 4);
+
+ // The arrow
+ marker.append("path")
+ .attr("fill",'black')
+ .attr("stroke",'#000000')
+ .style("stroke-dasharray", ("0, 0"))
+ .attr("stroke-width",'1px')
+ .attr("d", "M 9,2 V 6 L16,4 Z");
+
+ // The cross
+ marker.append("path")
+ .attr("fill",'none')
+ .attr("stroke",'#000000')
+ .style("stroke-dasharray", ("0, 0"))
+ .attr("stroke-width",'1px')
+ .attr("d", "M 0,1 L 6,7 M 6,1 L 0,7")
+ ; //this is actual shape for arrowhead
+
+};
exports.getTextObj = function(){
- var rect = {
+ var txt = {
x: 0,
y: 0,
'fill':'black',
@@ -66,7 +209,7 @@ exports.getTextObj = function(){
rx: 0,
ry: 0
};
- return rect;
+ return txt;
};
exports.getNoteRect = function(){
diff --git a/src/main.js b/src/main.js
index 6d8590fedd..8fa9ab8101 100644
--- a/src/main.js
+++ b/src/main.js
@@ -29,7 +29,9 @@ var init = function () {
// Check if previously processed
if(!element.getAttribute("data-processed")) {
element.setAttribute("data-processed", true);
- } else continue;
+ } else {
+ continue;
+ }
var id;
@@ -63,7 +65,7 @@ var init = function () {
case 'sequenceDiagram':
seq.draw(txt,id);
// TODO - Get styles for sequence diagram
- utils.cloneCssStyles(element.firstChild, classes);
+ utils.cloneCssStyles(element.firstChild, []);
break;
}
@@ -89,28 +91,9 @@ var equals = function (val, variable){
return (val === variable);
}
};
-if(typeof document !== 'undefined'){
- /**
- * Wait for coument loaded before starting the execution
- */
- document.addEventListener('DOMContentLoaded', function(){
- // Check presence of config object
- if(typeof mermaid_config !== 'undefined'){
- // Check if property startOnLoad is set
- if(equals(true,mermaid_config.startOnLoad)){
- init();
- }
- }
- else{
- // No config found, do autostart in this simple case
- init();
- }
- }, false);
-
-}
-
global.mermaid = {
+ startOnLoad:true,
init:function(){
init();
},
@@ -120,4 +103,36 @@ global.mermaid = {
getParser:function(){
return flow.parser;
}
-};
\ No newline at end of file
+};
+
+exports.contentLoaded = function(){
+ // Check state of start config mermaid namespece
+ //console.log('global.mermaid.startOnLoad',global.mermaid.startOnLoad);
+ //console.log('mermaid_config',mermaid_config);
+ if(global.mermaid.startOnLoad) {
+
+ // For backwards compatability reasons also check mermaid_config variable
+ if (typeof mermaid_config !== 'undefined') {
+ // Check if property startOnLoad is set
+ if (equals(true, mermaid_config.startOnLoad)) {
+ global.mermaid.init();
+ }
+ }
+ else {
+ // No config found, do autostart in this simple case
+ global.mermaid.init();
+ }
+ }
+
+};
+
+if(typeof document !== 'undefined'){
+ /**
+ * Wait for coument loaded before starting the execution
+ */
+ document.addEventListener('DOMContentLoaded', function(){
+ exports.contentLoaded();
+ }, false);
+}
+
+
diff --git a/src/main.spec.js b/src/main.spec.js
index 10c0ca2302..e4cd85369e 100644
--- a/src/main.spec.js
+++ b/src/main.spec.js
@@ -6,35 +6,71 @@
*/
var rewire = require("rewire");
var utils = require("./utils");
+var main = require("./main");
describe('when using main and ',function() {
describe('when detecting chart type ',function() {
- var main;
+ //var main;
+ //var document;
+ //var window;
beforeEach(function () {
var MockBrowser = require('mock-browser').mocks.MockBrowser;
var mock = new MockBrowser();
+ delete global.mermaid_config;
+
// and in the run-code inside some object
document = mock.getDocument();
+ window = mock.getWindow();
+ });
+ it('should not start rendering with mermaid_config.startOnLoad set to false', function () {
+ main = rewire('./main');
+ mermaid_config ={startOnLoad : false};
+ document.body.innerHTML = 'graph TD;\na;
';
+ spyOn(global.mermaid,'init');
+ //console.log(main);
+ main.contentLoaded();
+ expect(global.mermaid.init).not.toHaveBeenCalled();
});
- it('should not call start anything with an empty document', function () {
+ it('should not start rendering with mermaid.startOnLoad set to false', function () {
+ main = rewire('./main');
+ mermaid.startOnLoad = false;
+ mermaid_config ={startOnLoad : true};
- mermaid_config ={startOnLoad : false};
+ document.body.innerHTML = 'graph TD;\na;
';
+ spyOn(global.mermaid,'init');
+ main.contentLoaded();
+ expect(global.mermaid.init).not.toHaveBeenCalled();
+ });
+
+ it('should start rendering with both startOnLoad set', function () {
main = rewire('./main');
+ mermaid.startOnLoad = true;
+ mermaid_config ={startOnLoad : true};
+ document.body.innerHTML = 'graph TD;\na;
';
+ spyOn(global.mermaid,'init');
+ main.contentLoaded();
+ expect(global.mermaid.init).toHaveBeenCalled();
+ });
- spyOn(utils,'detectType');
- expect(utils.detectType).not.toHaveBeenCalled();
+ it('should start rendering with mermaid.startOnLoad set and no mermaid_config defined', function () {
+ main = rewire('./main');
+ mermaid.startOnLoad = true;
+ document.body.innerHTML = 'graph TD;\na;
';
+ spyOn(global.mermaid,'init');
+ main.contentLoaded();
+ expect(global.mermaid.init).toHaveBeenCalled();
});
- it('should start something with a mermaid document', function () {
- mermaid_config ={startOnLoad : false};
+
+ it('should start rendering as a default with no changes performed', function () {
main = rewire('./main');
document.body.innerHTML = 'graph TD;\na;
';
- spyOn(utils,'detectType');
- mermaid.init();
- expect(utils.detectType).toHaveBeenCalled();
+ spyOn(global.mermaid,'init');
+ main.contentLoaded();
+ expect(global.mermaid.init).toHaveBeenCalled();
});
});
diff --git a/src/utils.js b/src/utils.js
index 37cce8abc9..611b7c95ba 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -9,7 +9,6 @@
*/
module.exports.detectType = function(text,a){
if(text.match(/^\s*sequenceDiagram/)){
- console.log('Detected sequenceDiagram syntax');
return "sequenceDiagram";
}
@@ -37,14 +36,16 @@ module.exports.cloneCssStyles = function(svg, classes){
var sheets = document.styleSheets;
for (var i = 0; i < sheets.length; i++) {
// Avoid multiple inclusion on pages with multiple graphs
- if (sheets[i].title != 'mermaid-svg-internal-css') {
+ if (sheets[i].title !== 'mermaid-svg-internal-css') {
var rules = sheets[i].cssRules;
- for (var j = 0; j < rules.length; j++) {
- var rule = rules[j];
- if (typeof(rule.style) != "undefined") {
- var elems = svg.querySelectorAll(rule.selectorText);
- if (elems.length > 0) {
- usedStyles += rule.selectorText + " { " + rule.style.cssText + " }\n";
+ if(rules !== null) {
+ for (var j = 0; j < rules.length; j++) {
+ var rule = rules[j];
+ if (typeof(rule.style) !== 'undefined') {
+ var elems = svg.querySelectorAll(rule.selectorText);
+ if (elems.length > 0) {
+ usedStyles += rule.selectorText + " { " + rule.style.cssText + " }\n";
+ }
}
}
}
@@ -59,7 +60,8 @@ module.exports.cloneCssStyles = function(svg, classes){
if (className === 'default') {
defaultStyles = '.node' + ' { ' + classes[className].styles.join("; ") + '; }\n';
} else {
- embeddedStyles += '.' + className + ' { ' + classes[className].styles.join("; ") + '; }\n';
+ embeddedStyles += '.' + className + ' { ' + classes[className].styles.join("; ") + '; }\n';
+ //embeddedStyles += svg.id.trim() + ' .' + className + ' { ' + classes[className].styles.join("; ") + '; }\n';
}
}
}
diff --git a/src/utils.spec.js b/src/utils.spec.js
index ddd0d7f874..10c0162a1d 100644
--- a/src/utils.spec.js
+++ b/src/utils.spec.js
@@ -194,7 +194,7 @@ describe('when cloning CSS ',function() {
expect(stylesToArray(svg)).toEqual([ '.node { stroke:#fff; stroke-width:1.5px; }', '.node { stroke: #eee; }', '.node-square { stroke: #bbb; }']);
});
- it('should handle a default class together with stylesheet in document and classDefs', function () {
+ xit('should handle a default class together with stylesheet in document and classDefs', function () {
var svg = generateSVG();
addStyleToDocument();
utils.cloneCssStyles(svg, { "default": { "styles": ["stroke:#fff","stroke-width:1.5px"] },
diff --git a/test/cli_test-output.js b/test/cli_test-output.js
new file mode 100644
index 0000000000..5cea818d0a
--- /dev/null
+++ b/test/cli_test-output.js
@@ -0,0 +1,101 @@
+var fs = require('fs')
+ , path = require('path')
+
+var test = require('tape')
+ , async = require('async')
+ , clone = require('clone')
+ , rimraf = require('rimraf')
+
+var mermaid = require('../lib')
+
+var singleFile = {
+ files: ['test/fixtures/test.mermaid']
+ , outputDir: 'test/tmp/'
+ , phantomPath: './node_modules/.bin/phantomjs'
+ }
+ , multiFile = {
+ files: ['test/fixtures/test.mermaid', 'test/fixtures/test2.mermaid']
+ , outputDir: 'test/tmp/'
+ , phantomPath: './node_modules/.bin/phantomjs'
+ }
+
+
+test('output of single png', function(t) {
+ t.plan(3)
+
+ var expected = ['test.mermaid.png']
+
+ opt = clone(singleFile)
+ opt.png = true
+
+ mermaid.process(opt.files, opt, function(code) {
+ t.equal(code, 0, 'has clean exit code')
+
+ verifyFiles(expected, opt.outputDir, t)
+ })
+})
+
+test('output of multiple png', function(t) {
+ t.plan(3)
+
+ var expected = ['test.mermaid.png', 'test2.mermaid.png']
+
+ opt = clone(multiFile)
+ opt.png = true
+
+ mermaid.process(opt.files, opt, function(code) {
+ t.equal(code, 0, 'has clean exit code')
+
+ verifyFiles(expected, opt.outputDir, t)
+ })
+})
+
+test('output of single svg', function(t) {
+ t.plan(3)
+
+ var expected = ['test.mermaid.svg']
+
+ opt = clone(singleFile)
+ opt.svg = true
+
+ mermaid.process(opt.files, opt, function(code) {
+ t.equal(code, 0, 'has clean exit code')
+
+ verifyFiles(expected, opt.outputDir, t)
+ })
+})
+
+test('output of multiple svg', function(t) {
+ t.plan(3)
+
+ var expected = ['test.mermaid.svg', 'test2.mermaid.svg']
+
+ opt = clone(multiFile)
+ opt.svg = true
+
+ mermaid.process(opt.files, opt, function(code) {
+ t.equal(code, 0, 'has clean exit code')
+
+ verifyFiles(expected, opt.outputDir, t)
+ })
+})
+
+function verifyFiles(expected, dir, t) {
+ async.each(
+ expected
+ , function(file, cb) {
+ filename = path.join(dir, path.basename(file))
+ fs.stat(filename, function(err, stat) {
+ cb(err)
+ })
+ }
+ , function(err) {
+ t.notOk(err, 'all files passed')
+
+ rimraf(dir, function(rmerr) {
+ t.notOk(rmerr, 'cleaned up')
+ t.end()
+ })
+ }
+ )
+}
diff --git a/test/cli_test-parser.js b/test/cli_test-parser.js
new file mode 100644
index 0000000000..f21acfd677
--- /dev/null
+++ b/test/cli_test-parser.js
@@ -0,0 +1,100 @@
+var test = require('tape')
+ , cliPath = '../lib/cli'
+
+test('parses multiple files', function(t) {
+ t.plan(2)
+
+ var cli = require(cliPath)
+ , argv = ['example/file1.mermaid', 'file2.mermaid', 'file3.mermaid']
+ , expect = ['example/file1.mermaid', 'file2.mermaid', 'file3.mermaid']
+
+ cli.parse(argv, function(err, msg, opt) {
+ t.equal(opt.files.length, 3, 'should have 3 parameters')
+ t.deepEqual(opt.files, expect, 'should match expected values')
+
+ t.end()
+ })
+})
+
+test('defaults to png', function(t) {
+ t.plan(2)
+
+ var cli = require(cliPath)
+ , argv = ['example/file1.mermaid']
+
+ cli.parse(argv, function(err, msg, opt) {
+ t.ok(opt.png, 'png is set by default')
+ t.notOk(opt.svg, 'svg is not set by default')
+
+ t.end()
+ })
+})
+
+test('setting svg unsets png', function(t) {
+ t.plan(2)
+
+ var cli = require(cliPath)
+ , argv = ['example/file1.mermaid', '-s']
+
+ cli.parse(argv, function(err, msg, opt) {
+
+ t.ok(opt.svg, 'svg is set when requested')
+ t.notOk(opt.png, 'png is unset when svg is set')
+
+ t.end()
+ })
+})
+
+test('setting png and svg is allowed', function(t) {
+ t.plan(2)
+
+ var cli = require(cliPath)
+ , argv = ['example/file1.mermaid', '-s', '-p']
+
+ cli.parse(argv, function(err, msg, opt) {
+ t.ok(opt.png, 'png is set when requested')
+ t.ok(opt.svg, 'svg is set when requested')
+
+ t.end()
+ })
+})
+
+test('setting an output directory succeeds', function(t) {
+ t.plan(1)
+
+ var cli = require(cliPath)
+ , argv = ['-o', 'example/']
+
+ cli.parse(argv, function(err, msg, opt) {
+ t.equal(opt.outputDir, 'example/', 'output directory is set')
+ t.end()
+ })
+})
+
+test('setting an output directory incorrectly causes an error', function(t) {
+ t.plan(1)
+
+ var cli = require(cliPath)
+ , argv = ['-o']
+
+ cli.parse(argv, function(err) {
+ t.ok(err, 'an error is raised')
+
+ t.end()
+ })
+})
+
+test('a callback function is called after parsing', function(t) {
+ t.plan(2)
+
+ var cli = require(cliPath)
+ , argv = ['example/test.mermaid']
+ , expects = ['example/test.mermaid']
+
+ cli.parse(argv, function(err, msg, opts) {
+ t.ok(true, 'callback was called')
+ t.deepEqual(argv, opts.files, 'options are as expected')
+
+ t.end()
+ })
+})
diff --git a/test/fixtures/sequence.mermaid b/test/fixtures/sequence.mermaid
new file mode 100644
index 0000000000..e0f8a5b579
--- /dev/null
+++ b/test/fixtures/sequence.mermaid
@@ -0,0 +1,8 @@
+sequenceDiagram
+ Alice->Bob: Hello Bob, how are you?
+ Note right of Bob: Bob thinks
+ 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 than you!
diff --git a/test/fixtures/test.mermaid b/test/fixtures/test.mermaid
new file mode 100644
index 0000000000..d5bf6cb311
--- /dev/null
+++ b/test/fixtures/test.mermaid
@@ -0,0 +1,5 @@
+graph TD;
+ A-->B;
+ A-->C;
+ B-->D;
+ C-->D;
diff --git a/test/fixtures/test2.mermaid b/test/fixtures/test2.mermaid
new file mode 100644
index 0000000000..02a2a061ba
--- /dev/null
+++ b/test/fixtures/test2.mermaid
@@ -0,0 +1,7 @@
+graph LR;
+ A[Hard edge]-->|Link text|B(Round edge);
+ B-->C{Decision};
+ C-->|One|D[Result one];
+ C-->|Two|E[Result two];
+ classDef pink fill:#f9f,stroke:#333,stroke-width:4px;
+ class C pink;
diff --git a/test/seq.css b/test/seq.css
new file mode 100644
index 0000000000..40f9bc28c1
--- /dev/null
+++ b/test/seq.css
@@ -0,0 +1,81 @@
+
+body {
+ background: #fcfcfe;
+ font-family: Helvetica;
+}
+
+.actor {
+ stroke: #CCCCFF;
+ fill: #ECECFF;
+}
+text.actor {
+ fill:black;
+ stroke:none;
+ font-family: Helvetica;
+}
+
+.actor-line {
+ stroke:grey;
+}
+
+.messageLine0 {
+ stroke-width:1.5;
+ stroke-dasharray: "2 2";
+ marker-end:"url(#arrowhead)";
+ stroke:black;
+}
+
+.messageLine1 {
+ stroke-width:1.5;
+ stroke-dasharray: "2 2";
+ stroke:black;
+}
+
+#arrowhead {
+ fill:black;
+
+}
+
+.messageText {
+ fill:black;
+ stroke:none;
+ font-family: 'trebuchet ms', verdana, arial;
+ font-size:14px;
+}
+
+.labelBox {
+ stroke: #CCCCFF;
+ fill: #ECECFF;
+}
+
+.labelText {
+ fill:black;
+ stroke:none;
+ font-family: 'trebuchet ms', verdana, arial;
+}
+
+.loopText {
+ fill:black;
+ stroke:none;
+ font-family: 'trebuchet ms', verdana, arial;
+}
+
+.loopLine {
+ stroke-width:2;
+ stroke-dasharray: "2 2";
+ marker-end:"url(#arrowhead)";
+ stroke: #CCCCFF;
+}
+
+.note {
+ stroke: #decc93;
+ stroke: #CCCCFF;
+ fill: #fff5ad;
+}
+
+.noteText {
+ fill:black;
+ stroke:none;
+ font-family: 'trebuchet ms', verdana, arial;
+ font-size:14px;
+}
\ No newline at end of file
diff --git a/test/seq.html b/test/seq.html
new file mode 100644
index 0000000000..b4e22d3616
--- /dev/null
+++ b/test/seq.html
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ No line breaks
+
+ sequenceDiagram;Alice->>Bob: Hello Bob, how are you?;Bob-->Bob: Hmmm?;Bob-->Alice: Ok;
+
+
+ sequenceDiagram;loop Daily query;Alice->>Bob: Hello Bob, how are you?;alt is sick;Bob->>Alice: Not so good :(;else is well;Bob->>Alice: Feeling fresh like a daisy;end;opt Extra response;Bob->>Alice: Thanks for asking;end;end;
+
+ Message types
+
+
+ sequenceDiagram
+ Alice->>Bob: Hello Bob, how are you?
+ Bob-->>John: How about you John?
+ Bob--xAlice: I am good thanks!
+ Bob-xJohn: I am good thanks!
+ Note right of John: Bob thinks a long long time, so long that the text does not fit on a row.
+
+ Bob-->Alice: Checking with John...
+ Alice->John: Yes... John, how are you?
+
+ Loops, alt and opt
+
+ sequenceDiagram
+ loop Daily query
+ Alice->>Bob: Hello Bob, how are you?
+ alt is sick
+ Bob->>Alice: Not so good :(
+ else is well
+ Bob->>Alice: Feeling fresh like a daisy
+ end
+ opt Extra response
+ Bob->>Alice: Thanks for asking
+ end
+
+ end
+
+ Message to self in loop
+
+ sequenceDiagram
+ participant Alice
+ participant Bob
+ Alice->>John: Hello John, how are you?
+ loop Healthcheck
+ John->>John: Fight against hypochondria
+ end
+ Note right of John: Rational thoughts prevail...
+ John-->>Alice: Great!
+ John->>Bob: How about you?
+ Bob-->>John: Jolly good!
+
+ Bounding test & async message to self
+
+ sequenceDiagram
+ participant Alice
+ participant Bob
+ participant John the Long
+ Alice->Bob: Hello Bob, how are you?
+ loop Outer loop
+ Note left of Alice: Bob thinks about things to think about
+ Bob-xBob: I am good thanks!
+ loop Inner loop
+ Bob->>John the Long: How about you John?
+ Note right of John the Long: Bob thinks a long long time, so long that the text does not fit.
+ end
+ end
+
+ Bob-->>Alice: Checking with John...
+ Alice->>John the Long: Yes... John, how are you?
+ John the Long-->>Alice: Super!
+
+
+
+
+
+
+
+
diff --git a/test/web.html b/test/web.html
index 9bf860ec75..d7bc5dfbc6 100644
--- a/test/web.html
+++ b/test/web.html
@@ -4,70 +4,172 @@
+
+
+
Shapes
- Shape examples:
-
- graph TD;
- sq[Square shape]-->ci((Circle shape));
- od>Odd shape]---|Two line <br>edge comment|ro;
- od2>Really long text in an Odd shape]-->od3>Really long text with linebreak <br>in an Odd shape];
- di{Diamond is <br> broken}-->ro(Rounded <br>square <br>shape);
-
- %% Comments after double percent signs
- di-->ro2(Rounded square shape);
- e((Inner circle))-->f(,.?!+-*ز);
- style e red;
-
-
- graph TD;
- sq[Square shape]-->ci((Circle shape));
- od>Odd shape]---|Two line edge comment|ro;
- od2>Really long text in an Odd shape]-->od3>Really long text with linebreak in an Odd shape];
- di{Diamond is broken}-->ro(Rounded square shape);
- di-->ro2(Rounded square shape);
+ graph TD;
+ A-->B;
+ A-->C;
+ A-->D;
+ B-->D;
+ A-->|Link text|B
+ classDef default fill:#9f6,stroke:#333,stroke-width:2px;
+ classDef green fill:#9f6,stroke:#333,stroke-width:2px;
+ class green B;
+
+ Sub graphs
+ graph LR
+ subgraph old sys 1
+ a1(new client)-->b1(sys1 server)
+ oc1(Old client)-->b2
+ end
+
+ subgraph old sys 2
+ a2(new client)-->b2(sys2 server)
+ oc2(Old client)-->b2
+ end
+
+ subgraph old sys 3
+ a3(new client)-->b3(sys3 server)
+ end
+
+ subgraph New sys
+ a1
+ a2
+ a3
+ end
+
+
+ graph TB
+ subgraph one
+ a1-->a2
+ end
+ subgraph two
+ b1-->b2
+ end
+ subgraph three
+ c1-->c2
+ end
+ c1-->a2
+
+
+ graph TB
+ subgraph
+ sq[Square shape] -.-> ci((Circle shape))
+ od>Odd shape]-. Two line edge comment .-> ro
+ di{Diamond with line break} ==> ro(Rounded square shape)
+ di-->ro2(Rounded square shape)
+ end
+
+ %% Notice that no text in shape are added here instead that is appended further down
+ subgraph Go go
+ e --> od3>Really long text with linebreak in an Odd shape]
+
+ e((Inner / circle and some odd special characters)) --> f(,.?!+-*ز)
+
+ cyr[Cyrillic]-->cyr2((Circle shape Начало))
+ end
+ classDef green fill:#9f6,stroke:#333,stroke-width:2px;
+ classDef orange fill:#f96,stroke:#333,stroke-width:4px,font-size:50%,font-style:bold;
+ class sq,e green
+ class di orange
+
+
+ graph TB
+ subgraph
+ sq[Square shape]-->ci((Circle shape))
+ od>Odd shape]---|Two line edge comment|ro
+ end
+ subgraph
+ od2>Really long text in an Odd shape]-->od3>Really long text with linebreak in an Odd shape];
+ di{Diamond is broken}-->ro(Rounded square shape);
+ di-->ro2(Rounded square shape)
+ end
%% Comments after double percent signs
- e((Inner / circle))-->f(,.?!+-*ز);
- cyr[Cyrillic]-->cyr2((Circle shape Начало));
+ subgraph
+ e((Inner / circle))-->f(,.?!+-*ز);
+ cyr[Cyrillic]-->cyr2((Circle shape Начало));
+ A[Object foo,bar]-->B(Thing)
+ end
style e red;
+ classDef green fill:#9f6,stroke:#333,stroke-width:2px;
+ class green sq
+
+
+ graph LR;
+ A(Central Message Router);
+ B(R TD);
+ C(XYZ);
+ D(S Writer);
+ A-->|R TD Router|B;
+ B-->C;
+ C-->|XYZ Router|D;
Sequence diagrams (experimental)
sequenceDiagram
+ participant John the Long
Alice->Bob: Hello Bob, how are you?
- Note right of Bob: Bob thinks
+ Note left of Bob: Bob thinks
Bob-->Alice: I am good thanks!
Bob-->John the Long: How about you John?
+ Note left of John the Long: Bob thinks
Bob-->Alice: Checking with John...
+
+ loop Multiple status checks
+ loog Naging
Alice->John the Long: Yes... John, how are you?
+ end
John the Long-->Alice: Better then you!
+ end
-
+
sequenceDiagram
- Alice->Bob: Hello Bob, how are you?
- Note left of Bob: Bob thinks about things to think about
- Bob-->Alice: I am good thanks!
- Bob-->John the Long: How about you John?
+ participant Alice
+ Note left of Alice: Bob thinks about things to think about
+
+
+ sequenceDiagram
+ participant Alice
+ participant Bob
+ participant John
+ Alice->>Bob: Hello Bob, how are you?
+ Note left of Alice: Bob thinks about things to think about
+ Bob-->>Alice: I am good thanks!
+ loop Multiple status checks
+ Bob--xJohn: How about you John?
+ Note right of John: Bob thinks
+ end
- Bob-->Alice: Checking with John...
+ Bob--xAlice: Checking with John...
Alice->John the Long: Yes... John, how are you?
- John the Long-->Alice: Better then you!
+ John the Long-->Alice: Better then you!!
+
-
+
graph LR;
A[Start]-->B{a = '1,2'}
B-->|True|C[test = 1]
@@ -97,7 +199,7 @@
Dot syntax (experimental)
a -- e;
}
-
+
digraph
{
a -> b -> c -- d -> e;