mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-14 06:43:25 +08:00
#2050 Adding possibility to render subgrapgs in different directions
This commit is contained in:
parent
84ad8aabec
commit
09569301f1
@ -893,4 +893,26 @@ graph TD
|
||||
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
||||
);
|
||||
});
|
||||
it('2050: handling of different rendering direction in subgraphs', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart LR
|
||||
|
||||
subgraph TOP
|
||||
direction TB
|
||||
subgraph B1
|
||||
direction RL
|
||||
i1 -->f1
|
||||
end
|
||||
subgraph B2
|
||||
direction BT
|
||||
i2 -->f2
|
||||
end
|
||||
end
|
||||
A --> TOP --> B
|
||||
B1 --> B2
|
||||
`,
|
||||
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -27,7 +27,7 @@
|
||||
<div>info below</div>
|
||||
<div class="flex">
|
||||
|
||||
<div class="mermaid" style="width: 100%; height: 20%;">
|
||||
<div class="mermaid3" style="width: 100%; height: 20%;">
|
||||
stateDiagram-v2
|
||||
state S1 {
|
||||
sub1 -->sub2
|
||||
@ -65,14 +65,23 @@ stateDiagram-v2
|
||||
}
|
||||
|
||||
</div>
|
||||
<div class="mermaid3" style="width: 100%; height: 20%;">
|
||||
<div class="mermaid" style="width: 100%; height: 20%;">
|
||||
%%{init:{"theme":"base", "themeVariables": {"primaryColor":"#411d4e", "titleColor":"white", "darkMode":true}}}%%
|
||||
flowchart LR
|
||||
|
||||
subgraph B1
|
||||
i -->f
|
||||
subgraph TOP
|
||||
direction TB
|
||||
subgraph B1
|
||||
direction RL
|
||||
i1 -->f1
|
||||
end
|
||||
subgraph B2
|
||||
direction BT
|
||||
i2 -->f2
|
||||
end
|
||||
end
|
||||
A --> B1 --> B --> B1
|
||||
A --> TOP --> B
|
||||
B1 --> B2
|
||||
</div>
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 134 KiB |
Binary file not shown.
After Width: | Height: | Size: 153 KiB |
@ -50,7 +50,7 @@ export const lookUpDomId = function(id) {
|
||||
* @param style
|
||||
* @param classes
|
||||
*/
|
||||
export const addVertex = function(_id, text, type, style, classes) {
|
||||
export const addVertex = function(_id, text, type, style, classes, dir) {
|
||||
let txt;
|
||||
let id = _id;
|
||||
if (typeof id === 'undefined') {
|
||||
@ -103,6 +103,9 @@ export const addVertex = function(_id, text, type, style, classes) {
|
||||
});
|
||||
}
|
||||
}
|
||||
if (typeof dir !== 'undefined') {
|
||||
vertices[id].dir = dir;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -431,6 +434,7 @@ export const defaultStyle = function() {
|
||||
* Clears the internal graph db so that a new graph can be parsed.
|
||||
*/
|
||||
export const addSubGraph = function(_id, list, _title) {
|
||||
// console.log('addSubGraph', _id, list, _title);
|
||||
let id = _id.trim();
|
||||
let title = _title;
|
||||
if (_id === _title && _title.match(/\s/)) {
|
||||
@ -440,8 +444,13 @@ export const addSubGraph = function(_id, list, _title) {
|
||||
const prims = { boolean: {}, number: {}, string: {} };
|
||||
const objs = [];
|
||||
|
||||
return a.filter(function(item) {
|
||||
let dir = direction.trim();
|
||||
const nodeList = a.filter(function(item) {
|
||||
const type = typeof item;
|
||||
if (item.stmt && item.stmt === 'dir') {
|
||||
dir = item.value;
|
||||
return false;
|
||||
}
|
||||
if (item.trim() === '') {
|
||||
return false;
|
||||
}
|
||||
@ -451,11 +460,13 @@ export const addSubGraph = function(_id, list, _title) {
|
||||
return objs.indexOf(item) >= 0 ? false : objs.push(item);
|
||||
}
|
||||
});
|
||||
return { nodeList, dir };
|
||||
}
|
||||
|
||||
let nodeList = [];
|
||||
|
||||
nodeList = uniq(nodeList.concat.apply(nodeList, list));
|
||||
const { nodeList: nl, dir } = uniq(nodeList.concat.apply(nodeList, list));
|
||||
nodeList = nl;
|
||||
if (version === 'gen-1') {
|
||||
log.warn('LOOKING UP');
|
||||
for (let i = 0; i < nodeList.length; i++) {
|
||||
@ -468,9 +479,9 @@ export const addSubGraph = function(_id, list, _title) {
|
||||
title = title || '';
|
||||
title = common.sanitizeText(title, config);
|
||||
subCount = subCount + 1;
|
||||
const subGraph = { id: id, nodes: nodeList, title: title.trim(), classes: [] };
|
||||
const subGraph = { id: id, nodes: nodeList, title: title.trim(), classes: [], dir };
|
||||
|
||||
log.info('Adding', subGraph.id, subGraph.nodes);
|
||||
log.info('Adding', subGraph.id, subGraph.nodes, subGraph.dir);
|
||||
|
||||
/**
|
||||
* Deletes an id from all subgraphs
|
||||
|
@ -147,6 +147,7 @@ export const addVertices = function(vert, g, svgId) {
|
||||
domId: flowDb.lookUpDomId(vertex.id),
|
||||
haveCallback: vertex.haveCallback,
|
||||
width: vertex.type === 'group' ? 500 : undefined,
|
||||
dir: vertex.dir,
|
||||
type: vertex.type,
|
||||
padding: getConfig().flowchart.padding
|
||||
});
|
||||
@ -163,6 +164,7 @@ export const addVertices = function(vert, g, svgId) {
|
||||
domId: flowDb.lookUpDomId(vertex.id),
|
||||
width: vertex.type === 'group' ? 500 : undefined,
|
||||
type: vertex.type,
|
||||
dir: vertex.dir,
|
||||
padding: getConfig().flowchart.padding
|
||||
});
|
||||
});
|
||||
@ -385,7 +387,7 @@ export const draw = function(text, id) {
|
||||
for (let i = subGraphs.length - 1; i >= 0; i--) {
|
||||
subG = subGraphs[i];
|
||||
log.info('Subgraph - ', subG);
|
||||
flowDb.addVertex(subG.id, subG.title, 'group', undefined, subG.classes);
|
||||
flowDb.addVertex(subG.id, subG.title, 'group', undefined, subG.classes, subG.dir);
|
||||
}
|
||||
|
||||
// Fetch the verices/nodes and edges/links from the parsed graph definition
|
||||
|
95
src/diagrams/flowchart/parser/flow-direction.spec.js
Normal file
95
src/diagrams/flowchart/parser/flow-direction.spec.js
Normal file
@ -0,0 +1,95 @@
|
||||
import flowDb from '../flowDb';
|
||||
import flow from './flow';
|
||||
import filter from 'lodash/filter';
|
||||
import { setConfig } from '../../../config';
|
||||
|
||||
setConfig({
|
||||
securityLevel: 'strict'
|
||||
});
|
||||
|
||||
describe('when parsing directions', function() {
|
||||
beforeEach(function() {
|
||||
flow.parser.yy = flowDb;
|
||||
flow.parser.yy.clear();
|
||||
flow.parser.yy.setGen('gen-2');
|
||||
});
|
||||
|
||||
|
||||
fit('should use default direction from top level', function() {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
subgraph A
|
||||
a --> b
|
||||
end`);
|
||||
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(1);
|
||||
const subgraph = subgraphs[0];
|
||||
expect(subgraph.nodes.length).toBe(2);
|
||||
expect(subgraph.nodes[0]).toBe('b');
|
||||
expect(subgraph.nodes[1]).toBe('a');
|
||||
expect(subgraph.id).toBe('A');
|
||||
expect(subgraph.dir).toBe('TB');
|
||||
});
|
||||
fit('should handle a subgraph with a direction', function() {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
subgraph A
|
||||
direction BT
|
||||
a --> b
|
||||
end`);
|
||||
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(1);
|
||||
const subgraph = subgraphs[0];
|
||||
expect(subgraph.nodes.length).toBe(2);
|
||||
expect(subgraph.nodes[0]).toBe('b');
|
||||
expect(subgraph.nodes[1]).toBe('a');
|
||||
expect(subgraph.id).toBe('A');
|
||||
expect(subgraph.dir).toBe('BT');
|
||||
});
|
||||
fit('should use the last defined direction', function() {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
subgraph A
|
||||
direction BT
|
||||
a --> b
|
||||
direction RL
|
||||
end`);
|
||||
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(1);
|
||||
const subgraph = subgraphs[0];
|
||||
expect(subgraph.nodes.length).toBe(2);
|
||||
expect(subgraph.nodes[0]).toBe('b');
|
||||
expect(subgraph.nodes[1]).toBe('a');
|
||||
expect(subgraph.id).toBe('A');
|
||||
expect(subgraph.dir).toBe('RL');
|
||||
});
|
||||
|
||||
fit('should handle nested subgraphs 1', function() {
|
||||
const res = flow.parser.parse(`flowchart TB
|
||||
subgraph A
|
||||
direction RL
|
||||
b-->B
|
||||
a
|
||||
end
|
||||
a-->c
|
||||
subgraph B
|
||||
direction LR
|
||||
c
|
||||
end`);
|
||||
|
||||
const subgraphs = flow.parser.yy.getSubGraphs();
|
||||
expect(subgraphs.length).toBe(2);
|
||||
|
||||
const subgraphA = filter(subgraphs,o => o.id === 'A')[0];
|
||||
const subgraphB = filter(subgraphs,o => o.id === 'B')[0];
|
||||
|
||||
expect(subgraphB.nodes[0]).toBe('c');
|
||||
expect(subgraphB.dir).toBe('LR');
|
||||
expect(subgraphA.nodes).toContain('B');
|
||||
expect(subgraphA.nodes).toContain('b');
|
||||
expect(subgraphA.nodes).toContain('a');
|
||||
expect(subgraphA.nodes).not.toContain('c');
|
||||
expect(subgraphA.dir).toBe('RL');
|
||||
});
|
||||
|
||||
});
|
@ -92,6 +92,12 @@ that id.
|
||||
<dir>\s*">" { this.popState(); return 'DIR'; }
|
||||
<dir>\s*"^" { this.popState(); return 'DIR'; }
|
||||
<dir>\s*"v" { this.popState(); return 'DIR'; }
|
||||
|
||||
.*direction\s+TB[^\n]* return 'direction_tb';
|
||||
.*direction\s+BT[^\n]* return 'direction_bt';
|
||||
.*direction\s+RL[^\n]* return 'direction_rl';
|
||||
.*direction\s+LR[^\n]* return 'direction_lr';
|
||||
|
||||
[0-9]+ { return 'NUM';}
|
||||
\# return 'BRKT';
|
||||
":::" return 'STYLE_SEPARATOR';
|
||||
@ -327,6 +333,7 @@ statement
|
||||
// {$$=yy.addSubGraph($3,$5,$3);}
|
||||
| subgraph separator document end
|
||||
{$$=yy.addSubGraph(undefined,$3,undefined);}
|
||||
| direction
|
||||
;
|
||||
|
||||
separator: NEWLINE | SEMI | EOF ;
|
||||
@ -537,6 +544,17 @@ alphaNumStatement
|
||||
{$$='-';}
|
||||
;
|
||||
|
||||
direction
|
||||
: direction_tb
|
||||
{ $$={stmt:'dir', value:'TB'};}
|
||||
| direction_bt
|
||||
{ $$={stmt:'dir', value:'BT'};}
|
||||
| direction_rl
|
||||
{ $$={stmt:'dir', value:'RL'};}
|
||||
| direction_lr
|
||||
{ $$={stmt:'dir', value:'LR'};}
|
||||
;
|
||||
|
||||
alphaNumToken : PUNCTUATION | AMP | UNICODE_TEXT | NUM| ALPHA | COLON | COMMA | PLUS | EQUALS | MULT | DOT | BRKT| UNDERSCORE ;
|
||||
|
||||
idStringToken : ALPHA|UNDERSCORE |UNICODE_TEXT | NUM| COLON | COMMA | PLUS | MINUS | DOWN |EQUALS | MULT | BRKT | DOT | PUNCTUATION | AMP;
|
||||
|
Loading…
x
Reference in New Issue
Block a user