flowchart LR
- A{{A}}-->B{{B}};
+ A{{A}}-- apa -->B{{B}};
click A callback "Tooltip"
click B "http://www.github.com" "This is a link"
-flowchart LR
- A{{A}}-->B{{B}};
+
+graph LR
+ A{{A}}--apa-->B{{B}};
@@ -264,7 +255,7 @@ stateDiagram-v2
// arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0,
- flowchart: { curve: 'linear', "htmlLabels": false },
+ flowchart: { curve: 'linear', "htmlLabels": true },
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50, showSequenceNumbers: true },
// sequenceDiagram: { actorMargin: 300 } // deprecated
diff --git a/src/dagre-wrapper/clusters.js b/src/dagre-wrapper/clusters.js
index ac13f484d..db3aee001 100644
--- a/src/dagre-wrapper/clusters.js
+++ b/src/dagre-wrapper/clusters.js
@@ -1,6 +1,8 @@
import intersectRect from './intersect/intersect-rect';
import { logger as log } from '../logger'; // eslint-disable-line
import createLabel from './createLabel';
+import { select } from 'd3';
+import { getConfig } from '../config';
const rect = (parent, node) => {
log.trace('Creating subgraph rect for ', node.id, node);
@@ -17,10 +19,20 @@ const rect = (parent, node) => {
// Create the label and insert it after the rect
const label = shapeSvg.insert('g').attr('class', 'cluster-label');
- const text = label.node().appendChild(createLabel(node.labelText, node.labelStyle));
+ const text = label
+ .node()
+ .appendChild(createLabel(node.labelText, node.labelStyle, undefined, true));
// Get the size of the label
- const bbox = text.getBBox();
+ let bbox = text.getBBox();
+
+ if (getConfig().flowchart.htmlLabels) {
+ const div = text.children[0];
+ const dv = select(text);
+ bbox = div.getBoundingClientRect();
+ dv.attr('width', bbox.width);
+ dv.attr('height', bbox.height);
+ }
const padding = 0 * node.padding;
const halfPadding = padding / 2;
@@ -106,11 +118,20 @@ const roundedWithTitle = (parent, node) => {
const label = shapeSvg.insert('g').attr('class', 'cluster-label');
const innerRect = shapeSvg.append('rect');
- const text = label.node().appendChild(createLabel(node.labelText, node.labelStyle));
+ const text = label
+ .node()
+ .appendChild(createLabel(node.labelText, node.labelStyle, undefined, true));
// Get the size of the label
- const bbox = text.getBBox();
-
+ let bbox = text.getBBox();
+ if (getConfig().flowchart.htmlLabels) {
+ const div = text.children[0];
+ const dv = select(text);
+ bbox = div.getBoundingClientRect();
+ dv.attr('width', bbox.width);
+ dv.attr('height', bbox.height);
+ }
+ bbox = text.getBBox();
const padding = 0 * node.padding;
const halfPadding = padding / 2;
@@ -134,7 +155,7 @@ const roundedWithTitle = (parent, node) => {
'translate(' +
(node.x - bbox.width / 2) +
', ' +
- (node.y - node.height / 2 - node.padding / 3 + 3) +
+ (node.y - node.height / 2 - node.padding / 3 + (getConfig().flowchart.htmlLabels ? 5 : 3)) +
')'
);
@@ -191,7 +212,7 @@ export const insertCluster = (elem, node) => {
clusterElems[node.id] = shapes[shape](elem, node);
};
export const getClusterTitleWidth = (elem, node) => {
- const label = createLabel(node.labelText, node.labelStyle);
+ const label = createLabel(node.labelText, node.labelStyle, undefined, true);
elem.node().appendChild(label);
const width = label.getBBox().width;
elem.node().removeChild(label);
diff --git a/src/dagre-wrapper/createLabel.js b/src/dagre-wrapper/createLabel.js
index 4c430b9f9..055f6cfb5 100644
--- a/src/dagre-wrapper/createLabel.js
+++ b/src/dagre-wrapper/createLabel.js
@@ -1,29 +1,123 @@
-const createLabel = (vertexText, style, isTitle) => {
- const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text');
- svgLabel.setAttribute('style', style.replace('color:', 'fill:'));
- let rows = [];
- if (typeof vertexText === 'string') {
- rows = vertexText.split(/\\n|\n|
/gi);
- } else if (Array.isArray(vertexText)) {
- rows = vertexText;
- } else {
- rows = [];
- }
+import { select } from 'd3';
+import { logger } from '../logger'; // eslint-disable-line
+// let vertexNode;
+// if (getConfig().flowchart.htmlLabels) {
+// // TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
+// const node = {
+// label: vertexText.replace(/fa[lrsb]?:fa-[\w-]+/g, s => ``)
+// };
+// vertexNode = addHtmlLabel(svg, node).node();
+// vertexNode.parentNode.removeChild(vertexNode);
+// } else {
+// const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text');
+// svgLabel.setAttribute('style', styles.labelStyle.replace('color:', 'fill:'));
- for (let j = 0; j < rows.length; j++) {
- const tspan = document.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', '0');
- if (isTitle) {
- tspan.setAttribute('class', 'title-row');
- } else {
- tspan.setAttribute('class', 'row');
- }
- tspan.textContent = rows[j].trim();
- svgLabel.appendChild(tspan);
+// const rows = vertexText.split(common.lineBreakRegex);
+
+// for (let j = 0; j < rows.length; j++) {
+// const tspan = document.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 = rows[j];
+// svgLabel.appendChild(tspan);
+// }
+// vertexNode = svgLabel;
+// }
+import { getConfig } from '../config';
+
+function applyStyle(dom, styleFn) {
+ if (styleFn) {
+ dom.attr('style', styleFn);
+ }
+}
+
+function addHtmlLabel(node) {
+ // var fo = root.append('foreignObject').attr('width', '100000');
+
+ // var div = fo.append('xhtml:div');
+ // div.attr('xmlns', 'http://www.w3.org/1999/xhtml');
+
+ // var label = node.label;
+ // switch (typeof label) {
+ // case 'function':
+ // div.insert(label);
+ // break;
+ // case 'object':
+ // // Currently we assume this is a DOM object.
+ // div.insert(function() {
+ // return label;
+ // });
+ // break;
+ // default:
+ // div.html(label);
+ // }
+
+ // applyStyle(div, node.labelStyle);
+ // div.style('display', 'inline-block');
+ // // Fix for firefox
+ // div.style('white-space', 'nowrap');
+
+ // var client = div.node().getBoundingClientRect();
+ // fo.attr('width', client.width).attr('height', client.height);
+ const fo = select(document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject'));
+ const div = fo.append('xhtml:div');
+
+ const label = node.label;
+ const labelClass = node.isNode ? 'nodeLabel' : 'edgeLabel';
+ div.html('' + label + '');
+
+ applyStyle(div, node.labelStyle);
+ div.style('display', 'inline-block');
+ // Fix for firefox
+ div.style('white-space', 'nowrap');
+ div.attr('xmlns', 'http://www.w3.org/1999/xhtml');
+ return fo.node();
+}
+
+const createLabel = (_vertexText, style, isTitle, isNode) => {
+ let vertexText = _vertexText || '';
+ if (getConfig().flowchart.htmlLabels) {
+ // TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
+ vertexText = vertexText.replace(/\\n|\n/g, '
');
+ logger.info('vertexText' + vertexText);
+ const node = {
+ isNode,
+ label: vertexText.replace(
+ /fa[lrsb]?:fa-[\w-]+/g,
+ s => ``
+ )
+ };
+ let vertexNode = addHtmlLabel(node);
+ // vertexNode.parentNode.removeChild(vertexNode);
+ return vertexNode;
+ } else {
+ const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text');
+ svgLabel.setAttribute('style', style.replace('color:', 'fill:'));
+ let rows = [];
+ if (typeof vertexText === 'string') {
+ rows = vertexText.split(/\\n|\n|
/gi);
+ } else if (Array.isArray(vertexText)) {
+ rows = vertexText;
+ } else {
+ rows = [];
+ }
+
+ for (let j = 0; j < rows.length; j++) {
+ const tspan = document.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', '0');
+ if (isTitle) {
+ tspan.setAttribute('class', 'title-row');
+ } else {
+ tspan.setAttribute('class', 'row');
+ }
+ tspan.textContent = rows[j].trim();
+ svgLabel.appendChild(tspan);
+ }
+ return svgLabel;
}
- return svgLabel;
};
export default createLabel;
diff --git a/src/dagre-wrapper/edges.js b/src/dagre-wrapper/edges.js
index d3db26372..a53f035ac 100644
--- a/src/dagre-wrapper/edges.js
+++ b/src/dagre-wrapper/edges.js
@@ -1,6 +1,6 @@
import { logger } from '../logger'; // eslint-disable-line
import createLabel from './createLabel';
-import { line, curveBasis } from 'd3';
+import { line, curveBasis, select } from 'd3';
import { getConfig } from '../config';
let edgeLabels = {};
@@ -21,7 +21,14 @@ export const insertEdgeLabel = (elem, edge) => {
label.node().appendChild(labelElement);
// Center the label
- const bbox = labelElement.getBBox();
+ let bbox = labelElement.getBBox();
+ if (getConfig().flowchart.htmlLabels) {
+ const div = labelElement.children[0];
+ const dv = select(labelElement);
+ bbox = div.getBoundingClientRect();
+ dv.attr('width', bbox.width);
+ dv.attr('height', bbox.height);
+ }
label.attr('transform', 'translate(' + -bbox.width / 2 + ', ' + -bbox.height / 2 + ')');
// Make element accessible by id for positioning
diff --git a/src/dagre-wrapper/nodes.js b/src/dagre-wrapper/nodes.js
index c66f02be9..309c505cb 100644
--- a/src/dagre-wrapper/nodes.js
+++ b/src/dagre-wrapper/nodes.js
@@ -2,11 +2,12 @@ import intersect from './intersect/index.js';
import { select } from 'd3';
import { logger } from '../logger'; // eslint-disable-line
import { labelHelper, updateNodeBounds, insertPolygonShape } from './shapes/util';
+import { getConfig } from '../config';
import createLabel from './createLabel';
import note from './shapes/note';
const question = (parent, node) => {
- const { shapeSvg, bbox } = labelHelper(parent, node);
+ const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const w = bbox.width + node.padding;
const h = bbox.height + node.padding;
@@ -28,7 +29,7 @@ const question = (parent, node) => {
};
const hexagon = (parent, node) => {
- const { shapeSvg, bbox } = labelHelper(parent, node);
+ const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const f = 4;
const h = bbox.height + node.padding;
@@ -53,7 +54,7 @@ const hexagon = (parent, node) => {
};
const rect_left_inv_arrow = (parent, node) => {
- const { shapeSvg, bbox } = labelHelper(parent, node);
+ const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const w = bbox.width + node.padding;
const h = bbox.height + node.padding;
@@ -75,7 +76,7 @@ const rect_left_inv_arrow = (parent, node) => {
return shapeSvg;
};
const lean_right = (parent, node) => {
- const { shapeSvg, bbox } = labelHelper(parent, node);
+ const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const w = bbox.width + node.padding;
const h = bbox.height + node.padding;
@@ -97,7 +98,7 @@ const lean_right = (parent, node) => {
};
const lean_left = (parent, node) => {
- const { shapeSvg, bbox } = labelHelper(parent, node);
+ const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const w = bbox.width + node.padding;
const h = bbox.height + node.padding;
@@ -119,7 +120,7 @@ const lean_left = (parent, node) => {
};
const trapezoid = (parent, node) => {
- const { shapeSvg, bbox } = labelHelper(parent, node);
+ const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const w = bbox.width + node.padding;
const h = bbox.height + node.padding;
@@ -140,7 +141,7 @@ const trapezoid = (parent, node) => {
};
const inv_trapezoid = (parent, node) => {
- const { shapeSvg, bbox } = labelHelper(parent, node);
+ const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const w = bbox.width + node.padding;
const h = bbox.height + node.padding;
@@ -160,7 +161,7 @@ const inv_trapezoid = (parent, node) => {
return shapeSvg;
};
const rect_right_inv_arrow = (parent, node) => {
- const { shapeSvg, bbox } = labelHelper(parent, node);
+ const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const w = bbox.width + node.padding;
const h = bbox.height + node.padding;
@@ -181,7 +182,7 @@ const rect_right_inv_arrow = (parent, node) => {
return shapeSvg;
};
const cylinder = (parent, node) => {
- const { shapeSvg, bbox } = labelHelper(parent, node);
+ const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const w = bbox.width + node.padding;
const rx = w / 2;
@@ -248,7 +249,7 @@ const cylinder = (parent, node) => {
};
const rect = (parent, node) => {
- const { shapeSvg, bbox, halfPadding } = labelHelper(parent, node, 'node ' + node.classes);
+ const { shapeSvg, bbox, halfPadding } = labelHelper(parent, node, 'node ' + node.classes, true);
logger.trace('Classes = ', node.classes);
// add the rect
@@ -296,20 +297,54 @@ const rectWithTitle = (parent, node) => {
const text2 = node.labelText.flat();
logger.info('Label text', text2[0]);
- const text = label.node().appendChild(createLabel(text2[0], node.labelStyle, true));
+ const text = label.node().appendChild(createLabel(text2[0], node.labelStyle, true, true));
+ let bbox;
+ if (getConfig().flowchart.htmlLabels) {
+ const div = text.children[0];
+ const dv = select(text);
+ bbox = div.getBoundingClientRect();
+ dv.attr('width', bbox.width);
+ dv.attr('height', bbox.height);
+ }
+ logger.info('Text 2', text2);
const textRows = text2.slice(1, text2.length);
let titleBox = text.getBBox();
const descr = label
.node()
- .appendChild(createLabel(textRows.join('
'), node.labelStyle, true));
+ .appendChild(createLabel(textRows.join('
'), node.labelStyle, true, true));
- logger.info(descr);
+ if (getConfig().flowchart.htmlLabels) {
+ const div = descr.children[0];
+ const dv = select(descr);
+ bbox = div.getBoundingClientRect();
+ dv.attr('width', bbox.width);
+ dv.attr('height', bbox.height);
+ }
+ // bbox = label.getBBox();
+ // logger.info(descr);
const halfPadding = node.padding / 2;
- select(descr).attr('transform', 'translate( 0' + ', ' + (titleBox.height + halfPadding) + ')');
+ select(descr).attr(
+ 'transform',
+ 'translate( ' +
+ // (titleBox.width - bbox.width) / 2 +
+ (bbox.width > titleBox.width ? 0 : (titleBox.width - bbox.width) / 2) +
+ ', ' +
+ (titleBox.height + halfPadding + 5) +
+ ')'
+ );
+ select(text).attr(
+ 'transform',
+ 'translate( ' +
+ // (titleBox.width - bbox.width) / 2 +
+ (bbox.width < titleBox.width ? 0 : -(titleBox.width - bbox.width) / 2) +
+ ', ' +
+ 0 +
+ ')'
+ );
// Get the size of the label
// Bounding box for title and text
- const bbox = label.node().getBBox();
+ bbox = label.node().getBBox();
// Center the label
label.attr(
@@ -341,7 +376,7 @@ const rectWithTitle = (parent, node) => {
};
const stadium = (parent, node) => {
- const { shapeSvg, bbox } = labelHelper(parent, node);
+ const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const h = bbox.height + node.padding;
const w = bbox.width + h / 4 + node.padding;
@@ -365,7 +400,7 @@ const stadium = (parent, node) => {
return shapeSvg;
};
const circle = (parent, node) => {
- const { shapeSvg, bbox, halfPadding } = labelHelper(parent, node);
+ const { shapeSvg, bbox, halfPadding } = labelHelper(parent, node, undefined, true);
const circle = shapeSvg.insert('circle', ':first-child');
// center the circle around its coordinate
@@ -386,7 +421,7 @@ const circle = (parent, node) => {
};
const subroutine = (parent, node) => {
- const { shapeSvg, bbox } = labelHelper(parent, node);
+ const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
const w = bbox.width + node.padding;
const h = bbox.height + node.padding;
diff --git a/src/dagre-wrapper/shapes/note.js b/src/dagre-wrapper/shapes/note.js
index 34bb4356d..1fcfc1237 100644
--- a/src/dagre-wrapper/shapes/note.js
+++ b/src/dagre-wrapper/shapes/note.js
@@ -3,7 +3,7 @@ import { logger } from '../../logger'; // eslint-disable-line
import intersect from '../intersect/index.js';
const note = (parent, node) => {
- const { shapeSvg, bbox, halfPadding } = labelHelper(parent, node, 'node ' + node.classes);
+ const { shapeSvg, bbox, halfPadding } = labelHelper(parent, node, 'node ' + node.classes, true);
logger.info('Classes = ', node.classes);
// add the rect
diff --git a/src/dagre-wrapper/shapes/util.js b/src/dagre-wrapper/shapes/util.js
index cf7ff123f..0d4055554 100644
--- a/src/dagre-wrapper/shapes/util.js
+++ b/src/dagre-wrapper/shapes/util.js
@@ -1,6 +1,7 @@
import createLabel from '../createLabel';
-
-export const labelHelper = (parent, node, _classes) => {
+import { getConfig } from '../../config';
+import { select } from 'd3';
+export const labelHelper = (parent, node, _classes, isNode) => {
let classes;
if (!_classes) {
classes = 'node default';
@@ -16,10 +17,20 @@ export const labelHelper = (parent, node, _classes) => {
// Create the label and insert it after the rect
const label = shapeSvg.insert('g').attr('class', 'label');
- const text = label.node().appendChild(createLabel(node.labelText, node.labelStyle));
+ const text = label
+ .node()
+ .appendChild(createLabel(node.labelText, node.labelStyle, false, isNode));
// Get the size of the label
- const bbox = text.getBBox();
+ let bbox = text.getBBox();
+
+ if (getConfig().flowchart.htmlLabels) {
+ const div = text.children[0];
+ const dv = select(text);
+ bbox = div.getBoundingClientRect();
+ dv.attr('width', bbox.width);
+ dv.attr('height', bbox.height);
+ }
const halfPadding = node.padding / 2;
diff --git a/src/diagrams/state/stateDb.js b/src/diagrams/state/stateDb.js
index b5609bd40..aec95f7c4 100644
--- a/src/diagrams/state/stateDb.js
+++ b/src/diagrams/state/stateDb.js
@@ -148,6 +148,12 @@ export const clear = function() {
root: newDoc()
};
currentDocument = documents.root;
+
+ currentDocument = documents.root;
+
+ startCnt = 0;
+ endCnt = 0; // eslint-disable-line
+ classes = [];
};
export const getState = function(id) {
@@ -213,7 +219,7 @@ const getDividerId = () => {
return 'divider-id-' + dividerCnt;
};
-const classes = [];
+let classes = [];
const getClasses = () => classes;
diff --git a/src/diagrams/state/stateRenderer-v2.js b/src/diagrams/state/stateRenderer-v2.js
index a5f26bd17..a58bfcc60 100644
--- a/src/diagrams/state/stateRenderer-v2.js
+++ b/src/diagrams/state/stateRenderer-v2.js
@@ -15,7 +15,7 @@ export const setConf = function(cnf) {
}
};
-const nodeDb = {};
+let nodeDb = {};
/**
* Returns the all the styles from classDef statements in the graph definition.
@@ -203,6 +203,7 @@ const setupDoc = (g, parent, doc, altFlag) => {
export const draw = function(text, id) {
logger.info('Drawing state diagram (v2)', id);
stateDb.clear();
+ nodeDb = {};
const parser = state.parser;
parser.yy = stateDb;