diff --git a/cypress/platform/current.html b/cypress/platform/current.html
index c5c1d2486..982e12b06 100644
--- a/cypress/platform/current.html
+++ b/cypress/platform/current.html
@@ -49,20 +49,10 @@
}
- stateDiagram-v2
- state Active {
- [*] --> NumLockOff
- NumLockOff --> NumLockOn : EvNumLockPressed
- NumLockOn --> NumLockOff : EvNumLockPressed
- --
- [*] --> CapsLockOff
- CapsLockOff --> CapsLockOn : EvCapsLockPressed
- CapsLockOn --> CapsLockOff : EvCapsLockPressed
- --
- [*] --> ScrollLockOff
- ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
- ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
- }
+ stateDiagram-v2
+
+ [*] --> S1
+ state "Some long name" as S1: The description
continues
stateDiagram
diff --git a/src/dagre-wrapper/createLabel.js b/src/dagre-wrapper/createLabel.js
index 6fb944efa..5e06cbc1a 100644
--- a/src/dagre-wrapper/createLabel.js
+++ b/src/dagre-wrapper/createLabel.js
@@ -1,4 +1,4 @@
-const createLabel = (vertexText, style) => {
+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 = [];
@@ -11,6 +11,11 @@ const createLabel = (vertexText, style) => {
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);
}
diff --git a/src/dagre-wrapper/nodes.js b/src/dagre-wrapper/nodes.js
index 809f09701..ee05244ce 100644
--- a/src/dagre-wrapper/nodes.js
+++ b/src/dagre-wrapper/nodes.js
@@ -1,6 +1,8 @@
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 createLabel from './createLabel';
import note from './shapes/note';
const question = (parent, node) => {
@@ -269,6 +271,76 @@ const rect = (parent, node) => {
return shapeSvg;
};
+const rectWithTitle = (parent, node) => {
+ // const { shapeSvg, bbox, halfPadding } = labelHelper(parent, node, 'node ' + node.classes);
+
+ let classes;
+ if (!node.classes) {
+ classes = 'node default';
+ } else {
+ classes = 'node ' + node.classes;
+ }
+ // Add outer g element
+ const shapeSvg = parent
+ .insert('g')
+ .attr('class', classes)
+ .attr('id', node.id);
+
+ // Create the title label and insert it after the rect
+ const rect = shapeSvg.insert('rect', ':first-child');
+ // const innerRect = shapeSvg.insert('rect');
+ const innerLine = shapeSvg.insert('line');
+
+ const label = shapeSvg.insert('g').attr('class', 'label');
+
+ const text = label.node().appendChild(createLabel(node.labelText[0], node.labelStyle, true));
+ const textRows = node.labelText.slice(1, node.labelText.length);
+ let titleBox = text.getBBox();
+ const descr = label
+ .node()
+ .appendChild(createLabel(textRows.join('
'), node.labelStyle, true));
+
+ logger.info(descr);
+ const halfPadding = node.padding / 2;
+ select(descr).attr('transform', 'translate( 0' + ', ' + (titleBox.height + halfPadding) + ')');
+ // Get the size of the label
+
+ // Bounding box for title and text
+ const bbox = label.node().getBBox();
+
+ // Center the label
+ label.attr(
+ 'transform',
+ 'translate(' + -bbox.width / 2 + ', ' + (-bbox.height / 2 - halfPadding + 3) + ')'
+ );
+
+ rect
+ .attr('class', 'outer title-state')
+ .attr('x', -bbox.width / 2 - halfPadding)
+ .attr('y', -bbox.height / 2 - halfPadding)
+ .attr('width', bbox.width + node.padding)
+ .attr('height', bbox.height + node.padding);
+ // innerRect
+ // .attr('class', 'inner')
+ // .attr('x', -bbox.width / 2 - halfPadding)
+ // .attr('y', -bbox.height / 2 - halfPadding + titleBox.height + halfPadding)
+ // .attr('width', bbox.width + node.padding)
+ // .attr('height', bbox.height + node.padding - titleBox.height - halfPadding);
+ innerLine
+ .attr('class', 'divider')
+ .attr('x1', -bbox.width / 2 - halfPadding)
+ .attr('x2', bbox.width / 2 + halfPadding)
+ .attr('y1', -bbox.height / 2 - halfPadding + titleBox.height + halfPadding)
+ .attr('y2', -bbox.height / 2 - halfPadding + titleBox.height + halfPadding);
+
+ updateNodeBounds(node, rect);
+
+ node.intersect = function(point) {
+ return intersect.rect(node, point);
+ };
+
+ return shapeSvg;
+};
const stadium = (parent, node) => {
const { shapeSvg, bbox } = labelHelper(parent, node);
@@ -368,6 +440,7 @@ const end = (parent, node) => {
const shapes = {
question,
rect,
+ rectWithTitle,
circle,
stadium,
hexagon,
diff --git a/src/diagrams/state/stateRenderer-v2.js b/src/diagrams/state/stateRenderer-v2.js
index e6d9cedf2..763190f2e 100644
--- a/src/diagrams/state/stateRenderer-v2.js
+++ b/src/diagrams/state/stateRenderer-v2.js
@@ -54,7 +54,12 @@ const setupNode = (g, parent, node, altFlag) => {
// Description
if (node.description) {
- nodeDb[node.id].description = node.description;
+ if (Array.isArray(node.description)) {
+ nodeDb[node.id].shape = 'rectWithTitle';
+ nodeDb[node.id].description = node.description;
+ } else {
+ nodeDb[node.id].description = node.description;
+ }
}
// Save data for description and group so that for instance a statement without description overwrites
diff --git a/src/themes/state.scss b/src/themes/state.scss
index 6055db2d9..0fb7c0f86 100644
--- a/src/themes/state.scss
+++ b/src/themes/state.scss
@@ -90,6 +90,14 @@ g.stateGroup line {
rx: 5px;
ry: 5px;
}
+.statediagram-state .divider {
+ stroke: $nodeBorder;
+}
+
+.statediagram-state .title-state {
+ rx: 5px;
+ ry: 5px;
+}
.statediagram-cluster.statediagram-cluster .inner {
fill: white;
}