diff --git a/src/diagrams/flowchart/flowRenderer.js b/src/diagrams/flowchart/flowRenderer.js new file mode 100644 index 000000000..49cad4fb1 --- /dev/null +++ b/src/diagrams/flowchart/flowRenderer.js @@ -0,0 +1,278 @@ +/** + * Created by knut on 14-12-11. + */ +var graph = require('./graphDb'); +var flow = require('./parser/flow'); +var dot = require('./parser/dot'); +var utils = require('../../utils'); +var he = require('he'); +var dagreD3 = require('dagre-d3'); +/** + * Function that adds the vertices found in the graph definition to the graph to be rendered. + * @param vert Object containing the vertices. + * @param g The graph that is to be drawn. + */ +exports.addVertices = function (vert, g) { + var keys = Object.keys(vert); + + var styleFromStyleArr = function(styleStr,arr){ + var i; + // Create a compound style definition from the style definitions found for the node in the graph definition + for (i = 0; i < arr.length; i++) { + if (typeof arr[i] !== 'undefined') { + styleStr = styleStr + arr[i] + ';'; + } + } + + return styleStr; + }; + + // Iterate through each item in the vertice object (containing all the vertices found) in the graph definition + keys.forEach(function (id) { + var vertice = vert[id]; + var verticeText; + + var i; + + /** + * Variable for storing the extracted style for the vertice + * @type {string} + */ + var style = ''; + var classes = graph.getClasses(); + // Check if class is defined for the node + + if(vertice.classes.length >0){ + for (i = 0; i < vertice.classes.length; i++) { + style = styleFromStyleArr(style,classes[vertice.classes[i]].styles); + } + } + else{ + // Use default classes + style = styleFromStyleArr(style,classes.default.styles); + } + + + // Create a compound style definition from the style definitions found for the node in the graph definition + style = styleFromStyleArr(style, vertice.styles); + + // Use vertice id as text in the box if no text is provided by the graph definition + if (typeof vertice.text === 'undefined') { + verticeText = vertice.id; + } + else { + verticeText = vertice.text; + } + + var radious = 0; + var _shape = ''; + + // Set the shape based parameters + switch(vertice.type){ + case 'round': + radious = 5; + _shape = 'rect'; + break; + case 'square': + _shape = 'rect'; + break; + case 'diamond': + _shape = 'question'; + break; + case 'odd': + _shape = 'rect_left_inv_arrow'; + break; + case 'circle': + _shape = 'circle'; + break; + default: + _shape = 'rect'; + } + // Add the node + g.setNode(vertice.id, {labelType: "html",shape:_shape, label: verticeText, rx: radious, ry: radious, style: style, id:vertice.id}); + }); +}; + +/** + * Add edges to graph based on parsed graph defninition + * @param {Object} edges The edges to add to the graph + * @param {Object} g The graph object + */ +exports.addEdges = function (edges, g) { + var cnt=0; + var aHead; + edges.forEach(function (edge) { + cnt++; + + // Set link type for rendering + if(edge.type === 'arrow_open'){ + aHead = 'none'; + } + else{ + aHead = 'normal'; + } + + var style = ''; + if(typeof edge.style !== 'undefined'){ + edge.style.forEach(function(s){ + style = style + s +';'; + }); + } + + // Add the edge to the graph + if (typeof edge.text === 'undefined') { + if(typeof edge.style === 'undefined'){ + g.setEdge(edge.start, edge.end,{ style: "stroke: #333; stroke-width: 1.5px;fill:none", arrowheadStyle: "fill: #333", arrowhead: aHead},cnt); + }else{ + g.setEdge(edge.start, edge.end, { + style: style, arrowheadStyle: "fill: #333", arrowhead: aHead + },cnt); + } + } + // Edge with text + else { + + if(typeof edge.style === 'undefined'){ + g.setEdge(edge.start, edge.end,{labelType: "html",style: "stroke: #333; stroke-width: 1.5px;fill:none", labelpos:'c', label: ''+edge.text+'', arrowheadStyle: "fill: #333", arrowhead: aHead},cnt); + }else{ + g.setEdge(edge.start, edge.end, { + labelType: "html",style: style, arrowheadStyle: "fill: #333", label: edge.text, arrowhead: aHead + },cnt); + } + } + }); +}; + +/** + * Draws a flowchart in the tag with id: id based on the graph definition in text. + * @param text + * @param id + */ +exports.draw = function (text, id,isDot) { + var parser; + graph.clear(); + if(isDot){ + parser = dot.parser; + + }else{ + parser = flow.parser; + } + parser.yy = graph; + + // Parse the graph definition + parser.parse(text); + + // Fetch the default direction, use TD if none was found + var dir; + dir = graph.getDirection(); + if(typeof dir === 'undefined'){ + dir='TD'; + } + + // Create the input mermaid.graph + var g = new dagreD3.graphlib.Graph({multigraph:true}) + .setGraph({ + rankdir: dir, + marginx: 20, + marginy: 20 + + }) + .setDefaultEdgeLabel(function () { + return {}; + }); + + // Fetch the verices/nodes and edges/links from the parsed graph definition + var vert = graph.getVertices(); + var edges = graph.getEdges(); + var classes = graph.getClasses(); + + if(typeof classes.default === 'undefined'){ + classes.default = {id:'default'}; + classes.default.styles = ['fill:#eaeaea','stroke:#666','stroke-width:1.5px']; + } + exports.addVertices(vert, g); + exports.addEdges(edges, g); + + // Create the renderer + var render = new dagreD3.render(); + + // Add custom shape for rhombus type of boc (decision) + render.shapes().question = function (parent, bbox, node) { + var w = bbox.width, + h = bbox.height, + s = (w + h) * 0.8, + points = [ + {x: s / 2, y: 0}, + {x: s, y: -s / 2}, + {x: s / 2, y: -s}, + {x: 0, y: -s / 2} + ]; + shapeSvg = parent.insert("polygon", ":first-child") + .attr("points", points.map(function (d) { + return d.x + "," + d.y; + }).join(" ")) + .style("fill", "#fff") + .style("stroke", "#333") + .attr("rx", 5) + .attr("ry", 5) + .attr("transform", "translate(" + (-s / 2) + "," + (s * 2 / 4) + ")"); + node.intersect = function (point) { + return dagreD3.intersect.polygon(node, points, point); + }; + return shapeSvg; + }; + + // Add custom shape for box with inverted arrow on left side + render.shapes().rect_left_inv_arrow = function (parent, bbox, node) { + var w = bbox.width, + h = bbox.height, + points = [ + {x: -h/2, y: 0}, + {x: w, y: 0}, + {x: w, y: -h}, + {x: -h/2, y: -h}, + {x: 0, y: -h/2}, + ]; + shapeSvg = parent.insert("polygon", ":first-child") + .attr("points", points.map(function (d) { + return d.x + "," + d.y; + }).join(" ")) + .style("fill", "#fff") + .style("stroke", "#333") + .attr("transform", "translate(" + (-w / 2) + "," + (h * 2 / 4) + ")"); + node.intersect = function (point) { + return dagreD3.intersect.polygon(node, points, point); + }; + return shapeSvg; + }; + + // Add our custom arrow - an empty arrowhead + render.arrows().none = function normal(parent, id, edge, type) { + var marker = parent.append("marker") + .attr("id", id) + .attr("viewBox", "0 0 10 10") + .attr("refX", 9) + .attr("refY", 5) + .attr("markerUnits", "strokeWidth") + .attr("markerWidth", 8) + .attr("markerHeight", 6) + .attr("orient", "auto"); + + var path = marker.append("path") + .attr("d", "M 0 0 L 0 0 L 0 0 z"); + dagreD3.util.applyStyle(path, edge[type + "Style"]); + }; + + // Set up an SVG group so that we can translate the final graph. + var svg = d3.select("#" + id); + svgGroup = d3.select("#" + id + " g"); + + // Run the renderer. This is what draws the final graph. + render(d3.select("#" + id + " g"), g); + + // Center the graph + var xCenterOffset = (svg.attr("width") - g.graph().width) / 2; + //svgGroup.attr("transform", "translate(" + xCenterOffset + ", 20)"); + svg.attr("height", g.graph().height ); + svg.attr("width", g.graph().width ); +}; \ No newline at end of file diff --git a/src/graphDb.js b/src/diagrams/flowchart/graphDb.js similarity index 100% rename from src/graphDb.js rename to src/diagrams/flowchart/graphDb.js diff --git a/src/parser/dot.jison b/src/diagrams/flowchart/parser/dot.jison similarity index 100% rename from src/parser/dot.jison rename to src/diagrams/flowchart/parser/dot.jison diff --git a/src/parser/dot.js b/src/diagrams/flowchart/parser/dot.js similarity index 100% rename from src/parser/dot.js rename to src/diagrams/flowchart/parser/dot.js diff --git a/src/parser/flow.jison b/src/diagrams/flowchart/parser/flow.jison similarity index 100% rename from src/parser/flow.jison rename to src/diagrams/flowchart/parser/flow.jison diff --git a/src/parser/flow.js b/src/diagrams/flowchart/parser/flow.js similarity index 100% rename from src/parser/flow.js rename to src/diagrams/flowchart/parser/flow.js diff --git a/src/parser/flow.spec.js b/src/diagrams/flowchart/parser/flow.spec.js similarity index 100% rename from src/parser/flow.spec.js rename to src/diagrams/flowchart/parser/flow.spec.js diff --git a/src/parser/js-sequence-diagram.jison b/src/diagrams/sequenceDiagram/parser/js-sequence-diagram.jison similarity index 100% rename from src/parser/js-sequence-diagram.jison rename to src/diagrams/sequenceDiagram/parser/js-sequence-diagram.jison diff --git a/src/parser/sequence.jison b/src/diagrams/sequenceDiagram/parser/sequence.jison similarity index 100% rename from src/parser/sequence.jison rename to src/diagrams/sequenceDiagram/parser/sequence.jison diff --git a/src/parser/sequence.js b/src/diagrams/sequenceDiagram/parser/sequence.js similarity index 100% rename from src/parser/sequence.js rename to src/diagrams/sequenceDiagram/parser/sequence.js diff --git a/src/parser/sequenceDiagram.js b/src/diagrams/sequenceDiagram/parser/sequenceDiagram.js similarity index 100% rename from src/parser/sequenceDiagram.js rename to src/diagrams/sequenceDiagram/parser/sequenceDiagram.js diff --git a/src/sequence.spec.js b/src/diagrams/sequenceDiagram/sequence.spec.js similarity index 100% rename from src/sequence.spec.js rename to src/diagrams/sequenceDiagram/sequence.spec.js diff --git a/src/sequenceDb.js b/src/diagrams/sequenceDiagram/sequenceDb.js similarity index 100% rename from src/sequenceDb.js rename to src/diagrams/sequenceDiagram/sequenceDb.js diff --git a/src/sequenceDiagram.spec.js b/src/diagrams/sequenceDiagram/sequenceDiagram.spec.js similarity index 100% rename from src/sequenceDiagram.spec.js rename to src/diagrams/sequenceDiagram/sequenceDiagram.spec.js diff --git a/src/sequenceRenderer.js b/src/diagrams/sequenceDiagram/sequenceRenderer.js similarity index 100% rename from src/sequenceRenderer.js rename to src/diagrams/sequenceDiagram/sequenceRenderer.js diff --git a/src/main.js b/src/main.js index b1b773258..35dc5ba38 100644 --- a/src/main.js +++ b/src/main.js @@ -1,279 +1,9 @@ -var graph = require('./graphDb'); -var flow = require('./parser/flow'); -var dot = require('./parser/dot'); +var graph = require('./diagrams/flowchart/graphDb'); +var flow = require('./diagrams/flowchart/parser/flow'); var utils = require('./utils'); -var seq = require('./sequenceRenderer'); +var flowRenderer = require('./diagrams/flowchart/flowRenderer'); +var seq = require('./diagrams/sequenceDiagram/sequenceRenderer'); var he = require('he'); -var dagreD3 = require('dagre-d3'); -/** - * Function that adds the vertices found in the graph definition to the graph to be rendered. - * @param vert Object containing the vertices. - * @param g The graph that is to be drawn. - */ -exports.addVertices = function (vert, g) { - var keys = Object.keys(vert); - - var styleFromStyleArr = function(styleStr,arr){ - var i; - // Create a compound style definition from the style definitions found for the node in the graph definition - for (i = 0; i < arr.length; i++) { - if (typeof arr[i] !== 'undefined') { - styleStr = styleStr + arr[i] + ';'; - } - } - - return styleStr; - }; - - // Iterate through each item in the vertice object (containing all the vertices found) in the graph definition - keys.forEach(function (id) { - var vertice = vert[id]; - var verticeText; - - var i; - - /** - * Variable for storing the extracted style for the vertice - * @type {string} - */ - var style = ''; - var classes = graph.getClasses(); - // Check if class is defined for the node - - if(vertice.classes.length >0){ - for (i = 0; i < vertice.classes.length; i++) { - style = styleFromStyleArr(style,classes[vertice.classes[i]].styles); - } - } - else{ - // Use default classes - style = styleFromStyleArr(style,classes.default.styles); - } - - - // Create a compound style definition from the style definitions found for the node in the graph definition - style = styleFromStyleArr(style, vertice.styles); - - // Use vertice id as text in the box if no text is provided by the graph definition - if (typeof vertice.text === 'undefined') { - verticeText = vertice.id; - } - else { - verticeText = vertice.text; - } - - var radious = 0; - var _shape = ''; - - // Set the shape based parameters - switch(vertice.type){ - case 'round': - radious = 5; - _shape = 'rect'; - break; - case 'square': - _shape = 'rect'; - break; - case 'diamond': - _shape = 'question'; - break; - case 'odd': - _shape = 'rect_left_inv_arrow'; - break; - case 'circle': - _shape = 'circle'; - break; - default: - _shape = 'rect'; - } - // Add the node - g.setNode(vertice.id, {labelType: "html",shape:_shape, label: verticeText, rx: radious, ry: radious, style: style, id:vertice.id}); - }); -}; - -/** - * Add edges to graph based on parsed graph defninition - * @param {Object} edges The edges to add to the graph - * @param {Object} g The graph object - */ -exports.addEdges = function (edges, g) { - var cnt=0; - var aHead; - edges.forEach(function (edge) { - cnt++; - - // Set link type for rendering - if(edge.type === 'arrow_open'){ - aHead = 'none'; - } - else{ - aHead = 'normal'; - } - - var style = ''; - if(typeof edge.style !== 'undefined'){ - edge.style.forEach(function(s){ - style = style + s +';'; - }); - } - - // Add the edge to the graph - if (typeof edge.text === 'undefined') { - if(typeof edge.style === 'undefined'){ - g.setEdge(edge.start, edge.end,{ style: "stroke: #333; stroke-width: 1.5px;fill:none", arrowheadStyle: "fill: #333", arrowhead: aHead},cnt); - }else{ - g.setEdge(edge.start, edge.end, { - style: style, arrowheadStyle: "fill: #333", arrowhead: aHead - },cnt); - } - } - // Edge with text - else { - - if(typeof edge.style === 'undefined'){ - g.setEdge(edge.start, edge.end,{labelType: "html",style: "stroke: #333; stroke-width: 1.5px;fill:none", labelpos:'c', label: ''+edge.text+'', arrowheadStyle: "fill: #333", arrowhead: aHead},cnt); - }else{ - g.setEdge(edge.start, edge.end, { - labelType: "html",style: style, arrowheadStyle: "fill: #333", label: edge.text, arrowhead: aHead - },cnt); - } - } - }); -}; - -/** - * Draws a flowchart in the tag with id: id based on the graph definition in text. - * @param text - * @param id - */ -var draw = function (text, id,isDot) { - var parser; - graph.clear(); - if(isDot){ - parser = dot.parser; - - }else{ - parser = flow.parser; - } - parser.yy = graph; - - // Parse the graph definition - parser.parse(text); - - // Fetch the default direction, use TD if none was found - var dir; - dir = graph.getDirection(); - if(typeof dir === 'undefined'){ - dir='TD'; - } - - // Create the input mermaid.graph - var g = new dagreD3.graphlib.Graph({multigraph:true}) - .setGraph({ - rankdir: dir, - marginx: 20, - marginy: 20 - - }) - .setDefaultEdgeLabel(function () { - return {}; - }); - - // Fetch the verices/nodes and edges/links from the parsed graph definition - var vert = graph.getVertices(); - var edges = graph.getEdges(); - var classes = graph.getClasses(); - - if(typeof classes.default === 'undefined'){ - classes.default = {id:'default'}; - classes.default.styles = ['fill:#eaeaea','stroke:#666','stroke-width:1.5px']; - } - exports.addVertices(vert, g); - exports.addEdges(edges, g); - - // Create the renderer - var render = new dagreD3.render(); - - // Add custom shape for rhombus type of boc (decision) - render.shapes().question = function (parent, bbox, node) { - var w = bbox.width, - h = bbox.height, - s = (w + h) * 0.8, - points = [ - {x: s / 2, y: 0}, - {x: s, y: -s / 2}, - {x: s / 2, y: -s}, - {x: 0, y: -s / 2} - ]; - shapeSvg = parent.insert("polygon", ":first-child") - .attr("points", points.map(function (d) { - return d.x + "," + d.y; - }).join(" ")) - .style("fill", "#fff") - .style("stroke", "#333") - .attr("rx", 5) - .attr("ry", 5) - .attr("transform", "translate(" + (-s / 2) + "," + (s * 2 / 4) + ")"); - node.intersect = function (point) { - return dagreD3.intersect.polygon(node, points, point); - }; - return shapeSvg; - }; - - // Add custom shape for box with inverted arrow on left side - render.shapes().rect_left_inv_arrow = function (parent, bbox, node) { - var w = bbox.width, - h = bbox.height, - points = [ - {x: -h/2, y: 0}, - {x: w, y: 0}, - {x: w, y: -h}, - {x: -h/2, y: -h}, - {x: 0, y: -h/2}, - ]; - shapeSvg = parent.insert("polygon", ":first-child") - .attr("points", points.map(function (d) { - return d.x + "," + d.y; - }).join(" ")) - .style("fill", "#fff") - .style("stroke", "#333") - .attr("transform", "translate(" + (-w / 2) + "," + (h * 2 / 4) + ")"); - node.intersect = function (point) { - return dagreD3.intersect.polygon(node, points, point); - }; - return shapeSvg; - }; - - // Add our custom arrow - an empty arrowhead - render.arrows().none = function normal(parent, id, edge, type) { - var marker = parent.append("marker") - .attr("id", id) - .attr("viewBox", "0 0 10 10") - .attr("refX", 9) - .attr("refY", 5) - .attr("markerUnits", "strokeWidth") - .attr("markerWidth", 8) - .attr("markerHeight", 6) - .attr("orient", "auto"); - - var path = marker.append("path") - .attr("d", "M 0 0 L 0 0 L 0 0 z"); - dagreD3.util.applyStyle(path, edge[type + "Style"]); - }; - - // Set up an SVG group so that we can translate the final graph. - var svg = d3.select("#" + id); - svgGroup = d3.select("#" + id + " g"); - - // Run the renderer. This is what draws the final graph. - render(d3.select("#" + id + " g"), g); - - // Center the graph - var xCenterOffset = (svg.attr("width") - g.graph().width) / 2; - //svgGroup.attr("transform", "translate(" + xCenterOffset + ", 20)"); - svg.attr("height", g.graph().height ); - svg.attr("width", g.graph().width ); -}; /** * Function that goes through the document to find the chart definitions in there and render them. @@ -290,6 +20,7 @@ var draw = function (text, id,isDot) { */ var init = function () { var arr = document.querySelectorAll('.mermaid'); + var i; var cnt = 0; for (i = 0; i < arr.length; i++) { @@ -318,11 +49,12 @@ var init = function () { switch(graphType){ case 'graph': - draw(txt, id,false); + console.log('FC'); + flowRenderer.draw(txt, id,false); graph.bindFunctions(); break; case 'dotGraph': - draw(txt, id,true); + flowRenderer.draw(txt, id,true); break; case 'sequenceDiagram': seq.draw(txt,id); diff --git a/src/main.spec.js b/src/main.spec.js index ae240a4b5..10c0ca230 100644 --- a/src/main.spec.js +++ b/src/main.spec.js @@ -19,12 +19,7 @@ describe('when using main and ',function() { }); - xit('should have a version', function () { - div = document.createElement('div'); - mermaid_config ={startOnLoad : false}; - main = rewire('./main'); - expect(main.version()).toBe('0.2.10'); - }); + it('should not call start anything with an empty document', function () { mermaid_config ={startOnLoad : false}; @@ -46,8 +41,9 @@ describe('when using main and ',function() { describe('when calling addEdges ',function() { var main; - var graph = require('./graphDb'); - var flow = require('./parser/flow'); + var graph = require('./diagrams/flowchart/graphDb'); + var flow = require('./diagrams/flowchart/parser/flow'); + var flowRend = require('./diagrams/flowchart/flowRenderer'); beforeEach(function () { mermaid_config ={startOnLoad : false}; @@ -72,7 +68,7 @@ describe('when using main and ',function() { } }; - main.addEdges(edges,mockG); + flowRend.addEdges(edges,mockG); }); it('should handle edges without text', function () { @@ -88,7 +84,7 @@ describe('when using main and ',function() { } }; - main.addEdges(edges,mockG); + flowRend.addEdges(edges,mockG); }); @@ -105,7 +101,7 @@ describe('when using main and ',function() { } }; - main.addEdges(edges,mockG); + flowRend.addEdges(edges,mockG); }); it('should handle edges with styles defined', function () { @@ -122,7 +118,7 @@ describe('when using main and ',function() { } }; - main.addEdges(edges,mockG); + flowRend.addEdges(edges,mockG); }); it('should handle edges with text and styles defined', function () { var res = flow.parser.parse('graph TD;A---|the text|B; linkStyle 0 stroke:val1,stroke-width:val2;'); @@ -139,7 +135,7 @@ describe('when using main and ',function() { } }; - main.addEdges(edges,mockG); + flowRend.addEdges(edges,mockG); }); }); }); \ No newline at end of file