Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Feature/1893 data flow diagrams #2389

Merged
merged 14 commits into from
Dec 1, 2021
53 changes: 53 additions & 0 deletions dist/dataflowchart.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Mermaid Quick Test Page</title>
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">
<style>
div.mermaid {
/* font-family: 'trebuchet ms', verdana, arial; */
font-family: 'Courier New', Courier, monospace !important;
}
</style>
</head>
<body>
<h2>Data Flow Diagram Example</h2>
<div class="mermaid">
flowchart LR
DataStore[|borders:tb|Database] -->|input| Process((System)) -->|output| Entity[Customer];
</div>

<h2>Borders Example</h2>
<div class="mermaid">
flowchart TD
allSides[ stroke all sides ];
allSides2[|borders:ltrb| stroke all sides ];
rbSides[|borders:rb| stroke right and bottom sides ];
ltSides[|borders:lt| stroke left and top sides ];
lrSides[|borders:lr| stroke left and right sides ];
noSide[|borders:no| stroke no side ];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no works, since the word does not contain any of the border letters ltrb. It's not a bug, it's a feature 😉

</div>

<script src="./mermaid.js"></script>
<script>
mermaid.initialize({
theme: 'forest',
logLevel: 3,
securityLevel: 'loose',
flowchart: { curve: 'basis' }
});
</script>
<script>
function testClick(nodeId) {
console.log("clicked", nodeId)
var originalBgColor = document.querySelector('body').style.backgroundColor
document.querySelector('body').style.backgroundColor = 'yellow'
setTimeout(function() {
document.querySelector('body').style.backgroundColor = originalBgColor
}, 100)
}
</script>
</body>
</html>
54 changes: 52 additions & 2 deletions src/dagre-wrapper/nodes.js
Original file line number Diff line number Diff line change
Expand Up @@ -313,15 +313,28 @@ const rect = (parent, node) => {
// add the rect
const rect = shapeSvg.insert('rect', ':first-child');

const totalWidth = bbox.width + node.padding;
const totalHeight = bbox.height + node.padding;
rect
.attr('class', 'basic label-container')
.attr('style', node.style)
.attr('rx', node.rx)
.attr('ry', node.ry)
.attr('x', -bbox.width / 2 - halfPadding)
.attr('y', -bbox.height / 2 - halfPadding)
.attr('width', bbox.width + node.padding)
.attr('height', bbox.height + node.padding);
.attr('width', totalWidth)
.attr('height', totalHeight);

if (node.props) {
const propKeys = new Set(Object.keys(node.props));
if (node.props.borders) {
applyNodePropertyBorders(rect, node.props.borders, totalWidth, totalHeight);
propKeys.delete('borders');
}
propKeys.forEach((propKey) => {
log.warn(`Unknown node property ${propKey}`);
});
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More properties may be added here in the future 🙂


updateNodeBounds(node, rect);

Expand All @@ -332,6 +345,43 @@ const rect = (parent, node) => {
return shapeSvg;
};

function applyNodePropertyBorders(rect, borders, totalWidth, totalHeight) {
const strokeDashArray = [];
const addBorder = (length) => {
strokeDashArray.push(length);
strokeDashArray.push(0);
};
const skipBorder = (length) => {
strokeDashArray.push(0);
strokeDashArray.push(length);
};
if (borders.includes('t')) {
log.debug('add top border');
addBorder(totalWidth);
} else {
skipBorder(totalWidth);
}
if (borders.includes('r')) {
log.debug('add right border');
addBorder(totalHeight);
} else {
skipBorder(totalHeight);
}
if (borders.includes('b')) {
log.debug('add bottom border');
addBorder(totalWidth);
} else {
skipBorder(totalWidth);
}
if (borders.includes('l')) {
log.debug('add left border');
addBorder(totalHeight);
} else {
skipBorder(totalHeight);
}
rect.attr('stroke-dasharray', strokeDashArray.join(' '));
}

const rectWithTitle = (parent, node) => {
// const { shapeSvg, bbox, halfPadding } = labelHelper(parent, node, 'node ' + node.classes);

Expand Down
4 changes: 3 additions & 1 deletion src/diagrams/flowchart/flowDb.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ export const lookUpDomId = function (id) {
* @param style
* @param classes
* @param dir
* @param props
*/
export const addVertex = function (_id, text, type, style, classes, dir) {
export const addVertex = function (_id, text, type, style, classes, dir, props = {}) {
let txt;
let id = _id;
if (typeof id === 'undefined') {
Expand Down Expand Up @@ -109,6 +110,7 @@ export const addVertex = function (_id, text, type, style, classes, dir) {
if (typeof dir !== 'undefined') {
vertices[id].dir = dir;
}
vertices[id].props = props;
};

/**
Expand Down
2 changes: 2 additions & 0 deletions src/diagrams/flowchart/flowRenderer-v2.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ export const addVertices = function (vert, g, svgId) {
width: vertex.type === 'group' ? 500 : undefined,
dir: vertex.dir,
type: vertex.type,
props: vertex.props,
padding: getConfig().flowchart.padding,
});

Expand All @@ -168,6 +169,7 @@ export const addVertices = function (vert, g, svgId) {
width: vertex.type === 'group' ? 500 : undefined,
type: vertex.type,
dir: vertex.dir,
props: vertex.props,
padding: getConfig().flowchart.padding,
});
});
Expand Down
5 changes: 4 additions & 1 deletion src/diagrams/flowchart/parser/flow.jison
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ that id.
"])" return 'STADIUMEND';
"[[" return 'SUBROUTINESTART';
"]]" return 'SUBROUTINEEND';
"[|" return 'VERTEX_WITH_PROPS_START';
"[(" return 'CYLINDERSTART';
")]" return 'CYLINDEREND';
\- return 'MINUS';
Expand Down Expand Up @@ -380,6 +381,8 @@ vertex: idString SQS text SQE
{$$ = $1;yy.addVertex($1,$3,'stadium');}
| idString SUBROUTINESTART text SUBROUTINEEND
{$$ = $1;yy.addVertex($1,$3,'subroutine');}
| idString VERTEX_WITH_PROPS_START ALPHA COLON ALPHA PIPE text SQE
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if there is a better token (or rule) than ALPHA for the identifier and/or value. It does not allow to add a property thick-borders, but thickBorders would work. That's fine to me. Further, the rule could be changed in the future if required.

{$$ = $1;yy.addVertex($1,$7,'rect',undefined,undefined,undefined, Object.fromEntries([[$3, $5]]));}
| idString CYLINDERSTART text CYLINDEREND
{$$ = $1;yy.addVertex($1,$3,'cylinder');}
| idString PS text PE
Expand Down Expand Up @@ -559,5 +562,5 @@ alphaNumToken : PUNCTUATION | AMP | UNICODE_TEXT | NUM| ALPHA | COLON | COMMA |

idStringToken : ALPHA|UNDERSCORE |UNICODE_TEXT | NUM| COLON | COMMA | PLUS | MINUS | DOWN |EQUALS | MULT | BRKT | DOT | PUNCTUATION | AMP;

graphCodeTokens: STADIUMSTART | STADIUMEND | SUBROUTINESTART | SUBROUTINEEND | CYLINDERSTART | CYLINDEREND | TRAPSTART | TRAPEND | INVTRAPSTART | INVTRAPEND | PIPE | PS | PE | SQS | SQE | DIAMOND_START | DIAMOND_STOP | TAGSTART | TAGEND | ARROW_CROSS | ARROW_POINT | ARROW_CIRCLE | ARROW_OPEN | QUOTE | SEMI;
graphCodeTokens: STADIUMSTART | STADIUMEND | SUBROUTINESTART | SUBROUTINEEND | VERTEX_WITH_PROPS_START | CYLINDERSTART | CYLINDEREND | TRAPSTART | TRAPEND | INVTRAPSTART | INVTRAPEND | PIPE | PS | PE | SQS | SQE | DIAMOND_START | DIAMOND_STOP | TAGSTART | TAGEND | ARROW_CROSS | ARROW_POINT | ARROW_CIRCLE | ARROW_OPEN | QUOTE | SEMI;
%%