mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-14 06:43:25 +08:00
Fix for issue #178, auto-line wrap of notes in sequence diagrams
This commit is contained in:
parent
e5a701d04d
commit
4ed345101a
525
dist/mermaid.js
vendored
525
dist/mermaid.js
vendored
@ -24988,9 +24988,11 @@ module.exports={
|
||||
"browserify": "~6.2.0",
|
||||
"clone": "^0.2.0",
|
||||
"codeclimate-test-reporter": "0.0.4",
|
||||
"connect-livereload": "^0.5.3",
|
||||
"d3": "~3.4.13",
|
||||
"dateformat": "^1.0.11",
|
||||
"event-stream": "^3.2.0",
|
||||
"express": "^4.12.4",
|
||||
"foundation": "^4.2.1-1",
|
||||
"front-matter": "^0.2.0",
|
||||
"gulp": "~3.8.9",
|
||||
@ -25001,12 +25003,14 @@ module.exports={
|
||||
"gulp-ext-replace": "~0.1.0",
|
||||
"gulp-filelog": "^0.4.1",
|
||||
"gulp-hogan": "^1.1.0",
|
||||
"gulp-if": "^1.2.5",
|
||||
"gulp-insert": "^0.4.0",
|
||||
"gulp-istanbul": "^0.4.0",
|
||||
"gulp-jasmine": "~1.0.1",
|
||||
"gulp-jison": "~1.2.0",
|
||||
"gulp-jshint": "^1.9.0",
|
||||
"gulp-less": "^3.0.1",
|
||||
"gulp-livereload": "^3.8.0",
|
||||
"gulp-rename": "~1.2.0",
|
||||
"gulp-shell": "^0.2.10",
|
||||
"gulp-tag-version": "^1.2.1",
|
||||
@ -25036,7 +25040,10 @@ module.exports={
|
||||
"require-dir": "^0.3.0",
|
||||
"rewire": "^2.1.3",
|
||||
"rimraf": "^2.2.8",
|
||||
"tape": "^3.0.3"
|
||||
"tape": "^3.0.3",
|
||||
"tiny-lr": "^0.1.6",
|
||||
"vinyl-source-stream": "^1.1.0",
|
||||
"watchify": "^3.2.2"
|
||||
}
|
||||
}
|
||||
|
||||
@ -25069,6 +25076,460 @@ if (!d3) {
|
||||
//console.log(window);
|
||||
module.exports = d3;
|
||||
|
||||
/*
|
||||
|
||||
D3 Text Wrap
|
||||
By Vijith Assar
|
||||
http://www.vijithassar.com
|
||||
http://www.github.com/vijithassar
|
||||
@vijithassar
|
||||
|
||||
Detailed instructions at http://www.github.com/vijithassar/d3textwrap
|
||||
|
||||
*/
|
||||
|
||||
(function() {
|
||||
|
||||
// set this variable to a string value to always force a particular
|
||||
// wrap method for development purposes, for example to check tspan
|
||||
// rendering using a foreignobject-enabled browser. set to 'tspan' to
|
||||
// use tspans and 'foreignobject' to use foreignobject
|
||||
var force_wrap_method = false; // by default no wrap method is forced
|
||||
force_wrap_method = 'tspans'; // uncomment this statement to force tspans
|
||||
// force_wrap_method = 'foreignobjects'; // uncomment this statement to force foreignobjects
|
||||
|
||||
// exit immediately if something in this location
|
||||
// has already been defined; the plugin will defer to whatever
|
||||
// else you're doing in your code
|
||||
if(d3.selection.prototype.textwrap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// double check the force_wrap_method flag
|
||||
// and reset if someone screwed up the above
|
||||
// settings
|
||||
if(typeof force_wrap_method == 'undefined') {
|
||||
var force_wrap_method = false;
|
||||
}
|
||||
|
||||
// create the plugin method twice, both for regular use
|
||||
// and again for use inside the enter() selection
|
||||
d3.selection.prototype.textwrap = d3.selection.enter.prototype.textwrap = function(bounds, padding) {
|
||||
|
||||
// default value of padding is zero if it's undefined
|
||||
var padding = parseInt(padding) || 0;
|
||||
|
||||
// save callee into a variable so we can continue to refer to it
|
||||
// as the function scope changes
|
||||
var selection = this;
|
||||
|
||||
// create a variable to store desired return values in
|
||||
var return_value;
|
||||
|
||||
// extract wrap boundaries from any d3-selected rect and return them
|
||||
// in a format that matches the simpler object argument option
|
||||
var extract_bounds = function(bounds) {
|
||||
// discard the nested array wrappers added by d3
|
||||
var bounding_rect = bounds[0][0];
|
||||
// sanitize the svg element name so we can test against it
|
||||
var element_type = bounding_rect.tagName.toString();
|
||||
// if it's not a rect, exit
|
||||
if(element_type !== 'rect') {
|
||||
return false;
|
||||
// if it's a rect, proceed to extracting the position attributes
|
||||
} else {
|
||||
var bounds_extracted = {};
|
||||
bounds_extracted.x = d3.select(bounding_rect).attr('x') || 0;
|
||||
bounds_extracted.y = d3.select(bounding_rect).attr('y') || 0;
|
||||
bounds_extracted.width = d3.select(bounding_rect).attr('width') || 0;
|
||||
bounds_extracted.height = d3.select(bounding_rect).attr('height') || 0;
|
||||
// also pass along the getter function
|
||||
bounds_extracted.attr = bounds.attr;
|
||||
}
|
||||
return bounds_extracted;
|
||||
}
|
||||
|
||||
// double check the input argument for the wrapping
|
||||
// boundaries to make sure it actually contains all
|
||||
// the information we'll need in order to wrap successfully
|
||||
var verify_bounds = function(bounds) {
|
||||
// quickly add a simple getter method so you can use either
|
||||
// bounds.x or bounds.attr('x') as your notation,
|
||||
// the latter being a common convention among D3
|
||||
// developers
|
||||
if(!bounds.attr) {
|
||||
bounds.attr = function(property) {
|
||||
if(this[property]) {
|
||||
return this[property];
|
||||
}
|
||||
}
|
||||
}
|
||||
// if it's an associative array, make sure it has all the
|
||||
// necessary properties represented directly
|
||||
if(
|
||||
(typeof bounds == 'object') &&
|
||||
(typeof bounds.x !== 'undefined') &&
|
||||
(typeof bounds.y !== 'undefined') &&
|
||||
(typeof bounds.width !== 'undefined') &&
|
||||
(typeof bounds.height !== 'undefined')
|
||||
// if that's the case, then the bounds are fine
|
||||
) {
|
||||
// return the lightly modified bounds
|
||||
return bounds;
|
||||
// if it's a numerically indexed array, assume it's a
|
||||
// d3-selected rect and try to extract the positions
|
||||
} else if (
|
||||
// first try to make sure it's an array using Array.isArray
|
||||
(
|
||||
(typeof Array.isArray == 'function') &&
|
||||
(Array.isArray(bounds))
|
||||
) ||
|
||||
// but since Array.isArray isn't always supported, fall
|
||||
// back to casting to the object to string when it's not
|
||||
(Object.prototype.toString.call(bounds) === '[object Array]')
|
||||
) {
|
||||
// once you're sure it's an array, extract the boundaries
|
||||
// from the rect
|
||||
var extracted_bounds = extract_bounds(bounds);
|
||||
return extracted_bounds;
|
||||
} else {
|
||||
// but if the bounds are neither an object nor a numerical
|
||||
// array, then the bounds argument is invalid and you'll
|
||||
// need to fix it
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var apply_padding = function(bounds, padding) {
|
||||
var padded_bounds = bounds;
|
||||
if(padding !== 0) {
|
||||
padded_bounds.x = parseInt(padded_bounds.x) + padding;
|
||||
padded_bounds.y = parseInt(padded_bounds.y) + padding;
|
||||
padded_bounds.width -= padding * 2;
|
||||
padded_bounds.height -= padding * 2;
|
||||
}
|
||||
return padded_bounds;
|
||||
}
|
||||
|
||||
// verify bounds
|
||||
var verified_bounds = verify_bounds(bounds);
|
||||
|
||||
// modify bounds if a padding value is provided
|
||||
if(padding) {
|
||||
verified_bounds = apply_padding(verified_bounds, padding);
|
||||
}
|
||||
|
||||
// check that we have the necessary conditions for this function to operate properly
|
||||
if(
|
||||
// selection it's operating on cannot be not empty
|
||||
(selection.length == 0) ||
|
||||
// d3 must be available
|
||||
(!d3) ||
|
||||
// desired wrapping bounds must be provided as an input argument
|
||||
(!bounds) ||
|
||||
// input bounds must validate
|
||||
(!verified_bounds)
|
||||
) {
|
||||
// try to return the calling selection if possible
|
||||
// so as not to interfere with methods downstream in the
|
||||
// chain
|
||||
if(selection) {
|
||||
return selection;
|
||||
// if all else fails, just return false. if you hit this point then you're
|
||||
// almost certainly trying to call the textwrap() method on something that
|
||||
// doesn't make sense!
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
// if we've validated everything then we can finally proceed
|
||||
// to the meat of this operation
|
||||
} else {
|
||||
|
||||
// reassign the verified bounds as the set we want
|
||||
// to work with from here on; this ensures that we're
|
||||
// using the same data structure for our bounds regardless
|
||||
// of whether the input argument was a simple object or
|
||||
// a d3 selection
|
||||
bounds = verified_bounds;
|
||||
|
||||
// wrap using html and foreignObjects if they are supported
|
||||
var wrap_with_foreignobjects = function(item) {
|
||||
// establish variables to quickly reference target nodes later
|
||||
var parent = d3.select(item[0].parentNode);
|
||||
var text_node = parent.select('text');
|
||||
var styled_line_height = text_node.style('line-height');
|
||||
// extract our desired content from the single text element
|
||||
var text_to_wrap = text_node.text();
|
||||
// remove the text node and replace with a foreign object
|
||||
text_node.remove();
|
||||
var foreign_object = parent.append('foreignObject');
|
||||
// add foreign object and set dimensions, position, etc
|
||||
foreign_object
|
||||
.attr("requiredFeatures", "http://www.w3.org/TR/SVG11/feature#Extensibility")
|
||||
.attr('x', bounds.x)
|
||||
.attr('y', bounds.y)
|
||||
.attr('width', bounds.width)
|
||||
.attr('height', bounds.height);
|
||||
// insert an HTML div
|
||||
var wrap_div = foreign_object
|
||||
.append('xhtml:div')
|
||||
// this class is currently hardcoded
|
||||
// probably not necessary but easy to
|
||||
// override using .classed() and for now
|
||||
// it's nice to avoid a litany of input
|
||||
// arguments
|
||||
.attr('class', 'wrapped');
|
||||
// set div to same dimensions as foreign object
|
||||
wrap_div
|
||||
.style('height', bounds.height)
|
||||
.style('width', bounds.width)
|
||||
// insert text content
|
||||
.html(text_to_wrap);
|
||||
if(styled_line_height) {
|
||||
wrap_div.style('line-height', styled_line_height);
|
||||
}
|
||||
return_value = parent.select('foreignObject');
|
||||
}
|
||||
|
||||
// wrap with tspans if foreignObject is undefined
|
||||
var wrap_with_tspans = function(item) {
|
||||
// operate on the first text item in the selection
|
||||
var text_node = item[0];
|
||||
var parent = text_node.parentNode;
|
||||
var text_node_selected = d3.select(text_node);
|
||||
// measure initial size of the text node as rendered
|
||||
var text_node_height = text_node.getBBox().height;
|
||||
var text_node_width = text_node.getBBox().width;
|
||||
// figure out the line height, either from rendered height
|
||||
// of the font or attached styling
|
||||
var line_height;
|
||||
var rendered_line_height = text_node_height;
|
||||
var styled_line_height = text_node_selected.style('line-height');
|
||||
if(
|
||||
(styled_line_height) &&
|
||||
(parseInt(styled_line_height))
|
||||
) {
|
||||
line_height = parseInt(styled_line_height.replace('px', ''));
|
||||
} else {
|
||||
line_height = rendered_line_height;
|
||||
}
|
||||
// only fire the rest of this if the text content
|
||||
// overflows the desired dimensions
|
||||
if(text_node_width > bounds.width) {
|
||||
// store whatever is inside the text node
|
||||
// in a variable and then zero out the
|
||||
// initial content; we'll reinsert in a moment
|
||||
// using tspan elements.
|
||||
var text_to_wrap = text_node_selected.text();
|
||||
text_node_selected.text('');
|
||||
if(text_to_wrap) {
|
||||
// keep track of whether we are splitting by spaces
|
||||
// so we know whether to reinsert those spaces later
|
||||
var break_delimiter;
|
||||
// split at spaces to create an array of individual words
|
||||
var text_to_wrap_array;
|
||||
if(text_to_wrap.indexOf(' ') !== -1) {
|
||||
var break_delimiter = ' ';
|
||||
text_to_wrap_array = text_to_wrap.split(' ');
|
||||
} else {
|
||||
// if there are no spaces, figure out the split
|
||||
// points by comparing rendered text width against
|
||||
// bounds and translating that into character position
|
||||
// cuts
|
||||
break_delimiter = '';
|
||||
var string_length = text_to_wrap.length;
|
||||
var number_of_substrings = Math.ceil(text_node_width / bounds.width);
|
||||
var splice_interval = Math.floor(string_length / number_of_substrings);
|
||||
if(
|
||||
!(splice_interval * number_of_substrings >= string_length)
|
||||
) {
|
||||
number_of_substrings++;
|
||||
}
|
||||
var text_to_wrap_array = [];
|
||||
var substring;
|
||||
var start_position;
|
||||
for(var i = 0; i < number_of_substrings; i++) {
|
||||
start_position = i * splice_interval;
|
||||
substring = text_to_wrap.substr(start_position, splice_interval);
|
||||
text_to_wrap_array.push(substring);
|
||||
}
|
||||
}
|
||||
|
||||
// new array where we'll store the words re-assembled into
|
||||
// substrings that have been tested against the desired
|
||||
// maximum wrapping width
|
||||
var substrings = [];
|
||||
// computed text length is arguably incorrectly reported for
|
||||
// all tspans after the first one, in that they will include
|
||||
// the width of previous separate tspans. to compensate we need
|
||||
// to manually track the computed text length of all those
|
||||
// previous tspans and substrings, and then use that to offset
|
||||
// the miscalculation. this then gives us the actual correct
|
||||
// position we want to use in rendering the text in the SVG.
|
||||
var total_offset = 0;
|
||||
// object for storing the results of text length computations later
|
||||
var temp = {};
|
||||
// loop through the words and test the computed text length
|
||||
// of the string against the maximum desired wrapping width
|
||||
for(var i = 0; i < text_to_wrap_array.length; i++) {
|
||||
var word = text_to_wrap_array[i];
|
||||
var previous_string = text_node_selected.text();
|
||||
var previous_width = text_node.getComputedTextLength();
|
||||
// initialize the current word as the first word
|
||||
// or append to the previous string if one exists
|
||||
var new_string;
|
||||
if(previous_string) {
|
||||
new_string = previous_string + break_delimiter + word;
|
||||
} else {
|
||||
new_string = word;
|
||||
}
|
||||
// add the newest substring back to the text node and
|
||||
// measure the length
|
||||
text_node_selected.text(new_string);
|
||||
var new_width = text_node.getComputedTextLength();
|
||||
// adjust the length by the offset we've tracked
|
||||
// due to the misreported length discussed above
|
||||
var test_width = new_width - total_offset;
|
||||
// if our latest version of the string is too
|
||||
// big for the bounds, use the previous
|
||||
// version of the string (without the newest word
|
||||
// added) and use the latest word to restart the
|
||||
// process with a new tspan
|
||||
if(new_width > bounds.width) {
|
||||
if(
|
||||
(previous_string) &&
|
||||
(previous_string !== '')
|
||||
) {
|
||||
total_offset = total_offset + previous_width;
|
||||
temp = {string: previous_string, width: previous_width, offset: total_offset};
|
||||
substrings.push(temp);
|
||||
text_node_selected.text('');
|
||||
text_node_selected.text(word);
|
||||
}
|
||||
}
|
||||
// if we're up to the last word in the array,
|
||||
// get the computed length as is without
|
||||
// appending anything further to it
|
||||
else if(i == text_to_wrap_array.length - 1) {
|
||||
text_node_selected.text('');
|
||||
var final_string = new_string;
|
||||
if(
|
||||
(final_string) &&
|
||||
(final_string !== '')
|
||||
) {
|
||||
if((new_width - total_offset) > 0) {new_width = new_width - total_offset}
|
||||
temp = {string: final_string, width: new_width, offset: total_offset};
|
||||
substrings.push(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// position the overall text node
|
||||
text_node_selected.attr('y', function() {
|
||||
var y_offset = bounds.y;
|
||||
// shift by line-height to move the baseline into
|
||||
// the bounds – otherwise the text baseline would be
|
||||
// at the top of the bounds
|
||||
if(line_height) {y_offset += line_height;}
|
||||
return y_offset;
|
||||
});
|
||||
// shift to the right by the padding value
|
||||
if(padding) {
|
||||
text_node_selected
|
||||
.attr('x', bounds.x)
|
||||
;
|
||||
}
|
||||
|
||||
// append each substring as a tspan
|
||||
var current_tspan;
|
||||
var tspan_count;
|
||||
// double check that the text content has been removed
|
||||
// before we start appending tspans
|
||||
text_node_selected.text('');
|
||||
for(var i = 0; i < substrings.length; i++) {
|
||||
var substring = substrings[i].string;
|
||||
if(i > 0) {
|
||||
var previous_substring = substrings[i - 1];
|
||||
}
|
||||
// only append if we're sure it won't make the tspans
|
||||
// overflow the bounds.
|
||||
if((i) * line_height < bounds.height - (line_height * 1.5)) {
|
||||
current_tspan = text_node_selected.append('tspan')
|
||||
.text(substring);
|
||||
// vertical shift to all tspans after the first one
|
||||
current_tspan
|
||||
.attr('dy', function(d) {
|
||||
if(i > 0) {
|
||||
return line_height;
|
||||
}
|
||||
});
|
||||
// shift left from default position, which
|
||||
// is probably based on the full length of the
|
||||
// text string until we make this adjustment
|
||||
current_tspan
|
||||
// .attr('dx', function() {
|
||||
// if(i == 0) {
|
||||
// var render_offset = 0;
|
||||
// } else if(i > 0) {
|
||||
// render_offset = substrings[i - 1].width;
|
||||
// render_offset = render_offset * -1;
|
||||
// }
|
||||
// return render_offset;
|
||||
// })
|
||||
.attr('x', function() {
|
||||
|
||||
return bounds.x;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// assign our modified text node with tspans
|
||||
// to the return value
|
||||
return_value = d3.select(parent).selectAll('text');
|
||||
}
|
||||
|
||||
// variable used to hold the functions that let us
|
||||
// switch between the wrap methods
|
||||
var wrap_method;
|
||||
|
||||
// if a wrap method if being forced, assign that
|
||||
// function
|
||||
if(force_wrap_method) {
|
||||
if(force_wrap_method == 'foreignobjects') {
|
||||
wrap_method = wrap_with_foreignobjects;
|
||||
} else if (force_wrap_method == 'tspans') {
|
||||
wrap_method = wrap_with_tspans;
|
||||
}
|
||||
}
|
||||
|
||||
// if no wrap method is being forced, then instead
|
||||
// test for browser support of foreignobject and
|
||||
// use whichever wrap method makes sense accordingly
|
||||
if(!force_wrap_method) {
|
||||
if(typeof SVGForeignObjectElement !== 'undefined') {
|
||||
wrap_method = wrap_with_foreignobjects;
|
||||
} else {
|
||||
wrap_method = wrap_with_tspans;
|
||||
}
|
||||
}
|
||||
|
||||
// run the desired wrap function for each item
|
||||
// in the d3 selection that called .textwrap()
|
||||
for(var i = 0; i < selection.length; i++) {
|
||||
var item = selection[i];
|
||||
wrap_method(item);
|
||||
}
|
||||
|
||||
// return the modified nodes so we can chain other
|
||||
// methods to them.
|
||||
return return_value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})();
|
||||
},{"d3":1}],88:[function(require,module,exports){
|
||||
/**
|
||||
* Created by knut on 15-01-14.
|
||||
@ -30465,7 +30926,6 @@ var conf = {
|
||||
// Margin around loop boxes
|
||||
boxMargin:10,
|
||||
boxTextMargin:5,
|
||||
|
||||
noteMargin:10,
|
||||
// Space between messages
|
||||
messageMargin:35,
|
||||
@ -30579,21 +31039,31 @@ var drawNote = function(elem, startx, verticalPos, msg){
|
||||
rect.width = conf.width;
|
||||
rect.class = 'note';
|
||||
|
||||
var g = elem.append("g");
|
||||
var g = elem.append('g');
|
||||
var rectElem = svgDraw.drawRect(g, rect);
|
||||
|
||||
var textObj = svgDraw.getTextObj();
|
||||
textObj.x = startx;
|
||||
textObj.y = verticalPos+conf.noteMargin;
|
||||
textObj.y = verticalPos;
|
||||
textObj.textMargin = conf.noteMargin;
|
||||
textObj.dy = '1em';
|
||||
textObj.text = msg.message;
|
||||
textObj.class = 'noteText';
|
||||
|
||||
var textElem = svgDraw.drawText(g,textObj);
|
||||
var textElem = svgDraw.drawText(g,textObj, conf.width);
|
||||
|
||||
var textHeight = textElem[0][0].getBBox().height;
|
||||
exports.bounds.insert(startx, verticalPos, startx + conf.width, verticalPos + 2*conf.noteMargin + textHeight);
|
||||
if(textHeight > conf.width){
|
||||
textElem.remove();
|
||||
g = elem.append("g");
|
||||
|
||||
textElem = svgDraw.drawText(g,textObj, 2*conf.width);
|
||||
textHeight = textElem[0][0].getBBox().height;
|
||||
rectElem.attr('width',2*conf.width);
|
||||
exports.bounds.insert(startx, verticalPos, startx + 2*conf.width, verticalPos + 2*conf.noteMargin + textHeight);
|
||||
}else{
|
||||
exports.bounds.insert(startx, verticalPos, startx + conf.width, verticalPos + 2*conf.noteMargin + textHeight);
|
||||
}
|
||||
|
||||
rectElem.attr('height',textHeight+ 2*conf.noteMargin);
|
||||
exports.bounds.bumpVerticalPos(textHeight+ 2*conf.noteMargin);
|
||||
@ -30848,23 +31318,38 @@ exports.drawRect = function(elem , rectData){
|
||||
return rectElem;
|
||||
};
|
||||
|
||||
exports.drawText = function(elem , textData){
|
||||
exports.drawText = function(elem, textData, width) {
|
||||
// Remove and ignore br:s
|
||||
var nText = textData.text.replace(/<br\/?>/ig,' ');
|
||||
|
||||
var textElem = elem.append('text');
|
||||
textElem.attr('x', textData.x);
|
||||
textElem.attr('y', textData.y);
|
||||
textElem.style('text-anchor', textData.anchor);
|
||||
textElem.attr('fill', textData.fill);
|
||||
|
||||
textData.text.split(/<br\/?>/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'){
|
||||
if (typeof textData.class !== 'undefined') {
|
||||
textElem.attr("class", textData.class);
|
||||
}
|
||||
/* textData.text.split(/<br\/?>/ig).forEach(function(rowText){
|
||||
var span = textElem.append('tspan');
|
||||
span.attr('x', textData.x +textData.textMargin);
|
||||
span.attr('dy', textData.dy);
|
||||
span.text(rowText);
|
||||
});*/
|
||||
|
||||
|
||||
var span = textElem.append('tspan');
|
||||
span.attr('x', textData.x);
|
||||
span.attr('dy', textData.dy);
|
||||
span.text(nText);
|
||||
if(typeof textElem.textwrap !== 'undefined'){
|
||||
textElem.textwrap({
|
||||
x: textData.x+4, // bounding box is 300 pixels from the left
|
||||
y: textData.y-2, // bounding box is 400 pixels from the top
|
||||
width: width, // bounding box is 500 pixels across
|
||||
height: 1800 // bounding box is 600 pixels tall
|
||||
}, textData.textMargin);
|
||||
}
|
||||
|
||||
return textElem;
|
||||
};
|
||||
@ -31186,8 +31671,8 @@ global.mermaid = {
|
||||
console.log('Mermaid Syntax error:');
|
||||
console.log(err);
|
||||
},
|
||||
render:function(id, text){
|
||||
return mermaidAPI.render(id, text);
|
||||
render:function(id, text,callback, element){
|
||||
return mermaidAPI.render(id, text,callback, element);
|
||||
}
|
||||
};
|
||||
|
||||
@ -31259,6 +31744,10 @@ var d3 = require('./d3');
|
||||
var nextId = 0;
|
||||
|
||||
// Default options, can be overridden at initialization time
|
||||
/**
|
||||
* Object with the co0nfigurations
|
||||
* @type {Object}
|
||||
*/
|
||||
var config = {
|
||||
cloneCssStyles: true,
|
||||
flowchart:{
|
||||
|
8
dist/mermaid.min.js
vendored
8
dist/mermaid.min.js
vendored
File diff suppressed because one or more lines are too long
525
dist/mermaid.slim.js
vendored
525
dist/mermaid.slim.js
vendored
@ -15772,9 +15772,11 @@ module.exports={
|
||||
"browserify": "~6.2.0",
|
||||
"clone": "^0.2.0",
|
||||
"codeclimate-test-reporter": "0.0.4",
|
||||
"connect-livereload": "^0.5.3",
|
||||
"d3": "~3.4.13",
|
||||
"dateformat": "^1.0.11",
|
||||
"event-stream": "^3.2.0",
|
||||
"express": "^4.12.4",
|
||||
"foundation": "^4.2.1-1",
|
||||
"front-matter": "^0.2.0",
|
||||
"gulp": "~3.8.9",
|
||||
@ -15785,12 +15787,14 @@ module.exports={
|
||||
"gulp-ext-replace": "~0.1.0",
|
||||
"gulp-filelog": "^0.4.1",
|
||||
"gulp-hogan": "^1.1.0",
|
||||
"gulp-if": "^1.2.5",
|
||||
"gulp-insert": "^0.4.0",
|
||||
"gulp-istanbul": "^0.4.0",
|
||||
"gulp-jasmine": "~1.0.1",
|
||||
"gulp-jison": "~1.2.0",
|
||||
"gulp-jshint": "^1.9.0",
|
||||
"gulp-less": "^3.0.1",
|
||||
"gulp-livereload": "^3.8.0",
|
||||
"gulp-rename": "~1.2.0",
|
||||
"gulp-shell": "^0.2.10",
|
||||
"gulp-tag-version": "^1.2.1",
|
||||
@ -15820,7 +15824,10 @@ module.exports={
|
||||
"require-dir": "^0.3.0",
|
||||
"rewire": "^2.1.3",
|
||||
"rimraf": "^2.2.8",
|
||||
"tape": "^3.0.3"
|
||||
"tape": "^3.0.3",
|
||||
"tiny-lr": "^0.1.6",
|
||||
"vinyl-source-stream": "^1.1.0",
|
||||
"watchify": "^3.2.2"
|
||||
}
|
||||
}
|
||||
|
||||
@ -15853,6 +15860,460 @@ if (!d3) {
|
||||
//console.log(window);
|
||||
module.exports = d3;
|
||||
|
||||
/*
|
||||
|
||||
D3 Text Wrap
|
||||
By Vijith Assar
|
||||
http://www.vijithassar.com
|
||||
http://www.github.com/vijithassar
|
||||
@vijithassar
|
||||
|
||||
Detailed instructions at http://www.github.com/vijithassar/d3textwrap
|
||||
|
||||
*/
|
||||
|
||||
(function() {
|
||||
|
||||
// set this variable to a string value to always force a particular
|
||||
// wrap method for development purposes, for example to check tspan
|
||||
// rendering using a foreignobject-enabled browser. set to 'tspan' to
|
||||
// use tspans and 'foreignobject' to use foreignobject
|
||||
var force_wrap_method = false; // by default no wrap method is forced
|
||||
force_wrap_method = 'tspans'; // uncomment this statement to force tspans
|
||||
// force_wrap_method = 'foreignobjects'; // uncomment this statement to force foreignobjects
|
||||
|
||||
// exit immediately if something in this location
|
||||
// has already been defined; the plugin will defer to whatever
|
||||
// else you're doing in your code
|
||||
if(d3.selection.prototype.textwrap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// double check the force_wrap_method flag
|
||||
// and reset if someone screwed up the above
|
||||
// settings
|
||||
if(typeof force_wrap_method == 'undefined') {
|
||||
var force_wrap_method = false;
|
||||
}
|
||||
|
||||
// create the plugin method twice, both for regular use
|
||||
// and again for use inside the enter() selection
|
||||
d3.selection.prototype.textwrap = d3.selection.enter.prototype.textwrap = function(bounds, padding) {
|
||||
|
||||
// default value of padding is zero if it's undefined
|
||||
var padding = parseInt(padding) || 0;
|
||||
|
||||
// save callee into a variable so we can continue to refer to it
|
||||
// as the function scope changes
|
||||
var selection = this;
|
||||
|
||||
// create a variable to store desired return values in
|
||||
var return_value;
|
||||
|
||||
// extract wrap boundaries from any d3-selected rect and return them
|
||||
// in a format that matches the simpler object argument option
|
||||
var extract_bounds = function(bounds) {
|
||||
// discard the nested array wrappers added by d3
|
||||
var bounding_rect = bounds[0][0];
|
||||
// sanitize the svg element name so we can test against it
|
||||
var element_type = bounding_rect.tagName.toString();
|
||||
// if it's not a rect, exit
|
||||
if(element_type !== 'rect') {
|
||||
return false;
|
||||
// if it's a rect, proceed to extracting the position attributes
|
||||
} else {
|
||||
var bounds_extracted = {};
|
||||
bounds_extracted.x = d3.select(bounding_rect).attr('x') || 0;
|
||||
bounds_extracted.y = d3.select(bounding_rect).attr('y') || 0;
|
||||
bounds_extracted.width = d3.select(bounding_rect).attr('width') || 0;
|
||||
bounds_extracted.height = d3.select(bounding_rect).attr('height') || 0;
|
||||
// also pass along the getter function
|
||||
bounds_extracted.attr = bounds.attr;
|
||||
}
|
||||
return bounds_extracted;
|
||||
}
|
||||
|
||||
// double check the input argument for the wrapping
|
||||
// boundaries to make sure it actually contains all
|
||||
// the information we'll need in order to wrap successfully
|
||||
var verify_bounds = function(bounds) {
|
||||
// quickly add a simple getter method so you can use either
|
||||
// bounds.x or bounds.attr('x') as your notation,
|
||||
// the latter being a common convention among D3
|
||||
// developers
|
||||
if(!bounds.attr) {
|
||||
bounds.attr = function(property) {
|
||||
if(this[property]) {
|
||||
return this[property];
|
||||
}
|
||||
}
|
||||
}
|
||||
// if it's an associative array, make sure it has all the
|
||||
// necessary properties represented directly
|
||||
if(
|
||||
(typeof bounds == 'object') &&
|
||||
(typeof bounds.x !== 'undefined') &&
|
||||
(typeof bounds.y !== 'undefined') &&
|
||||
(typeof bounds.width !== 'undefined') &&
|
||||
(typeof bounds.height !== 'undefined')
|
||||
// if that's the case, then the bounds are fine
|
||||
) {
|
||||
// return the lightly modified bounds
|
||||
return bounds;
|
||||
// if it's a numerically indexed array, assume it's a
|
||||
// d3-selected rect and try to extract the positions
|
||||
} else if (
|
||||
// first try to make sure it's an array using Array.isArray
|
||||
(
|
||||
(typeof Array.isArray == 'function') &&
|
||||
(Array.isArray(bounds))
|
||||
) ||
|
||||
// but since Array.isArray isn't always supported, fall
|
||||
// back to casting to the object to string when it's not
|
||||
(Object.prototype.toString.call(bounds) === '[object Array]')
|
||||
) {
|
||||
// once you're sure it's an array, extract the boundaries
|
||||
// from the rect
|
||||
var extracted_bounds = extract_bounds(bounds);
|
||||
return extracted_bounds;
|
||||
} else {
|
||||
// but if the bounds are neither an object nor a numerical
|
||||
// array, then the bounds argument is invalid and you'll
|
||||
// need to fix it
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var apply_padding = function(bounds, padding) {
|
||||
var padded_bounds = bounds;
|
||||
if(padding !== 0) {
|
||||
padded_bounds.x = parseInt(padded_bounds.x) + padding;
|
||||
padded_bounds.y = parseInt(padded_bounds.y) + padding;
|
||||
padded_bounds.width -= padding * 2;
|
||||
padded_bounds.height -= padding * 2;
|
||||
}
|
||||
return padded_bounds;
|
||||
}
|
||||
|
||||
// verify bounds
|
||||
var verified_bounds = verify_bounds(bounds);
|
||||
|
||||
// modify bounds if a padding value is provided
|
||||
if(padding) {
|
||||
verified_bounds = apply_padding(verified_bounds, padding);
|
||||
}
|
||||
|
||||
// check that we have the necessary conditions for this function to operate properly
|
||||
if(
|
||||
// selection it's operating on cannot be not empty
|
||||
(selection.length == 0) ||
|
||||
// d3 must be available
|
||||
(!d3) ||
|
||||
// desired wrapping bounds must be provided as an input argument
|
||||
(!bounds) ||
|
||||
// input bounds must validate
|
||||
(!verified_bounds)
|
||||
) {
|
||||
// try to return the calling selection if possible
|
||||
// so as not to interfere with methods downstream in the
|
||||
// chain
|
||||
if(selection) {
|
||||
return selection;
|
||||
// if all else fails, just return false. if you hit this point then you're
|
||||
// almost certainly trying to call the textwrap() method on something that
|
||||
// doesn't make sense!
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
// if we've validated everything then we can finally proceed
|
||||
// to the meat of this operation
|
||||
} else {
|
||||
|
||||
// reassign the verified bounds as the set we want
|
||||
// to work with from here on; this ensures that we're
|
||||
// using the same data structure for our bounds regardless
|
||||
// of whether the input argument was a simple object or
|
||||
// a d3 selection
|
||||
bounds = verified_bounds;
|
||||
|
||||
// wrap using html and foreignObjects if they are supported
|
||||
var wrap_with_foreignobjects = function(item) {
|
||||
// establish variables to quickly reference target nodes later
|
||||
var parent = d3.select(item[0].parentNode);
|
||||
var text_node = parent.select('text');
|
||||
var styled_line_height = text_node.style('line-height');
|
||||
// extract our desired content from the single text element
|
||||
var text_to_wrap = text_node.text();
|
||||
// remove the text node and replace with a foreign object
|
||||
text_node.remove();
|
||||
var foreign_object = parent.append('foreignObject');
|
||||
// add foreign object and set dimensions, position, etc
|
||||
foreign_object
|
||||
.attr("requiredFeatures", "http://www.w3.org/TR/SVG11/feature#Extensibility")
|
||||
.attr('x', bounds.x)
|
||||
.attr('y', bounds.y)
|
||||
.attr('width', bounds.width)
|
||||
.attr('height', bounds.height);
|
||||
// insert an HTML div
|
||||
var wrap_div = foreign_object
|
||||
.append('xhtml:div')
|
||||
// this class is currently hardcoded
|
||||
// probably not necessary but easy to
|
||||
// override using .classed() and for now
|
||||
// it's nice to avoid a litany of input
|
||||
// arguments
|
||||
.attr('class', 'wrapped');
|
||||
// set div to same dimensions as foreign object
|
||||
wrap_div
|
||||
.style('height', bounds.height)
|
||||
.style('width', bounds.width)
|
||||
// insert text content
|
||||
.html(text_to_wrap);
|
||||
if(styled_line_height) {
|
||||
wrap_div.style('line-height', styled_line_height);
|
||||
}
|
||||
return_value = parent.select('foreignObject');
|
||||
}
|
||||
|
||||
// wrap with tspans if foreignObject is undefined
|
||||
var wrap_with_tspans = function(item) {
|
||||
// operate on the first text item in the selection
|
||||
var text_node = item[0];
|
||||
var parent = text_node.parentNode;
|
||||
var text_node_selected = d3.select(text_node);
|
||||
// measure initial size of the text node as rendered
|
||||
var text_node_height = text_node.getBBox().height;
|
||||
var text_node_width = text_node.getBBox().width;
|
||||
// figure out the line height, either from rendered height
|
||||
// of the font or attached styling
|
||||
var line_height;
|
||||
var rendered_line_height = text_node_height;
|
||||
var styled_line_height = text_node_selected.style('line-height');
|
||||
if(
|
||||
(styled_line_height) &&
|
||||
(parseInt(styled_line_height))
|
||||
) {
|
||||
line_height = parseInt(styled_line_height.replace('px', ''));
|
||||
} else {
|
||||
line_height = rendered_line_height;
|
||||
}
|
||||
// only fire the rest of this if the text content
|
||||
// overflows the desired dimensions
|
||||
if(text_node_width > bounds.width) {
|
||||
// store whatever is inside the text node
|
||||
// in a variable and then zero out the
|
||||
// initial content; we'll reinsert in a moment
|
||||
// using tspan elements.
|
||||
var text_to_wrap = text_node_selected.text();
|
||||
text_node_selected.text('');
|
||||
if(text_to_wrap) {
|
||||
// keep track of whether we are splitting by spaces
|
||||
// so we know whether to reinsert those spaces later
|
||||
var break_delimiter;
|
||||
// split at spaces to create an array of individual words
|
||||
var text_to_wrap_array;
|
||||
if(text_to_wrap.indexOf(' ') !== -1) {
|
||||
var break_delimiter = ' ';
|
||||
text_to_wrap_array = text_to_wrap.split(' ');
|
||||
} else {
|
||||
// if there are no spaces, figure out the split
|
||||
// points by comparing rendered text width against
|
||||
// bounds and translating that into character position
|
||||
// cuts
|
||||
break_delimiter = '';
|
||||
var string_length = text_to_wrap.length;
|
||||
var number_of_substrings = Math.ceil(text_node_width / bounds.width);
|
||||
var splice_interval = Math.floor(string_length / number_of_substrings);
|
||||
if(
|
||||
!(splice_interval * number_of_substrings >= string_length)
|
||||
) {
|
||||
number_of_substrings++;
|
||||
}
|
||||
var text_to_wrap_array = [];
|
||||
var substring;
|
||||
var start_position;
|
||||
for(var i = 0; i < number_of_substrings; i++) {
|
||||
start_position = i * splice_interval;
|
||||
substring = text_to_wrap.substr(start_position, splice_interval);
|
||||
text_to_wrap_array.push(substring);
|
||||
}
|
||||
}
|
||||
|
||||
// new array where we'll store the words re-assembled into
|
||||
// substrings that have been tested against the desired
|
||||
// maximum wrapping width
|
||||
var substrings = [];
|
||||
// computed text length is arguably incorrectly reported for
|
||||
// all tspans after the first one, in that they will include
|
||||
// the width of previous separate tspans. to compensate we need
|
||||
// to manually track the computed text length of all those
|
||||
// previous tspans and substrings, and then use that to offset
|
||||
// the miscalculation. this then gives us the actual correct
|
||||
// position we want to use in rendering the text in the SVG.
|
||||
var total_offset = 0;
|
||||
// object for storing the results of text length computations later
|
||||
var temp = {};
|
||||
// loop through the words and test the computed text length
|
||||
// of the string against the maximum desired wrapping width
|
||||
for(var i = 0; i < text_to_wrap_array.length; i++) {
|
||||
var word = text_to_wrap_array[i];
|
||||
var previous_string = text_node_selected.text();
|
||||
var previous_width = text_node.getComputedTextLength();
|
||||
// initialize the current word as the first word
|
||||
// or append to the previous string if one exists
|
||||
var new_string;
|
||||
if(previous_string) {
|
||||
new_string = previous_string + break_delimiter + word;
|
||||
} else {
|
||||
new_string = word;
|
||||
}
|
||||
// add the newest substring back to the text node and
|
||||
// measure the length
|
||||
text_node_selected.text(new_string);
|
||||
var new_width = text_node.getComputedTextLength();
|
||||
// adjust the length by the offset we've tracked
|
||||
// due to the misreported length discussed above
|
||||
var test_width = new_width - total_offset;
|
||||
// if our latest version of the string is too
|
||||
// big for the bounds, use the previous
|
||||
// version of the string (without the newest word
|
||||
// added) and use the latest word to restart the
|
||||
// process with a new tspan
|
||||
if(new_width > bounds.width) {
|
||||
if(
|
||||
(previous_string) &&
|
||||
(previous_string !== '')
|
||||
) {
|
||||
total_offset = total_offset + previous_width;
|
||||
temp = {string: previous_string, width: previous_width, offset: total_offset};
|
||||
substrings.push(temp);
|
||||
text_node_selected.text('');
|
||||
text_node_selected.text(word);
|
||||
}
|
||||
}
|
||||
// if we're up to the last word in the array,
|
||||
// get the computed length as is without
|
||||
// appending anything further to it
|
||||
else if(i == text_to_wrap_array.length - 1) {
|
||||
text_node_selected.text('');
|
||||
var final_string = new_string;
|
||||
if(
|
||||
(final_string) &&
|
||||
(final_string !== '')
|
||||
) {
|
||||
if((new_width - total_offset) > 0) {new_width = new_width - total_offset}
|
||||
temp = {string: final_string, width: new_width, offset: total_offset};
|
||||
substrings.push(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// position the overall text node
|
||||
text_node_selected.attr('y', function() {
|
||||
var y_offset = bounds.y;
|
||||
// shift by line-height to move the baseline into
|
||||
// the bounds – otherwise the text baseline would be
|
||||
// at the top of the bounds
|
||||
if(line_height) {y_offset += line_height;}
|
||||
return y_offset;
|
||||
});
|
||||
// shift to the right by the padding value
|
||||
if(padding) {
|
||||
text_node_selected
|
||||
.attr('x', bounds.x)
|
||||
;
|
||||
}
|
||||
|
||||
// append each substring as a tspan
|
||||
var current_tspan;
|
||||
var tspan_count;
|
||||
// double check that the text content has been removed
|
||||
// before we start appending tspans
|
||||
text_node_selected.text('');
|
||||
for(var i = 0; i < substrings.length; i++) {
|
||||
var substring = substrings[i].string;
|
||||
if(i > 0) {
|
||||
var previous_substring = substrings[i - 1];
|
||||
}
|
||||
// only append if we're sure it won't make the tspans
|
||||
// overflow the bounds.
|
||||
if((i) * line_height < bounds.height - (line_height * 1.5)) {
|
||||
current_tspan = text_node_selected.append('tspan')
|
||||
.text(substring);
|
||||
// vertical shift to all tspans after the first one
|
||||
current_tspan
|
||||
.attr('dy', function(d) {
|
||||
if(i > 0) {
|
||||
return line_height;
|
||||
}
|
||||
});
|
||||
// shift left from default position, which
|
||||
// is probably based on the full length of the
|
||||
// text string until we make this adjustment
|
||||
current_tspan
|
||||
// .attr('dx', function() {
|
||||
// if(i == 0) {
|
||||
// var render_offset = 0;
|
||||
// } else if(i > 0) {
|
||||
// render_offset = substrings[i - 1].width;
|
||||
// render_offset = render_offset * -1;
|
||||
// }
|
||||
// return render_offset;
|
||||
// })
|
||||
.attr('x', function() {
|
||||
|
||||
return bounds.x;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// assign our modified text node with tspans
|
||||
// to the return value
|
||||
return_value = d3.select(parent).selectAll('text');
|
||||
}
|
||||
|
||||
// variable used to hold the functions that let us
|
||||
// switch between the wrap methods
|
||||
var wrap_method;
|
||||
|
||||
// if a wrap method if being forced, assign that
|
||||
// function
|
||||
if(force_wrap_method) {
|
||||
if(force_wrap_method == 'foreignobjects') {
|
||||
wrap_method = wrap_with_foreignobjects;
|
||||
} else if (force_wrap_method == 'tspans') {
|
||||
wrap_method = wrap_with_tspans;
|
||||
}
|
||||
}
|
||||
|
||||
// if no wrap method is being forced, then instead
|
||||
// test for browser support of foreignobject and
|
||||
// use whichever wrap method makes sense accordingly
|
||||
if(!force_wrap_method) {
|
||||
if(typeof SVGForeignObjectElement !== 'undefined') {
|
||||
wrap_method = wrap_with_foreignobjects;
|
||||
} else {
|
||||
wrap_method = wrap_with_tspans;
|
||||
}
|
||||
}
|
||||
|
||||
// run the desired wrap function for each item
|
||||
// in the d3 selection that called .textwrap()
|
||||
for(var i = 0; i < selection.length; i++) {
|
||||
var item = selection[i];
|
||||
wrap_method(item);
|
||||
}
|
||||
|
||||
// return the modified nodes so we can chain other
|
||||
// methods to them.
|
||||
return return_value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})();
|
||||
},{"d3":"tokjIE"}],87:[function(require,module,exports){
|
||||
/**
|
||||
* Created by knut on 15-01-14.
|
||||
@ -21249,7 +21710,6 @@ var conf = {
|
||||
// Margin around loop boxes
|
||||
boxMargin:10,
|
||||
boxTextMargin:5,
|
||||
|
||||
noteMargin:10,
|
||||
// Space between messages
|
||||
messageMargin:35,
|
||||
@ -21363,21 +21823,31 @@ var drawNote = function(elem, startx, verticalPos, msg){
|
||||
rect.width = conf.width;
|
||||
rect.class = 'note';
|
||||
|
||||
var g = elem.append("g");
|
||||
var g = elem.append('g');
|
||||
var rectElem = svgDraw.drawRect(g, rect);
|
||||
|
||||
var textObj = svgDraw.getTextObj();
|
||||
textObj.x = startx;
|
||||
textObj.y = verticalPos+conf.noteMargin;
|
||||
textObj.y = verticalPos;
|
||||
textObj.textMargin = conf.noteMargin;
|
||||
textObj.dy = '1em';
|
||||
textObj.text = msg.message;
|
||||
textObj.class = 'noteText';
|
||||
|
||||
var textElem = svgDraw.drawText(g,textObj);
|
||||
var textElem = svgDraw.drawText(g,textObj, conf.width);
|
||||
|
||||
var textHeight = textElem[0][0].getBBox().height;
|
||||
exports.bounds.insert(startx, verticalPos, startx + conf.width, verticalPos + 2*conf.noteMargin + textHeight);
|
||||
if(textHeight > conf.width){
|
||||
textElem.remove();
|
||||
g = elem.append("g");
|
||||
|
||||
textElem = svgDraw.drawText(g,textObj, 2*conf.width);
|
||||
textHeight = textElem[0][0].getBBox().height;
|
||||
rectElem.attr('width',2*conf.width);
|
||||
exports.bounds.insert(startx, verticalPos, startx + 2*conf.width, verticalPos + 2*conf.noteMargin + textHeight);
|
||||
}else{
|
||||
exports.bounds.insert(startx, verticalPos, startx + conf.width, verticalPos + 2*conf.noteMargin + textHeight);
|
||||
}
|
||||
|
||||
rectElem.attr('height',textHeight+ 2*conf.noteMargin);
|
||||
exports.bounds.bumpVerticalPos(textHeight+ 2*conf.noteMargin);
|
||||
@ -21632,23 +22102,38 @@ exports.drawRect = function(elem , rectData){
|
||||
return rectElem;
|
||||
};
|
||||
|
||||
exports.drawText = function(elem , textData){
|
||||
exports.drawText = function(elem, textData, width) {
|
||||
// Remove and ignore br:s
|
||||
var nText = textData.text.replace(/<br\/?>/ig,' ');
|
||||
|
||||
var textElem = elem.append('text');
|
||||
textElem.attr('x', textData.x);
|
||||
textElem.attr('y', textData.y);
|
||||
textElem.style('text-anchor', textData.anchor);
|
||||
textElem.attr('fill', textData.fill);
|
||||
|
||||
textData.text.split(/<br\/?>/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'){
|
||||
if (typeof textData.class !== 'undefined') {
|
||||
textElem.attr("class", textData.class);
|
||||
}
|
||||
/* textData.text.split(/<br\/?>/ig).forEach(function(rowText){
|
||||
var span = textElem.append('tspan');
|
||||
span.attr('x', textData.x +textData.textMargin);
|
||||
span.attr('dy', textData.dy);
|
||||
span.text(rowText);
|
||||
});*/
|
||||
|
||||
|
||||
var span = textElem.append('tspan');
|
||||
span.attr('x', textData.x);
|
||||
span.attr('dy', textData.dy);
|
||||
span.text(nText);
|
||||
if(typeof textElem.textwrap !== 'undefined'){
|
||||
textElem.textwrap({
|
||||
x: textData.x+4, // bounding box is 300 pixels from the left
|
||||
y: textData.y-2, // bounding box is 400 pixels from the top
|
||||
width: width, // bounding box is 500 pixels across
|
||||
height: 1800 // bounding box is 600 pixels tall
|
||||
}, textData.textMargin);
|
||||
}
|
||||
|
||||
return textElem;
|
||||
};
|
||||
@ -21970,8 +22455,8 @@ global.mermaid = {
|
||||
console.log('Mermaid Syntax error:');
|
||||
console.log(err);
|
||||
},
|
||||
render:function(id, text){
|
||||
return mermaidAPI.render(id, text);
|
||||
render:function(id, text,callback, element){
|
||||
return mermaidAPI.render(id, text,callback, element);
|
||||
}
|
||||
};
|
||||
|
||||
@ -22043,6 +22528,10 @@ var d3 = require('./d3');
|
||||
var nextId = 0;
|
||||
|
||||
// Default options, can be overridden at initialization time
|
||||
/**
|
||||
* Object with the co0nfigurations
|
||||
* @type {Object}
|
||||
*/
|
||||
var config = {
|
||||
cloneCssStyles: true,
|
||||
flowchart:{
|
||||
|
8
dist/mermaid.slim.min.js
vendored
8
dist/mermaid.slim.min.js
vendored
File diff suppressed because one or more lines are too long
521
dist/mermaidAPI.js
vendored
521
dist/mermaidAPI.js
vendored
@ -24655,9 +24655,11 @@ module.exports={
|
||||
"browserify": "~6.2.0",
|
||||
"clone": "^0.2.0",
|
||||
"codeclimate-test-reporter": "0.0.4",
|
||||
"connect-livereload": "^0.5.3",
|
||||
"d3": "~3.4.13",
|
||||
"dateformat": "^1.0.11",
|
||||
"event-stream": "^3.2.0",
|
||||
"express": "^4.12.4",
|
||||
"foundation": "^4.2.1-1",
|
||||
"front-matter": "^0.2.0",
|
||||
"gulp": "~3.8.9",
|
||||
@ -24668,12 +24670,14 @@ module.exports={
|
||||
"gulp-ext-replace": "~0.1.0",
|
||||
"gulp-filelog": "^0.4.1",
|
||||
"gulp-hogan": "^1.1.0",
|
||||
"gulp-if": "^1.2.5",
|
||||
"gulp-insert": "^0.4.0",
|
||||
"gulp-istanbul": "^0.4.0",
|
||||
"gulp-jasmine": "~1.0.1",
|
||||
"gulp-jison": "~1.2.0",
|
||||
"gulp-jshint": "^1.9.0",
|
||||
"gulp-less": "^3.0.1",
|
||||
"gulp-livereload": "^3.8.0",
|
||||
"gulp-rename": "~1.2.0",
|
||||
"gulp-shell": "^0.2.10",
|
||||
"gulp-tag-version": "^1.2.1",
|
||||
@ -24703,7 +24707,10 @@ module.exports={
|
||||
"require-dir": "^0.3.0",
|
||||
"rewire": "^2.1.3",
|
||||
"rimraf": "^2.2.8",
|
||||
"tape": "^3.0.3"
|
||||
"tape": "^3.0.3",
|
||||
"tiny-lr": "^0.1.6",
|
||||
"vinyl-source-stream": "^1.1.0",
|
||||
"watchify": "^3.2.2"
|
||||
}
|
||||
}
|
||||
|
||||
@ -24736,6 +24743,460 @@ if (!d3) {
|
||||
//console.log(window);
|
||||
module.exports = d3;
|
||||
|
||||
/*
|
||||
|
||||
D3 Text Wrap
|
||||
By Vijith Assar
|
||||
http://www.vijithassar.com
|
||||
http://www.github.com/vijithassar
|
||||
@vijithassar
|
||||
|
||||
Detailed instructions at http://www.github.com/vijithassar/d3textwrap
|
||||
|
||||
*/
|
||||
|
||||
(function() {
|
||||
|
||||
// set this variable to a string value to always force a particular
|
||||
// wrap method for development purposes, for example to check tspan
|
||||
// rendering using a foreignobject-enabled browser. set to 'tspan' to
|
||||
// use tspans and 'foreignobject' to use foreignobject
|
||||
var force_wrap_method = false; // by default no wrap method is forced
|
||||
force_wrap_method = 'tspans'; // uncomment this statement to force tspans
|
||||
// force_wrap_method = 'foreignobjects'; // uncomment this statement to force foreignobjects
|
||||
|
||||
// exit immediately if something in this location
|
||||
// has already been defined; the plugin will defer to whatever
|
||||
// else you're doing in your code
|
||||
if(d3.selection.prototype.textwrap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// double check the force_wrap_method flag
|
||||
// and reset if someone screwed up the above
|
||||
// settings
|
||||
if(typeof force_wrap_method == 'undefined') {
|
||||
var force_wrap_method = false;
|
||||
}
|
||||
|
||||
// create the plugin method twice, both for regular use
|
||||
// and again for use inside the enter() selection
|
||||
d3.selection.prototype.textwrap = d3.selection.enter.prototype.textwrap = function(bounds, padding) {
|
||||
|
||||
// default value of padding is zero if it's undefined
|
||||
var padding = parseInt(padding) || 0;
|
||||
|
||||
// save callee into a variable so we can continue to refer to it
|
||||
// as the function scope changes
|
||||
var selection = this;
|
||||
|
||||
// create a variable to store desired return values in
|
||||
var return_value;
|
||||
|
||||
// extract wrap boundaries from any d3-selected rect and return them
|
||||
// in a format that matches the simpler object argument option
|
||||
var extract_bounds = function(bounds) {
|
||||
// discard the nested array wrappers added by d3
|
||||
var bounding_rect = bounds[0][0];
|
||||
// sanitize the svg element name so we can test against it
|
||||
var element_type = bounding_rect.tagName.toString();
|
||||
// if it's not a rect, exit
|
||||
if(element_type !== 'rect') {
|
||||
return false;
|
||||
// if it's a rect, proceed to extracting the position attributes
|
||||
} else {
|
||||
var bounds_extracted = {};
|
||||
bounds_extracted.x = d3.select(bounding_rect).attr('x') || 0;
|
||||
bounds_extracted.y = d3.select(bounding_rect).attr('y') || 0;
|
||||
bounds_extracted.width = d3.select(bounding_rect).attr('width') || 0;
|
||||
bounds_extracted.height = d3.select(bounding_rect).attr('height') || 0;
|
||||
// also pass along the getter function
|
||||
bounds_extracted.attr = bounds.attr;
|
||||
}
|
||||
return bounds_extracted;
|
||||
}
|
||||
|
||||
// double check the input argument for the wrapping
|
||||
// boundaries to make sure it actually contains all
|
||||
// the information we'll need in order to wrap successfully
|
||||
var verify_bounds = function(bounds) {
|
||||
// quickly add a simple getter method so you can use either
|
||||
// bounds.x or bounds.attr('x') as your notation,
|
||||
// the latter being a common convention among D3
|
||||
// developers
|
||||
if(!bounds.attr) {
|
||||
bounds.attr = function(property) {
|
||||
if(this[property]) {
|
||||
return this[property];
|
||||
}
|
||||
}
|
||||
}
|
||||
// if it's an associative array, make sure it has all the
|
||||
// necessary properties represented directly
|
||||
if(
|
||||
(typeof bounds == 'object') &&
|
||||
(typeof bounds.x !== 'undefined') &&
|
||||
(typeof bounds.y !== 'undefined') &&
|
||||
(typeof bounds.width !== 'undefined') &&
|
||||
(typeof bounds.height !== 'undefined')
|
||||
// if that's the case, then the bounds are fine
|
||||
) {
|
||||
// return the lightly modified bounds
|
||||
return bounds;
|
||||
// if it's a numerically indexed array, assume it's a
|
||||
// d3-selected rect and try to extract the positions
|
||||
} else if (
|
||||
// first try to make sure it's an array using Array.isArray
|
||||
(
|
||||
(typeof Array.isArray == 'function') &&
|
||||
(Array.isArray(bounds))
|
||||
) ||
|
||||
// but since Array.isArray isn't always supported, fall
|
||||
// back to casting to the object to string when it's not
|
||||
(Object.prototype.toString.call(bounds) === '[object Array]')
|
||||
) {
|
||||
// once you're sure it's an array, extract the boundaries
|
||||
// from the rect
|
||||
var extracted_bounds = extract_bounds(bounds);
|
||||
return extracted_bounds;
|
||||
} else {
|
||||
// but if the bounds are neither an object nor a numerical
|
||||
// array, then the bounds argument is invalid and you'll
|
||||
// need to fix it
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var apply_padding = function(bounds, padding) {
|
||||
var padded_bounds = bounds;
|
||||
if(padding !== 0) {
|
||||
padded_bounds.x = parseInt(padded_bounds.x) + padding;
|
||||
padded_bounds.y = parseInt(padded_bounds.y) + padding;
|
||||
padded_bounds.width -= padding * 2;
|
||||
padded_bounds.height -= padding * 2;
|
||||
}
|
||||
return padded_bounds;
|
||||
}
|
||||
|
||||
// verify bounds
|
||||
var verified_bounds = verify_bounds(bounds);
|
||||
|
||||
// modify bounds if a padding value is provided
|
||||
if(padding) {
|
||||
verified_bounds = apply_padding(verified_bounds, padding);
|
||||
}
|
||||
|
||||
// check that we have the necessary conditions for this function to operate properly
|
||||
if(
|
||||
// selection it's operating on cannot be not empty
|
||||
(selection.length == 0) ||
|
||||
// d3 must be available
|
||||
(!d3) ||
|
||||
// desired wrapping bounds must be provided as an input argument
|
||||
(!bounds) ||
|
||||
// input bounds must validate
|
||||
(!verified_bounds)
|
||||
) {
|
||||
// try to return the calling selection if possible
|
||||
// so as not to interfere with methods downstream in the
|
||||
// chain
|
||||
if(selection) {
|
||||
return selection;
|
||||
// if all else fails, just return false. if you hit this point then you're
|
||||
// almost certainly trying to call the textwrap() method on something that
|
||||
// doesn't make sense!
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
// if we've validated everything then we can finally proceed
|
||||
// to the meat of this operation
|
||||
} else {
|
||||
|
||||
// reassign the verified bounds as the set we want
|
||||
// to work with from here on; this ensures that we're
|
||||
// using the same data structure for our bounds regardless
|
||||
// of whether the input argument was a simple object or
|
||||
// a d3 selection
|
||||
bounds = verified_bounds;
|
||||
|
||||
// wrap using html and foreignObjects if they are supported
|
||||
var wrap_with_foreignobjects = function(item) {
|
||||
// establish variables to quickly reference target nodes later
|
||||
var parent = d3.select(item[0].parentNode);
|
||||
var text_node = parent.select('text');
|
||||
var styled_line_height = text_node.style('line-height');
|
||||
// extract our desired content from the single text element
|
||||
var text_to_wrap = text_node.text();
|
||||
// remove the text node and replace with a foreign object
|
||||
text_node.remove();
|
||||
var foreign_object = parent.append('foreignObject');
|
||||
// add foreign object and set dimensions, position, etc
|
||||
foreign_object
|
||||
.attr("requiredFeatures", "http://www.w3.org/TR/SVG11/feature#Extensibility")
|
||||
.attr('x', bounds.x)
|
||||
.attr('y', bounds.y)
|
||||
.attr('width', bounds.width)
|
||||
.attr('height', bounds.height);
|
||||
// insert an HTML div
|
||||
var wrap_div = foreign_object
|
||||
.append('xhtml:div')
|
||||
// this class is currently hardcoded
|
||||
// probably not necessary but easy to
|
||||
// override using .classed() and for now
|
||||
// it's nice to avoid a litany of input
|
||||
// arguments
|
||||
.attr('class', 'wrapped');
|
||||
// set div to same dimensions as foreign object
|
||||
wrap_div
|
||||
.style('height', bounds.height)
|
||||
.style('width', bounds.width)
|
||||
// insert text content
|
||||
.html(text_to_wrap);
|
||||
if(styled_line_height) {
|
||||
wrap_div.style('line-height', styled_line_height);
|
||||
}
|
||||
return_value = parent.select('foreignObject');
|
||||
}
|
||||
|
||||
// wrap with tspans if foreignObject is undefined
|
||||
var wrap_with_tspans = function(item) {
|
||||
// operate on the first text item in the selection
|
||||
var text_node = item[0];
|
||||
var parent = text_node.parentNode;
|
||||
var text_node_selected = d3.select(text_node);
|
||||
// measure initial size of the text node as rendered
|
||||
var text_node_height = text_node.getBBox().height;
|
||||
var text_node_width = text_node.getBBox().width;
|
||||
// figure out the line height, either from rendered height
|
||||
// of the font or attached styling
|
||||
var line_height;
|
||||
var rendered_line_height = text_node_height;
|
||||
var styled_line_height = text_node_selected.style('line-height');
|
||||
if(
|
||||
(styled_line_height) &&
|
||||
(parseInt(styled_line_height))
|
||||
) {
|
||||
line_height = parseInt(styled_line_height.replace('px', ''));
|
||||
} else {
|
||||
line_height = rendered_line_height;
|
||||
}
|
||||
// only fire the rest of this if the text content
|
||||
// overflows the desired dimensions
|
||||
if(text_node_width > bounds.width) {
|
||||
// store whatever is inside the text node
|
||||
// in a variable and then zero out the
|
||||
// initial content; we'll reinsert in a moment
|
||||
// using tspan elements.
|
||||
var text_to_wrap = text_node_selected.text();
|
||||
text_node_selected.text('');
|
||||
if(text_to_wrap) {
|
||||
// keep track of whether we are splitting by spaces
|
||||
// so we know whether to reinsert those spaces later
|
||||
var break_delimiter;
|
||||
// split at spaces to create an array of individual words
|
||||
var text_to_wrap_array;
|
||||
if(text_to_wrap.indexOf(' ') !== -1) {
|
||||
var break_delimiter = ' ';
|
||||
text_to_wrap_array = text_to_wrap.split(' ');
|
||||
} else {
|
||||
// if there are no spaces, figure out the split
|
||||
// points by comparing rendered text width against
|
||||
// bounds and translating that into character position
|
||||
// cuts
|
||||
break_delimiter = '';
|
||||
var string_length = text_to_wrap.length;
|
||||
var number_of_substrings = Math.ceil(text_node_width / bounds.width);
|
||||
var splice_interval = Math.floor(string_length / number_of_substrings);
|
||||
if(
|
||||
!(splice_interval * number_of_substrings >= string_length)
|
||||
) {
|
||||
number_of_substrings++;
|
||||
}
|
||||
var text_to_wrap_array = [];
|
||||
var substring;
|
||||
var start_position;
|
||||
for(var i = 0; i < number_of_substrings; i++) {
|
||||
start_position = i * splice_interval;
|
||||
substring = text_to_wrap.substr(start_position, splice_interval);
|
||||
text_to_wrap_array.push(substring);
|
||||
}
|
||||
}
|
||||
|
||||
// new array where we'll store the words re-assembled into
|
||||
// substrings that have been tested against the desired
|
||||
// maximum wrapping width
|
||||
var substrings = [];
|
||||
// computed text length is arguably incorrectly reported for
|
||||
// all tspans after the first one, in that they will include
|
||||
// the width of previous separate tspans. to compensate we need
|
||||
// to manually track the computed text length of all those
|
||||
// previous tspans and substrings, and then use that to offset
|
||||
// the miscalculation. this then gives us the actual correct
|
||||
// position we want to use in rendering the text in the SVG.
|
||||
var total_offset = 0;
|
||||
// object for storing the results of text length computations later
|
||||
var temp = {};
|
||||
// loop through the words and test the computed text length
|
||||
// of the string against the maximum desired wrapping width
|
||||
for(var i = 0; i < text_to_wrap_array.length; i++) {
|
||||
var word = text_to_wrap_array[i];
|
||||
var previous_string = text_node_selected.text();
|
||||
var previous_width = text_node.getComputedTextLength();
|
||||
// initialize the current word as the first word
|
||||
// or append to the previous string if one exists
|
||||
var new_string;
|
||||
if(previous_string) {
|
||||
new_string = previous_string + break_delimiter + word;
|
||||
} else {
|
||||
new_string = word;
|
||||
}
|
||||
// add the newest substring back to the text node and
|
||||
// measure the length
|
||||
text_node_selected.text(new_string);
|
||||
var new_width = text_node.getComputedTextLength();
|
||||
// adjust the length by the offset we've tracked
|
||||
// due to the misreported length discussed above
|
||||
var test_width = new_width - total_offset;
|
||||
// if our latest version of the string is too
|
||||
// big for the bounds, use the previous
|
||||
// version of the string (without the newest word
|
||||
// added) and use the latest word to restart the
|
||||
// process with a new tspan
|
||||
if(new_width > bounds.width) {
|
||||
if(
|
||||
(previous_string) &&
|
||||
(previous_string !== '')
|
||||
) {
|
||||
total_offset = total_offset + previous_width;
|
||||
temp = {string: previous_string, width: previous_width, offset: total_offset};
|
||||
substrings.push(temp);
|
||||
text_node_selected.text('');
|
||||
text_node_selected.text(word);
|
||||
}
|
||||
}
|
||||
// if we're up to the last word in the array,
|
||||
// get the computed length as is without
|
||||
// appending anything further to it
|
||||
else if(i == text_to_wrap_array.length - 1) {
|
||||
text_node_selected.text('');
|
||||
var final_string = new_string;
|
||||
if(
|
||||
(final_string) &&
|
||||
(final_string !== '')
|
||||
) {
|
||||
if((new_width - total_offset) > 0) {new_width = new_width - total_offset}
|
||||
temp = {string: final_string, width: new_width, offset: total_offset};
|
||||
substrings.push(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// position the overall text node
|
||||
text_node_selected.attr('y', function() {
|
||||
var y_offset = bounds.y;
|
||||
// shift by line-height to move the baseline into
|
||||
// the bounds – otherwise the text baseline would be
|
||||
// at the top of the bounds
|
||||
if(line_height) {y_offset += line_height;}
|
||||
return y_offset;
|
||||
});
|
||||
// shift to the right by the padding value
|
||||
if(padding) {
|
||||
text_node_selected
|
||||
.attr('x', bounds.x)
|
||||
;
|
||||
}
|
||||
|
||||
// append each substring as a tspan
|
||||
var current_tspan;
|
||||
var tspan_count;
|
||||
// double check that the text content has been removed
|
||||
// before we start appending tspans
|
||||
text_node_selected.text('');
|
||||
for(var i = 0; i < substrings.length; i++) {
|
||||
var substring = substrings[i].string;
|
||||
if(i > 0) {
|
||||
var previous_substring = substrings[i - 1];
|
||||
}
|
||||
// only append if we're sure it won't make the tspans
|
||||
// overflow the bounds.
|
||||
if((i) * line_height < bounds.height - (line_height * 1.5)) {
|
||||
current_tspan = text_node_selected.append('tspan')
|
||||
.text(substring);
|
||||
// vertical shift to all tspans after the first one
|
||||
current_tspan
|
||||
.attr('dy', function(d) {
|
||||
if(i > 0) {
|
||||
return line_height;
|
||||
}
|
||||
});
|
||||
// shift left from default position, which
|
||||
// is probably based on the full length of the
|
||||
// text string until we make this adjustment
|
||||
current_tspan
|
||||
// .attr('dx', function() {
|
||||
// if(i == 0) {
|
||||
// var render_offset = 0;
|
||||
// } else if(i > 0) {
|
||||
// render_offset = substrings[i - 1].width;
|
||||
// render_offset = render_offset * -1;
|
||||
// }
|
||||
// return render_offset;
|
||||
// })
|
||||
.attr('x', function() {
|
||||
|
||||
return bounds.x;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// assign our modified text node with tspans
|
||||
// to the return value
|
||||
return_value = d3.select(parent).selectAll('text');
|
||||
}
|
||||
|
||||
// variable used to hold the functions that let us
|
||||
// switch between the wrap methods
|
||||
var wrap_method;
|
||||
|
||||
// if a wrap method if being forced, assign that
|
||||
// function
|
||||
if(force_wrap_method) {
|
||||
if(force_wrap_method == 'foreignobjects') {
|
||||
wrap_method = wrap_with_foreignobjects;
|
||||
} else if (force_wrap_method == 'tspans') {
|
||||
wrap_method = wrap_with_tspans;
|
||||
}
|
||||
}
|
||||
|
||||
// if no wrap method is being forced, then instead
|
||||
// test for browser support of foreignobject and
|
||||
// use whichever wrap method makes sense accordingly
|
||||
if(!force_wrap_method) {
|
||||
if(typeof SVGForeignObjectElement !== 'undefined') {
|
||||
wrap_method = wrap_with_foreignobjects;
|
||||
} else {
|
||||
wrap_method = wrap_with_tspans;
|
||||
}
|
||||
}
|
||||
|
||||
// run the desired wrap function for each item
|
||||
// in the d3 selection that called .textwrap()
|
||||
for(var i = 0; i < selection.length; i++) {
|
||||
var item = selection[i];
|
||||
wrap_method(item);
|
||||
}
|
||||
|
||||
// return the modified nodes so we can chain other
|
||||
// methods to them.
|
||||
return return_value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})();
|
||||
},{"d3":1}],87:[function(require,module,exports){
|
||||
/**
|
||||
* Created by knut on 15-01-14.
|
||||
@ -30132,7 +30593,6 @@ var conf = {
|
||||
// Margin around loop boxes
|
||||
boxMargin:10,
|
||||
boxTextMargin:5,
|
||||
|
||||
noteMargin:10,
|
||||
// Space between messages
|
||||
messageMargin:35,
|
||||
@ -30246,21 +30706,31 @@ var drawNote = function(elem, startx, verticalPos, msg){
|
||||
rect.width = conf.width;
|
||||
rect.class = 'note';
|
||||
|
||||
var g = elem.append("g");
|
||||
var g = elem.append('g');
|
||||
var rectElem = svgDraw.drawRect(g, rect);
|
||||
|
||||
var textObj = svgDraw.getTextObj();
|
||||
textObj.x = startx;
|
||||
textObj.y = verticalPos+conf.noteMargin;
|
||||
textObj.y = verticalPos;
|
||||
textObj.textMargin = conf.noteMargin;
|
||||
textObj.dy = '1em';
|
||||
textObj.text = msg.message;
|
||||
textObj.class = 'noteText';
|
||||
|
||||
var textElem = svgDraw.drawText(g,textObj);
|
||||
var textElem = svgDraw.drawText(g,textObj, conf.width);
|
||||
|
||||
var textHeight = textElem[0][0].getBBox().height;
|
||||
exports.bounds.insert(startx, verticalPos, startx + conf.width, verticalPos + 2*conf.noteMargin + textHeight);
|
||||
if(textHeight > conf.width){
|
||||
textElem.remove();
|
||||
g = elem.append("g");
|
||||
|
||||
textElem = svgDraw.drawText(g,textObj, 2*conf.width);
|
||||
textHeight = textElem[0][0].getBBox().height;
|
||||
rectElem.attr('width',2*conf.width);
|
||||
exports.bounds.insert(startx, verticalPos, startx + 2*conf.width, verticalPos + 2*conf.noteMargin + textHeight);
|
||||
}else{
|
||||
exports.bounds.insert(startx, verticalPos, startx + conf.width, verticalPos + 2*conf.noteMargin + textHeight);
|
||||
}
|
||||
|
||||
rectElem.attr('height',textHeight+ 2*conf.noteMargin);
|
||||
exports.bounds.bumpVerticalPos(textHeight+ 2*conf.noteMargin);
|
||||
@ -30515,23 +30985,38 @@ exports.drawRect = function(elem , rectData){
|
||||
return rectElem;
|
||||
};
|
||||
|
||||
exports.drawText = function(elem , textData){
|
||||
exports.drawText = function(elem, textData, width) {
|
||||
// Remove and ignore br:s
|
||||
var nText = textData.text.replace(/<br\/?>/ig,' ');
|
||||
|
||||
var textElem = elem.append('text');
|
||||
textElem.attr('x', textData.x);
|
||||
textElem.attr('y', textData.y);
|
||||
textElem.style('text-anchor', textData.anchor);
|
||||
textElem.attr('fill', textData.fill);
|
||||
|
||||
textData.text.split(/<br\/?>/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'){
|
||||
if (typeof textData.class !== 'undefined') {
|
||||
textElem.attr("class", textData.class);
|
||||
}
|
||||
/* textData.text.split(/<br\/?>/ig).forEach(function(rowText){
|
||||
var span = textElem.append('tspan');
|
||||
span.attr('x', textData.x +textData.textMargin);
|
||||
span.attr('dy', textData.dy);
|
||||
span.text(rowText);
|
||||
});*/
|
||||
|
||||
|
||||
var span = textElem.append('tspan');
|
||||
span.attr('x', textData.x);
|
||||
span.attr('dy', textData.dy);
|
||||
span.text(nText);
|
||||
if(typeof textElem.textwrap !== 'undefined'){
|
||||
textElem.textwrap({
|
||||
x: textData.x+4, // bounding box is 300 pixels from the left
|
||||
y: textData.y-2, // bounding box is 400 pixels from the top
|
||||
width: width, // bounding box is 500 pixels across
|
||||
height: 1800 // bounding box is 600 pixels tall
|
||||
}, textData.textMargin);
|
||||
}
|
||||
|
||||
return textElem;
|
||||
};
|
||||
@ -30747,6 +31232,10 @@ var d3 = require('./d3');
|
||||
var nextId = 0;
|
||||
|
||||
// Default options, can be overridden at initialization time
|
||||
/**
|
||||
* Object with the co0nfigurations
|
||||
* @type {Object}
|
||||
*/
|
||||
var config = {
|
||||
cloneCssStyles: true,
|
||||
flowchart:{
|
||||
|
523
dist/mermaidAPI.slim.js
vendored
523
dist/mermaidAPI.slim.js
vendored
File diff suppressed because one or more lines are too long
12
dist/mermaidAPI.slim.min.js
vendored
12
dist/mermaidAPI.slim.min.js
vendored
File diff suppressed because one or more lines are too long
@ -61,11 +61,11 @@ gulp.task('fullDist', ['slimDist'], function() {
|
||||
//]));
|
||||
|
||||
// Basic usage
|
||||
gulp.task('mermaid',function() {
|
||||
gulp.task('mermaid.slim',function() {
|
||||
// Single entry point to browserify
|
||||
var EXTERNALS = ['d3'];
|
||||
|
||||
gulp.src('src/mermaid.js')
|
||||
return gulp.src('src/mermaid.js')
|
||||
.pipe(browserify({
|
||||
external: ['d3'],
|
||||
entry:'src/mermaid.js'
|
||||
@ -85,6 +85,10 @@ gulp.task('mermaid',function() {
|
||||
.pipe(uglify())
|
||||
.pipe(extReplace('.min.js'))
|
||||
.pipe(gulp.dest('./dist/'));
|
||||
});
|
||||
|
||||
// Basic usage
|
||||
gulp.task('mermaid',function() {
|
||||
|
||||
return gulp.src('src/mermaid.js')
|
||||
.pipe(browserify({
|
||||
@ -96,12 +100,13 @@ gulp.task('mermaid',function() {
|
||||
.pipe(extReplace('.min.js'))
|
||||
.pipe(gulp.dest('./dist/'));
|
||||
});
|
||||
|
||||
// Basic usage
|
||||
gulp.task('mermaidAPI',function() {
|
||||
return gulp.src('src/mermaidAPI.js')
|
||||
.pipe(browserify({
|
||||
}))
|
||||
.pipe(gulp.dest('./dist/'))
|
||||
.pipe(gulp.dest('./dist/'));
|
||||
//.pipe(uglify())
|
||||
//.pipe(extReplace('.min.js'))
|
||||
//.pipe(gulp.dest('./dist/'));
|
||||
@ -135,4 +140,4 @@ gulp.task('editor', function() {
|
||||
//gulp.task('dist', ['slimDist', 'fullDist','jasmine']);
|
||||
gulp.task('legacy', ['slimDist', 'fullDist']);
|
||||
|
||||
gulp.task('dist', ['mermaidAPI', 'mermaidAPI.slim','mermaid']);
|
||||
gulp.task('dist', ['mermaidAPI', 'mermaidAPI.slim','mermaid.slim','mermaid']);
|
||||
|
@ -38,9 +38,11 @@
|
||||
"browserify": "~6.2.0",
|
||||
"clone": "^0.2.0",
|
||||
"codeclimate-test-reporter": "0.0.4",
|
||||
"connect-livereload": "^0.5.3",
|
||||
"d3": "~3.4.13",
|
||||
"dateformat": "^1.0.11",
|
||||
"event-stream": "^3.2.0",
|
||||
"express": "^4.12.4",
|
||||
"foundation": "^4.2.1-1",
|
||||
"front-matter": "^0.2.0",
|
||||
"gulp": "~3.8.9",
|
||||
@ -51,12 +53,14 @@
|
||||
"gulp-ext-replace": "~0.1.0",
|
||||
"gulp-filelog": "^0.4.1",
|
||||
"gulp-hogan": "^1.1.0",
|
||||
"gulp-if": "^1.2.5",
|
||||
"gulp-insert": "^0.4.0",
|
||||
"gulp-istanbul": "^0.4.0",
|
||||
"gulp-jasmine": "~1.0.1",
|
||||
"gulp-jison": "~1.2.0",
|
||||
"gulp-jshint": "^1.9.0",
|
||||
"gulp-less": "^3.0.1",
|
||||
"gulp-livereload": "^3.8.0",
|
||||
"gulp-rename": "~1.2.0",
|
||||
"gulp-shell": "^0.2.10",
|
||||
"gulp-tag-version": "^1.2.1",
|
||||
@ -86,6 +90,9 @@
|
||||
"require-dir": "^0.3.0",
|
||||
"rewire": "^2.1.3",
|
||||
"rimraf": "^2.2.8",
|
||||
"tape": "^3.0.3"
|
||||
"tape": "^3.0.3",
|
||||
"tiny-lr": "^0.1.6",
|
||||
"vinyl-source-stream": "^1.1.0",
|
||||
"watchify": "^3.2.2"
|
||||
}
|
||||
}
|
||||
|
455
src/d3.js
vendored
455
src/d3.js
vendored
@ -25,3 +25,458 @@ if (!d3) {
|
||||
//console.log('window');
|
||||
//console.log(window);
|
||||
module.exports = d3;
|
||||
|
||||
/*
|
||||
|
||||
D3 Text Wrap
|
||||
By Vijith Assar
|
||||
http://www.vijithassar.com
|
||||
http://www.github.com/vijithassar
|
||||
@vijithassar
|
||||
|
||||
Detailed instructions at http://www.github.com/vijithassar/d3textwrap
|
||||
|
||||
*/
|
||||
|
||||
(function() {
|
||||
|
||||
// set this variable to a string value to always force a particular
|
||||
// wrap method for development purposes, for example to check tspan
|
||||
// rendering using a foreignobject-enabled browser. set to 'tspan' to
|
||||
// use tspans and 'foreignobject' to use foreignobject
|
||||
var force_wrap_method = false; // by default no wrap method is forced
|
||||
force_wrap_method = 'tspans'; // uncomment this statement to force tspans
|
||||
// force_wrap_method = 'foreignobjects'; // uncomment this statement to force foreignobjects
|
||||
|
||||
// exit immediately if something in this location
|
||||
// has already been defined; the plugin will defer to whatever
|
||||
// else you're doing in your code
|
||||
if(d3.selection.prototype.textwrap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// double check the force_wrap_method flag
|
||||
// and reset if someone screwed up the above
|
||||
// settings
|
||||
if(typeof force_wrap_method == 'undefined') {
|
||||
var force_wrap_method = false;
|
||||
}
|
||||
|
||||
// create the plugin method twice, both for regular use
|
||||
// and again for use inside the enter() selection
|
||||
d3.selection.prototype.textwrap = d3.selection.enter.prototype.textwrap = function(bounds, padding) {
|
||||
|
||||
// default value of padding is zero if it's undefined
|
||||
var padding = parseInt(padding) || 0;
|
||||
|
||||
// save callee into a variable so we can continue to refer to it
|
||||
// as the function scope changes
|
||||
var selection = this;
|
||||
|
||||
// create a variable to store desired return values in
|
||||
var return_value;
|
||||
|
||||
// extract wrap boundaries from any d3-selected rect and return them
|
||||
// in a format that matches the simpler object argument option
|
||||
var extract_bounds = function(bounds) {
|
||||
// discard the nested array wrappers added by d3
|
||||
var bounding_rect = bounds[0][0];
|
||||
// sanitize the svg element name so we can test against it
|
||||
var element_type = bounding_rect.tagName.toString();
|
||||
// if it's not a rect, exit
|
||||
if(element_type !== 'rect') {
|
||||
return false;
|
||||
// if it's a rect, proceed to extracting the position attributes
|
||||
} else {
|
||||
var bounds_extracted = {};
|
||||
bounds_extracted.x = d3.select(bounding_rect).attr('x') || 0;
|
||||
bounds_extracted.y = d3.select(bounding_rect).attr('y') || 0;
|
||||
bounds_extracted.width = d3.select(bounding_rect).attr('width') || 0;
|
||||
bounds_extracted.height = d3.select(bounding_rect).attr('height') || 0;
|
||||
// also pass along the getter function
|
||||
bounds_extracted.attr = bounds.attr;
|
||||
}
|
||||
return bounds_extracted;
|
||||
}
|
||||
|
||||
// double check the input argument for the wrapping
|
||||
// boundaries to make sure it actually contains all
|
||||
// the information we'll need in order to wrap successfully
|
||||
var verify_bounds = function(bounds) {
|
||||
// quickly add a simple getter method so you can use either
|
||||
// bounds.x or bounds.attr('x') as your notation,
|
||||
// the latter being a common convention among D3
|
||||
// developers
|
||||
if(!bounds.attr) {
|
||||
bounds.attr = function(property) {
|
||||
if(this[property]) {
|
||||
return this[property];
|
||||
}
|
||||
}
|
||||
}
|
||||
// if it's an associative array, make sure it has all the
|
||||
// necessary properties represented directly
|
||||
if(
|
||||
(typeof bounds == 'object') &&
|
||||
(typeof bounds.x !== 'undefined') &&
|
||||
(typeof bounds.y !== 'undefined') &&
|
||||
(typeof bounds.width !== 'undefined') &&
|
||||
(typeof bounds.height !== 'undefined')
|
||||
// if that's the case, then the bounds are fine
|
||||
) {
|
||||
// return the lightly modified bounds
|
||||
return bounds;
|
||||
// if it's a numerically indexed array, assume it's a
|
||||
// d3-selected rect and try to extract the positions
|
||||
} else if (
|
||||
// first try to make sure it's an array using Array.isArray
|
||||
(
|
||||
(typeof Array.isArray == 'function') &&
|
||||
(Array.isArray(bounds))
|
||||
) ||
|
||||
// but since Array.isArray isn't always supported, fall
|
||||
// back to casting to the object to string when it's not
|
||||
(Object.prototype.toString.call(bounds) === '[object Array]')
|
||||
) {
|
||||
// once you're sure it's an array, extract the boundaries
|
||||
// from the rect
|
||||
var extracted_bounds = extract_bounds(bounds);
|
||||
return extracted_bounds;
|
||||
} else {
|
||||
// but if the bounds are neither an object nor a numerical
|
||||
// array, then the bounds argument is invalid and you'll
|
||||
// need to fix it
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var apply_padding = function(bounds, padding) {
|
||||
var padded_bounds = bounds;
|
||||
if(padding !== 0) {
|
||||
padded_bounds.x = parseInt(padded_bounds.x) + padding;
|
||||
padded_bounds.y = parseInt(padded_bounds.y) + padding;
|
||||
padded_bounds.width -= padding * 2;
|
||||
padded_bounds.height -= padding * 2;
|
||||
}
|
||||
return padded_bounds;
|
||||
}
|
||||
|
||||
// verify bounds
|
||||
var verified_bounds = verify_bounds(bounds);
|
||||
|
||||
// modify bounds if a padding value is provided
|
||||
if(padding) {
|
||||
verified_bounds = apply_padding(verified_bounds, padding);
|
||||
}
|
||||
|
||||
// check that we have the necessary conditions for this function to operate properly
|
||||
if(
|
||||
// selection it's operating on cannot be not empty
|
||||
(selection.length == 0) ||
|
||||
// d3 must be available
|
||||
(!d3) ||
|
||||
// desired wrapping bounds must be provided as an input argument
|
||||
(!bounds) ||
|
||||
// input bounds must validate
|
||||
(!verified_bounds)
|
||||
) {
|
||||
// try to return the calling selection if possible
|
||||
// so as not to interfere with methods downstream in the
|
||||
// chain
|
||||
if(selection) {
|
||||
return selection;
|
||||
// if all else fails, just return false. if you hit this point then you're
|
||||
// almost certainly trying to call the textwrap() method on something that
|
||||
// doesn't make sense!
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
// if we've validated everything then we can finally proceed
|
||||
// to the meat of this operation
|
||||
} else {
|
||||
|
||||
// reassign the verified bounds as the set we want
|
||||
// to work with from here on; this ensures that we're
|
||||
// using the same data structure for our bounds regardless
|
||||
// of whether the input argument was a simple object or
|
||||
// a d3 selection
|
||||
bounds = verified_bounds;
|
||||
|
||||
// wrap using html and foreignObjects if they are supported
|
||||
var wrap_with_foreignobjects = function(item) {
|
||||
// establish variables to quickly reference target nodes later
|
||||
var parent = d3.select(item[0].parentNode);
|
||||
var text_node = parent.select('text');
|
||||
var styled_line_height = text_node.style('line-height');
|
||||
// extract our desired content from the single text element
|
||||
var text_to_wrap = text_node.text();
|
||||
// remove the text node and replace with a foreign object
|
||||
text_node.remove();
|
||||
var foreign_object = parent.append('foreignObject');
|
||||
// add foreign object and set dimensions, position, etc
|
||||
foreign_object
|
||||
.attr("requiredFeatures", "http://www.w3.org/TR/SVG11/feature#Extensibility")
|
||||
.attr('x', bounds.x)
|
||||
.attr('y', bounds.y)
|
||||
.attr('width', bounds.width)
|
||||
.attr('height', bounds.height);
|
||||
// insert an HTML div
|
||||
var wrap_div = foreign_object
|
||||
.append('xhtml:div')
|
||||
// this class is currently hardcoded
|
||||
// probably not necessary but easy to
|
||||
// override using .classed() and for now
|
||||
// it's nice to avoid a litany of input
|
||||
// arguments
|
||||
.attr('class', 'wrapped');
|
||||
// set div to same dimensions as foreign object
|
||||
wrap_div
|
||||
.style('height', bounds.height)
|
||||
.style('width', bounds.width)
|
||||
// insert text content
|
||||
.html(text_to_wrap);
|
||||
if(styled_line_height) {
|
||||
wrap_div.style('line-height', styled_line_height);
|
||||
}
|
||||
return_value = parent.select('foreignObject');
|
||||
}
|
||||
|
||||
// wrap with tspans if foreignObject is undefined
|
||||
var wrap_with_tspans = function(item) {
|
||||
// operate on the first text item in the selection
|
||||
var text_node = item[0];
|
||||
var parent = text_node.parentNode;
|
||||
var text_node_selected = d3.select(text_node);
|
||||
// measure initial size of the text node as rendered
|
||||
var text_node_height = text_node.getBBox().height;
|
||||
var text_node_width = text_node.getBBox().width;
|
||||
// figure out the line height, either from rendered height
|
||||
// of the font or attached styling
|
||||
var line_height;
|
||||
var rendered_line_height = text_node_height;
|
||||
var styled_line_height = text_node_selected.style('line-height');
|
||||
if(
|
||||
(styled_line_height) &&
|
||||
(parseInt(styled_line_height))
|
||||
) {
|
||||
line_height = parseInt(styled_line_height.replace('px', ''));
|
||||
} else {
|
||||
line_height = rendered_line_height;
|
||||
}
|
||||
// only fire the rest of this if the text content
|
||||
// overflows the desired dimensions
|
||||
if(text_node_width > bounds.width) {
|
||||
// store whatever is inside the text node
|
||||
// in a variable and then zero out the
|
||||
// initial content; we'll reinsert in a moment
|
||||
// using tspan elements.
|
||||
var text_to_wrap = text_node_selected.text();
|
||||
text_node_selected.text('');
|
||||
if(text_to_wrap) {
|
||||
// keep track of whether we are splitting by spaces
|
||||
// so we know whether to reinsert those spaces later
|
||||
var break_delimiter;
|
||||
// split at spaces to create an array of individual words
|
||||
var text_to_wrap_array;
|
||||
if(text_to_wrap.indexOf(' ') !== -1) {
|
||||
var break_delimiter = ' ';
|
||||
text_to_wrap_array = text_to_wrap.split(' ');
|
||||
} else {
|
||||
// if there are no spaces, figure out the split
|
||||
// points by comparing rendered text width against
|
||||
// bounds and translating that into character position
|
||||
// cuts
|
||||
break_delimiter = '';
|
||||
var string_length = text_to_wrap.length;
|
||||
var number_of_substrings = Math.ceil(text_node_width / bounds.width);
|
||||
var splice_interval = Math.floor(string_length / number_of_substrings);
|
||||
if(
|
||||
!(splice_interval * number_of_substrings >= string_length)
|
||||
) {
|
||||
number_of_substrings++;
|
||||
}
|
||||
var text_to_wrap_array = [];
|
||||
var substring;
|
||||
var start_position;
|
||||
for(var i = 0; i < number_of_substrings; i++) {
|
||||
start_position = i * splice_interval;
|
||||
substring = text_to_wrap.substr(start_position, splice_interval);
|
||||
text_to_wrap_array.push(substring);
|
||||
}
|
||||
}
|
||||
|
||||
// new array where we'll store the words re-assembled into
|
||||
// substrings that have been tested against the desired
|
||||
// maximum wrapping width
|
||||
var substrings = [];
|
||||
// computed text length is arguably incorrectly reported for
|
||||
// all tspans after the first one, in that they will include
|
||||
// the width of previous separate tspans. to compensate we need
|
||||
// to manually track the computed text length of all those
|
||||
// previous tspans and substrings, and then use that to offset
|
||||
// the miscalculation. this then gives us the actual correct
|
||||
// position we want to use in rendering the text in the SVG.
|
||||
var total_offset = 0;
|
||||
// object for storing the results of text length computations later
|
||||
var temp = {};
|
||||
// loop through the words and test the computed text length
|
||||
// of the string against the maximum desired wrapping width
|
||||
for(var i = 0; i < text_to_wrap_array.length; i++) {
|
||||
var word = text_to_wrap_array[i];
|
||||
var previous_string = text_node_selected.text();
|
||||
var previous_width = text_node.getComputedTextLength();
|
||||
// initialize the current word as the first word
|
||||
// or append to the previous string if one exists
|
||||
var new_string;
|
||||
if(previous_string) {
|
||||
new_string = previous_string + break_delimiter + word;
|
||||
} else {
|
||||
new_string = word;
|
||||
}
|
||||
// add the newest substring back to the text node and
|
||||
// measure the length
|
||||
text_node_selected.text(new_string);
|
||||
var new_width = text_node.getComputedTextLength();
|
||||
// adjust the length by the offset we've tracked
|
||||
// due to the misreported length discussed above
|
||||
var test_width = new_width - total_offset;
|
||||
// if our latest version of the string is too
|
||||
// big for the bounds, use the previous
|
||||
// version of the string (without the newest word
|
||||
// added) and use the latest word to restart the
|
||||
// process with a new tspan
|
||||
if(new_width > bounds.width) {
|
||||
if(
|
||||
(previous_string) &&
|
||||
(previous_string !== '')
|
||||
) {
|
||||
total_offset = total_offset + previous_width;
|
||||
temp = {string: previous_string, width: previous_width, offset: total_offset};
|
||||
substrings.push(temp);
|
||||
text_node_selected.text('');
|
||||
text_node_selected.text(word);
|
||||
}
|
||||
}
|
||||
// if we're up to the last word in the array,
|
||||
// get the computed length as is without
|
||||
// appending anything further to it
|
||||
else if(i == text_to_wrap_array.length - 1) {
|
||||
text_node_selected.text('');
|
||||
var final_string = new_string;
|
||||
if(
|
||||
(final_string) &&
|
||||
(final_string !== '')
|
||||
) {
|
||||
if((new_width - total_offset) > 0) {new_width = new_width - total_offset}
|
||||
temp = {string: final_string, width: new_width, offset: total_offset};
|
||||
substrings.push(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// position the overall text node
|
||||
text_node_selected.attr('y', function() {
|
||||
var y_offset = bounds.y;
|
||||
// shift by line-height to move the baseline into
|
||||
// the bounds – otherwise the text baseline would be
|
||||
// at the top of the bounds
|
||||
if(line_height) {y_offset += line_height;}
|
||||
return y_offset;
|
||||
});
|
||||
// shift to the right by the padding value
|
||||
if(padding) {
|
||||
text_node_selected
|
||||
.attr('x', bounds.x)
|
||||
;
|
||||
}
|
||||
|
||||
// append each substring as a tspan
|
||||
var current_tspan;
|
||||
var tspan_count;
|
||||
// double check that the text content has been removed
|
||||
// before we start appending tspans
|
||||
text_node_selected.text('');
|
||||
for(var i = 0; i < substrings.length; i++) {
|
||||
var substring = substrings[i].string;
|
||||
if(i > 0) {
|
||||
var previous_substring = substrings[i - 1];
|
||||
}
|
||||
// only append if we're sure it won't make the tspans
|
||||
// overflow the bounds.
|
||||
if((i) * line_height < bounds.height - (line_height * 1.5)) {
|
||||
current_tspan = text_node_selected.append('tspan')
|
||||
.text(substring);
|
||||
// vertical shift to all tspans after the first one
|
||||
current_tspan
|
||||
.attr('dy', function(d) {
|
||||
if(i > 0) {
|
||||
return line_height;
|
||||
}
|
||||
});
|
||||
// shift left from default position, which
|
||||
// is probably based on the full length of the
|
||||
// text string until we make this adjustment
|
||||
current_tspan
|
||||
// .attr('dx', function() {
|
||||
// if(i == 0) {
|
||||
// var render_offset = 0;
|
||||
// } else if(i > 0) {
|
||||
// render_offset = substrings[i - 1].width;
|
||||
// render_offset = render_offset * -1;
|
||||
// }
|
||||
// return render_offset;
|
||||
// })
|
||||
.attr('x', function() {
|
||||
|
||||
return bounds.x;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// assign our modified text node with tspans
|
||||
// to the return value
|
||||
return_value = d3.select(parent).selectAll('text');
|
||||
}
|
||||
|
||||
// variable used to hold the functions that let us
|
||||
// switch between the wrap methods
|
||||
var wrap_method;
|
||||
|
||||
// if a wrap method if being forced, assign that
|
||||
// function
|
||||
if(force_wrap_method) {
|
||||
if(force_wrap_method == 'foreignobjects') {
|
||||
wrap_method = wrap_with_foreignobjects;
|
||||
} else if (force_wrap_method == 'tspans') {
|
||||
wrap_method = wrap_with_tspans;
|
||||
}
|
||||
}
|
||||
|
||||
// if no wrap method is being forced, then instead
|
||||
// test for browser support of foreignobject and
|
||||
// use whichever wrap method makes sense accordingly
|
||||
if(!force_wrap_method) {
|
||||
if(typeof SVGForeignObjectElement !== 'undefined') {
|
||||
wrap_method = wrap_with_foreignobjects;
|
||||
} else {
|
||||
wrap_method = wrap_with_tspans;
|
||||
}
|
||||
}
|
||||
|
||||
// run the desired wrap function for each item
|
||||
// in the d3 selection that called .textwrap()
|
||||
for(var i = 0; i < selection.length; i++) {
|
||||
var item = selection[i];
|
||||
wrap_method(item);
|
||||
}
|
||||
|
||||
// return the modified nodes so we can chain other
|
||||
// methods to them.
|
||||
return return_value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})();
|
@ -12,7 +12,7 @@ var d3 = {
|
||||
return new newD3();
|
||||
}
|
||||
};
|
||||
var sd = proxyquire('./sequenceRenderer', { './d3': d3 });
|
||||
//var sd = proxyquire('./sequenceRenderer', { './d3': d3 });
|
||||
var sd = proxyquire('./sequenceRenderer', { '../../d3': d3 });
|
||||
|
||||
var str;
|
||||
|
@ -19,7 +19,6 @@ var conf = {
|
||||
// Margin around loop boxes
|
||||
boxMargin:10,
|
||||
boxTextMargin:5,
|
||||
|
||||
noteMargin:10,
|
||||
// Space between messages
|
||||
messageMargin:35,
|
||||
@ -133,21 +132,31 @@ var drawNote = function(elem, startx, verticalPos, msg){
|
||||
rect.width = conf.width;
|
||||
rect.class = 'note';
|
||||
|
||||
var g = elem.append("g");
|
||||
var g = elem.append('g');
|
||||
var rectElem = svgDraw.drawRect(g, rect);
|
||||
|
||||
var textObj = svgDraw.getTextObj();
|
||||
textObj.x = startx;
|
||||
textObj.y = verticalPos+conf.noteMargin;
|
||||
textObj.y = verticalPos;
|
||||
textObj.textMargin = conf.noteMargin;
|
||||
textObj.dy = '1em';
|
||||
textObj.text = msg.message;
|
||||
textObj.class = 'noteText';
|
||||
|
||||
var textElem = svgDraw.drawText(g,textObj);
|
||||
var textElem = svgDraw.drawText(g,textObj, conf.width);
|
||||
|
||||
var textHeight = textElem[0][0].getBBox().height;
|
||||
exports.bounds.insert(startx, verticalPos, startx + conf.width, verticalPos + 2*conf.noteMargin + textHeight);
|
||||
if(textHeight > conf.width){
|
||||
textElem.remove();
|
||||
g = elem.append("g");
|
||||
|
||||
textElem = svgDraw.drawText(g,textObj, 2*conf.width);
|
||||
textHeight = textElem[0][0].getBBox().height;
|
||||
rectElem.attr('width',2*conf.width);
|
||||
exports.bounds.insert(startx, verticalPos, startx + 2*conf.width, verticalPos + 2*conf.noteMargin + textHeight);
|
||||
}else{
|
||||
exports.bounds.insert(startx, verticalPos, startx + conf.width, verticalPos + 2*conf.noteMargin + textHeight);
|
||||
}
|
||||
|
||||
rectElem.attr('height',textHeight+ 2*conf.noteMargin);
|
||||
exports.bounds.bumpVerticalPos(textHeight+ 2*conf.noteMargin);
|
||||
|
@ -19,23 +19,38 @@ exports.drawRect = function(elem , rectData){
|
||||
return rectElem;
|
||||
};
|
||||
|
||||
exports.drawText = function(elem , textData){
|
||||
exports.drawText = function(elem, textData, width) {
|
||||
// Remove and ignore br:s
|
||||
var nText = textData.text.replace(/<br\/?>/ig,' ');
|
||||
|
||||
var textElem = elem.append('text');
|
||||
textElem.attr('x', textData.x);
|
||||
textElem.attr('y', textData.y);
|
||||
textElem.style('text-anchor', textData.anchor);
|
||||
textElem.attr('fill', textData.fill);
|
||||
|
||||
textData.text.split(/<br\/?>/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'){
|
||||
if (typeof textData.class !== 'undefined') {
|
||||
textElem.attr("class", textData.class);
|
||||
}
|
||||
/* textData.text.split(/<br\/?>/ig).forEach(function(rowText){
|
||||
var span = textElem.append('tspan');
|
||||
span.attr('x', textData.x +textData.textMargin);
|
||||
span.attr('dy', textData.dy);
|
||||
span.text(rowText);
|
||||
});*/
|
||||
|
||||
|
||||
var span = textElem.append('tspan');
|
||||
span.attr('x', textData.x);
|
||||
span.attr('dy', textData.dy);
|
||||
span.text(nText);
|
||||
if(typeof textElem.textwrap !== 'undefined'){
|
||||
textElem.textwrap({
|
||||
x: textData.x+4, // bounding box is 300 pixels from the left
|
||||
y: textData.y-2, // bounding box is 400 pixels from the top
|
||||
width: width, // bounding box is 500 pixels across
|
||||
height: 1800 // bounding box is 600 pixels tall
|
||||
}, textData.textMargin);
|
||||
}
|
||||
|
||||
return textElem;
|
||||
};
|
||||
|
34
src/main.js
34
src/main.js
@ -1,21 +1,21 @@
|
||||
var graph = require('./diagrams/flowchart/graphDb');
|
||||
var flow = require('./diagrams/flowchart/parser/flow');
|
||||
var utils = require('./utils');
|
||||
var flowRenderer = require('./diagrams/flowchart/flowRenderer');
|
||||
var seq = require('./diagrams/sequenceDiagram/sequenceRenderer');
|
||||
var info = require('./diagrams/example/exampleRenderer');
|
||||
var he = require('he');
|
||||
var infoParser = require('./diagrams/example/parser/example');
|
||||
var flowParser = require('./diagrams/flowchart/parser/flow');
|
||||
var dotParser = require('./diagrams/flowchart/parser/dot');
|
||||
var graph = require('./diagrams/flowchart/graphDb');
|
||||
var flow = require('./diagrams/flowchart/parser/flow');
|
||||
var utils = require('./utils');
|
||||
var flowRenderer = require('./diagrams/flowchart/flowRenderer');
|
||||
var seq = require('./diagrams/sequenceDiagram/sequenceRenderer');
|
||||
var info = require('./diagrams/example/exampleRenderer');
|
||||
var he = require('he');
|
||||
var infoParser = require('./diagrams/example/parser/example');
|
||||
var flowParser = require('./diagrams/flowchart/parser/flow');
|
||||
var dotParser = require('./diagrams/flowchart/parser/dot');
|
||||
var sequenceParser = require('./diagrams/sequenceDiagram/parser/sequenceDiagram');
|
||||
var sequenceDb = require('./diagrams/sequenceDiagram/sequenceDb');
|
||||
var infoDb = require('./diagrams/example/exampleDb');
|
||||
var gantt = require('./diagrams/gantt/ganttRenderer');
|
||||
var ganttParser = require('./diagrams/gantt/parser/gantt');
|
||||
var ganttDb = require('./diagrams/gantt/ganttDb');
|
||||
var d3 = require('./d3');
|
||||
var nextId = 0;
|
||||
var sequenceDb = require('./diagrams/sequenceDiagram/sequenceDb');
|
||||
var infoDb = require('./diagrams/example/exampleDb');
|
||||
var gantt = require('./diagrams/gantt/ganttRenderer');
|
||||
var ganttParser = require('./diagrams/gantt/parser/gantt');
|
||||
var ganttDb = require('./diagrams/gantt/ganttDb');
|
||||
var d3 = require('./d3');
|
||||
var nextId = 0;
|
||||
|
||||
/**
|
||||
* Function that parses a mermaid diagram defintion. If parsing fails the parseError callback is called and an error is
|
||||
|
@ -123,8 +123,8 @@ global.mermaid = {
|
||||
console.log('Mermaid Syntax error:');
|
||||
console.log(err);
|
||||
},
|
||||
render:function(id, text){
|
||||
return mermaidAPI.render(id, text);
|
||||
render:function(id, text,callback, element){
|
||||
return mermaidAPI.render(id, text,callback, element);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -17,6 +17,10 @@ var d3 = require('./d3');
|
||||
var nextId = 0;
|
||||
|
||||
// Default options, can be overridden at initialization time
|
||||
/**
|
||||
* Object with the co0nfigurations
|
||||
* @type {Object}
|
||||
*/
|
||||
var config = {
|
||||
cloneCssStyles: true,
|
||||
flowchart:{
|
||||
|
@ -12,10 +12,11 @@
|
||||
cloneCssStyles: false
|
||||
},
|
||||
sequenceDiagram:{
|
||||
mirrorActors:true
|
||||
mirrorActors:true,
|
||||
height:35
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
//mermaid.sequenceConfig = '{"diagramMarginX":50,"diagramMarginY":10,"actorMargin":50,"width":150,"height":45,"boxMargin":10,"boxTextMargin":5,"noteMargin":10,"messageMargin":35, "mirrorActors":true}';
|
||||
//mermaid.sequenceConfig = JSON.parse('{"diagramMarginX":50,"diagramMarginY":10,"actorMargin":50,"width":150,"height":165,"boxMargin":10,"boxTextMargin":5,"noteMargin":10,"messageMargin":35}');
|
||||
|
||||
@ -28,6 +29,19 @@
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<h1>Autowrap</h1>
|
||||
|
||||
<div class="mermaid">
|
||||
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 In a row. Bob thinks a long long time, so long that the text does not fit In a row. Bob thinks a long long time, so long that the text does not fit In a row. Bob thinks a long long time, so long that the text does not fit In a row.
|
||||
|
||||
Bob-->Alice: Checking with John...
|
||||
Alice->John: Yes... John, how are you?
|
||||
</div>
|
||||
<h1>No line breaks</h1>
|
||||
<div class="mermaid">
|
||||
sequenceDiagram;Alice->>Bob: Hello Bob, how are you?;Bob-->Bob: Hmmm?;Bob-->Alice: Ok;
|
||||
|
Loading…
x
Reference in New Issue
Block a user