Merge pull request #4268 from Valentine14th/bug/4023-image-rendering

fix: image rendering in nodes
This commit is contained in:
Justin Greywolf 2023-04-10 10:09:40 -07:00 committed by GitHub
commit 727bf30824
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 351 additions and 289 deletions

View File

@ -685,6 +685,16 @@ A ~~~ B
{ titleTopMargin: 0 }
);
});
it('4023: Should render html labels with images and-or text correctly', () => {
imgSnapshotTest(
`flowchart TD
B[<img src='https://mermaid.js.org/mermaid-logo.svg'>]
B-->C[<img src="https://mermaid.js.org/mermaid-logo.svg"> more text <img src='https://mermaid.js.org/mermaid-logo.svg'>]
B-->D(<img src='https://mermaid.js.org/mermaid-logo.svg'> some text)
B-->E(plain)`,
{}
);
});
describe('Markdown strings flowchart (#4220)', () => {
describe('html labels', () => {
it('With styling and classes', () => {

View File

@ -96,7 +96,7 @@ mermaid.initialize(config);
#### Defined in
[mermaidAPI.ts:667](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L667)
[mermaidAPI.ts:673](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L673)
## Functions

View File

@ -14,7 +14,7 @@ import { insertCluster, clear as clearClusters } from './clusters';
import { insertEdgeLabel, positionEdgeLabel, insertEdge, clear as clearEdges } from './edges';
import { log } from '../logger';
const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
const recursiveRender = async (_elem, graph, diagramtype, parentCluster) => {
log.info('Graph in recursive render: XXX', graphlibJson.write(graph), parentCluster);
const dir = graph.graph().rankdir;
log.trace('Dir in recursive render - dir:', dir);
@ -35,44 +35,46 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
// Insert nodes, this will insert them into the dom and each node will get a size. The size is updated
// to the abstract node and is later used by dagre for the layout
graph.nodes().forEach(function (v) {
const node = graph.node(v);
if (parentCluster !== undefined) {
const data = JSON.parse(JSON.stringify(parentCluster.clusterData));
// data.clusterPositioning = true;
log.info('Setting data for cluster XXX (', v, ') ', data, parentCluster);
graph.setNode(parentCluster.id, data);
if (!graph.parent(v)) {
log.trace('Setting parent', v, parentCluster.id);
graph.setParent(v, parentCluster.id, data);
await Promise.all(
graph.nodes().map(async function (v) {
const node = graph.node(v);
if (parentCluster !== undefined) {
const data = JSON.parse(JSON.stringify(parentCluster.clusterData));
// data.clusterPositioning = true;
log.info('Setting data for cluster XXX (', v, ') ', data, parentCluster);
graph.setNode(parentCluster.id, data);
if (!graph.parent(v)) {
log.trace('Setting parent', v, parentCluster.id);
graph.setParent(v, parentCluster.id, data);
}
}
}
log.info('(Insert) Node XXX' + v + ': ' + JSON.stringify(graph.node(v)));
if (node && node.clusterNode) {
// const children = graph.children(v);
log.info('Cluster identified', v, node.width, graph.node(v));
const o = recursiveRender(nodes, node.graph, diagramtype, graph.node(v));
const newEl = o.elem;
updateNodeBounds(node, newEl);
node.diff = o.diff || 0;
log.info('Node bounds (abc123)', v, node, node.width, node.x, node.y);
setNodeElem(newEl, node);
log.info('(Insert) Node XXX' + v + ': ' + JSON.stringify(graph.node(v)));
if (node && node.clusterNode) {
// const children = graph.children(v);
log.info('Cluster identified', v, node.width, graph.node(v));
const o = await recursiveRender(nodes, node.graph, diagramtype, graph.node(v));
const newEl = o.elem;
updateNodeBounds(node, newEl);
node.diff = o.diff || 0;
log.info('Node bounds (abc123)', v, node, node.width, node.x, node.y);
setNodeElem(newEl, node);
log.warn('Recursive render complete ', newEl, node);
} else {
if (graph.children(v).length > 0) {
// This is a cluster but not to be rendered recursively
// Render as before
log.info('Cluster - the non recursive path XXX', v, node.id, node, graph);
log.info(findNonClusterChild(node.id, graph));
clusterDb[node.id] = { id: findNonClusterChild(node.id, graph), node };
// insertCluster(clusters, graph.node(v));
log.warn('Recursive render complete ', newEl, node);
} else {
log.info('Node - the non recursive path', v, node.id, node);
insertNode(nodes, graph.node(v), dir);
if (graph.children(v).length > 0) {
// This is a cluster but not to be rendered recursively
// Render as before
log.info('Cluster - the non recursive path XXX', v, node.id, node, graph);
log.info(findNonClusterChild(node.id, graph));
clusterDb[node.id] = { id: findNonClusterChild(node.id, graph), node };
// insertCluster(clusters, graph.node(v));
} else {
log.info('Node - the non recursive path', v, node.id, node);
await insertNode(nodes, graph.node(v), dir);
}
}
}
});
})
);
// Insert labels, this will insert them into the dom so that the width can be calculated
// Also figure out which edges point to/from clusters and adjust them accordingly
@ -146,7 +148,7 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
return { elem, diff };
};
export const render = (elem, graph, markers, diagramtype, id) => {
export const render = async (elem, graph, markers, diagramtype, id) => {
insertMarkers(elem, markers, diagramtype, id);
clearNodes();
clearEdges();
@ -157,7 +159,7 @@ export const render = (elem, graph, markers, diagramtype, id) => {
adjustClustersAndEdges(graph);
log.warn('Graph after:', graphlibJson.write(graph));
// log.warn('Graph ever after:', graphlibJson.write(graph.node('A').graph));
recursiveRender(elem, graph, diagramtype);
await recursiveRender(elem, graph, diagramtype);
};
// const shapeDefinitions = {};

View File

@ -8,8 +8,8 @@ import note from './shapes/note';
import { parseMember } from '../diagrams/class/svgDraw';
import { evaluate } from '../diagrams/common/common';
const question = (parent, node) => {
const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const question = async (parent, node) => {
const { shapeSvg, bbox } = await labelHelper(parent, node, undefined, true);
const w = bbox.width + node.padding;
const h = bbox.height + node.padding;
@ -69,8 +69,8 @@ const choice = (parent, node) => {
return shapeSvg;
};
const hexagon = (parent, node) => {
const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const hexagon = async (parent, node) => {
const { shapeSvg, bbox } = await labelHelper(parent, node, undefined, true);
const f = 4;
const h = bbox.height + node.padding;
@ -96,8 +96,8 @@ const hexagon = (parent, node) => {
return shapeSvg;
};
const rect_left_inv_arrow = (parent, node) => {
const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const rect_left_inv_arrow = async (parent, node) => {
const { shapeSvg, bbox } = await labelHelper(parent, node, undefined, true);
const w = bbox.width + node.padding;
const h = bbox.height + node.padding;
@ -122,8 +122,8 @@ const rect_left_inv_arrow = (parent, node) => {
return shapeSvg;
};
const lean_right = (parent, node) => {
const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const lean_right = async (parent, node) => {
const { shapeSvg, bbox } = await labelHelper(parent, node, undefined, true);
const w = bbox.width + node.padding;
const h = bbox.height + node.padding;
@ -145,8 +145,8 @@ const lean_right = (parent, node) => {
return shapeSvg;
};
const lean_left = (parent, node) => {
const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const lean_left = async (parent, node) => {
const { shapeSvg, bbox } = await labelHelper(parent, node, undefined, true);
const w = bbox.width + node.padding;
const h = bbox.height + node.padding;
@ -168,8 +168,8 @@ const lean_left = (parent, node) => {
return shapeSvg;
};
const trapezoid = (parent, node) => {
const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const trapezoid = async (parent, node) => {
const { shapeSvg, bbox } = await labelHelper(parent, node, undefined, true);
const w = bbox.width + node.padding;
const h = bbox.height + node.padding;
@ -191,8 +191,8 @@ const trapezoid = (parent, node) => {
return shapeSvg;
};
const inv_trapezoid = (parent, node) => {
const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const inv_trapezoid = async (parent, node) => {
const { shapeSvg, bbox } = await labelHelper(parent, node, undefined, true);
const w = bbox.width + node.padding;
const h = bbox.height + node.padding;
@ -214,8 +214,8 @@ const inv_trapezoid = (parent, node) => {
return shapeSvg;
};
const rect_right_inv_arrow = (parent, node) => {
const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const rect_right_inv_arrow = async (parent, node) => {
const { shapeSvg, bbox } = await labelHelper(parent, node, undefined, true);
const w = bbox.width + node.padding;
const h = bbox.height + node.padding;
@ -238,8 +238,8 @@ const rect_right_inv_arrow = (parent, node) => {
return shapeSvg;
};
const cylinder = (parent, node) => {
const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const cylinder = async (parent, node) => {
const { shapeSvg, bbox } = await labelHelper(parent, node, undefined, true);
const w = bbox.width + node.padding;
const rx = w / 2;
@ -310,8 +310,13 @@ const cylinder = (parent, node) => {
return shapeSvg;
};
const rect = (parent, node) => {
const { shapeSvg, bbox, halfPadding } = labelHelper(parent, node, 'node ' + node.classes, true);
const rect = async (parent, node) => {
const { shapeSvg, bbox, halfPadding } = await labelHelper(
parent,
node,
'node ' + node.classes,
true
);
// add the rect
const rect = shapeSvg.insert('rect', ':first-child');
@ -352,8 +357,8 @@ const rect = (parent, node) => {
return shapeSvg;
};
const labelRect = (parent, node) => {
const { shapeSvg } = labelHelper(parent, node, 'label', true);
const labelRect = async (parent, node) => {
const { shapeSvg } = await labelHelper(parent, node, 'label', true);
log.trace('Classes = ', node.classes);
// add the rect
@ -539,8 +544,8 @@ const rectWithTitle = (parent, node) => {
return shapeSvg;
};
const stadium = (parent, node) => {
const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const stadium = async (parent, node) => {
const { shapeSvg, bbox } = await labelHelper(parent, node, undefined, true);
const h = bbox.height + node.padding;
const w = bbox.width + h / 4 + node.padding;
@ -565,8 +570,8 @@ const stadium = (parent, node) => {
return shapeSvg;
};
const circle = (parent, node) => {
const { shapeSvg, bbox, halfPadding } = labelHelper(parent, node, undefined, true);
const circle = async (parent, node) => {
const { shapeSvg, bbox, halfPadding } = await labelHelper(parent, node, undefined, true);
const circle = shapeSvg.insert('circle', ':first-child');
// center the circle around its coordinate
@ -590,8 +595,8 @@ const circle = (parent, node) => {
return shapeSvg;
};
const doublecircle = (parent, node) => {
const { shapeSvg, bbox, halfPadding } = labelHelper(parent, node, undefined, true);
const doublecircle = async (parent, node) => {
const { shapeSvg, bbox, halfPadding } = await labelHelper(parent, node, undefined, true);
const gap = 5;
const circleGroup = shapeSvg.insert('g', ':first-child');
const outerCircle = circleGroup.insert('circle');
@ -626,8 +631,8 @@ const doublecircle = (parent, node) => {
return shapeSvg;
};
const subroutine = (parent, node) => {
const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const subroutine = async (parent, node) => {
const { shapeSvg, bbox } = await labelHelper(parent, node, undefined, true);
const w = bbox.width + node.padding;
const h = bbox.height + node.padding;
@ -976,7 +981,7 @@ const shapes = {
let nodeElems = {};
export const insertNode = (elem, node, dir) => {
export const insertNode = async (elem, node, dir) => {
let newEl;
let el;
@ -989,9 +994,9 @@ export const insertNode = (elem, node, dir) => {
target = node.linkTarget || '_blank';
}
newEl = elem.insert('svg:a').attr('xlink:href', node.link).attr('target', target);
el = shapes[node.shape](newEl, node, dir);
el = await shapes[node.shape](newEl, node, dir);
} else {
el = shapes[node.shape](elem, node, dir);
el = await shapes[node.shape](elem, node, dir);
newEl = el;
}
if (node.tooltip) {
@ -1017,6 +1022,7 @@ export const clear = () => {
export const positionNode = (node) => {
const el = nodeElems[node.id];
log.trace(
'Transforming node',
node.diff,

View File

@ -3,12 +3,17 @@ import { log } from '../../logger';
import { getConfig } from '../../config';
import intersect from '../intersect/index.js';
const note = (parent, node) => {
const note = async (parent, node) => {
const useHtmlLabels = node.useHtmlLabels || getConfig().flowchart.htmlLabels;
if (!useHtmlLabels) {
node.centerLabel = true;
}
const { shapeSvg, bbox, halfPadding } = labelHelper(parent, node, 'node ' + node.classes, true);
const { shapeSvg, bbox, halfPadding } = await labelHelper(
parent,
node,
'node ' + node.classes,
true
);
log.info('Classes = ', node.classes);
// add the rect

View File

@ -4,7 +4,8 @@ import { getConfig } from '../../config';
import { decodeEntities } from '../../mermaidAPI';
import { select } from 'd3';
import { evaluate, sanitizeText } from '../../diagrams/common/common';
export const labelHelper = (parent, node, _classes, isNode) => {
export const labelHelper = async (parent, node, _classes, isNode) => {
let classes;
const useHtmlLabels = node.useHtmlLabels || evaluate(getConfig().flowchart.htmlLabels);
if (!_classes) {
@ -51,17 +52,47 @@ export const labelHelper = (parent, node, _classes, isNode) => {
// Get the size of the label
let bbox = text.getBBox();
const halfPadding = node.padding / 2;
if (evaluate(getConfig().flowchart.htmlLabels)) {
const div = text.children[0];
const dv = select(text);
// if there are images, need to wait for them to load before getting the bounding box
const images = div.getElementsByTagName('img');
if (images) {
const noImgText = labelText.replace(/<img[^>]*>/g, '').trim() === '';
await Promise.all(
[...images].map(
(img) =>
new Promise((res) =>
img.addEventListener('load', function () {
img.style.display = 'flex';
img.style.flexDirection = 'column';
if (noImgText) {
// default size if no text
const bodyFontSize = getConfig().fontSize
? getConfig().fontSize
: window.getComputedStyle(document.body).fontSize;
const enlargingFactor = 5;
img.style.width = parseInt(bodyFontSize, 10) * enlargingFactor + 'px';
} else {
img.style.width = '100%';
}
res(img);
})
)
)
);
}
bbox = div.getBoundingClientRect();
dv.attr('width', bbox.width);
dv.attr('height', bbox.height);
}
const halfPadding = node.padding / 2;
// Center the label
if (useHtmlLabels) {
label.attr('transform', 'translate(' + -bbox.width / 2 + ', ' + -bbox.height / 2 + ')');

View File

@ -248,7 +248,7 @@ export const setConf = function (cnf: any) {
* @param _version -
* @param diagObj -
*/
export const draw = function (text: string, id: string, _version: string, diagObj: any) {
export const draw = async function (text: string, id: string, _version: string, diagObj: any) {
log.info('Drawing class - ', id);
// TODO V10: Why flowchart? Might be a mistake when copying.
@ -300,7 +300,7 @@ export const draw = function (text: string, id: string, _version: string, diagOb
// Run the renderer. This is what draws the final graph.
// @ts-ignore Ignore type error for now
const element = root.select('#' + id + ' g');
render(
await render(
element,
g,
['aggregation', 'extension', 'composition', 'dependency', 'lollipop'],

View File

@ -35,229 +35,231 @@ let nodeDb = {};
// * @param doc
// * @param diagObj
// */
export const addVertices = function (vert, svgId, root, doc, diagObj, parentLookupDb, graph) {
export const addVertices = async function (vert, svgId, root, doc, diagObj, parentLookupDb, graph) {
const svg = root.select(`[id="${svgId}"]`);
const nodes = svg.insert('g').attr('class', 'nodes');
const keys = Object.keys(vert);
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
keys.forEach(function (id) {
const vertex = vert[id];
await Promise.all(
keys.map(async function (id) {
const vertex = vert[id];
/**
* Variable for storing the classes for the vertex
*
* @type {string}
*/
let classStr = 'default';
if (vertex.classes.length > 0) {
classStr = vertex.classes.join(' ');
}
classStr = classStr + ' flowchart-label';
const styles = getStylesFromArray(vertex.styles);
/**
* Variable for storing the classes for the vertex
*
* @type {string}
*/
let classStr = 'default';
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
let vertexText = vertex.text !== undefined ? vertex.text : vertex.id;
// Use vertex id as text in the box if no text is provided by the graph definition
let vertexText = vertex.text !== undefined ? vertex.text : vertex.id;
// We create a SVG label, either by delegating to addHtmlLabel or manually
let vertexNode;
const labelData = { width: 0, height: 0 };
// We create a SVG label, either by delegating to addHtmlLabel or manually
let vertexNode;
const labelData = { width: 0, height: 0 };
const ports = [
{
id: vertex.id + '-west',
layoutOptions: {
'port.side': 'WEST',
const ports = [
{
id: vertex.id + '-west',
layoutOptions: {
'port.side': 'WEST',
},
},
},
{
id: vertex.id + '-east',
layoutOptions: {
'port.side': 'EAST',
{
id: vertex.id + '-east',
layoutOptions: {
'port.side': 'EAST',
},
},
},
{
id: vertex.id + '-south',
layoutOptions: {
'port.side': 'SOUTH',
{
id: vertex.id + '-south',
layoutOptions: {
'port.side': 'SOUTH',
},
},
},
{
id: vertex.id + '-north',
layoutOptions: {
'port.side': 'NORTH',
{
id: vertex.id + '-north',
layoutOptions: {
'port.side': 'NORTH',
},
},
},
];
];
let radious = 0;
let _shape = '';
let layoutOptions = {};
// Set the shape based parameters
switch (vertex.type) {
case 'round':
radious = 5;
_shape = 'rect';
break;
case 'square':
_shape = 'rect';
break;
case 'diamond':
_shape = 'question';
layoutOptions = {
portConstraints: 'FIXED_SIDE',
};
break;
case 'hexagon':
_shape = 'hexagon';
break;
case 'odd':
_shape = 'rect_left_inv_arrow';
break;
case 'lean_right':
_shape = 'lean_right';
break;
case 'lean_left':
_shape = 'lean_left';
break;
case 'trapezoid':
_shape = 'trapezoid';
break;
case 'inv_trapezoid':
_shape = 'inv_trapezoid';
break;
case 'odd_right':
_shape = 'rect_left_inv_arrow';
break;
case 'circle':
_shape = 'circle';
break;
case 'ellipse':
_shape = 'ellipse';
break;
case 'stadium':
_shape = 'stadium';
break;
case 'subroutine':
_shape = 'subroutine';
break;
case 'cylinder':
_shape = 'cylinder';
break;
case 'group':
_shape = 'rect';
break;
case 'doublecircle':
_shape = 'doublecircle';
break;
default:
_shape = 'rect';
}
let radious = 0;
let _shape = '';
let layoutOptions = {};
// Set the shape based parameters
switch (vertex.type) {
case 'round':
radious = 5;
_shape = 'rect';
break;
case 'square':
_shape = 'rect';
break;
case 'diamond':
_shape = 'question';
layoutOptions = {
portConstraints: 'FIXED_SIDE',
};
break;
case 'hexagon':
_shape = 'hexagon';
break;
case 'odd':
_shape = 'rect_left_inv_arrow';
break;
case 'lean_right':
_shape = 'lean_right';
break;
case 'lean_left':
_shape = 'lean_left';
break;
case 'trapezoid':
_shape = 'trapezoid';
break;
case 'inv_trapezoid':
_shape = 'inv_trapezoid';
break;
case 'odd_right':
_shape = 'rect_left_inv_arrow';
break;
case 'circle':
_shape = 'circle';
break;
case 'ellipse':
_shape = 'ellipse';
break;
case 'stadium':
_shape = 'stadium';
break;
case 'subroutine':
_shape = 'subroutine';
break;
case 'cylinder':
_shape = 'cylinder';
break;
case 'group':
_shape = 'rect';
break;
case 'doublecircle':
_shape = 'doublecircle';
break;
default:
_shape = 'rect';
}
// Add the node
const node = {
labelStyle: styles.labelStyle,
shape: _shape,
labelText: vertexText,
labelType: vertex.labelType,
rx: radious,
ry: radious,
class: classStr,
style: styles.style,
id: vertex.id,
link: vertex.link,
linkTarget: vertex.linkTarget,
tooltip: diagObj.db.getTooltip(vertex.id) || '',
domId: diagObj.db.lookUpDomId(vertex.id),
haveCallback: vertex.haveCallback,
width: vertex.type === 'group' ? 500 : undefined,
dir: vertex.dir,
type: vertex.type,
props: vertex.props,
padding: getConfig().flowchart.padding,
};
let boundingBox;
let nodeEl;
// Add the node
const node = {
labelStyle: styles.labelStyle,
shape: _shape,
labelText: vertexText,
labelType: vertex.labelType,
rx: radious,
ry: radious,
class: classStr,
style: styles.style,
id: vertex.id,
link: vertex.link,
linkTarget: vertex.linkTarget,
tooltip: diagObj.db.getTooltip(vertex.id) || '',
domId: diagObj.db.lookUpDomId(vertex.id),
haveCallback: vertex.haveCallback,
width: vertex.type === 'group' ? 500 : undefined,
dir: vertex.dir,
type: vertex.type,
props: vertex.props,
padding: getConfig().flowchart.padding,
};
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);
// 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 } = await 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 } = await labelHelper(svg, node, undefined, true);
const data = {
id: vertex.id,
ports: vertex.type === 'diamond' ? ports : [],
// labelStyle: styles.labelStyle,
// shape: _shape,
layoutOptions,
labelText: vertexText,
labelData,
// labels: [{ text: vertexText }],
// rx: radius,
// ry: radius,
// class: classStr,
// style: styles.style,
// link: vertex.link,
// linkTarget: vertex.linkTarget,
// tooltip: diagObj.db.getTooltip(vertex.id) || '',
domId: diagObj.db.lookUpDomId(vertex.id),
// haveCallback: vertex.haveCallback,
width: boundingBox?.width,
height: boundingBox?.height,
// dir: vertex.dir,
type: vertex.type,
// props: vertex.props,
// padding: getConfig().flowchart.padding,
// boundingBox,
el: nodeEl,
parent: parentLookupDb.parentById[vertex.id],
};
// if (!Object.keys(parentLookupDb.childrenById).includes(vertex.id)) {
// graph.children.push({
// ...data,
// });
// }
// 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,
ports: vertex.type === 'diamond' ? ports : [],
// labelStyle: styles.labelStyle,
// shape: _shape,
layoutOptions,
labelText: vertexText,
labelData,
// labels: [{ text: vertexText }],
// rx: radius,
// ry: radius,
// class: classStr,
// style: styles.style,
// link: vertex.link,
// linkTarget: vertex.linkTarget,
// tooltip: diagObj.db.getTooltip(vertex.id) || '',
domId: diagObj.db.lookUpDomId(vertex.id),
// haveCallback: vertex.haveCallback,
width: boundingBox?.width,
height: boundingBox?.height,
// dir: vertex.dir,
type: vertex.type,
// props: vertex.props,
// padding: getConfig().flowchart.padding,
// boundingBox,
el: nodeEl,
parent: parentLookupDb.parentById[vertex.id],
};
// if (!Object.keys(parentLookupDb.childrenById).includes(vertex.id)) {
// graph.children.push({
// ...data,
// });
// }
nodeDb[node.id] = data;
// log.trace('setNode', {
// labelStyle: styles.labelStyle,
// shape: _shape,
// labelText: vertexText,
// rx: radius,
// ry: radius,
// class: classStr,
// style: styles.style,
// id: vertex.id,
// domId: diagObj.db.lookUpDomId(vertex.id),
// width: vertex.type === 'group' ? 500 : undefined,
// type: vertex.type,
// dir: vertex.dir,
// props: vertex.props,
// padding: getConfig().flowchart.padding,
// parent: parentLookupDb.parentById[vertex.id],
// });
});
nodeDb[node.id] = data;
// log.trace('setNode', {
// labelStyle: styles.labelStyle,
// shape: _shape,
// labelText: vertexText,
// rx: radius,
// ry: radius,
// class: classStr,
// style: styles.style,
// id: vertex.id,
// domId: diagObj.db.lookUpDomId(vertex.id),
// width: vertex.type === 'group' ? 500 : undefined,
// type: vertex.type,
// dir: vertex.dir,
// props: vertex.props,
// padding: getConfig().flowchart.padding,
// parent: parentLookupDb.parentById[vertex.id],
// });
})
);
return graph;
};
@ -861,7 +863,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, svg);
graph = await addVertices(vert, id, root, doc, diagObj, parentLookupDb, graph);
// 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');

View File

@ -362,7 +362,7 @@ export const getClasses = function (text, diagObj) {
* @param id
*/
export const draw = function (text, id, _version, diagObj) {
export const draw = async function (text, id, _version, diagObj) {
log.info('Drawing flowchart');
diagObj.db.clear();
flowDb.setGen('gen-2');
@ -451,7 +451,7 @@ export const draw = function (text, id, _version, diagObj) {
// Run the renderer. This is what draws the final graph.
const element = root.select('#' + id + ' g');
render(element, g, ['point', 'circle', 'cross'], 'flowchart', id);
await render(element, g, ['point', 'circle', 'cross'], 'flowchart', id);
utils.insertTitle(svg, 'flowchartTitleText', conf.titleTopMargin, diagObj.db.getDiagramTitle());

View File

@ -382,7 +382,7 @@ const getDir = (parsedItem, defaultDir = DEFAULT_NESTED_DOC_DIR) => {
* @param _version
* @param diag
*/
export const draw = function (text, id, _version, diag) {
export const draw = async function (text, id, _version, diag) {
log.info('Drawing state diagram (v2)', id);
// diag.sb.clear();
nodeDb = {};
@ -436,7 +436,7 @@ export const draw = function (text, id, _version, diag) {
// Run the renderer. This is what draws the final graph.
const element = root.select('#' + id + ' g');
render(element, g, ['barb'], CSS_DIAGRAM, id);
await render(element, g, ['barb'], CSS_DIAGRAM, id);
const padding = 8;

View File

@ -406,6 +406,12 @@ const render = async function (
// clean up text CRLFs
text = text.replace(/\r\n?/g, '\n'); // parser problems on CRLF ignore all CR and leave LF;;
// clean up html tags so that all attributes use single quotes, parser throws error on double quotes
text = text.replace(
/<(\w+)([^>]*)>/g,
(match, tag, attributes) => '<' + tag + attributes.replace(/="([^"]*)"/g, "='$1'") + '>'
);
const idSelector = '#' + id;
const iFrameID = 'i' + id;
const iFrameID_selector = '#' + iFrameID;