diff --git a/src/d3.js b/src/d3.js index 5bf6f4952..4fdcbe2d2 100644 --- a/src/d3.js +++ b/src/d3.js @@ -28,15 +28,15 @@ module.exports = d3; /* jshint ignore:start */ /* -D3 Text Wrap -By Vijith Assar -http://www.vijithassar.com -http://www.github.com/vijithassar -@vijithassar + 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 + Detailed instructions at http://www.github.com/vijithassar/d3textwrap -*/ + */ (function() { @@ -86,7 +86,7 @@ Detailed instructions at http://www.github.com/vijithassar/d3textwrap // if it's not a rect, exit if(element_type !== 'rect') { return false; - // if it's a rect, proceed to extracting the position attributes + // 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; @@ -122,30 +122,30 @@ Detailed instructions at http://www.github.com/vijithassar/d3textwrap (typeof bounds.y !== 'undefined') && (typeof bounds.width !== 'undefined') && (typeof bounds.height !== 'undefined') - // if that's the case, then the bounds are fine + // 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 + // 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]') + // 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 + // 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; } } @@ -172,27 +172,27 @@ Detailed instructions at http://www.github.com/vijithassar/d3textwrap // 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) || + (selection.length == 0) || // d3 must be available - (!d3) || + (!d3) || // desired wrapping bounds must be provided as an input argument - (!bounds) || + (!bounds) || // input bounds must validate - (!verified_bounds) + (!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! + // 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 + // 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 @@ -241,6 +241,7 @@ Detailed instructions at http://www.github.com/vijithassar/d3textwrap 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 @@ -355,12 +356,18 @@ Detailed instructions at http://www.github.com/vijithassar/d3textwrap substrings.push(temp); text_node_selected.text(''); text_node_selected.text(word); + // Handle case where there is just one more word to be wrapped + if(i == text_to_wrap_array.length - 1) { + new_string = word; + text_node_selected.text(new_string); + new_width = text_node.getComputedTextLength(); + } } } // 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) { + if(i == text_to_wrap_array.length - 1) { text_node_selected.text(''); var final_string = new_string; if( @@ -374,22 +381,6 @@ Detailed instructions at http://www.github.com/vijithassar/d3textwrap } } - // 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; @@ -417,23 +408,43 @@ Detailed instructions at http://www.github.com/vijithassar/d3textwrap // 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; + var x_offset = bounds.x; + if(padding) {x_offset += padding;} + return x_offset; }); +// .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; +// }); } } } } + // position the overall text node, whether wrapped or not + 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;} + // shift by padding, if it's there + if(padding) {y_offset += padding;} + return y_offset; + }); + // shift to the right by the padding value + text_node_selected.attr('x', function() { + var x_offset = bounds.x; + if(padding) {x_offset += padding;} + return x_offset; + }); + + // assign our modified text node with tspans // to the return value return_value = d3.select(parent).selectAll('text'); diff --git a/src/diagrams/flowchart/flowRenderer.js b/src/diagrams/flowchart/flowRenderer.js index 819cde6ce..593b600ee 100644 --- a/src/diagrams/flowchart/flowRenderer.js +++ b/src/diagrams/flowchart/flowRenderer.js @@ -414,7 +414,7 @@ exports.draw = function (text, id,isDot) { if(conf.useMaxWidth) { // Center the graph svg.attr("height", '100%'); - svg.attr("width", '100%'); + svg.attr("width", conf.width); //svg.attr("viewBox", svgb.getBBox().x + ' 0 '+ g.graph().width+' '+ g.graph().height); svg.attr("viewBox", '0 0 ' + (g.graph().width + 20) + ' ' + (g.graph().height + 20)); svg.attr('style', 'max-width:' + (g.graph().width + 20) + 'px;'); diff --git a/src/diagrams/sequenceDiagram/sequenceRenderer.js b/src/diagrams/sequenceDiagram/sequenceRenderer.js index acfdbd5f8..edcca2059 100644 --- a/src/diagrams/sequenceDiagram/sequenceRenderer.js +++ b/src/diagrams/sequenceDiagram/sequenceRenderer.js @@ -138,21 +138,23 @@ var drawNote = function(elem, startx, verticalPos, msg){ var rectElem = svgDraw.drawRect(g, rect); var textObj = svgDraw.getTextObj(); - textObj.x = startx; - textObj.y = verticalPos; + textObj.x = startx-4; + textObj.y = verticalPos-13; textObj.textMargin = conf.noteMargin; textObj.dy = '1em'; textObj.text = msg.message; textObj.class = 'noteText'; - var textElem = svgDraw.drawText(g,textObj, conf.width); + var textElem = svgDraw.drawText(g,textObj, conf.width-conf.noteMargin); var textHeight = textElem[0][0].getBBox().height; if(textHeight > conf.width){ textElem.remove(); g = elem.append("g"); - - textElem = svgDraw.drawText(g,textObj, 2*conf.width); + + //textObj.x = textObj.x - conf.width; + //textElem = svgDraw.drawText(g,textObj, 2*conf.noteMargin); + textElem = svgDraw.drawText(g,textObj, 2*conf.width-conf.noteMargin); 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); @@ -228,11 +230,11 @@ var drawMessage = function(elem, startx, stopx, verticalPos, msg){ line.attr("stroke", "black"); line.style("fill", "none"); // remove any fill colour if (msg.type === sq.yy.LINETYPE.SOLID || msg.type === sq.yy.LINETYPE.DOTTED){ - line.attr("marker-end", "url(#arrowhead)"); + line.attr("marker-end", "url(" + window.location.protocol+'//'+window.location.host+window.location.pathname + "#arrowhead)"); } if (msg.type === sq.yy.LINETYPE.SOLID_CROSS || msg.type === sq.yy.LINETYPE.DOTTED_CROSS){ - line.attr("marker-end", "url(#crosshead)"); + line.attr("marker-end", "url(" + window.location.protocol+'//'+window.location.host+window.location.pathname + "#crosshead)"); } }; diff --git a/src/diagrams/sequenceDiagram/svgDraw.js b/src/diagrams/sequenceDiagram/svgDraw.js index 8fc5dd72f..3c9bfbcbf 100644 --- a/src/diagrams/sequenceDiagram/svgDraw.js +++ b/src/diagrams/sequenceDiagram/svgDraw.js @@ -41,13 +41,14 @@ exports.drawText = function(elem, textData, width) { var span = textElem.append('tspan'); - span.attr('x', textData.x); - span.attr('dy', textData.dy); + //span.attr('x', textData.x); + span.attr('x', textData.x+textData.textMargin*2); + //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 + x: textData.x, // bounding box is 300 pixels from the left + y: textData.y, // 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); diff --git a/src/main.js b/src/main.js deleted file mode 100644 index e5d92c65b..000000000 --- a/src/main.js +++ /dev/null @@ -1,378 +0,0 @@ -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 log = require('./logger').create(); - -/** - * Function that parses a mermaid diagram defintion. If parsing fails the parseError callback is called and an error is - * thrown and - * @param text - */ -var parse = function(text){ - var graphType = utils.detectType(text); - var parser; - - switch(graphType){ - case 'graph': - parser = flowParser; - parser.parser.yy = graph; - break; - case 'dotGraph': - parser = dotParser; - parser.parser.yy = graph; - break; - case 'sequenceDiagram': - parser = sequenceParser; - parser.parser.yy = sequenceDb; - break; - case 'info': - parser = infoParser; - parser.parser.yy = infoDb; - break; - case 'gantt': - parser = ganttParser; - parser.parser.yy = ganttDb; - break; - } - - try{ - parser.parse(text); - return true; - } - catch(err){ - return false; - } -}; -/** - * Function that goes through the document to find the chart definitions in there and render them. - * - * The function tags the processed attributes with the attribute data-processed and ignores found elements with the - * attribute already set. This way the init function can be triggered several times. - * - * Optionally, `init` can accept in the second argument one of the following: - * - a DOM Node - * - an array of DOM nodes (as would come from a jQuery selector) - * - a W3C selector, a la `.mermaid` - * - * ``` - * graph LR; - * a(Find elements)-->b{Processed}; - * b-->|Yes|c(Leave element); - * c-->|No |d(Transform); - * ``` - */ - -/** - * Renders the mermaid diagrams - * @* param nodes- a css selector or an array of nodes - */ -var init = function () { - var nodes; - if(arguments.length === 2){ - // sequence config was passed as #1 - if(typeof arguments[0] !== 'undefined'){ - mermaid.sequenceConfig = arguments[0]; - } - - nodes = arguments[1]; - } - else{ - nodes = arguments[0]; - } - - nodes = nodes === undefined ? document.querySelectorAll('.mermaid') - : typeof nodes === "string" ? document.querySelectorAll(nodes) - : nodes instanceof Node ? [nodes] - // Last case - sequence config was passed pick next - : nodes; - - var i; - - log.debug('Found ',nodes.length,' nodes'); - for (i = 0; i < nodes.length; i++) { - var element = nodes[i]; - - // Check if previously processed - if(!element.getAttribute("data-processed")) { - element.setAttribute("data-processed", true); - } else { - continue; - } - - var id = 'mermaidChart' + nextId++; - - var txt = element.innerHTML; - txt = txt.replace(/>/g,'>'); - txt = txt.replace(/' + - '' + - ''; - - var graphType = utils.detectType(txt); - var classes = {}; - switch(graphType){ - case 'graph': - classes = flowRenderer.getClasses(txt, false); - - if(typeof mermaid.flowchartConfig === 'object'){ - flowRenderer.setConf(mermaid.flowchartConfig); - } - flowRenderer.draw(txt, id, false); - utils.cloneCssStyles(element.firstChild, classes); - graph.bindFunctions(); - break; - case 'dotGraph': - classes = flowRenderer.getClasses(txt, true); - flowRenderer.draw(txt, id, true); - utils.cloneCssStyles(element.firstChild, classes); - break; - case 'sequenceDiagram': - if(typeof mermaid.sequenceConfig === 'object'){ - seq.setConf(mermaid.sequenceConfig); - } - seq.draw(txt,id); - utils.cloneCssStyles(element.firstChild, []); - break; - case 'gantt': - if(typeof mermaid.ganttConfig === 'object'){ - gantt.setConf(mermaid.ganttConfig); - - } - gantt.draw(txt,id); - utils.cloneCssStyles(element.firstChild, []); - break; - case 'info': - info.draw(txt,id,exports.version()); - utils.cloneCssStyles(element.firstChild, []); - break; - } - - } - -}; - -exports.tester = function(){}; - -/** - * Function returning version information - * @returns {string} A string containing the version info - */ -exports.version = function(){ - return require('../package.json').version; -}; - -var equals = function (val, variable){ - if(typeof variable === 'undefined'){ - return false; - } - else{ - return (val === variable); - } -}; - -var render = function(id, txt,cb){ -// var element = doc.createElement('svg'); -// element.setAttribute('id',id); -// element.setAttribute('width','100%'); -// element.setAttribute('xmlns','http://www.w3.org/2000/svg'); -// element.innerHTML = ''; - - //var element = doc.createElement('div'); - //element.setAttribute('id','d'+id); - // - //element.innerHTML = '' + - // '' + - // ''; - //document.body.appendChild(element); - d3.select('body').append('div') - .attr('id', 'd'+id) - .append('svg') - .attr('id', id) - .attr('width','100%') - .attr('xmlns','http://www.w3.org/2000/svg') - .append('g'); - - - - log.debug(d3.select('#d'+id).node().innerHTML); - var element = d3.select('#d'+id).node(); - var graphType = utils.detectType(txt); - var classes = {}; - switch(graphType){ - case 'graph': - classes = flowRenderer.getClasses(txt, false); - - if(typeof mermaid.flowchartConfig === 'object'){ - flowRenderer.setConf(mermaid.flowchartConfig); - } - flowRenderer.draw(txt, id, false); - utils.cloneCssStyles(element.firstChild, classes); - graph.bindFunctions(); - break; - case 'dotGraph': - classes = flowRenderer.getClasses(txt, true); - flowRenderer.draw(txt, id, true); - utils.cloneCssStyles(element.firstChild, classes); - break; - case 'sequenceDiagram': - if(typeof mermaid.sequenceConfig === 'object'){ - seq.setConf(mermaid.sequenceConfig); - } - seq.draw(txt,id); - utils.cloneCssStyles(element.firstChild, []); - break; - case 'gantt': - if(typeof mermaid.ganttConfig === 'object'){ - gantt.setConf(mermaid.ganttConfig); - - } - gantt.draw(txt,id); - utils.cloneCssStyles(element.firstChild, []); - break; - case 'info': - info.draw(txt,id,exports.version()); - utils.cloneCssStyles(element.firstChild, []); - break; - } - //log.debug(document.body.innerHTML); - cb(d3.select('#d'+id).node().innerHTML); - - d3.select('#d'+id).node().remove(); - }; - - -exports.render = function(id, text){ - - var callback = function(svgText){ - log.debug(svgText); - }; - - if(typeof document === 'undefined'){ - //jsdom = require('jsdom').jsdom; - //log.debug(jsdom); - - //htmlStub = '
'+text+'
'; - htmlStub = ''; - // // html file skull with a container div for the d3 dataviz - // - // pass the html stub to jsDom - /* jsdom.env({ - features : { QuerySelectorAll : true }, - html : htmlStub, - done : function(errors, win) { - // process the html document, like if we were at client side - // code to generate the dataviz and process the resulting html file to be added here - //var d3 = require('d3'); - //log.debug('Here we go: '+JSON.stringify(d3)); - - global.document = win.document; - global.window = win; - - var element = win.document.createElement('div'); - element.setAttribute('id','did'); - //document. - log.debug(document.body.innerHTML); - //log.debug('Element:',element); - //log.debug(win); - //mermaid.init(); - //render(win.document, 'myId', text, callback); - - } - });*/ - //var jsdom = require('jsdom').jsdom; - //global.document = jsdom(htmlStub); - //global.window = document.parentWindow; - - render(id, text, callback); - //var element = win.document.createElement('div'); - //element.setAttribute('id','did'); - //document. - } - else{ - // In browser - render( id, text, callback); - } - - - -}; - -global.mermaid = { - startOnLoad: true, - htmlLabels: true, - - init: function(sequenceConfig, nodes) { - init.apply(null, arguments); - }, - version: function() { - return exports.version(); - }, - getParser: function() { - return flow.parser; - }, - parse: function(text) { - return parse(text); - }, - parseError: function(err, hash) { - log.debug('Mermaid Syntax error:'); - log.debug(err); - }, - render:function(id, text){ - return exports.render(id, text); - } -}; - -exports.contentLoaded = function(){ - // Check state of start config mermaid namespace - //log.debug('global.mermaid.startOnLoad',global.mermaid.startOnLoad); - //log.debug('mermaid_config',mermaid_config); - if (typeof mermaid_config !== 'undefined') { - if (equals(false, mermaid_config.htmlLabels)) { - global.mermaid.htmlLabels = false; - } - } - - if(global.mermaid.startOnLoad) { - - // For backwards compatability reasons also check mermaid_config variable - if (typeof mermaid_config !== 'undefined') { - // Check if property startOnLoad is set - if (equals(true, mermaid_config.startOnLoad)) { - global.mermaid.init(); - } - } - else { - // No config found, do autostart in this simple case - global.mermaid.init(); - } - } - -}; - - - -if(typeof document !== 'undefined'){ - /** - * Wait for document loaded before starting the execution - */ - document.addEventListener('DOMContentLoaded', function(){ - exports.contentLoaded(); - }, false); -} diff --git a/src/mermaid.js b/src/mermaid.js index f49ecc535..66ad8b031 100644 --- a/src/mermaid.js +++ b/src/mermaid.js @@ -1,8 +1,22 @@ +//(function (root, factory) { +// if (typeof exports === 'object') { +// // CommonJS +// module.exports = factory(require('b')); +// } else if (typeof define === 'function' && define.amd) { +// // AMD +// define(['b'], function (b) { +// return (root.returnExportsGlobal = factory(b)); +// }); +// } else { +// // Global Variables +// root.returnExportsGlobal = factory(root.b); +// } +//}(this, function (b) { /** * Web page integration module for the mermaid framework. It uses the mermaidAPI for mermaid functionality and to render * the diagrams to svg code. */ -var he = require('he'); + var mermaidAPI = require('./mermaidAPI'); var nextId = 0; var log = require('./logger').create(); @@ -14,12 +28,12 @@ module.exports.mermaidAPI = mermaidAPI; * * The function tags the processed attributes with the attribute data-processed and ignores found elements with the * attribute already set. This way the init function can be triggered several times. - * + * * Optionally, `init` can accept in the second argument one of the following: * - a DOM Node * - an array of DOM nodes (as would come from a jQuery selector) * - a W3C selector, a la `.mermaid` - * + * * ```mermaid * graph LR; * a(Find elements)-->b{Processed} @@ -35,7 +49,7 @@ var init = function () { if(arguments.length >= 2){ /*! sequence config was passed as #1 */ if(typeof arguments[0] !== 'undefined'){ - mermaid.sequenceConfig = arguments[0]; + mermaid.sequenceConfig = arguments[0]; } nodes = arguments[1]; @@ -65,14 +79,12 @@ var init = function () { : nodes instanceof Node ? [nodes] /*! Last case - sequence config was passed pick next */ : nodes; - + var i; if(typeof mermaid_config !== 'undefined'){ mermaidAPI.initialize(mermaid_config); - } - log.debug('Start On Load before: '+mermaid.startOnLoad); if(typeof mermaid.startOnLoad !== 'undefined'){ log.debug('Start On Load inner: '+mermaid.startOnLoad); @@ -91,7 +103,7 @@ var init = function () { callback(id); } }; - + for (i = 0; i < nodes.length; i++) { var element = nodes[i]; @@ -104,6 +116,7 @@ var init = function () { var id = 'mermaidChart' + nextId++; + var he = require('he'); var txt = element.innerHTML; txt = txt.replace(/>/g,'>'); txt = txt.replace(/