diff --git a/cypress/integration/rendering/flowchart-v2.spec.js b/cypress/integration/rendering/flowchart-v2.spec.js
index 60fba981e..b31d501c4 100644
--- a/cypress/integration/rendering/flowchart-v2.spec.js
+++ b/cypress/integration/rendering/flowchart-v2.spec.js
@@ -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 }
);
diff --git a/demos/flowchart.html b/demos/flowchart.html
index 1263a5b54..c0265baef 100644
--- a/demos/flowchart.html
+++ b/demos/flowchart.html
@@ -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
diff --git a/src/dagre-wrapper/nodes.js b/src/dagre-wrapper/nodes.js
index 2b164ea92..b79e8853c 100644
--- a/src/dagre-wrapper/nodes.js
+++ b/src/dagre-wrapper/nodes.js
@@ -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
diff --git a/src/diagrams/flowchart/flowRenderer-v2.js b/src/diagrams/flowchart/flowRenderer-v2.js
index b046d9c67..aa1be1e3e 100644
--- a/src/diagrams/flowchart/flowRenderer-v2.js
+++ b/src/diagrams/flowchart/flowRenderer-v2.js
@@ -131,6 +131,9 @@ export const addVertices = function (vert, g, svgId) {
case 'group':
_shape = 'rect';
break;
+ case 'doublecircle':
+ _shape = 'doublecircle';
+ break;
default:
_shape = 'rect';
}
diff --git a/src/diagrams/flowchart/flowRenderer.spec.js b/src/diagrams/flowchart/flowRenderer.spec.js
index 43f1511e0..21ecad908 100644
--- a/src/diagrams/flowchart/flowRenderer.spec.js
+++ b/src/diagrams/flowchart/flowRenderer.spec.js
@@ -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 = [];
diff --git a/src/diagrams/flowchart/parser/flow-singlenode.spec.js b/src/diagrams/flowchart/parser/flow-singlenode.spec.js
index acf0263fb..27ca2e519 100644
--- a/src/diagrams/flowchart/parser/flow-singlenode.spec.js
+++ b/src/diagrams/flowchart/parser/flow-singlenode.spec.js
@@ -159,6 +159,40 @@ describe('[Singlenodes] when parsing', () => {
expect(vert['a'].text).toBe('A
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
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
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;');
diff --git a/src/diagrams/flowchart/parser/flow.jison b/src/diagrams/flowchart/parser/flow.jison
index f07182395..5dc7e65d9 100644
--- a/src/diagrams/flowchart/parser/flow.jison
+++ b/src/diagrams/flowchart/parser/flow.jison
@@ -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 '-)'