Skip to content

Commit

Permalink
Merge pull request mermaid-js#1166 from GDFaber/feature/flowchart_add…
Browse files Browse the repository at this point in the history
…_cylindric_shape

mermaid-js#1154 Flow diagram DB shape request
  • Loading branch information
knsv authored Jan 1, 2020
2 parents 2db8075 + bc59d01 commit 75e2abe
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 19 deletions.
55 changes: 38 additions & 17 deletions cypress/integration/rendering/flowchart.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-env jest */
import { imgSnapshotTest } from '../../helpers/util';

describe('Flowcart', () => {
describe('Flowchart', () => {
it('1: should render a simple flowchart no htmlLabels', () => {
imgSnapshotTest(
`graph TD
Expand Down Expand Up @@ -57,7 +57,7 @@ describe('Flowcart', () => {
);
});

it('4: should style nodes via a class.', () => {
it('5: should style nodes via a class.', () => {
imgSnapshotTest(
`
graph TD
Expand All @@ -73,7 +73,7 @@ describe('Flowcart', () => {
);
});

it('5: should render a flowchart full of circles', () => {
it('6: should render a flowchart full of circles', () => {
imgSnapshotTest(
`
graph LR
Expand Down Expand Up @@ -102,7 +102,7 @@ describe('Flowcart', () => {
);
});

it('6: should render a flowchart full of icons', () => {
it('7: should render a flowchart full of icons', () => {
imgSnapshotTest(
`
graph TD
Expand Down Expand Up @@ -173,7 +173,7 @@ describe('Flowcart', () => {
);
});

it('7: should render labels with numbers at the start', () => {
it('8: should render labels with numbers at the start', () => {
imgSnapshotTest(
`
graph TB;subgraph "number as labels";1;end;
Expand All @@ -182,7 +182,7 @@ describe('Flowcart', () => {
);
});

it('8: should render subgraphs', () => {
it('9: should render subgraphs', () => {
imgSnapshotTest(
`
graph TB
Expand All @@ -194,7 +194,7 @@ describe('Flowcart', () => {
);
});

it('9: should render subgraphs with a title starting with a digit', () => {
it('10: should render subgraphs with a title starting with a digit', () => {
imgSnapshotTest(
`
graph TB
Expand All @@ -206,7 +206,7 @@ describe('Flowcart', () => {
);
});

it('10: should render styled subgraphs', () => {
it('11: should render styled subgraphs', () => {
imgSnapshotTest(
`
graph TB
Expand Down Expand Up @@ -241,7 +241,7 @@ describe('Flowcart', () => {
);
});

it('11: should render a flowchart with long names and class definitions', () => {
it('12: should render a flowchart with long names and class definitions', () => {
imgSnapshotTest(
`graph LR
sid-B3655226-6C29-4D00-B685-3D5C734DC7E1["
Expand Down Expand Up @@ -343,7 +343,7 @@ describe('Flowcart', () => {
);
});

it('12: should render color of styled nodes', () => {
it('13: should render color of styled nodes', () => {
imgSnapshotTest(
`
graph LR
Expand All @@ -361,7 +361,7 @@ describe('Flowcart', () => {
);
});

it('13: should render hexagons', () => {
it('14: should render hexagons', () => {
imgSnapshotTest(
`
graph TD
Expand All @@ -383,7 +383,7 @@ describe('Flowcart', () => {
);
});

it('14: should render a simple flowchart with comments', () => {
it('15: should render a simple flowchart with comments', () => {
imgSnapshotTest(
`graph TD
A[Christmas] -->|Get money| B(Go shopping)
Expand All @@ -396,7 +396,7 @@ describe('Flowcart', () => {
{ flowchart: { htmlLabels: false } }
);
});
it('15: Render Stadium shape', () => {
it('16: Render Stadium shape', () => {
imgSnapshotTest(
` graph TD
A([stadium shape test])
Expand All @@ -412,7 +412,7 @@ describe('Flowcart', () => {
{ flowchart: { htmlLabels: false } }
);
});
it('16: Render Stadium shape', () => {
it('17: Render multiline texts', () => {
imgSnapshotTest(
`graph LR
A1[Multi<br>Line] -->|Multi<br>Line| B1(Multi<br>Line)
Expand All @@ -428,23 +428,23 @@ describe('Flowcart', () => {
{ flowchart: { htmlLabels: false } }
);
});
it('17: Chaining of nodes', () => {
it('18: Chaining of nodes', () => {
imgSnapshotTest(
`graph LR
a --> b --> c
`,
{ flowchart: { htmlLabels: false } }
);
});
it('18: Multiple nodes and chaining in one statement', () => {
it('19: Multiple nodes and chaining in one statement', () => {
imgSnapshotTest(
`graph LR
a --> b c--> d
`,
{ flowchart: { htmlLabels: false } }
);
});
it('19: Multiple nodes and chaining in one statement', () => {
it('20: Multiple nodes and chaining in one statement', () => {
imgSnapshotTest(
`graph TD
A[ h ] -- hello --> B[" test "]:::exClass C --> D;
Expand All @@ -453,4 +453,25 @@ describe('Flowcart', () => {
{ flowchart: { htmlLabels: false } }
);
});
it('21: Render cylindrical shape', () => {
imgSnapshotTest(
`graph LR
A[(cylindrical<br />shape<br />test)]
A -->|Get money| B1[(Go shopping 1)]
A -->|Get money| B2[(Go shopping 2)]
A -->|Get money| B3[(Go shopping 3)]
C[(Let me think...<br />Do I want something for work,<br />something to spend every free second with,<br />or something to get around?)]
B1 --> C
B2 --> C
B3 --> C
C -->|One| D[(Laptop)]
C -->|Two| E[(iPhone)]
C -->|Three| F[(Car)]
click A "index.html#link-clicked" "link test"
click B testClick "click test"
classDef someclass fill:#f96;
class A someclass;`,
{ flowchart: { htmlLabels: false } }
);
});
});
18 changes: 18 additions & 0 deletions dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,24 @@
classDef someclass fill:#f96;
class A someclass;
</div>
<div class="mermaid">
graph LR
A[(cylindrical<br />shape<br />test)]
A -->|Get money| B1[(Go shopping 1)]
A -->|Get money| B2[(Go shopping 2)]
A -->|Get money| B3[(Go shopping 3)]
C[(Let me think...<br />Do I want something for work,<br />something to spend every free second with,<br />or something to get around?)]
B1 --> C
B2 --> C
B3 --> C
C -->|One| D[(Laptop)]
C -->|Two| E[(iPhone)]
C -->|Three| F[(Car)]
click A "index.html#link-clicked" "link test"
click B testClick "click test"
classDef someclass fill:#f96;
class A someclass;
</div>
<div class="mermaid">
graph LR
A1[Multi<br>Line] -->|Multi<br>Line| B1(Multi<br>Line)
Expand Down
11 changes: 11 additions & 0 deletions docs/flowchart.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,17 @@ graph LR
id1([This is the text in the box])
```

### A node in a cylindrical shape

```
graph LR
id1[(Database)]
```
```mermaid
graph LR
id1[(Database)]
```

### A node in the form of a circle

```
Expand Down
64 changes: 64 additions & 0 deletions src/diagrams/flowchart/flowChartShapes.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,74 @@ function stadium(parent, bbox, node) {
return shapeSvg;
}

function cylinder(parent, bbox, node) {
const w = bbox.width;
const rx = w / 2;
const ry = rx / (2.5 + w / 50);
const h = bbox.height + ry;

const shape =
'M 0,' +
ry +
' a ' +
rx +
',' +
ry +
' 0,0,0 ' +
w +
' 0 a ' +
rx +
',' +
ry +
' 0,0,0 ' +
-w +
' 0 l 0,' +
h +
' a ' +
rx +
',' +
ry +
' 0,0,0 ' +
w +
' 0 l 0,' +
-h;

const shapeSvg = parent
.attr('label-offset-y', ry)
.insert('path', ':first-child')
.attr('d', shape)
.attr('transform', 'translate(' + -w / 2 + ',' + -(h / 2 + ry) + ')');

node.intersect = function(point) {
const pos = dagreD3.intersect.rect(node, point);
const x = pos.x - node.x;

if (
rx != 0 &&
(Math.abs(x) < node.width / 2 ||
(Math.abs(x) == node.width / 2 && Math.abs(pos.y - node.y) > node.height / 2 - ry))
) {
// ellipsis equation: x*x / a*a + y*y / b*b = 1
// solve for y to get adjustion value for pos.y
let y = ry * ry * (1 - (x * x) / (rx * rx));
if (y != 0) y = Math.sqrt(y);
y = ry - y;
if (point.y - node.y > 0) y = -y;

pos.y += y;
}

return pos;
};

return shapeSvg;
}

export function addToRender(render) {
render.shapes().question = question;
render.shapes().hexagon = hexagon;
render.shapes().stadium = stadium;
render.shapes().cylinder = cylinder;

// Add custom shape for box with inverted arrow on left side
render.shapes().rect_left_inv_arrow = rect_left_inv_arrow;
Expand Down
17 changes: 17 additions & 0 deletions src/diagrams/flowchart/flowChartShapes.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,23 @@ describe('flowchart shapes', function() {
});
});

// path-based shapes
[
['cylinder', useWidth, useHeight]
].forEach(function([shapeType, getW, getH]) {
it(`should add a ${shapeType} shape that renders a properly positioned path element`, function() {
const mockRender = MockRender();
const mockSvg = MockSvg();
addToRender(mockRender);

[[100, 100], [123, 45], [71, 300]].forEach(function([width, height]) {
const shape = mockRender.shapes()[shapeType](mockSvg, { width, height }, {});
expect(shape.__tag).toEqual('path');
expect(shape.__attrs).toHaveProperty('d');
});
});
});

// polygon-based shapes
[
[
Expand Down
3 changes: 3 additions & 0 deletions src/diagrams/flowchart/flowRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ export const addVertices = function(vert, g, svgId) {
case 'stadium':
_shape = 'stadium';
break;
case 'cylinder':
_shape = 'cylinder';
break;
case 'group':
_shape = 'rect';
break;
Expand Down
1 change: 1 addition & 0 deletions src/diagrams/flowchart/flowRenderer.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ describe('the flowchart renderer', function() {
['circle', 'circle'],
['ellipse', 'ellipse'],
['stadium', 'stadium'],
['cylinder', 'cylinder'],
['group', 'rect']
].forEach(function([type, expectedShape, expectedRadios = 0]) {
it(`should add the correct shaped node to the graph for vertex type ${type}`, function() {
Expand Down
6 changes: 5 additions & 1 deletion src/diagrams/flowchart/parser/flow.jison
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@
"-)" return '-)';
"([" return 'STADIUMSTART';
"])" return 'STADIUMEND';
"[(" return 'CYLINDERSTART';
")]" return 'CYLINDEREND';
\- return 'MINUS';
"." return 'DOT';
[\_] return 'UNDERSCORE';
Expand Down Expand Up @@ -312,6 +314,8 @@ vertex: idString SQS text SQE
{$$ = $1;yy.addVertex($1,$3,'ellipse');}
| idString STADIUMSTART text STADIUMEND
{$$ = $1;yy.addVertex($1,$3,'stadium');}
| idString CYLINDERSTART text CYLINDEREND
{$$ = $1;yy.addVertex($1,$3,'cylinder');}
| idString PS text PE
{$$ = $1;yy.addVertex($1,$3,'round');}
| idString DIAMOND_START text DIAMOND_STOP
Expand Down Expand Up @@ -468,5 +472,5 @@ alphaNumToken : PUNCTUATION | UNICODE_TEXT | NUM| ALPHA | COLON | COMMA | PLUS

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

graphCodeTokens: STADIUMSTART | STADIUMEND | 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 | 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;
%%
3 changes: 2 additions & 1 deletion src/themes/flowchart.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
.node rect,
.node circle,
.node ellipse,
.node polygon {
.node polygon,
.node path {
fill: $mainBkg;
stroke: $nodeBorder;
stroke-width: 1px;
Expand Down

0 comments on commit 75e2abe

Please sign in to comment.