diff --git a/cypress/integration/rendering/flowchart-v2.spec.js b/cypress/integration/rendering/flowchart-v2.spec.js index e7ce3e358..fc35980bc 100644 --- a/cypress/integration/rendering/flowchart-v2.spec.js +++ b/cypress/integration/rendering/flowchart-v2.spec.js @@ -101,7 +101,7 @@ describe('Flowchart v2', () => { const style = svg.attr('style'); expect(style).to.match(/^max-width: [\d.]+px;$/); const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join('')); - expect(maxWidthValue).to.be.within(300 * .95, 300 * 1.05); + expect(maxWidthValue).to.be.within(300 * .95-1, 300 * 1.05); }); }); it('8: should render a flowchart when useMaxWidth is false', () => { @@ -121,7 +121,7 @@ describe('Flowchart v2', () => { const width = parseFloat(svg.attr('width')); // use within because the absolute value can be slightly different depending on the environment ±5% expect(height).to.be.within(446 * .95, 446 * 1.05); - expect(width).to.be.within(300 * .95, 300 * 1.05); + expect(width).to.be.within(300 * .95-1, 300 * 1.05); expect(svg).to.not.have.attr('style'); }); }); @@ -229,18 +229,12 @@ describe('Flowchart v2', () => { it('54: handle nested subgraphs with outgoing links', () => { imgSnapshotTest( `flowchart TD - -subgraph one[One] - subgraph sub_one[Sub One] - _sub_one + subgraph main + subgraph subcontainer + subcontainer-child end -end - -subgraph two[Two] - _two -end - -sub_one --> two + subcontainer-child--> subcontainer-sibling + end `, {htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'} ); @@ -269,23 +263,30 @@ _one --> b }); - it('56: handle nested subgraphs with outgoing links 2', () => { + it('56: handle nested subgraphs with outgoing links 3', () => { imgSnapshotTest( - `flowchart TD - -subgraph one[One] - subgraph sub_one[Sub One] - _sub_one + `flowchart TB + subgraph container_Beta + process_C-->Process_D + end + subgraph container_Alpha + process_A-->process_B + process_A-->|messages|process_C end - subgraph sub_two[Sub Two] - _sub_two - end - _one + process_B-->|via_AWSBatch|container_Beta + `, + {htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'} + ); + }); + it('57: handle nested subgraphs with outgoing links 4', () => { + imgSnapshotTest( + `flowchart LR +subgraph A +a -->b +end +subgraph B +b end - -%% here, either the first or the second one -sub_one --> sub_two -_one --> b `, {htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'} ); diff --git a/cypress/platform/knsv.html b/cypress/platform/knsv.html index 3731155cc..d7a5cee31 100644 --- a/cypress/platform/knsv.html +++ b/cypress/platform/knsv.html @@ -22,27 +22,36 @@

info below

-
- graph TB; - subgraph "number as labels"; - 1 --> 2 - end; +
+flowchart TD + subgraph main + subgraph subcontainer + subcontainer-child + end + subcontainer-child--> subcontainer-sibling + end
- flowchart TB; - subgraph "number as labels"; - 1 --> 2 - end; +flowchart TB + b-->B + a-->c + subgraph B + c + end + subgraph A + a + b + B + end
-
- %%{init: { 'theme': 'base', 'themeVariables':{ 'primaryColor': '#ff0000'}}}%% -graph TD - A(Start) --> B[/Another/] - A[/Another/] --> C[End] - subgraph section - B - C - end +
+ flowchart TB +subgraph A +a -->b +end +subgraph B +b +end
%%{init: {"fontFamily": "arial2"}}%% diff --git a/src/diagrams/flowchart/flowDb.js b/src/diagrams/flowchart/flowDb.js index 3a813d396..a5e89a515 100644 --- a/src/diagrams/flowchart/flowDb.js +++ b/src/diagrams/flowchart/flowDb.js @@ -414,7 +414,6 @@ export const defaultStyle = function() { * Clears the internal graph db so that a new graph can be parsed. */ export const addSubGraph = function(_id, list, _title) { - // logger.warn('addSubgraph', _id, list, _title); let id = _id.trim(); let title = _title; if (_id === _title && _title.match(/\s/)) { @@ -454,19 +453,25 @@ export const addSubGraph = function(_id, list, _title) { subCount = subCount + 1; const subGraph = { id: id, nodes: nodeList, title: title.trim(), classes: [] }; + console.log('Adding', subGraph.id, subGraph.nodes); + /** * Deletes an id from all subgraphs */ - const del = _id => { - subGraphs.forEach(sg => { - const pos = sg.nodes.indexOf(_id); - if (pos >= 0) { - sg.nodes.splice(pos, 1); - } - }); - }; - // Removes the members of this subgraph from any other subgraphs, a node only belong to one subgraph - subGraph.nodes.forEach(_id => del(_id)); + // const del = _id => { + // subGraphs.forEach(sg => { + // const pos = sg.nodes.indexOf(_id); + // if (pos >= 0) { + // sg.nodes.splice(pos, 1); + // } + // }); + // }; + + // // Removes the members of this subgraph from any other subgraphs, a node only belong to one subgraph + // subGraph.nodes.forEach(_id => del(_id)); + + // Remove the members in the new subgraph if they already belong to another subgraph + subGraph.nodes = makeUniq(subGraph, subGraphs).nodes; subGraphs.push(subGraph); subGraphLookup[id] = subGraph; return id; @@ -664,6 +669,30 @@ const destructLink = (_str, _startStr) => { return info; }; +// Todo optimizer this by caching existing nodes +const exists = (allSgs, _id) => { + let res = false; + allSgs.forEach(sg => { + const pos = sg.nodes.indexOf(_id); + if (pos >= 0) { + res = true; + } + }); + return res; +}; +/** + * Deletes an id from all subgraphs + */ +const makeUniq = (sg, allSubgraphs) => { + const res = []; + sg.nodes.forEach((_id, pos) => { + if (!exists(allSubgraphs, _id)) { + res.push(sg.nodes[pos]); + } + }); + return { nodes: res }; +}; + export default { parseDirective, defaultConfig: () => configApi.defaultConfig.flowchart, @@ -693,5 +722,7 @@ export default { destructLink, lex: { firstGraph - } + }, + exists, + makeUniq }; diff --git a/src/diagrams/flowchart/flowDb.spec.js b/src/diagrams/flowchart/flowDb.spec.js new file mode 100644 index 000000000..6c1d9e282 --- /dev/null +++ b/src/diagrams/flowchart/flowDb.spec.js @@ -0,0 +1,44 @@ +import flowDb from './flowDb'; + +describe('flow db subgraphs', () => { + let subgraphs; + beforeEach( ()=>{ + subgraphs = [ + {nodes:['a', 'b', 'c', 'e']}, + {nodes:['f', 'g', 'h']}, + {nodes:['i', 'j']}, + {nodes:['k']}, + ]; + }); + describe('exist', () => { + it('should return true when the is exists in a subgraph', () => { + expect(flowDb.exists(subgraphs, 'a')).toBe(true); + expect(flowDb.exists(subgraphs, 'h')).toBe(true); + expect(flowDb.exists(subgraphs, 'j')).toBe(true); + expect(flowDb.exists(subgraphs, 'k')).toBe(true); + }); + it('should return false when the is exists in a subgraph', () => { + expect(flowDb.exists(subgraphs, 'a2')).toBe(false); + expect(flowDb.exists(subgraphs, 'l')).toBe(false); + }); + }); + + describe('makeUniq', () => { + it('should remove ids from sungraph that already exists in another subgraph even if it gets empty', () => { + const subgraph = flowDb.makeUniq({nodes:['i', 'j']}, subgraphs); + + expect(subgraph.nodes).toEqual([]); + }); + it('should remove ids from sungraph that already exists in another subgraph', () => { + const subgraph = flowDb.makeUniq({nodes:['i', 'j', 'o']}, subgraphs); + + expect(subgraph.nodes).toEqual(['o']); + }); + it('should not remove ids from subgraph if they are unique', () => { + const subgraph = flowDb.makeUniq({nodes:['q', 'r', 's']}, subgraphs); + + expect(subgraph.nodes).toEqual(['q', 'r', 's']); + }); + }); +}); + diff --git a/src/diagrams/flowchart/parser/subgraph.spec.js b/src/diagrams/flowchart/parser/subgraph.spec.js index 6a7fefb71..0c435a2c4 100644 --- a/src/diagrams/flowchart/parser/subgraph.spec.js +++ b/src/diagrams/flowchart/parser/subgraph.spec.js @@ -244,8 +244,9 @@ describe('when parsing subgraphs', function() { const res = flow.parser.parse(`flowchart TB subgraph A b-->B - a-->c + a end + a-->c subgraph B c end`);