mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-11-04 21:04:12 +01:00
Adding support for markdown string in flowchart-elk
This commit is contained in:
@@ -57,11 +57,11 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
<pre id="diagram" class="mermaid">
|
||||
%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%
|
||||
%%
|
||||
graph BT
|
||||
a("`The **cat** in the hat} -- 1o --> b
|
||||
graph LR
|
||||
a{"`The **cat** in the hat`"} -- 1o --> b
|
||||
a -- 2o --> c
|
||||
a -- 3o --> d
|
||||
g --2i--> a
|
||||
@@ -69,39 +69,52 @@ d --1i--> a
|
||||
h --3i -->a
|
||||
b --> d(The dog in the hog)
|
||||
c --> d
|
||||
%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%
|
||||
</pre>
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid">
|
||||
%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%
|
||||
flowchart LR
|
||||
b("`The dog in **the** hog... a a a a *very long text* about it
|
||||
b("`The dog in **the** hog.(1)
|
||||
NL`") --"`1o **bold**`"--> c
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid">
|
||||
flowchart-elk LR
|
||||
b("`The dog in **the** hog.(1)
|
||||
NL`") --"`1o **bold**`"--> c
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid">
|
||||
flowchart-elk LR
|
||||
b("`The dog in **the** hog.(1).. a a a a *very long text* about it
|
||||
Word!
|
||||
|
||||
Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. `")
|
||||
Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. `") --> c
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid">
|
||||
%%{init: {"flowchart": {"htmlLabels": true}} }%%
|
||||
flowchart LR
|
||||
b("`The dog in **the** hog... a a a a *very long text* about it
|
||||
flowchart-elk LR
|
||||
b("`The dog in **the** hog(2)... a a a a *very long text* about it
|
||||
Word!
|
||||
Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. `")
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid">
|
||||
%%{init: {"flowchart": {"htmlLabels": false}} }%%
|
||||
flowchart LR
|
||||
flowchart-elk LR
|
||||
b("The dog in the hog... a very<br/>long text about it<br/>Word!")
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
%%{init: {"flowchart": {"htmlLabels": true}} }%%
|
||||
flowchart LR
|
||||
flowchart-elk LR
|
||||
b("The dog in the hog... a very<br/>long text about it<br/>Word!")
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
flowchart LR
|
||||
flowchart-elk LR
|
||||
subgraph "One"
|
||||
a("`The **cat**
|
||||
in the hat`") -- 1o --> b{{"`The **dog** in the hog`"}}
|
||||
in the hat`") -- "1o" --> b{{"`The **dog** in the hog`"}}
|
||||
end
|
||||
subgraph "`**Two**`"
|
||||
c("`The **cat**
|
||||
@@ -129,7 +142,7 @@ mindmap
|
||||
id2["`The dog in **the** hog... a *very long text* about it
|
||||
Word!`"]
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
<pre id="diagram" class="mermaid">
|
||||
%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%
|
||||
flowchart TB
|
||||
%% I could not figure out how to use double quotes in labels in Mermaid
|
||||
@@ -185,7 +198,7 @@ flowchart TB
|
||||
</pre
|
||||
>
|
||||
<br />
|
||||
<pre id="diagram" class="mermaid2">
|
||||
<pre id="diagram" class="mermaid">
|
||||
flowchart TB
|
||||
%% I could not figure out how to use double quotes in labels in Mermaid
|
||||
subgraph ibm[IBM Espresso CPU]
|
||||
@@ -241,7 +254,7 @@ flowchart TB
|
||||
>
|
||||
<br />
|
||||
|
||||
<pre id="diagram" class="mermaid2">
|
||||
<pre id="diagram" class="mermaid">
|
||||
flowchart LR
|
||||
B1 --be be--x B2
|
||||
B1 --bo bo--o B3
|
||||
@@ -274,7 +287,7 @@ flowchart TB
|
||||
B6 --> B5
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
<pre id="diagram" class="mermaid">
|
||||
sequenceDiagram
|
||||
Customer->>+Stripe: Makes a payment request
|
||||
Stripe->>+Bank: Forwards the payment request to the bank
|
||||
@@ -287,7 +300,7 @@ sequenceDiagram
|
||||
Customer->>+Merchant: Receives goods or services
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
<pre id="diagram" class="mermaid">
|
||||
mindmap
|
||||
root((mindmap))
|
||||
Origins
|
||||
@@ -307,7 +320,7 @@ mindmap
|
||||
Mermaid
|
||||
</pre>
|
||||
<br />
|
||||
<pre id="diagram" class="mermaid2">
|
||||
<pre id="diagram" class="mermaid">
|
||||
example-diagram
|
||||
</pre>
|
||||
|
||||
@@ -332,8 +345,8 @@ mindmap
|
||||
flowchart: {
|
||||
// defaultRenderer: 'elk',
|
||||
useMaxWidth: false,
|
||||
// htmlLabels: false,
|
||||
htmlLabels: false,
|
||||
// htmlLabels: true,
|
||||
},
|
||||
htmlLabels: false,
|
||||
gantt: {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[defaultConfig.ts:2093](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L2093)
|
||||
[defaultConfig.ts:2105](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L2105)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@ export class Diagram {
|
||||
// calls diagram.db.clear(), which would reset anything set by
|
||||
// extractFrontMatter().
|
||||
this.parser.parse = (text: string) => originalParse(extractFrontMatter(text, this.db));
|
||||
|
||||
// this.parser.parse = (text: string) => {
|
||||
// console.log('parse called');
|
||||
// try {
|
||||
|
||||
@@ -385,6 +385,7 @@ export interface FlowchartDiagramConfig extends BaseDiagramConfig {
|
||||
curve?: string;
|
||||
padding?: number;
|
||||
defaultRenderer?: string;
|
||||
wrappingWidth?: number;
|
||||
}
|
||||
|
||||
export interface FontConfig {
|
||||
|
||||
@@ -19,7 +19,11 @@ export const insertEdgeLabel = (elem, edge) => {
|
||||
// Create the actual text element
|
||||
const labelElement =
|
||||
edge.labelType === 'markdown'
|
||||
? createText(elem, edge.label, { style: edge.labelStyle, useHtmlLabels })
|
||||
? createText(elem, edge.label, {
|
||||
style: edge.labelStyle,
|
||||
useHtmlLabels,
|
||||
addSvgBackground: true,
|
||||
})
|
||||
: createLabel(edge.label, edge.labelStyle);
|
||||
log.info('abc82', edge, edge.labelType);
|
||||
|
||||
|
||||
@@ -997,6 +997,7 @@ export const insertNode = (elem, node, dir) => {
|
||||
el.attr('class', 'node default ' + node.class);
|
||||
}
|
||||
|
||||
/* MC: 7e790808-9c49-4f74-93de-15c22872377f */
|
||||
nodeElems[node.id] = newEl;
|
||||
|
||||
if (node.haveCallback) {
|
||||
|
||||
@@ -34,7 +34,7 @@ export const labelHelper = (parent, node, _classes, isNode) => {
|
||||
// text = textNode;
|
||||
text = createText(label, sanitizeText(decodeEntities(labelText), getConfig()), {
|
||||
useHtmlLabels: getConfig().flowchart.htmlLabels,
|
||||
width: node.width || 200,
|
||||
width: node.width || getConfig().flowchart.wrappingWidth,
|
||||
classes: 'markdown-node-label',
|
||||
});
|
||||
} else {
|
||||
@@ -67,7 +67,7 @@ export const labelHelper = (parent, node, _classes, isNode) => {
|
||||
} else {
|
||||
label.attr('transform', 'translate(' + 0 + ', ' + -bbox.height / 2 + ')');
|
||||
}
|
||||
|
||||
label.insert('rect', ':first-child');
|
||||
return { shapeSvg, bbox, halfPadding, label };
|
||||
};
|
||||
|
||||
|
||||
@@ -258,6 +258,18 @@ const config: Partial<MermaidConfig> = {
|
||||
* Default value: 'dagre-wrapper'
|
||||
*/
|
||||
defaultRenderer: 'dagre-wrapper',
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | --------------- | ----------- | ------- | -------- | ----------------------- |
|
||||
* | wrappingWidth | See notes | number | 4 | width of nodes where text is wrapped |
|
||||
*
|
||||
* **Notes:**
|
||||
*
|
||||
* When using markdown strings the text ius wrapped automatically, this
|
||||
* value sets the max width of a text before it continues on a new line.
|
||||
* Default value: 'dagre-wrapper'
|
||||
*/
|
||||
wrappingWidth: 200,
|
||||
},
|
||||
|
||||
/** The object containing configurations specific for sequence diagrams */
|
||||
|
||||
@@ -3,6 +3,7 @@ import { insertNode } from '../../../dagre-wrapper/nodes.js';
|
||||
import insertMarkers from '../../../dagre-wrapper/markers.js';
|
||||
import { insertEdgeLabel } from '../../../dagre-wrapper/edges.js';
|
||||
import { findCommonAncestor } from './render-utils';
|
||||
import { labelHelper } from '../../../dagre-wrapper/shapes/util';
|
||||
import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js';
|
||||
import { getConfig } from '../../../config';
|
||||
import { log } from '../../../logger';
|
||||
@@ -52,7 +53,7 @@ export const addVertices = function (vert, svgId, root, doc, diagObj, parentLook
|
||||
if (vertex.classes.length > 0) {
|
||||
classStr = vertex.classes.join(' ');
|
||||
}
|
||||
|
||||
classStr = classStr + ' flowchart-label';
|
||||
const styles = getStylesFromArray(vertex.styles);
|
||||
|
||||
// Use vertex id as text in the box if no text is provided by the graph definition
|
||||
@@ -61,40 +62,6 @@ export const addVertices = function (vert, svgId, root, doc, diagObj, parentLook
|
||||
// We create a SVG label, either by delegating to addHtmlLabel or manually
|
||||
let vertexNode;
|
||||
const labelData = { width: 0, height: 0 };
|
||||
if (evaluate(getConfig().flowchart.htmlLabels)) {
|
||||
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
||||
const node = {
|
||||
label: vertexText.replace(
|
||||
/fa[blrs]?:fa-[\w-]+/g,
|
||||
(s) => `<i class='${s.replace(':', ' ')}'></i>`
|
||||
),
|
||||
};
|
||||
vertexNode = addHtmlLabel(svg, node).node();
|
||||
const bbox = vertexNode.getBBox();
|
||||
labelData.width = bbox.width;
|
||||
labelData.height = bbox.height;
|
||||
labelData.labelNode = vertexNode;
|
||||
vertexNode.parentNode.removeChild(vertexNode);
|
||||
} else {
|
||||
const svgLabel = doc.createElementNS('http://www.w3.org/2000/svg', 'text');
|
||||
svgLabel.setAttribute('style', styles.labelStyle.replace('color:', 'fill:'));
|
||||
|
||||
const rows = vertexText.split(common.lineBreakRegex);
|
||||
|
||||
for (const row of rows) {
|
||||
const tspan = doc.createElementNS('http://www.w3.org/2000/svg', 'tspan');
|
||||
tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
|
||||
tspan.setAttribute('dy', '1em');
|
||||
tspan.setAttribute('x', '1');
|
||||
tspan.textContent = row;
|
||||
svgLabel.appendChild(tspan);
|
||||
}
|
||||
vertexNode = svgLabel;
|
||||
const bbox = vertexNode.getBBox();
|
||||
labelData.width = bbox.width;
|
||||
labelData.height = bbox.height;
|
||||
labelData.labelNode = vertexNode;
|
||||
}
|
||||
|
||||
const ports = [
|
||||
{
|
||||
@@ -186,11 +153,13 @@ export const addVertices = function (vert, svgId, root, doc, diagObj, parentLook
|
||||
default:
|
||||
_shape = 'rect';
|
||||
}
|
||||
|
||||
// Add the node
|
||||
const node = {
|
||||
labelStyle: styles.labelStyle,
|
||||
shape: _shape,
|
||||
labelText: vertexText,
|
||||
labelType: vertex.labelType,
|
||||
rx: radious,
|
||||
ry: radious,
|
||||
class: classStr,
|
||||
@@ -209,10 +178,33 @@ export const addVertices = function (vert, svgId, root, doc, diagObj, parentLook
|
||||
};
|
||||
let boundingBox;
|
||||
let nodeEl;
|
||||
|
||||
// Add the element to the DOM
|
||||
if (node.type !== 'group') {
|
||||
nodeEl = insertNode(nodes, node, vertex.dir);
|
||||
boundingBox = nodeEl.node().getBBox();
|
||||
} else {
|
||||
const svgLabel = doc.createElementNS('http://www.w3.org/2000/svg', 'text');
|
||||
// svgLabel.setAttribute('style', styles.labelStyle.replace('color:', 'fill:'));
|
||||
// const rows = vertexText.split(common.lineBreakRegex);
|
||||
// for (const row of rows) {
|
||||
// const tspan = doc.createElementNS('http://www.w3.org/2000/svg', 'tspan');
|
||||
// tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
|
||||
// tspan.setAttribute('dy', '1em');
|
||||
// tspan.setAttribute('x', '1');
|
||||
// tspan.textContent = row;
|
||||
// svgLabel.appendChild(tspan);
|
||||
// }
|
||||
// vertexNode = svgLabel;
|
||||
// const bbox = vertexNode.getBBox();
|
||||
const { shapeSvg, bbox } = labelHelper(nodes, node, undefined, true);
|
||||
labelData.width = bbox.width;
|
||||
labelData.wrappingWidth = getConfig().flowchart.wrappingWidth;
|
||||
labelData.height = bbox.height;
|
||||
labelData.labelNode = shapeSvg.node();
|
||||
node.labelData = labelData;
|
||||
}
|
||||
// const { shapeSvg, bbox } = labelHelper(svg, node, undefined, true);
|
||||
|
||||
const data = {
|
||||
id: vertex.id,
|
||||
@@ -520,7 +512,7 @@ export const addEdges = function (edges, diagObj, graph, svg) {
|
||||
edgeData.labelpos = 'c';
|
||||
}
|
||||
|
||||
edgeData.labelType = 'text';
|
||||
edgeData.labelType = edge.labelType;
|
||||
edgeData.label = edge.text.replace(common.lineBreakRegex, '\n');
|
||||
|
||||
if (edge.style === undefined) {
|
||||
@@ -845,9 +837,17 @@ export const draw = async function (text, id, _version, diagObj) {
|
||||
log.info('Subgraphs - ', subGraphs);
|
||||
for (let i = subGraphs.length - 1; i >= 0; i--) {
|
||||
subG = subGraphs[i];
|
||||
diagObj.db.addVertex(subG.id, subG.title, 'group', undefined, subG.classes, subG.dir);
|
||||
diagObj.db.addVertex(
|
||||
subG.id,
|
||||
{ text: subG.title, type: subG.labelType },
|
||||
'group',
|
||||
undefined,
|
||||
subG.classes,
|
||||
subG.dir
|
||||
);
|
||||
}
|
||||
|
||||
// debugger;
|
||||
// Add an element in the svg to be used to hold the subgraphs container
|
||||
// elements
|
||||
const subGraphsEl = svg.insert('g').attr('class', 'subgraphs');
|
||||
@@ -860,7 +860,7 @@ export const draw = async function (text, id, _version, diagObj) {
|
||||
// in order to get the size of the node. You can't get the size of a node
|
||||
// that is not in the dom so we need to add it to the dom, get the size
|
||||
// we will position the nodes when we get the layout from elkjs
|
||||
graph = addVertices(vert, id, root, doc, diagObj, parentLookupDb, graph);
|
||||
graph = addVertices(vert, id, root, doc, diagObj, parentLookupDb, graph, svg);
|
||||
|
||||
// Time for the edges, we start with adding an element in the node to hold the edges
|
||||
const edgesEl = svg.insert('g').attr('class', 'edges edgePath');
|
||||
@@ -887,6 +887,8 @@ export const draw = async function (text, id, _version, diagObj) {
|
||||
},
|
||||
width: node.labelData.width,
|
||||
height: node.labelData.height,
|
||||
// width: 100,
|
||||
// height: 100,
|
||||
},
|
||||
];
|
||||
delete node.x;
|
||||
@@ -895,6 +897,7 @@ export const draw = async function (text, id, _version, diagObj) {
|
||||
delete node.height;
|
||||
}
|
||||
});
|
||||
|
||||
insertChildren(graph.children, parentLookupDb);
|
||||
log.info('after layout', JSON.stringify(graph, null, 2));
|
||||
const g = await elk.layout(graph);
|
||||
|
||||
@@ -81,7 +81,7 @@ const getStyles = (options: FlowChartStyleOptions) =>
|
||||
.edgeLabel {
|
||||
background-color: ${options.edgeLabelBackground};
|
||||
rect {
|
||||
opacity: 0.5;
|
||||
opacity: 0.85;
|
||||
background-color: ${options.edgeLabelBackground};
|
||||
fill: ${options.edgeLabelBackground};
|
||||
}
|
||||
@@ -132,6 +132,11 @@ const getStyles = (options: FlowChartStyleOptions) =>
|
||||
// fill:#ccc;
|
||||
// // stroke:black;
|
||||
// }
|
||||
|
||||
.flowchart-label text {
|
||||
text-anchor: middle;
|
||||
}
|
||||
|
||||
${genSections(options)}
|
||||
`;
|
||||
|
||||
|
||||
@@ -143,6 +143,7 @@ export const addSingleLink = function (_start, _end, type) {
|
||||
// log.info('Got edge...', start, end);
|
||||
|
||||
const edge = { start: start, end: end, type: undefined, text: '', labelType: 'text' };
|
||||
log.info('abc78 Got edge...', edge);
|
||||
const linkTextObj = type.text;
|
||||
|
||||
if (linkTextObj !== undefined) {
|
||||
@@ -163,6 +164,7 @@ export const addSingleLink = function (_start, _end, type) {
|
||||
edges.push(edge);
|
||||
};
|
||||
export const addLink = function (_start, _end, type) {
|
||||
log.info('addLink (abc78)', _start, _end, type);
|
||||
let i, j;
|
||||
for (i = 0; i < _start.length; i++) {
|
||||
for (j = 0; j < _end.length; j++) {
|
||||
|
||||
@@ -440,7 +440,7 @@ arrowText:
|
||||
text: textToken
|
||||
{ $$={text:$1, type: 'text'};}
|
||||
| text textToken
|
||||
{$$={text:$1.text+''+$2, type: 'text'};}
|
||||
{ $$={text:$1.text+''+$2, type: $1.type};}
|
||||
| STR
|
||||
{ $$={text: $1, type: 'text'};}
|
||||
| MD_STR
|
||||
|
||||
@@ -83,11 +83,13 @@ function createTspan(textElement, lineIndex, lineHeight) {
|
||||
* @param {number} width - The maximum allowed width of the text.
|
||||
* @param {object} g - The parent group element to append the formatted text.
|
||||
* @param {Array} structuredText - The structured text data to format.
|
||||
* @param addBackground
|
||||
*/
|
||||
function createFormattedText(width, g, structuredText) {
|
||||
function createFormattedText(width, g, structuredText, addBackground = false) {
|
||||
const lineHeight = 1.1;
|
||||
|
||||
const textElement = g.append('text').attr('y', '-10.1');
|
||||
const labelGroup = g.append('g');
|
||||
let bkg = labelGroup.insert('rect').attr('class', 'background');
|
||||
const textElement = labelGroup.append('text').attr('y', '-10.1');
|
||||
// .attr('dominant-baseline', 'middle')
|
||||
// .attr('text-anchor', 'middle');
|
||||
// .attr('text-anchor', 'middle');
|
||||
@@ -118,8 +120,20 @@ function createFormattedText(width, g, structuredText) {
|
||||
}
|
||||
}
|
||||
});
|
||||
if (addBackground) {
|
||||
const bbox = textElement.node().getBBox();
|
||||
const padding = 2;
|
||||
bkg
|
||||
.attr('x', -padding)
|
||||
.attr('y', -padding)
|
||||
.attr('width', bbox.width + 2 * padding)
|
||||
.attr('height', bbox.height + 2 * padding);
|
||||
// .style('fill', 'red');
|
||||
|
||||
return labelGroup.node();
|
||||
} else {
|
||||
return textElement.node();
|
||||
// return g.node();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -183,9 +197,17 @@ function updateTextContentAndStyles(tspan, wrappedLine) {
|
||||
export const createText = (
|
||||
el,
|
||||
text = '',
|
||||
{ style = '', isTitle = false, classes = '', useHtmlLabels = true, isNode = true, width } = {}
|
||||
{
|
||||
style = '',
|
||||
isTitle = false,
|
||||
classes = '',
|
||||
useHtmlLabels = true,
|
||||
isNode = true,
|
||||
width,
|
||||
addSvgBackground = false,
|
||||
} = {}
|
||||
) => {
|
||||
log.info('createText', text, style, isTitle, classes, useHtmlLabels, isNode);
|
||||
log.info('createText', text, style, isTitle, classes, useHtmlLabels, isNode, addSvgBackground);
|
||||
if (useHtmlLabels) {
|
||||
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
||||
// text = text.replace(/\\n|\n/g, '<br />');
|
||||
@@ -203,6 +225,8 @@ export const createText = (
|
||||
return vertexNode;
|
||||
} else {
|
||||
const structuredText = markdownToLines(text);
|
||||
return createFormattedText(width, el, structuredText);
|
||||
|
||||
const svgLabel = createFormattedText(width, el, structuredText, addSvgBackground);
|
||||
return svgLabel;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user