Merge pull request #1709 from mermaid-js/1704_subgraphs

1704 subgraphs
This commit is contained in:
Knut Sveidqvist 2020-10-08 18:25:43 +02:00 committed by GitHub
commit 4c849554da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 144 additions and 58 deletions

View File

@ -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'}
);

View File

@ -22,27 +22,36 @@
<body>
<h1>info below</h1>
<div class="flex">
<div class="mermaid" style="width: 50%; height: 400px;">
graph TB;
subgraph "number as labels";
1 --> 2
end;
<div class="mermaid2" style="width: 50%; height: 400px;">
flowchart TD
subgraph main
subgraph subcontainer
subcontainer-child
end
subcontainer-child--> subcontainer-sibling
end
</div>
<div class="mermaid" style="width: 50%; height: 400px;">
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
</div>
<div class="mermaid2" style="width: 50%; height: 20%;">
%%{init: { 'theme': 'base', 'themeVariables':{ 'primaryColor': '#ff0000'}}}%%
graph TD
A(Start) --> B[/Another/]
A[/Another/] --> C[End]
subgraph section
B
C
end
<div class="mermaid" style="width: 50%; height: 20%;">
flowchart TB
subgraph A
a -->b
end
subgraph B
b
end
</div>
<div class="mermaid2" style="width: 50%; height: 20%;">
%%{init: {"fontFamily": "arial2"}}%%

View File

@ -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
};

View File

@ -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']);
});
});
});

View File

@ -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`);