mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-08-30 05:36:43 +02:00
#1704 handling of subgraph data
This commit is contained in:
@@ -101,7 +101,7 @@ describe('Flowchart v2', () => {
|
|||||||
const style = svg.attr('style');
|
const style = svg.attr('style');
|
||||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||||
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
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', () => {
|
it('8: should render a flowchart when useMaxWidth is false', () => {
|
||||||
@@ -121,7 +121,7 @@ describe('Flowchart v2', () => {
|
|||||||
const width = parseFloat(svg.attr('width'));
|
const width = parseFloat(svg.attr('width'));
|
||||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
// 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(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');
|
expect(svg).to.not.have.attr('style');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -229,18 +229,12 @@ describe('Flowchart v2', () => {
|
|||||||
it('54: handle nested subgraphs with outgoing links', () => {
|
it('54: handle nested subgraphs with outgoing links', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`flowchart TD
|
`flowchart TD
|
||||||
|
subgraph main
|
||||||
subgraph one[One]
|
subgraph subcontainer
|
||||||
subgraph sub_one[Sub One]
|
subcontainer-child
|
||||||
_sub_one
|
end
|
||||||
|
subcontainer-child--> subcontainer-sibling
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
subgraph two[Two]
|
|
||||||
_two
|
|
||||||
end
|
|
||||||
|
|
||||||
sub_one --> two
|
|
||||||
`,
|
`,
|
||||||
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
{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(
|
imgSnapshotTest(
|
||||||
`flowchart TD
|
`flowchart TB
|
||||||
|
subgraph container_Beta
|
||||||
subgraph one[One]
|
process_C-->Process_D
|
||||||
subgraph sub_one[Sub One]
|
|
||||||
_sub_one
|
|
||||||
end
|
end
|
||||||
subgraph sub_two[Sub Two]
|
subgraph container_Alpha
|
||||||
_sub_two
|
process_A-->process_B
|
||||||
|
process_A-->|messages|process_C
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
%% here, either the first or the second one
|
|
||||||
sub_one --> sub_two
|
|
||||||
_one --> b
|
|
||||||
`,
|
`,
|
||||||
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
||||||
);
|
);
|
||||||
|
@@ -22,27 +22,34 @@
|
|||||||
<body>
|
<body>
|
||||||
<h1>info below</h1>
|
<h1>info below</h1>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="mermaid" style="width: 50%; height: 400px;">
|
<div class="mermaid2" style="width: 50%; height: 400px;">
|
||||||
graph TB;
|
flowchart TD
|
||||||
subgraph "number as labels";
|
subgraph main
|
||||||
1 --> 2
|
subgraph subcontainer
|
||||||
end;
|
subcontainer-child
|
||||||
</div>
|
|
||||||
<div class="mermaid" style="width: 50%; height: 400px;">
|
|
||||||
flowchart TB;
|
|
||||||
subgraph "number as labels";
|
|
||||||
1 --> 2
|
|
||||||
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
|
end
|
||||||
|
subcontainer-child--> subcontainer-sibling
|
||||||
|
end
|
||||||
|
</div>
|
||||||
|
<div class="mermaid2" style="width: 50%; height: 400px;">
|
||||||
|
flowchart TB
|
||||||
|
subgraph container_Beta
|
||||||
|
process_C-->Process_D
|
||||||
|
end
|
||||||
|
subgraph container_Alpha
|
||||||
|
process_A-->process_B
|
||||||
|
process_A-->|messages|process_C
|
||||||
|
end
|
||||||
|
process_B-->|via_AWSBatch|container_Beta
|
||||||
|
</div>
|
||||||
|
<div class="mermaid" style="width: 50%; height: 20%;">
|
||||||
|
flowchart TB
|
||||||
|
subgraph A
|
||||||
|
a -->b
|
||||||
|
end
|
||||||
|
subgraph B
|
||||||
|
b
|
||||||
|
end
|
||||||
</div>
|
</div>
|
||||||
<div class="mermaid2" style="width: 50%; height: 20%;">
|
<div class="mermaid2" style="width: 50%; height: 20%;">
|
||||||
%%{init: {"fontFamily": "arial2"}}%%
|
%%{init: {"fontFamily": "arial2"}}%%
|
||||||
|
@@ -454,19 +454,8 @@ export const addSubGraph = function(_id, list, _title) {
|
|||||||
subCount = subCount + 1;
|
subCount = subCount + 1;
|
||||||
const subGraph = { id: id, nodes: nodeList, title: title.trim(), classes: [] };
|
const subGraph = { id: id, nodes: nodeList, title: title.trim(), classes: [] };
|
||||||
|
|
||||||
/**
|
// Remove the members in the new subgraph if they already belong to another subgraph
|
||||||
* Deletes an id from all subgraphs
|
subGraph.nodes.nodes = makeUniq(subGraph, 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));
|
|
||||||
subGraphs.push(subGraph);
|
subGraphs.push(subGraph);
|
||||||
subGraphLookup[id] = subGraph;
|
subGraphLookup[id] = subGraph;
|
||||||
return id;
|
return id;
|
||||||
@@ -664,6 +653,31 @@ const destructLink = (_str, _startStr) => {
|
|||||||
return info;
|
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) => {
|
||||||
|
console.log('Checking: ', _id);
|
||||||
|
if (!exists(allSubgraphs, _id)) {
|
||||||
|
res.push(sg.nodes[pos]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { nodes: res };
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
parseDirective,
|
parseDirective,
|
||||||
defaultConfig: () => configApi.defaultConfig.flowchart,
|
defaultConfig: () => configApi.defaultConfig.flowchart,
|
||||||
@@ -693,5 +707,7 @@ export default {
|
|||||||
destructLink,
|
destructLink,
|
||||||
lex: {
|
lex: {
|
||||||
firstGraph
|
firstGraph
|
||||||
}
|
},
|
||||||
|
exists,
|
||||||
|
makeUniq
|
||||||
};
|
};
|
||||||
|
44
src/diagrams/flowchart/flowDb.spec.js
Normal file
44
src/diagrams/flowchart/flowDb.spec.js
Normal 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']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
Reference in New Issue
Block a user