feat(flowchart): implement double circle node

The implementation uses two circles, inside each other.
A double circle node is opend with `()(` and closed with `)()`.
This commit is contained in:
Guy Adler
2022-02-16 23:05:46 +01:00
parent 9110bdfb5d
commit e1f0e69263
7 changed files with 87 additions and 0 deletions

View File

@@ -368,6 +368,7 @@ flowchart TD
I{{red text}} -->|default style| J[/blue text/]
K[\\ red text\\] -->|default style| L[/blue text\\]
M[\\ red text/] -->|default style| N[blue text];
O()(red text)() -->|default style| P()(blue text)();
linkStyle default color:Sienna;
style A stroke:#ff0000,fill:#ffcccc,color:#ff0000;
style B stroke:#0000ff,fill:#ccccff,color:#0000ff;
@@ -383,6 +384,8 @@ flowchart TD
style L stroke:#0000ff,fill:#ccccff,color:#0000ff;
style M stroke:#ff0000,fill:#ffcccc,color:#ff0000;
style N stroke:#0000ff,fill:#ccccff,color:#0000ff;
style O stroke:#ff0000,fill:#ffcccc,color:#ff0000;
style P stroke:#0000ff,fill:#ccccff,color:#0000ff;
`,
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', logLevel: 2 }
);

View File

@@ -1047,6 +1047,7 @@
L1[/red text\] <-->|default style| L2[/blue text\]
M1[\red text/] <-->|default style| M2[\blue text/]
N1[red text] <-->|default style| N2[blue text]
O1()(red text)() <-->|default style| O2()(blue text)()
linkStyle default color:Sienna;
style A1 stroke:#ff0000,fill:#ffcccc,color:#ff0000
style B1 stroke:#ff0000,fill:#ffcccc,color:#ff0000
@@ -1062,6 +1063,7 @@
style L1 stroke:#ff0000,fill:#ffcccc,color:#ff0000
style M1 stroke:#ff0000,fill:#ffcccc,color:#ff0000
style N1 stroke:#ff0000,fill:#ffcccc,color:#ff0000
style O1 stroke:#ff0000,fill:#ffcccc,color:#ff0000
style A2 stroke:#0000ff,fill:#ccccff,color:#0000ff
style B2 stroke:#0000ff,fill:#ccccff,color:#0000ff
style C2 stroke:#0000ff,fill:#ccccff,color:#0000ff
@@ -1076,6 +1078,7 @@
style L2 stroke:#0000ff,fill:#ccccff,color:#0000ff
style M2 stroke:#0000ff,fill:#ccccff,color:#0000ff
style N2 stroke:#0000ff,fill:#ccccff,color:#0000ff
style O2 stroke:#0000ff,fill:#ccccff,color:#0000ff
</div>
<hr/>

View File

@@ -552,6 +552,42 @@ const circle = (parent, node) => {
return shapeSvg;
};
const doublecircle = (parent, node) => {
const { shapeSvg, bbox, halfPadding } = labelHelper(parent, node, undefined, true);
const gap = 5;
const circleGroup = shapeSvg.insert('g', ':first-child');
const outerCircle = circleGroup.insert('circle');
const innerCircle = circleGroup.insert('circle');
// center the circle around its coordinate
outerCircle
.attr('style', node.style)
.attr('rx', node.rx)
.attr('ry', node.ry)
.attr('r', bbox.width / 2 + halfPadding + gap)
.attr('width', bbox.width + node.padding + gap * 2)
.attr('height', bbox.height + node.padding + gap * 2);
innerCircle
.attr('style', node.style)
.attr('rx', node.rx)
.attr('ry', node.ry)
.attr('r', bbox.width / 2 + halfPadding)
.attr('width', bbox.width + node.padding)
.attr('height', bbox.height + node.padding);
log.info('DoubleCircle main');
updateNodeBounds(node, outerCircle);
node.intersect = function (point) {
log.info('DoubleCircle intersect', node, bbox.width / 2 + halfPadding + gap, point);
return intersect.circle(node, bbox.width / 2 + halfPadding + gap, point);
};
return shapeSvg;
};
const subroutine = (parent, node) => {
const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
@@ -941,6 +977,7 @@ const shapes = {
rectWithTitle,
choice,
circle,
doublecircle,
stadium,
hexagon,
rect_left_inv_arrow,
@@ -965,6 +1002,8 @@ export const insertNode = (elem, node, dir) => {
let newEl;
let el;
console.log(shapes);
// Add link when appropriate
if (node.link) {
newEl = elem

View File

@@ -131,6 +131,9 @@ export const addVertices = function (vert, g, svgId) {
case 'group':
_shape = 'rect';
break;
case 'doublecircle':
_shape = 'doublecircle';
break;
default:
_shape = 'rect';
}

View File

@@ -26,6 +26,7 @@ describe('the flowchart renderer', function () {
['subroutine', 'subroutine'],
['cylinder', 'cylinder'],
['group', 'rect'],
['doublecircle', 'doublecircle'],
].forEach(function ([type, expectedShape, expectedRadios = 0]) {
it(`should add the correct shaped node to the graph for vertex type ${type}`, function () {
const addedNodes = [];

View File

@@ -159,6 +159,40 @@ describe('[Singlenodes] when parsing', () => {
expect(vert['a'].text).toBe('A <br> end');
});
it('should handle a single double circle node', function () {
// Silly but syntactically correct
const res = flow.parser.parse('graph TD;a()(A)();');
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(edges.length).toBe(0);
expect(vert['a'].type).toBe('doublecircle');
});
it('should handle a single double circle node with whitespace after it', function () {
// Silly but syntactically correct
const res = flow.parser.parse('graph TD;a()(A)() ;');
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(edges.length).toBe(0);
expect(vert['a'].type).toBe('doublecircle');
});
it('should handle a single double circle node with html in it (SN3)', function () {
// Silly but syntactically correct
const res = flow.parser.parse('graph TD;a()(A <br> end)();');
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
expect(edges.length).toBe(0);
expect(vert['a'].type).toBe('doublecircle');
expect(vert['a'].text).toBe('A <br> end');
});
it('should handle a single node with alphanumerics starting on a char', function () {
// Silly but syntactically correct
const res = flow.parser.parse('graph TD;id1;');

View File

@@ -121,6 +121,8 @@ that id.
"[|" return 'VERTEX_WITH_PROPS_START';
"[(" return 'CYLINDERSTART';
")]" return 'CYLINDEREND';
"()(" return 'DOUBLECIRCLESTART';
")()" return 'DOUBLECIRCLEEND';
\- return 'MINUS';
"." return 'DOT';
[\_] return 'UNDERSCORE';
@@ -373,6 +375,8 @@ node: vertex
vertex: idString SQS text SQE
{$$ = $1;yy.addVertex($1,$3,'square');}
| idString DOUBLECIRCLESTART text DOUBLECIRCLEEND
{$$ = $1;yy.addVertex($1,$3,'doublecircle');}
| idString PS PS text PE PE
{$$ = $1;yy.addVertex($1,$4,'circle');}
| idString '(-' text '-)'