From 0aede618eca12ee8a9454f3e762d0794d2d6134f Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Sat, 25 Apr 2020 17:01:20 +0200 Subject: [PATCH] #1295 Adding support for multiline descriptions for states --- cypress/platform/current.html | 18 ++----- src/dagre-wrapper/createLabel.js | 7 ++- src/dagre-wrapper/nodes.js | 73 ++++++++++++++++++++++++++ src/diagrams/state/stateRenderer-v2.js | 7 ++- src/themes/state.scss | 8 +++ 5 files changed, 97 insertions(+), 16 deletions(-) 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; }