mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-14 06:43:25 +08:00
Merge branch 'master' into bug/1110_state_diagram_rendering_composit_state
This commit is contained in:
commit
c337c9128c
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal 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']
|
@ -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,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -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,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -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',
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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)));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user