Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

added attributes to grammar #74

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,35 @@ $(".diagram").sequenceDiagram({theme: 'hand'});
</script>;
```

Extended example
----------------
we turn

Title: Sample Diagram[fontcolor="white", fillcolor="blue", color="red"]
Participant Alice as A [color="red"]
Participant Bob [fillcolor="blue", fontcolor="white"]
A->Bob: Message [color="gray"]
Note left of A: Hello color\nNotes [URL="http://example.com", fillcolor="orange"]
Note right of Bob: Click Me\nI will take you\nto example.com [URL="http://example.com"]
Note over A, Bob: Gradient colors [fillcolor="90-#f00:5-#00f:95"]

into

![Sample generated UML diagram](https://cdn.rawgit.com/winfinit/images/master/js-sequence-diagram/issue28/color-output-example.svg)

Attributes
----------
We support subset of Graphviz attributes

Attribute | Description
--- | --- |
color | Basic drawing color for graphics, not text.
fillcolor | Color used to fill the background of a node.
fontcolor | Color used for text.
URL | Hyperlinks incorporated into device-dependent output.
href | Same as URL


Build requirements
------------------
```bash
Expand Down
6 changes: 3 additions & 3 deletions build/sequence-diagram-min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion build/sequence-diagram-min.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/copyright.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** js sequence diagrams 1.0.4
/** js sequence diagrams 1.0.5
* http://bramp.github.io/js-sequence-diagrams/
* (c) 2012-2013 Andrew Brampton (bramp.net)
* @license Simplified BSD license.
Expand Down
111 changes: 106 additions & 5 deletions src/diagram.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
}

Diagram.prototype.getActor = function(alias) {
var s = /^(.+) as (\S+)$/i.exec(alias.trim());
alias = alias.trim();
var s = /^(.+) as (\S+)$/i.exec(alias);
var name;
if (s) {
name = s[1].trim();
Expand All @@ -24,13 +25,13 @@
}

name = name.replace(/\\n/gm, "\n");

var i, actors = this.actors;
for (i in actors) {
if (actors[i].alias == alias)
return actors[i];
}
i = actors.push( new Diagram.Actor(alias, name, actors.length) );
var message = new Diagram.Message(name);
i = actors.push( new Diagram.Actor(alias, message, actors.length) );
return actors[ i - 1 ];
};

Expand Down Expand Up @@ -71,11 +72,110 @@
throw new Error("Note should be over two different actors");
}
};

Diagram.Message = function(message) {
this.type = "Message";
this.text = message;
};

Diagram.Message.prototype.setAttr = function(attr_obj) {
this.attr = attr_obj;
};

Diagram.Attributes = function(attr_str) {
this.type = "Attributes";
var text = Object.create({}, {
fill: {
value: "black",
writable: true,
enumerable: true,
configrable: true
},
url: {
writable: true,
enumerable: true,
configrable: true
}
});

var box = Object.create({}, {
url: {
writable: true,
enumerable: true,
configrable: true
},
fill: {
value: "white",
writable: true,
enumerable: true,
configrable: true
}
});

var line = Object.create({}, {
url: {
writable: true,
enumerable: true,
configrable: true
}
});

var paper = Object.create({}, {
fill: {
writable: true,
enumerable: true,
configrable: true
}
});

var attribs = attr_str.split(",");

attribs.map(function(attr) {
/* split key value pairs foo="bar" accounting for different
* quotes and spaces
*/
/^\s*(?:'|")?(.*?)(?:'|")?\s*=\s*(?:'|")(.*?)(?:'|")?\s*$/.exec(attr);
/* raphael implements attributes based on
* types of objects, however attributes that
* DOT provides are flat, so we will attempt to
* translate DOT attributes to raphael
*/
var key = RegExp.$1.toLowerCase();
var value = RegExp.$2;

switch(key) {
case "color":
line.stroke = value;
break;
case "bgcolor":
paper.fill = value;
break;
case "fillcolor":
box.fill = value;
break;
case "fontcolor":
text.fill = value;
break;
case "url":
case "href":
text.href = value;
box.href = value;
line.href = value;
break;
default:
break;
}
});

this.text = text;
this.box = box;
this.line = line;
};

Diagram.Note.prototype.hasManyActors = function() {
return _.isArray(this.actor);
};

Diagram.LINETYPE = {
SOLID : 0,
DOTTED : 1
Expand Down Expand Up @@ -113,11 +213,12 @@

Diagram.parse = function(input) {
grammar.yy = new Diagram();

return grammar.parse(input);
};

// Expose this class externally
this.Diagram = Diagram;


}).call(this);
16 changes: 11 additions & 5 deletions src/grammar.ebnf
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,20 @@
document ::= statement*

