Skip to content

Commit

Permalink
Merge 6dcc538 into f86f027
Browse files Browse the repository at this point in the history
  • Loading branch information
knsv committed May 9, 2021
2 parents f86f027 + 6dcc538 commit a66633c
Show file tree
Hide file tree
Showing 12 changed files with 231 additions and 53 deletions.
20 changes: 20 additions & 0 deletions cypress/integration/rendering/stateDiagram-v2.spec.js
Expand Up @@ -398,6 +398,26 @@ stateDiagram-v2
}
);
});
it('v2 should handle different rendering directions in composite states', () => {
imgSnapshotTest(
`
stateDiagram
direction LR
state A {
direction BT
a --> b
}
state C {
direction RL
c --> d
}
A --> C
`,
{
logLevel: 0, fontFamily: 'courier',
}
);
});
it('v2 handle transition from one state in a composite state to a composite state', () => {
imgSnapshotTest(
`
Expand Down
4 changes: 2 additions & 2 deletions cypress/integration/rendering/stateDiagram.spec.js
Expand Up @@ -358,7 +358,7 @@ describe('State diagram', () => {
expect(svg).to.have.attr('width', '100%');
expect(svg).to.have.attr('height');
const height = parseFloat(svg.attr('height'));
expect(height).to.eq(171);
expect(height).to.be.within(139,141);
const style = svg.attr('style');
expect(style).to.match(/^max-width: [\d.]+px;$/);
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
Expand All @@ -379,7 +379,7 @@ describe('State diagram', () => {
.should((svg) => {
const height = parseFloat(svg.attr('height'));
const width = parseFloat(svg.attr('width'));
expect(height).to.eq(171);
expect(height).to.be.within(139,141);
// use within because the absolute value can be slightly different depending on the environment ±5%
expect(width).to.be.within(112 * .95, 112 * 1.05);
expect(svg).to.not.have.attr('style');
Expand Down
15 changes: 11 additions & 4 deletions cypress/platform/knsv.html
Expand Up @@ -29,9 +29,16 @@

<div class="mermaid" style="width: 100%; height: 20%;">
stateDiagram
MyState
note left of MyState : I am a leftie
note right of MyState : I am a rightie
direction LR
state A {
direction BT
a --> b
}
state C {
direction RL
c --> d
}
A --> C
</div>
<div class="mermaid2" style="width: 100%; height: 20%;">
%%{int:{
Expand Down Expand Up @@ -70,7 +77,7 @@
theme: 'default',
arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0,
logLevel: 5,
flowchart: { nodeSpacing: 10, curve: 'cardinal', htmlLabels: true },
htmlLabels: true,
// gantt: { axisFormat: '%m/%d/%Y' },
Expand Down
80 changes: 68 additions & 12 deletions dist/mermaid.core.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/mermaid.core.js.map

Large diffs are not rendered by default.

82 changes: 69 additions & 13 deletions dist/mermaid.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/mermaid.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/mermaid.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/mermaid.min.js.map

Large diffs are not rendered by default.

38 changes: 29 additions & 9 deletions src/diagrams/state/parser/stateDiagram.jison
@@ -1,6 +1,6 @@
/** mermaid
* https://mermaidjs.github.io/
* (c) 2014-2015 Knut Sveidqvist
* (c) 2014-2021 Knut Sveidqvist
* MIT license.
*
* Based on js sequence diagrams jison grammr
Expand Down Expand Up @@ -35,36 +35,46 @@
%x LINE

%%

.*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';

\%\%\{ { this.begin('open_directive'); return 'open_directive'; }
<open_directive>((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; }
<type_directive>":" { this.popState(); this.begin('arg_directive'); return ':'; }
<type_directive,arg_directive>\}\%\% { this.popState(); this.popState(); return 'close_directive'; }
<arg_directive>((?:(?!\}\%\%).|\n)*) return 'arg_directive';
\%\%(?!\{)[^\n]* /* skip comments */
[^\}]\%\%[^\n]* /* skip comments */{ console.log('Crap after close'); }
[^\}]\%\%[^\n]* /* skip comments */{ /*console.log('Crap after close');*/ }

[\n]+ return 'NL';
[\s]+ /* skip all whitespace */
<ID,STATE,struct,LINE,open_directive,type_directive,arg_directive,close_directive>((?!\n)\s)+ /* skip same-line whitespace */
<INITIAL,ID,STATE,struct,LINE,open_directive,type_directive,arg_directive,close_directive>\#[^\n]* /* skip comments */
\%%[^\n]* /* skip comments */

"scale"\s+ { this.pushState('SCALE'); /* console.log('Got scale', yytext);*/ return 'scale'; }
<SCALE>\d+ return 'WIDTH';
<SCALE>\s+"width" {this.popState();}

<INITIAL,struct>"state"\s+ { console.log('Starting STATE');this.pushState('STATE'); }
<INITIAL,struct>"state"\s+ { /*console.log('Starting STATE zxzx'+yy.getDirection());*/this.pushState('STATE'); }
<STATE>.*"<<fork>>" {this.popState();yytext=yytext.slice(0,-8).trim(); /*console.warn('Fork Fork: ',yytext);*/return 'FORK';}
<STATE>.*"<<join>>" {this.popState();yytext=yytext.slice(0,-8).trim();/*console.warn('Fork Join: ',yytext);*/return 'JOIN';}
<STATE>.*"<<choice>>" {this.popState();yytext=yytext.slice(0,-10).trim();/*console.warn('Fork Join: ',yytext);*/return 'CHOICE';}
<STATE>.*"[[fork]]" {this.popState();yytext=yytext.slice(0,-8).trim();/*console.warn('Fork Fork: ',yytext);*/return 'FORK';}
<STATE>.*"[[join]]" {this.popState();yytext=yytext.slice(0,-8).trim();/*console.warn('Fork Join: ',yytext);*/return 'JOIN';}
<STATE>.*"[[choice]]" {this.popState();yytext=yytext.slice(0,-10).trim();/*console.warn('Fork Join: ',yytext);*/return 'CHOICE';}
<STATE>["] { console.log('Starting STATE_STRING');this.begin("STATE_STRING");}
<struct>.*direction\s+TB[^\n]* { return 'direction_tb';}
<struct>.*direction\s+BT[^\n]* { return 'direction_bt';}
<struct>.*direction\s+RL[^\n]* { return 'direction_rl';}
<struct>.*direction\s+LR[^\n]* { return 'direction_lr';}

<STATE>["] { /*console.log('Starting STATE_STRING zxzx');*/this.begin("STATE_STRING");}
<STATE>\s*"as"\s+ {this.popState();this.pushState('STATE_ID');return "AS";}
<STATE_ID>[^\n\{]* {this.popState();/* console.log('STATE_ID', yytext);*/return "ID";}
<STATE_STRING>["] this.popState();
<STATE_STRING>[^"]* { console.log('Long description:', yytext);return "STATE_DESCR";}
<STATE_STRING>[^"]* { /*console.log('Long description:', yytext);*/return "STATE_DESCR";}
<STATE>[^\n\s\{]+ {/*console.log('COMPOSIT_STATE', yytext);*/return 'COMPOSIT_STATE';}
<STATE>\n {this.popState();}
<INITIAL,STATE>\{ {this.popState();this.pushState('struct'); /*console.log('begin struct', yytext);*/return 'STRUCT_START';}
Expand Down Expand Up @@ -144,7 +154,6 @@ statement
| COMPOSIT_STATE
| COMPOSIT_STATE STRUCT_START document STRUCT_STOP
{
/* console.warn('Adding document for state without id ', $1);*/
$$={ stmt: 'state', id: $1, type: 'default', description: '', doc: $3 }
}
Expand All @@ -161,7 +170,7 @@ statement
}
| STATE_DESCR AS ID STRUCT_START document STRUCT_STOP
{
//console.warn('Adding document for state with id ', $3, $4); yy.addDocument($3);
// console.warn('Adding document for state with id zxzx', $3, $4, yy.getDirection()); yy.addDocument($3);
$$={ stmt: 'state', id: $3, type: 'default', description: $1, doc: $5 }
}
| FORK {
Expand All @@ -178,17 +187,28 @@ statement
}
| note notePosition ID NOTE_TEXT
{
/*console.warn('got NOTE, position: ', $2.trim(), 'id = ', $3.trim(), 'note: ', $4);*/
/* console.warn('got NOTE, position: ', $2.trim(), 'id = ', $3.trim(), 'note: ', $4);*/
$$={ stmt: 'state', id: $3.trim(), note:{position: $2.trim(), text: $4.trim()}};
}
| note NOTE_TEXT AS ID
| directive
| direction
;

directive
: openDirective typeDirective closeDirective
| openDirective typeDirective ':' argDirective closeDirective
;
direction
: direction_tb
{ yy.setDirection('TB');$$={stmt:'dir', value:'TB'};}
| direction_bt
{ yy.setDirection('BT');$$={stmt:'dir', value:'BT'};}
| direction_rl
{ yy.setDirection('RL'); $$={stmt:'dir', value:'RL'};}
| direction_lr
{ yy.setDirection('LR');$$={stmt:'dir', value:'LR'};}
;

eol
: NL
Expand Down
8 changes: 7 additions & 1 deletion src/diagrams/state/stateDb.js
Expand Up @@ -67,6 +67,7 @@ const docTranslator = (parent, node, first) => {
const getRootDocV2 = () => {
docTranslator({ id: 'root' }, { id: 'root', doc: rootDoc }, true);
return { id: 'root', doc: rootDoc };
// Here
};

const extract = _doc => {
Expand Down Expand Up @@ -230,7 +231,11 @@ let classes = [];

const getClasses = () => classes;

const getDirection = () => 'TB';
let direction = 'TB';
const getDirection = () => direction;
const setDirection = dir => {
direction = dir;
};

export const relationType = {
AGGREGATION: 0,
Expand All @@ -253,6 +258,7 @@ export default {
getDirection,
addRelation,
getDividerId,
setDirection,
// addDescription,
cleanupLabel,
lineType,
Expand Down
27 changes: 20 additions & 7 deletions src/diagrams/state/stateRenderer-v2.js
Expand Up @@ -84,8 +84,9 @@ const setupNode = (g, parent, node, altFlag) => {

// group
if (!nodeDb[node.id].type && node.doc) {
log.info('Setting cluser for ', node.id);
log.info('Setting cluster for ', node.id, getDir(node));
nodeDb[node.id].type = 'group';
nodeDb[node.id].dir = getDir(node);
nodeDb[node.id].shape = node.type === 'divider' ? 'divider' : 'roundedWithTitle';
nodeDb[node.id].classes =
nodeDb[node.id].classes +
Expand All @@ -103,7 +104,7 @@ const setupNode = (g, parent, node, altFlag) => {
classes: nodeDb[node.id].classes, //classStr,
style: '', //styles.style,
id: node.id,
dir: altFlag ? 'LR' : 'TB',
dir: nodeDb[node.id].dir,
domId: 'state-' + node.id + '-' + cnt,
type: nodeDb[node.id].type,
padding: 15 //getConfig().flowchart.padding
Expand Down Expand Up @@ -208,7 +209,18 @@ const setupDoc = (g, parent, doc, altFlag) => {
}
});
};

const getDir = (nodes, defaultDir) => {
let dir = defaultDir || 'TB';
if (nodes.doc) {
for (let i = 0; i < nodes.doc.length; i++) {
const node = nodes.doc[i];
if (node.stmt === 'dir') {
dir = node.value;
}
}
}
return dir;
};
/**
* Draws a flowchart in the tag with id: id based on the graph definition in text.
* @param text
Expand All @@ -234,13 +246,17 @@ export const draw = function(text, id) {
const nodeSpacing = conf.nodeSpacing || 50;
const rankSpacing = conf.rankSpacing || 50;

log.info(stateDb.getRootDocV2());
stateDb.extract(stateDb.getRootDocV2());
log.info(stateDb.getRootDocV2());

// Create the input mermaid.graph
const g = new graphlib.Graph({
multigraph: true,
compound: true
})
.setGraph({
rankdir: 'TB',
rankdir: getDir(stateDb.getRootDocV2()),
nodesep: nodeSpacing,
ranksep: rankSpacing,
marginx: 8,
Expand All @@ -250,9 +266,6 @@ export const draw = function(text, id) {
return {};
});

log.info(stateDb.getRootDocV2());
stateDb.extract(stateDb.getRootDocV2());
log.info(stateDb.getRootDocV2());
setupNode(g, undefined, stateDb.getRootDocV2(), true);

// Set up an SVG group so that we can translate the final graph.
Expand Down

0 comments on commit a66633c

Please sign in to comment.