Skip to content

added attributes to grammar #74

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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
@@ -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
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.
111 changes: 106 additions & 5 deletions src/diagram.js
Original file line number Diff line number Diff line change
@@ -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();
@@ -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 ];
};

@@ -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
@@ -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
@@ -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
@@ -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';

@@ -81,6 +82,7 @@ signal

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

signaltype
@@ -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
@@ -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);
}

@@ -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;
},

@@ -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) {
@@ -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);
@@ -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();
},
@@ -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);
@@ -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");
//}
});

/******************