Merge branch 'master' into bug/1110_state_diagram_rendering_composit_state

This commit is contained in:
Knut Sveidqvist 2019-12-03 21:04:18 +01:00
commit c337c9128c
6 changed files with 208 additions and 58 deletions

12
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,12 @@
# These are supported funding model platforms
github: [knsv]
#patreon: # Replace with a single Patreon username
#open_collective: # Replace with a single Open Collective username
#ko_fi: # Replace with a single Ko-fi username
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
#liberapay: # Replace with a single Liberapay username
#issuehunt: # Replace with a single IssueHunt username
#otechie: # Replace with a single Otechie username
#custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@ -2,19 +2,20 @@
import { imgSnapshotTest } from '../../helpers/util'; import { imgSnapshotTest } from '../../helpers/util';
describe('State diagram', () => { describe('State diagram', () => {
it('should render a flowchart full of circles', () => { it('should render a state with states in it', () => {
imgSnapshotTest( imgSnapshotTest(
` `
stateDiagram stateDiagram
State1: The state with a note state PersonalizedCockpit {
note right of State1 Other
Important information! You\ncan write state Parent {
notes with multiple lines... C
Here is another line... }
And another line... }
end note
`, `,
{} {
logLevel: 0,
}
); );
}); });
}); });

View File

@ -106,6 +106,22 @@ describe('State diagram', () => {
); );
cy.get('svg'); cy.get('svg');
}); });
it('should render a note with multiple lines in it', () => {
imgSnapshotTest(
`
stateDiagram
State1: The state with a note
note right of State1
Important information! You\ncan write
notes with multiple lines...
Here is another line...
And another line...
end note
`,
{}
);
});
it('should render a states with descriptions including multi-line descriptions', () => { it('should render a states with descriptions including multi-line descriptions', () => {
imgSnapshotTest( imgSnapshotTest(
` `
@ -276,4 +292,33 @@ describe('State diagram', () => {
); );
cy.get('svg'); cy.get('svg');
}); });
it('should render a state with states in it', () => {
imgSnapshotTest(
`
stateDiagram
state PilotCockpit {
state Parent {
C
}
}
`,
{
logLevel: 0,
}
);
});
it('Simplest compone state', () => {
imgSnapshotTest(
`
stateDiagram
state Parent {
C
}
`,
{
logLevel: 0,
}
);
});
}); });

View File