statement ::=
( 'title' ':' message
| 'participant' actor
| 'note' ('left of' | 'right of' | 'over') actor ':' message
| actor ( '-' | '--' ) ( '>' | '>>' )? actor ':' message
( 'title' ':' message (attributes)?
| 'participant' ActorName (as ActorAlias)? (attributes)?
| 'note' ('left of' | 'right of' | 'over') ActorId ':' message (attributes)?
| ActorId ( '-' | '--' ) ( '>' | '>>' )? ActorId ':' message (attributes)?
)

ActorId ::= (ActorName | ActorAlias)

attributes ::= '[' attribute (',' attribute)* ']'

attribute ::= key '=' '"' value '"'

/*
message ::= [^\n]+

actor ::= [^\->:\n,]+
actor ::= [^\[\->:\n,]+
*/
17 changes: 13 additions & 4 deletions src/grammar.jison
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@
"note" return 'note';
"title" return 'title';
"," return ',';
[^\->:\n,]+ return 'ACTOR';
[^\[\->:\n,]+ return 'ACTOR';
"--" return 'DOTLINE';
"-" return 'LINE';
">>" return 'OPENARROW';
">" return 'ARROW';
:[^#\n]+ return 'MESSAGE';
:[^\[#\n]+ return 'MESSAGE';
"["[^\n]+"]" return 'MESSAGE_ATTR';
<<EOF>> return 'EOF';
. return 'INVALID';

Expand Down Expand Up @@ -81,6 +82,7 @@ signal

actor
: ACTOR { $$ = yy.getActor($1); }
| actor attribs { $1.name.setAttr($2); }
;

signaltype
Expand All @@ -99,8 +101,15 @@ arrowtype
;

message
: MESSAGE { $$ = $1.substring(1).trim().replace(/\\n/gm, "\n"); }
: MESSAGE
{
$$ = new Diagram.Message($1.substring(1).trim().replace(/\\n/gm, "\n")); }
}
| message attribs { $1.setAttr( $2 ); }
;

attribs
:MESSAGE_ATTR { $$ = new Diagram.Attributes($1.substring(1, $1.length - 1)); }
;

%%
%%
64 changes: 42 additions & 22 deletions src/sequence-diagram.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,13 @@
/**
* Returns the text's bounding box
*/
Raphael.fn.text_bbox = function (text, font) {
Raphael.fn.text_bbox = function (message, font) {
var p;

if (font._obj) {
p = this.print_center(0, 0, text, font._obj, font['font-size']);
p = this.print_center(0, 0, message.text, font._obj, font['font-size']);
} else {
p = this.text(0, 0, text);
p = this.text(0, 0, message.text);
p.attr(font);
}

Expand Down Expand Up @@ -384,7 +385,6 @@
// TODO Refactor a little
diagram.width += 2 * DIAGRAM_MARGIN;
diagram.height += 2 * DIAGRAM_MARGIN + 2 * this._actors_height + this._signals_height;

return this;
},

Expand Down Expand Up @@ -458,13 +458,26 @@
var line;
line = this.draw_line(aX, y1, aX + SELF_SIGNAL_WIDTH, y1);
line.attr(attr);


if ( signal.message.attr ) {
line.attr(signal.message.attr.line);
}

line = this.draw_line(aX + SELF_SIGNAL_WIDTH, y1, aX + SELF_SIGNAL_WIDTH, y2);
line.attr(attr);


if ( signal.message.attr ) {
line.attr(signal.message.attr.line);
}

line = this.draw_line(aX + SELF_SIGNAL_WIDTH, y2, aX, y2);
attr['arrow-end'] = this.arrow_types[signal.arrowtype] + '-wide-long';

line.attr(attr);

if ( signal.message.attr ) {
line.attr(signal.message.attr.line);
}
},

draw_signal : function (signal, offsetY) {
Expand All @@ -486,7 +499,11 @@
'arrow-end': this.arrow_types[signal.arrowtype] + '-wide-long',
'stroke-dasharray': this.line_types[signal.linetype]
});


if ( signal.message.attr ) {
line.attr(signal.message.attr.line);
}

//var ARROW_SIZE = 16;
//var dir = this.actorA.x < this.actorB.x ? 1 : -1;
//draw_arrowhead(bX, offsetY, ARROW_SIZE, dir);
Expand Down Expand Up @@ -525,20 +542,28 @@
* x,y (int) x,y center point for this text
* TODO Horz center the text when it's multi-line print
*/
draw_text : function (x, y, text, font) {
draw_text : function (x, y, message, font) {
var paper = this._paper;
var f = font || {};
var t;

if (f._obj) {
t = paper.print_center(x, y, text, f._obj, f['font-size']);
t = paper.print_center(x, y, message.text, f._obj, f['font-size']);
} else {
t = paper.text(x, y, text);
t = paper.text(x, y, message.text);
t.attr(f);
}

// draw a rect behind it
var bb = t.getBBox();
var r = paper.rect(bb.x, bb.y, bb.width, bb.height);
r.attr({'fill': "#fff", 'stroke': 'none'});
r.attr({'stroke': 'none'});

if ( message.attr ) {
t.attr(message.attr.text);
r.attr(message.attr.box);
}


t.toFront();
},
Expand All @@ -552,6 +577,12 @@
// Draw inner box
var rect = this.draw_rect(x, y, w, h);
rect.attr(LINE);

if ( text.attr ) {
rect.attr(text.attr.box);
rect.attr(text.attr.line);
}


// Draw text (in the center)
x = getCenterX(box);
Expand All @@ -560,17 +591,6 @@
this.draw_text(x, y, text, font);
}

/**
* Draws a arrow head
* direction must be -1 for left, or 1 for right
*/
//function draw_arrowhead(x, y, size, direction) {
// var dx = (size/2) * direction;
// var dy = (size/2);
//
// y -= dy; x -= dx;
// var p = this._paper.path("M" + x + "," + y + "v" + size + "l" + dx + ",-" + (size/2) + "Z");
//}
});

/******************
Expand Down