diff --git a/cypress/platform/current.html b/cypress/platform/current.html
index 55655dc8f..c341c70cf 100644
--- a/cypress/platform/current.html
+++ b/cypress/platform/current.html
@@ -31,7 +31,7 @@
G-->H
G-->c
-
+
flowchart LR
subgraph id1 [Test]
b
@@ -56,21 +56,13 @@
stateDiagram-v2
- [*] --> First
-
- state First {
- [*] --> Second
-
- state Second {
- [*] --> second
- second --> Third
-
- state Third {
- [*] --> third
- third --> [*]
- }
- }
- }
+ State1: The state with a note
+ note right of State1
+ Important information! You can write
+ notes.
+ end note
+ State1 --> State2
+ note left of State2 : This is the note to the left.
stateDiagram-v2
diff --git a/src/dagre-wrapper/clusters.js b/src/dagre-wrapper/clusters.js
index 813d2dc6e..55db0b32e 100644
--- a/src/dagre-wrapper/clusters.js
+++ b/src/dagre-wrapper/clusters.js
@@ -55,11 +55,47 @@ const rect = (parent, node) => {
return shapeSvg;
};
+/**
+ * Non visiable cluster where the note is group with its
+ */
+const noteGroup = (parent, node) => {
+ // Add outer g element
+ const shapeSvg = parent
+ .insert('g')
+ .attr('class', 'note-cluster')
+ .attr('id', node.id);
+
+ // add the rect
+ const rect = shapeSvg.insert('rect', ':first-child');
+
+ const padding = 0 * node.padding;
+ const halfPadding = padding / 2;
+
+ // center the rect around its coordinate
+ rect
+ .attr('rx', node.rx)
+ .attr('ry', node.ry)
+ .attr('x', node.x - node.width / 2 - halfPadding)
+ .attr('y', node.y - node.height / 2 - halfPadding)
+ .attr('width', node.width + padding)
+ .attr('height', node.height + padding)
+ .attr('fill', 'none');
+
+ const rectBox = rect.node().getBBox();
+ node.width = rectBox.width;
+ node.height = rectBox.height;
+
+ node.intersect = function(point) {
+ return intersectRect(node, point);
+ };
+
+ return shapeSvg;
+};
const roundedWithTitle = (parent, node) => {
// Add outer g element
const shapeSvg = parent
.insert('g')
- .attr('class', node.class)
+ .attr('class', node.classes)
.attr('id', node.id);
// add the rect
@@ -114,7 +150,7 @@ const roundedWithTitle = (parent, node) => {
return shapeSvg;
};
-const shapes = { rect, roundedWithTitle };
+const shapes = { rect, roundedWithTitle, noteGroup };
let clusterElems = {};
diff --git a/src/dagre-wrapper/createLabel.js b/src/dagre-wrapper/createLabel.js
index 3f01e4071..b7edb1572 100644
--- a/src/dagre-wrapper/createLabel.js
+++ b/src/dagre-wrapper/createLabel.js
@@ -2,14 +2,14 @@ const createLabel = (vertexText, style) => {
const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text');
svgLabel.setAttribute('style', style.replace('color:', 'fill:'));
- const rows = vertexText.split(/
/gi);
+ const rows = vertexText.split(/\n|
/gi);
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');
- tspan.textContent = rows[j];
+ tspan.textContent = rows[j].trim();
svgLabel.appendChild(tspan);
}
return svgLabel;
diff --git a/src/dagre-wrapper/edges.js b/src/dagre-wrapper/edges.js
index 41ba9ea90..ecf4254a8 100644
--- a/src/dagre-wrapper/edges.js
+++ b/src/dagre-wrapper/edges.js
@@ -192,7 +192,7 @@ export const insertEdge = function(elem, edge, clusterDb, diagramType) {
.append('path')
.attr('d', lineFunction(lineData))
.attr('id', edge.id)
- .attr('class', 'transition');
+ .attr('class', 'transition' + (edge.classes ? ' ' + edge.classes : ''));
// DEBUG code, adds a red circle at each edge coordinate
// edge.points.forEach(point => {
diff --git a/src/dagre-wrapper/nodes.js b/src/dagre-wrapper/nodes.js
index 21ffc77f4..f1db09a43 100644
--- a/src/dagre-wrapper/nodes.js
+++ b/src/dagre-wrapper/nodes.js
@@ -1,49 +1,8 @@
import intersect from './intersect/index.js';
import { logger } from '../logger'; // eslint-disable-line
-import createLabel from './createLabel';
+import { labelHelper, updateNodeBounds, insertPolygonShape } from './shapes/util';
+import note from './shapes/note';
-const labelHelper = (parent, node) => {
- // Add outer g element
- const shapeSvg = parent
- .insert('g')
- .attr('class', 'node default')
- .attr('id', node.id);
-
- // 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));
-
- // Get the size of the label
- const bbox = text.getBBox();
-
- const halfPadding = node.padding / 2;
-
- // Center the label
- label.attr('transform', 'translate(' + -bbox.width / 2 + ', ' + -bbox.height / 2 + ')');
-
- return { shapeSvg, bbox, halfPadding, label };
-};
-
-const updateNodeBounds = (node, element) => {
- const bbox = element.node().getBBox();
- node.width = bbox.width;
- node.height = bbox.height;
-};
-
-function insertPolygonShape(parent, w, h, points) {
- return parent
- .insert('polygon', ':first-child')
- .attr(
- 'points',
- points
- .map(function(d) {
- return d.x + ',' + d.y;
- })
- .join(' ')
- )
- .attr('transform', 'translate(' + -w / 2 + ',' + h / 2 + ')');
-}
const question = (parent, node) => {
const { shapeSvg, bbox } = labelHelper(parent, node);
@@ -287,8 +246,9 @@ const cylinder = (parent, node) => {
};
const rect = (parent, node) => {
- const { shapeSvg, bbox, halfPadding } = labelHelper(parent, node);
+ const { shapeSvg, bbox, halfPadding } = labelHelper(parent, node, 'node ' + node.classes);
+ logger.info('Classes = ', node.classes);
// add the rect
const rect = shapeSvg.insert('rect', ':first-child');
@@ -418,7 +378,8 @@ const shapes = {
rect_right_inv_arrow,
cylinder,
start,
- end
+ end,
+ note
};
let nodeElems = {};
diff --git a/src/dagre-wrapper/shapes/note.js b/src/dagre-wrapper/shapes/note.js
new file mode 100644
index 000000000..34bb4356d
--- /dev/null
+++ b/src/dagre-wrapper/shapes/note.js
@@ -0,0 +1,29 @@
+import { updateNodeBounds, labelHelper } from './util';
+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);
+
+ logger.info('Classes = ', node.classes);
+ // add the rect
+ const rect = shapeSvg.insert('rect', ':first-child');
+
+ rect
+ .attr('rx', node.rx)
+ .attr('ry', node.ry)
+ .attr('x', -bbox.width / 2 - halfPadding)
+ .attr('y', -bbox.height / 2 - halfPadding)
+ .attr('width', bbox.width + node.padding)
+ .attr('height', bbox.height + node.padding);
+
+ updateNodeBounds(node, rect);
+
+ node.intersect = function(point) {
+ return intersect.rect(node, point);
+ };
+
+ return shapeSvg;
+};
+
+export default note;
diff --git a/src/dagre-wrapper/shapes/util.js b/src/dagre-wrapper/shapes/util.js
new file mode 100644
index 000000000..632652e16
--- /dev/null
+++ b/src/dagre-wrapper/shapes/util.js
@@ -0,0 +1,50 @@
+import createLabel from '../createLabel';
+
+export const labelHelper = (parent, node, _classes) => {
+ let classes;
+ if (!_classes) {
+ classes = 'node default';
+ } else {
+ classes = _classes;
+ }
+ // Add outer g element
+ const shapeSvg = parent
+ .insert('g')
+ .attr('class', classes)
+ .attr('id', node.id);
+
+ // 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));
+
+ // Get the size of the label
+ const bbox = text.getBBox();
+
+ const halfPadding = node.padding / 2;
+
+ // Center the label
+ label.attr('transform', 'translate(' + -bbox.width / 2 + ', ' + -bbox.height / 2 + ')');
+
+ return { shapeSvg, bbox, halfPadding, label };
+};
+
+export const updateNodeBounds = (node, element) => {
+ const bbox = element.node().getBBox();
+ node.width = bbox.width;
+ node.height = bbox.height;
+};
+
+export function insertPolygonShape(parent, w, h, points) {
+ return parent
+ .insert('polygon', ':first-child')
+ .attr(
+ 'points',
+ points
+ .map(function(d) {
+ return d.x + ',' + d.y;
+ })
+ .join(' ')
+ )
+ .attr('transform', 'translate(' + -w / 2 + ',' + h / 2 + ')');
+}
diff --git a/src/diagrams/state/parser/stateDiagram.jison b/src/diagrams/state/parser/stateDiagram.jison
index fbbce5234..b57265fc3 100644
--- a/src/diagrams/state/parser/stateDiagram.jison
+++ b/src/diagrams/state/parser/stateDiagram.jison
@@ -114,7 +114,7 @@ line
statement
: idStatement { /*console.warn('got id and descr', $1);*/$$={ stmt: 'state', id: $1, type: 'default', description: ''};}
- | idStatement DESCR { /*console.warn('got id and descr', $1, $2.trim());*/$$={ stmt: 'state', id: $1, type: 'default', description: $2.trim()};}
+ | idStatement DESCR { /*console.warn('got id and descr', $1, $2.trim());*/$$={ stmt: 'state', id: $1, type: 'default', description: yy.trimColon($2)};}
| idStatement '-->' idStatement
{
/*console.warn('got id', $1);yy.addRelation($1, $3);*/
diff --git a/src/diagrams/state/stateDb.js b/src/diagrams/state/stateDb.js
index 3419fdad5..9b8031f75 100644
--- a/src/diagrams/state/stateDb.js
+++ b/src/diagrams/state/stateDb.js
@@ -180,6 +180,8 @@ export const relationType = {
DEPENDENCY: 3
};
+const trimColon = str => (str && str[0] === ':' ? str.substr(1).trim() : str.trim());
+
export default {
addState,
clear,
@@ -198,5 +200,6 @@ export default {
getRootDoc,
setRootDoc,
getRootDocV2,
- extract
+ extract,
+ trimColon
};
diff --git a/src/diagrams/state/stateRenderer-v2.js b/src/diagrams/state/stateRenderer-v2.js
index 3418df584..76dc2f186 100644
--- a/src/diagrams/state/stateRenderer-v2.js
+++ b/src/diagrams/state/stateRenderer-v2.js
@@ -47,7 +47,8 @@ const setupNode = (g, parent, node, altFlag) => {
nodeDb[node.id] = {
id: node.id,
shape,
- description: node.id
+ description: node.id,
+ classes: 'statediagram-state'
};
}
@@ -64,6 +65,10 @@ const setupNode = (g, parent, node, altFlag) => {
logger.info('Setting cluser for ', node.id);
nodeDb[node.id].type = 'group';
nodeDb[node.id].shape = 'roundedWithTitle';
+ nodeDb[node.id].classes =
+ nodeDb[node.id].classes +
+ ' ' +
+ (altFlag ? 'statediagram-cluster statediagram-cluster-alt' : 'statediagram-cluster');
}
const nodeData = {
@@ -72,14 +77,68 @@ const setupNode = (g, parent, node, altFlag) => {
shape: nodeDb[node.id].shape,
label: node.id,
labelText: nodeDb[node.id].description,
- class: altFlag ? 'statediagram-cluster statediagram-cluster-alt' : 'statediagram-cluster', //classStr,
+ classes: nodeDb[node.id].classes, //classStr,
style: '', //styles.style,
id: node.id,
type: nodeDb[node.id].type,
padding: 15 //getConfig().flowchart.padding
};
- g.setNode(node.id, nodeData);
+ if (node.note) {
+ // Todo: set random id
+ const noteData = {
+ labelType: 'svg',
+ labelStyle: '',
+ shape: 'note',
+ label: node.id,
+ labelText: node.note.text,
+ classes: 'statediagram-note', //classStr,
+ style: '', //styles.style,
+ id: node.id + '----note',
+ type: nodeDb[node.id].type,
+ padding: 15 //getConfig().flowchart.padding
+ };
+ const groupData = {
+ labelType: 'svg',
+ labelStyle: '',
+ shape: 'noteGroup',
+ label: node.id + '----parent',
+ labelText: node.note.text,
+ classes: nodeDb[node.id].classes, //classStr,
+ style: '', //styles.style,
+ id: node.id + '----parent',
+ type: 'group',
+ padding: 0 //getConfig().flowchart.padding
+ };
+ g.setNode(node.id + '----parent', groupData);
+
+ g.setNode(noteData.id, noteData);
+ g.setNode(node.id, nodeData);
+
+ g.setParent(node.id, node.id + '----parent');
+ g.setParent(noteData.id, node.id + '----parent');
+
+ let from = node.id;
+ let to = noteData.id;
+
+ if (node.note.position === 'left of') {
+ from = noteData.id;
+ to = node.id;
+ }
+ g.setEdge(from, to, {
+ arrowhead: 'none',
+ arrowType: '',
+ style: 'fill:none',
+ labelStyle: '',
+ classes: 'note-edge',
+ arrowheadStyle: 'fill: #333',
+ labelpos: 'c',
+ labelType: 'text',
+ label: ''
+ });
+ } else {
+ g.setNode(node.id, nodeData);
+ }
}
if (parent) {
@@ -166,6 +225,7 @@ export const draw = function(text, id) {
});
// logger.info(stateDb.getRootDoc());
+ stateDb.extract(stateDb.getRootDocV2().doc);
logger.info(stateDb.getRootDocV2());
setupNode(g, undefined, stateDb.getRootDocV2(), true);
diff --git a/src/themes/state.scss b/src/themes/state.scss
index 1e0bcc92d..aa8bd4df3 100644
--- a/src/themes/state.scss
+++ b/src/themes/state.scss
@@ -98,4 +98,21 @@ g.stateGroup line {
.statediagram-cluster .inner {
rx:0;
ry:0;
-}
\ No newline at end of file
+}
+
+.statediagram-state rect {
+ rx: 5px;
+ ry: 5px;
+}
+
+.note-edge {
+ stroke-dasharray: 5;
+}
+
+.statediagram-note rect {
+ fill: $noteBkgColor;
+ stroke: $noteBorderColor;
+ stroke-width: 1px;
+ rx: 0;
+ ry: 0;
+}