diff --git a/cypress/integration/rendering/flowchart-v2.spec.js b/cypress/integration/rendering/flowchart-v2.spec.js index 60fba981e..10731de05 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..0ab1f6481 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/docs/flowchart.md b/docs/flowchart.md index 795d27579..f33fe39cc 100644 --- a/docs/flowchart.md +++ b/docs/flowchart.md @@ -141,6 +141,13 @@ flowchart TD B[\Go shopping/] ``` +### Double circle + +```mermaid-example +flowchart TD + id1(((This is the text in the circle))) +``` + ## Links between nodes Nodes can be connected with links/edges. It is possible to have different types of links or attach a text string to a link. diff --git a/src/dagre-wrapper/nodes.js b/src/dagre-wrapper/nodes.js index cb25f7fc0..52c6e0777 100644 --- a/src/dagre-wrapper/nodes.js +++ b/src/dagre-wrapper/nodes.js @@ -554,6 +554,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); @@ -943,6 +979,7 @@ const shapes = { rectWithTitle, choice, circle, + doublecircle, stadium, hexagon, rect_left_inv_arrow, diff --git a/src/diagrams/flowchart/flowRenderer-v2.js b/src/diagrams/flowchart/flowRenderer-v2.js index 21300992c..ae58a0212 100644 --- a/src/diagrams/flowchart/flowRenderer-v2.js +++ b/src/diagrams/flowchart/flowRenderer-v2.js @@ -133,6 +133,9 @@ export const addVertices = function (vert, g, svgId, root, doc) { case 'group': _shape = 'rect'; break; + case 'doublecircle': + _shape = 'doublecircle'; + break; default: _shape = 'rect'; } diff --git a/src/diagrams/flowchart/parser/flow-singlenode.spec.js b/src/diagrams/flowchart/parser/flow-singlenode.spec.js index acf0263fb..ee41a5c39 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..79175307a 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 '-)'