@ -8,12 +8,55 @@
</head> </head>
<body> <body>
<h1>info below</h1> <h1>info below</h1>
<div class="mermaid">graph TB <div style="display: flex;">
a --> b <div class="mermaid">stateDiagram
a --> c state P {
a --> d Child
}
</div>
<div class="mermaid">stateDiagram
state P {
state Par {
Child
}
}
</div>
<div class="mermaid">stateDiagram
state P {
state GPar {
state Parent {
TheLongChild
}
}
}
</div>
</div>
<div style="display: flex;">
<div class="mermaid">stateDiagram
state Parent {
C
}
</div> </div>
<script src="./mermaid.js"></script>
<div class="mermaid">stateDiagram
state PilotCockpit {
state Parent {
C
}
}
</div>
<div class="mermaid">stateDiagram
state PilotCockpit {
state GParent {
state Parent {
Child
}
}
}
</div>
</div>
<script src="./mermaid.js"></script>
<script> <script>
mermaid.initialize({ mermaid.initialize({
theme: 'forest', theme: 'forest',

View File

@ -129,71 +129,120 @@ export const drawDescrState = (g, stateDef) => {
* Adds the creates a box around the existing content and adds a * Adds the creates a box around the existing content and adds a
* panel for the id on top of the content. * panel for the id on top of the content.
*/ */
export const addIdAndBox = (g, stateDef) => { /**
// TODO Move hardcodings to conf * Function that creates an title row and a frame around a substate for a composit state diagram.
// const addTspan = function(textEl, txt, isFirst) { * The function returns a new d3 svg object with updated width and height properties;
// const tSpan = textEl * @param {*} g The d3 svg object for the substate to framed
// .append('tspan') * @param {*} stateDef The info about the
// .attr('x', 2 * getConfig().state.padding) */
// .text(txt); export const addTitleAndBox = (g, stateDef) => {
// if (!isFirst) { const pad = getConfig().state.padding;
// tSpan.attr('dy', getConfig().state.textHeight); const dblPad = 2 * getConfig().state.padding;
// } const orgBox = g.node().getBBox();
// }; const orgWidth = orgBox.width;
const orgX = orgBox.x;
const title = g const title = g
.append('text') .append('text')
.attr('x', 2 * getConfig().state.padding) .attr('x', 0)
.attr('y', getConfig().state.titleShift) .attr('y', getConfig().state.titleShift)
.attr('font-size', getConfig().state.fontSize) .attr('font-size', getConfig().state.fontSize)
.attr('class', 'state-title') .attr('class', 'state-title')
.text(stateDef.id); .text(stateDef.id);
const titleBox = title.node().getBBox(); const titleBox = title.node().getBBox();
const titleWidth = titleBox.width + dblPad;
const lineY = 1 - getConfig().state.textHeight; let width = Math.max(titleWidth, orgWidth); // + dblPad;
const descrLine = g if (width === orgWidth) {
.append('line') // text label for the x axis width = width + dblPad;
.attr('x1', 0) }
.attr('y1', lineY) let startX;
.attr('y2', lineY) // const lineY = 1 - getConfig().state.textHeight;
.attr('class', 'descr-divider'); // const descrLine = g
// .append('line') // text label for the x axis
// .attr('x1', 0)
// .attr('y1', lineY)
// .attr('y2', lineY)
// .attr('class', 'descr-divider');
const graphBox = g.node().getBBox(); const graphBox = g.node().getBBox();
title.attr('x', graphBox.width / 2 - titleBox.width / 2); // console.warn(width / 2, titleWidth / 2, getConfig().state.padding, orgBox);
descrLine.attr('x2', graphBox.width + getConfig().state.padding); // descrLine.attr('x2', graphBox.width + getConfig().state.padding);
// White color if (stateDef.doc) {
g.insert('rect', ':first-child') // console.warn(
.attr('x', graphBox.x) // stateDef.id,
.attr('y', lineY) // ' orgWidth: ',
.attr('class', 'composit') // orgWidth,
.attr('width', graphBox.width + getConfig().state.padding) // ' adjusted orgWidth: ',
.attr( // orgWidth - dblPad,
'height', // titleWidth,
graphBox.height + getConfig().state.textHeight + getConfig().state.titleShift + 1 // stateDef.doc
) // );
.attr('rx', '0'); // startX = orgX - (orgWidth - width) / 2 - pad;
// console.warn(' orgX: ', orgX, graphBox.x);
console.warn(
stateDef.id,
'orgX: ',
orgX,
'width: ',
width,
'titleWidth: ',
titleWidth,
'orgWidth: ',
orgWidth,
'width',
width
);
}
// Title background startX = orgX - pad;
if (titleWidth > orgWidth) {
startX = (orgWidth - width) / 2 + pad;
// startX = orgX + (orgWidth - titleWidth) / 2;
}
if (Math.abs(orgX - graphBox.x) < pad) {
console.warn('resetting startX', startX);
if (titleWidth > orgWidth) {
startX = orgX - (titleWidth - orgWidth) / 2;
}
}
console.warn('startX', startX);
// // White color
// g.insert('rect', ':first-child')
// .attr('x', graphBox.x)
// .attr('y', lineY)
// .attr('class', 'composit')
// .attr('width', graphBox.width + getConfig().state.padding)
// .attr(
// 'height',
// graphBox.height + getConfig().state.textHeight + getConfig().state.titleShift + 1
// )
// .attr('rx', '0');
title.attr('x', startX + pad);
if (titleWidth <= orgWidth) title.attr('x', startX + width / 2 - pad / 2);
// // Title background
g.insert('rect', ':first-child') g.insert('rect', ':first-child')
.attr('x', graphBox.x) .attr('x', startX)
.attr( .attr(
'y', 'y',
getConfig().state.titleShift - getConfig().state.textHeight - getConfig().state.padding getConfig().state.titleShift - getConfig().state.textHeight - getConfig().state.padding
) )
.attr('width', graphBox.width + getConfig().state.padding) .attr('width', width)
// Just needs to be higher then the descr line, will be clipped by the white color box // Just needs to be higher then the descr line, will be clipped by the white color box
.attr('height', getConfig().state.textHeight * 3) .attr('height', getConfig().state.textHeight * 3)
.attr('rx', getConfig().state.radius); .attr('rx', getConfig().state.radius);
// Full background // Full background
g.insert('rect', ':first-child') g.insert('rect', ':first-child')
.attr('x', graphBox.x) .attr('x', startX)
.attr( .attr(
'y', 'y',
getConfig().state.titleShift - getConfig().state.textHeight - getConfig().state.padding getConfig().state.titleShift - getConfig().state.textHeight - getConfig().state.padding
) )
.attr('width', graphBox.width + getConfig().state.padding) .attr('width', width)
.attr('height', graphBox.height + 3 + 2 * getConfig().state.textHeight) .attr('height', graphBox.height + 3 + 2 * getConfig().state.textHeight)
.attr('rx', getConfig().state.radius); .attr('rx', getConfig().state.radius);

View File

@ -5,7 +5,7 @@ import { logger } from '../../logger';
import stateDb from './stateDb'; import stateDb from './stateDb';
import { parser } from './parser/stateDiagram'; import { parser } from './parser/stateDiagram';
// import idCache from './id-cache'; // import idCache from './id-cache';
import { drawState, addIdAndBox, drawEdge } from './shapes'; import { drawState, addTitleAndBox, drawEdge } from './shapes';
import { getConfig } from '../../config'; import { getConfig } from '../../config';
parser.yy = stateDb; parser.yy = stateDb;
@ -100,7 +100,7 @@ export const draw = function(text, id) {
// diagram.attr('height', height); // diagram.attr('height', height);
// Zoom in a bit // Zoom in a bit
diagram.attr('width', width * 2); diagram.attr('width', width);
// diagram.attr('height', bounds.height * 3 + conf.padding * 2); // diagram.attr('height', bounds.height * 3 + conf.padding * 2);
diagram.attr( diagram.attr(
'viewBox', 'viewBox',
@ -189,7 +189,7 @@ const renderDoc = (doc, diagram, parentId) => {
if (first) { if (first) {
// first = false; // first = false;
sub = addIdAndBox(sub, stateDef); sub = addTitleAndBox(sub, stateDef);
let boxBounds = sub.node().getBBox(); let boxBounds = sub.node().getBBox();
node.width = boxBounds.width; node.width = boxBounds.width;
node.height = boxBounds.height + 2 * conf.padding; node.height = boxBounds.height + 2 * conf.padding;
@ -278,8 +278,8 @@ const renderDoc = (doc, diagram, parentId) => {
pShift = 0; pShift = 0;
} }
} }
divider.setAttribute('x1', 0 - pShift); divider.setAttribute('x1', 0 - pShift + 8);
divider.setAttribute('x2', pWidth - pShift); divider.setAttribute('x2', pWidth - pShift - 8);
}); });
} else { } else {
logger.debug('No Node ' + v + ': ' + JSON.stringify(graph.node(v))); logger.debug('No Node ' + v + ': ' + JSON.stringify(graph.node(v)));