diff --git a/cypress/platform/current.html b/cypress/platform/current.html
index cc4b9e862..6b52388a7 100644
--- a/cypress/platform/current.html
+++ b/cypress/platform/current.html
@@ -32,13 +32,31 @@
G-->c
- flowchart LR
- subgraph id1 [Test]
- b
- end
- a-->id1
+ stateDiagram-v2
+ [*] --> monkey
+ state monkey {
+ Sitting
+ --
+ Eating
+ }
-
+
+ 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
[*] --> Still
Still --> [*]
@@ -52,15 +70,39 @@
Moving --> Crash
Crash --> [*]
+
+stateDiagram-v2
+ [*] --> First
+ First --> Second
+% First --> Third
+
+ state First {
+ [*] --> fir
+ fir --> [*]
+ }
+ state Second {
+ [*] --> sec
+ sec --> [*]
+ }
+
- stateDiagram-v2
- 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
+ [*] --> First
+ First --> Second
+ First --> Third
+
+ state First {
+ [*] --> fir
+ fir --> [*]
+ }
+ state Second {
+ [*] --> sec
+ sec --> [*]
+ }
+ state Third {
+ [*] --> thi
+ thi --> [*]
+ }
stateDiagram-v2
diff --git a/src/dagre-wrapper/GraphObjects.md b/src/dagre-wrapper/GraphObjects.md
index 8821c7c36..b21d7efef 100644
--- a/src/dagre-wrapper/GraphObjects.md
+++ b/src/dagre-wrapper/GraphObjects.md
@@ -7,12 +7,10 @@ Explains the representation of various objects used to render the flow charts an
Sample object:
```json
{
- "labelType":"svg",
- "labelStyle":"",
"shape":"rect",
- "label":{},
"labelText":"Test",
- "rx":0,"ry":0,
+ "rx":0,
+ "ry":0,
"class":"default",
"style":"",
"id":"Test",
@@ -24,18 +22,16 @@ This is set by the renderer of the diagram and insert the data that the wrapper
| property | description |
| ---------- | ----------------------------------------------------------------------------------------------------------- |
-| labelType | If the label should be html label or a svg label. Should we continue to support both? |
-| labelStyle | Css styles for the label. Not currently used. |
-| shape | The shape of the node. Currently on rect is suppoerted. This will change. |
-| label | ?? |
+| labelStyle | Css styles for the label. User for instance for stylling the labels for clusters |
+| shape | The shape of the node. |
| labelText | The text on the label |
-| rx | The corner radius - maybe part of the shape instead? |
-| ry | The corner radius - maybe part of the shape instead? |
-| class | Class to be set for the shape |
+| rx | The corner radius - maybe part of the shape instead? Used for rects. |
+| ry | The corner radius - maybe part of the shape instead? Used for rects. |
+| classes | Classes to be set for the shape. Not used |
| style | Css styles for the actual shape |
| id | id of the shape |
-| type | if set to group then this node indicates *a cluster*. |
-| padding | Padding. Passed from the renderr as this might differ between react for different diagrams. Maybe obsolete. |
+| type | if set to group then this node indicates *a cluster*. |
+| padding | Padding. Passed from the render as this might differ between different diagrams. Maybe obsolete. |
# edge
diff --git a/src/dagre-wrapper/createLabel.js b/src/dagre-wrapper/createLabel.js
index b7edb1572..a029f59fd 100644
--- a/src/dagre-wrapper/createLabel.js
+++ b/src/dagre-wrapper/createLabel.js
@@ -1,8 +1,10 @@
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(/\n|
/gi);
+ let rows = [];
+ if (vertexText) {
+ rows = vertexText.split(/\n|
/gi);
+ }
for (let j = 0; j < rows.length; j++) {
const tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
diff --git a/src/dagre-wrapper/edges.js b/src/dagre-wrapper/edges.js
index ecf4254a8..6b141a863 100644
--- a/src/dagre-wrapper/edges.js
+++ b/src/dagre-wrapper/edges.js
@@ -63,34 +63,17 @@ const outsideNode = (node, point) => {
return false;
};
-// const intersection = (node, outsidePoint, insidePoint) => {
-// const x = node.x;
-// const y = node.y;
-
-// const dx = Math.abs(x - insidePoint.x);
-// const w = node.width / 2;
-// let r = w - dx;
-// const dy = Math.abs(y - insidePoint.y);
-// const h = node.height / 2;
-// const q = h - dy;
-
-// const Q = Math.abs(outsidePoint.y - insidePoint.y);
-// const R = Math.abs(outsidePoint.x - insidePoint.x);
-// r = (R * q) / Q;
-
-// return { x: insidePoint.x + r, y: insidePoint.y + q };
-// };
const intersection = (node, outsidePoint, insidePoint) => {
- // logger.info('intersection', outsidePoint, insidePoint, node);
+ logger.info('intersection o:', outsidePoint, ' i:', insidePoint, node);
const x = node.x;
const y = node.y;
const dx = Math.abs(x - insidePoint.x);
const w = node.width / 2;
- let r = w - dx;
+ let r = insidePoint.x < outsidePoint.x ? w - dx : w + dx;
const dy = Math.abs(y - insidePoint.y);
const h = node.height / 2;
- let q = h - dy;
+ let q = insidePoint.y < outsidePoint.y ? h - dy : h - dy;
const Q = Math.abs(outsidePoint.y - insidePoint.y);
const R = Math.abs(outsidePoint.x - insidePoint.x);
@@ -105,9 +88,10 @@ const intersection = (node, outsidePoint, insidePoint) => {
};
} else {
q = (Q * r) / R;
+ r = (R * q) / Q;
return {
- x: insidePoint.x < outsidePoint.x ? insidePoint.x + r : insidePoint.x - r,
+ x: insidePoint.x < outsidePoint.x ? insidePoint.x + r : insidePoint.x + dx - w,
y: insidePoint.y < outsidePoint.y ? insidePoint.y + q : insidePoint.y - q
};
}
@@ -117,8 +101,8 @@ export const insertEdge = function(elem, edge, clusterDb, diagramType) {
logger.info('\n\n\n\n');
let points = edge.points;
if (edge.toCluster) {
- // logger.info('edge', edge);
- // logger.info('to cluster', clusterDb[edge.toCluster]);
+ logger.info('edge', edge);
+ logger.info('to cluster', clusterDb[edge.toCluster]);
points = [];
let lastPointOutside;
let isInside = false;
@@ -126,13 +110,12 @@ export const insertEdge = function(elem, edge, clusterDb, diagramType) {
const node = clusterDb[edge.toCluster].node;
if (!outsideNode(node, point) && !isInside) {
- // logger.info('inside', edge.toCluster, point);
+ logger.info('inside', edge.toCluster, point, lastPointOutside);
// First point inside the rect
const insterection = intersection(node, lastPointOutside, point);
- // logger.info('intersect', inter.rect(node, lastPointOutside));
+ logger.info('intersect', insterection);
points.push(insterection);
- // points.push(insterection);
isInside = true;
} else {
if (!isInside) points.push(point);
@@ -142,8 +125,8 @@ export const insertEdge = function(elem, edge, clusterDb, diagramType) {
}
if (edge.fromCluster) {
- // logger.info('edge', edge);
- // logger.info('from cluster', clusterDb[edge.toCluster]);
+ logger.info('edge', edge);
+ logger.info('from cluster', clusterDb[edge.toCluster]);
const updatedPoints = [];
let lastPointOutside;
let isInside = false;
@@ -152,7 +135,7 @@ export const insertEdge = function(elem, edge, clusterDb, diagramType) {
const node = clusterDb[edge.fromCluster].node;
if (!outsideNode(node, point) && !isInside) {
- // logger.info('inside', edge.toCluster, point);
+ logger.info('inside', edge.toCluster, point);
// First point inside the rect
const insterection = intersection(node, lastPointOutside, point);
@@ -162,7 +145,7 @@ export const insertEdge = function(elem, edge, clusterDb, diagramType) {
isInside = true;
} else {
// at the outside
- // logger.info('Outside point', point);
+ logger.info('Outside point', point);
if (!isInside) updatedPoints.unshift(point);
}
lastPointOutside = point;
@@ -170,10 +153,6 @@ export const insertEdge = function(elem, edge, clusterDb, diagramType) {
points = updatedPoints;
}
- // logger.info('Poibts', points);
-
- // logger.info('Edge', edge);
-
// The data for our line
const lineData = points.filter(p => !Number.isNaN(p.y));
diff --git a/src/dagre-wrapper/index.js b/src/dagre-wrapper/index.js
index 8f5a5c731..be024b4d1 100644
--- a/src/dagre-wrapper/index.js
+++ b/src/dagre-wrapper/index.js
@@ -7,8 +7,28 @@ import { logger } from '../logger';
let clusterDb = {};
-const translateClusterId = id => {
- if (clusterDb[id]) return clusterDb[id].id;
+const getAnchorId = (id, graph, nodes) => {
+ // Only insert an achor once
+ if (clusterDb[id]) {
+ // if (!clusterDb[id].inserted) {
+ // // Create anchor node for cluster
+ // const anchorData = {
+ // shape: 'start',
+ // labelText: '',
+ // classes: '',
+ // style: '',
+ // id: id + '_anchor',
+ // type: 'anchor',
+ // padding: 0
+ // };
+ // insertNode(nodes, anchorData);
+
+ // graph.setNode(anchorData.id, anchorData);
+ // graph.setParent(anchorData.id, id);
+ // clusterDb[id].inserted = true;
+ // }
+ return clusterDb[id].id;
+ }
return id;
};
@@ -24,24 +44,24 @@ export const render = (elem, graph, markers, diagramtype, id) => {
const edgeLabels = elem.insert('g').attr('class', 'edgeLabels');
const nodes = elem.insert('g').attr('class', 'nodes');
- logger.warn('graph', graph);
-
// 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);
- logger.warn('Node ' + v + ': ' + JSON.stringify(graph.node(v)));
+ logger.info('Node ' + v + ': ' + JSON.stringify(graph.node(v)));
if (node.type !== 'group') {
insertNode(nodes, graph.node(v));
} else {
// const width = getClusterTitleWidth(clusters, node);
const children = graph.children(v);
+
logger.info('Cluster identified', node.id, children[0]);
// nodes2expand.push({ id: children[0], width });
clusterDb[node.id] = { id: children[0] };
- logger.info('Clusters ', clusterDb);
+ // clusterDb[node.id] = { id: node.id + '_anchor' };
}
});
+ logger.info('Clusters ', clusterDb);
// 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
@@ -49,21 +69,37 @@ export const render = (elem, graph, markers, diagramtype, id) => {
// TODO: pick optimal child in the cluster to us as link anchor
graph.edges().forEach(function(e) {
const edge = graph.edge(e);
- logger.warn('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(e));
- // logger.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(graph.edge(e)));
- const v = translateClusterId(e.v);
- const w = translateClusterId(e.w);
- if (v !== e.v || w !== e.w) {
+ logger.trace('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(e));
+ logger.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(graph.edge(e)));
+
+ let v = e.v;
+ let w = e.w;
+ // Check if link is either from or to a cluster
+ logger.info(
+ 'Fix',
+ clusterDb,
+ 'ids:',
+ e.v,
+ e.w,
+ 'Translateing: ',
+ clusterDb[e.v],
+ clusterDb[e.w]
+ );
+ if (clusterDb[e.v] || clusterDb[e.w]) {
+ logger.info('Fixing and trixing - rwemoving', e.v, e.w, e.name);
+ v = getAnchorId(e.v, graph, nodes);
+ w = getAnchorId(e.w, graph, nodes);
graph.removeEdge(e.v, e.w, e.name);
if (v !== e.v) edge.fromCluster = e.v;
if (w !== e.w) edge.toCluster = e.w;
+ logger.info('Fixing Replacing with', v, w, e.name);
graph.setEdge(v, w, edge, e.name);
}
insertEdgeLabel(edgeLabels, edge);
});
graph.edges().forEach(function(e) {
- logger.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(e));
+ logger.trace('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(e));
});
logger.info('#############################################');
logger.info('### Layout ###');
@@ -74,7 +110,7 @@ export const render = (elem, graph, markers, diagramtype, id) => {
// Move the nodes to the correct place
graph.nodes().forEach(function(v) {
const node = graph.node(v);
- logger.info('Node ' + v + ': ' + JSON.stringify(graph.node(v)));
+ logger.trace('Node ' + v + ': ' + JSON.stringify(graph.node(v)));
if (node.type !== 'group') {
positionNode(node);
} else {
@@ -86,7 +122,7 @@ export const render = (elem, graph, markers, diagramtype, id) => {
// Move the edge labels to the correct place after layout
graph.edges().forEach(function(e) {
const edge = graph.edge(e);
- logger.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(edge), edge);
+ logger.trace('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(edge), edge);
insertEdge(edgePaths, edge, clusterDb, diagramtype);
positionEdgeLabel(edge);
diff --git a/src/diagrams/flowchart/flowRenderer-v2.js b/src/diagrams/flowchart/flowRenderer-v2.js
index e8915fc08..e0cce8df8 100644
--- a/src/diagrams/flowchart/flowRenderer-v2.js
+++ b/src/diagrams/flowchart/flowRenderer-v2.js
@@ -130,10 +130,8 @@ export const addVertices = function(vert, g, svgId) {
}
// Add the node
g.setNode(vertex.id, {
- labelType: 'svg',
labelStyle: styles.labelStyle,
shape: _shape,
- label: vertexNode,
labelText: vertexText,
rx: radious,
ry: radious,
@@ -146,10 +144,8 @@ export const addVertices = function(vert, g, svgId) {
});
logger.info('setNode', {
- labelType: 'svg',
labelStyle: styles.labelStyle,
shape: _shape,
- label: vertexNode,
labelText: vertexText,
rx: radious,
ry: radious,
diff --git a/src/diagrams/state/stateDb.js b/src/diagrams/state/stateDb.js
index d72e8f00c..c56dcd1a3 100644
--- a/src/diagrams/state/stateDb.js
+++ b/src/diagrams/state/stateDb.js
@@ -1,4 +1,7 @@
import { logger } from '../../logger';
+import { generateId } from '../../utils';
+
+const clone = o => JSON.parse(JSON.stringify(o));
let rootDoc = [];
const setRootDoc = o => {
@@ -22,6 +25,34 @@ const docTranslator = (parent, node, first) => {
}
if (node.doc) {
+ const doc = [];
+ // Check for concurrency
+ let i = 0;
+ let currentDoc = [];
+ for (i = 0; i < node.doc.length; i++) {
+ if (node.doc[i].type === 'divider') {
+ // debugger;
+ const newNode = clone(node.doc[i]);
+ newNode.doc = clone(currentDoc);
+ doc.push(newNode);
+ currentDoc = [];
+ } else {
+ currentDoc.push(node.doc[i]);
+ }
+ }
+
+ // If any divider was encountered
+ if (doc.length > 0 && currentDoc.length > 0) {
+ const newNode = {
+ stmt: 'state',
+ id: generateId(),
+ type: 'divider',
+ doc: clone(currentDoc)
+ };
+ doc.push(clone(newNode));
+ node.doc = doc;
+ }
+
node.doc.forEach(docNode => docTranslator(node, docNode, true));
}
}
@@ -31,8 +62,14 @@ const getRootDocV2 = () => {
return { id: 'root', doc: rootDoc };
};
-const extract = doc => {
+const extract = _doc => {
// const res = { states: [], relations: [] };
+ let doc;
+ if (_doc.doc) {
+ doc = _doc.doc;
+ } else {
+ doc = _doc;
+ }
// let doc = root.doc;
// if (!doc) {
// doc = root;
@@ -40,6 +77,8 @@ const extract = doc => {
logger.info(doc);
clear();
+ logger.info('Extract', doc);
+
doc.forEach(item => {
if (item.stmt === 'state') {
addState(item.id, item.type, item.doc, item.description, item.note);
diff --git a/src/diagrams/state/stateRenderer-v2.js b/src/diagrams/state/stateRenderer-v2.js
index 76dc2f186..f69d94ed3 100644
--- a/src/diagrams/state/stateRenderer-v2.js
+++ b/src/diagrams/state/stateRenderer-v2.js
@@ -72,10 +72,8 @@ const setupNode = (g, parent, node, altFlag) => {
}
const nodeData = {
- labelType: 'svg',
labelStyle: '',
shape: nodeDb[node.id].shape,
- label: node.id,
labelText: nodeDb[node.id].description,
classes: nodeDb[node.id].classes, //classStr,
style: '', //styles.style,
@@ -87,10 +85,8 @@ const setupNode = (g, parent, node, altFlag) => {
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,
@@ -99,10 +95,8 @@ const setupNode = (g, parent, node, altFlag) => {
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,
@@ -133,8 +127,7 @@ const setupNode = (g, parent, node, altFlag) => {
classes: 'note-edge',
arrowheadStyle: 'fill: #333',
labelpos: 'c',
- labelType: 'text',
- label: ''
+ labelType: 'text'
});
} else {
g.setNode(node.id, nodeData);
@@ -143,12 +136,12 @@ const setupNode = (g, parent, node, altFlag) => {
if (parent) {
if (parent.id !== 'root') {
- logger.trace('Setting node ', node.id, ' to be child of its parent ', parent.id);
+ logger.info('Setting node ', node.id, ' to be child of its parent ', parent.id);
g.setParent(node.id, parent.id);
}
}
if (node.doc) {
- logger.trace('Adding nodes children ');
+ logger.info('Adding nodes children ');
setupDoc(g, node, node.doc, !altFlag);
}
};
@@ -168,8 +161,7 @@ const setupDoc = (g, parent, doc, altFlag) => {
labelStyle: '',
arrowheadStyle: 'fill: #333',
labelpos: 'c',
- labelType: 'text',
- label: ''
+ labelType: 'text'
};
let startId = item.state1.id;
let endId = item.state2.id;
@@ -214,7 +206,7 @@ export const draw = function(text, id) {
compound: true
})
.setGraph({
- rankdir: 'LR',
+ rankdir: 'TB',
nodesep: nodeSpacing,
ranksep: rankSpacing,
marginx: 8,
@@ -224,8 +216,8 @@ export const draw = function(text, id) {
return {};
});
- // logger.info(stateDb.getRootDoc());
- stateDb.extract(stateDb.getRootDocV2().doc);
+ logger.info(stateDb.getRootDocV2());
+ stateDb.extract(stateDb.getRootDocV2());
logger.info(stateDb.getRootDocV2());
setupNode(g, undefined, stateDb.getRootDocV2(), true);
diff --git a/src/utils.js b/src/utils.js
index 823191ffc..1adcb86f0 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -210,6 +210,19 @@ export const getStylesFromArray = arr => {
return { style: style, labelStyle: labelStyle };
};
+let cnt = 0;
+export const generateId = () => {
+ cnt++;
+ return (
+ 'id-' +
+ Math.random()
+ .toString(36)
+ .substr(2, 12) +
+ '-' +
+ cnt
+ );
+};
+
export default {
detectType,
isSubstringInArray,
@@ -217,5 +230,6 @@ export default {
calcLabelPosition,
calcCardinalityPosition,
formatUrl,
- getStylesFromArray
+ getStylesFromArray,
+ generateId
};