1295 Support for subgraphs with wide labels

This commit is contained in:
Knut Sveidqvist 2020-03-11 19:52:57 +01:00
parent 1b64af143e
commit 7bd5529bb7
6 changed files with 156 additions and 8 deletions

View File

@ -36,14 +36,14 @@
<div class="mermaid" style="width: 100%; height: 100%">
graph TB
A[apan klättrar]-- i träd -->B
subgraph Test
subgraph id1 [Test with title wider then the node in the subgraph]
B
end
</div>
<div class="mermaid" style="width: 100%; height: 100%">
flowchart TB
A[apan klättrar]-- i träd -->B
subgraph Test
subgraph id1 [Test with title wider then the node in the subgraph]
B
end
</div>

View File

@ -409,6 +409,22 @@ graph TB
end
```
You can also set an excplicit id for the subgraph.
```
graph TB
c1-->a2
subgraph ide1 [one]
a1-->a2
end
```
```mermaid
graph TB
c1-->a2
subgraph id1 [one]
a1-->a2
end
```
## Interaction

View File

@ -0,0 +1,38 @@
# Graph objects and their properties
Explains the representation of various objects used to render the flow charts and what the properties mean. This ofc from the perspective of the dagre-wrapper.
## node
Sample object:
```json
{
"labelType":"svg",
"labelStyle":"",
"shape":"rect",
"label":{},
"labelText":"Test",
"rx":0,"ry":0,
"class":"default",
"style":"",
"id":"Test",
"type":"group",
"padding":15}
```
This is set by the renderer of the diagram and insert the data that the wrapper neds for rendering.
| 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 | ?? |
| 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 |
| 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. |

View File

@ -0,0 +1,70 @@
import intersectRect from './intersect/intersect-rect';
import { logger } from '../logger'; // eslint-disable-line
import createLabel from './createLabel';
const rect = (parent, node) => {
// Add outer g element
const shapeSvg = parent
.insert('g')
.attr('class', 'cluster')
.attr('id', node.id);
// add the rect
const rect = shapeSvg.insert('rect', ':first-child');
// 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));
// Get the size of the label
const bbox = text.getBBox();
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);
const adj = (node.width + node.padding - bbox.width) / 2;
// Center the label
label.attr('transform', 'translate(' + adj + ', ' + (node.y - node.height / 2) + ')');
// label.attr('transform', 'translate(' + 70 + ', ' + -node.height / 2 + ')');
const rectBox = rect.node().getBBox();
node.width = rectBox.width;
node.height = rectBox.height;
node.intersect = function(point) {
return intersectRect(node, point);
};
return shapeSvg;
};
const shapes = { rect };
const clusterElems = {};
export const insertCluster = (elem, node) => {
clusterElems[node.id] = shapes[node.shape](elem, node);
};
export const getClusterTitleWidth = (elem, node) => {
const label = createLabel(node.labelText, node.labelStyle);
elem.node().appendChild(label);
const width = label.getBBox().width;
elem.node().removeChild(label);
return width;
};
export const positionCluster = node => {
const el = clusterElems[node.id];
el.attr('transform', 'translate(' + node.x + ', ' + node.y + ')');
};

View File

@ -1,6 +1,7 @@
import dagre from 'dagre';
import insertMarkers from './markers';
import { insertNode, positionNode } from './nodes';
import { insertCluster, positionCluster, getClusterTitleWidth } from './clusters';
import { insertEdgeLabel, positionEdgeLabel, insertEdge } from './edges';
import { logger } from '../logger';
@ -14,29 +15,50 @@ export const render = (elem, 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
const nodes2expand = [];
graph.nodes().forEach(function(v) {
logger.trace('Node ' + v + ': ' + JSON.stringify(graph.node(v)));
insertNode(nodes, graph.node(v));
const node = 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);
nodes2expand.push({ id: children[0], width });
}
});
nodes2expand.forEach(item => {
const node = graph.node(item.id);
node.width = item.width;
});
// Inster labels, this will insert them into the dom so that the width can be calculated
graph.edges().forEach(function(e) {
logger.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(graph.edge(e)));
logger.trace('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(graph.edge(e)));
insertEdgeLabel(edgeLabels, graph.edge(e));
});
logger.info('#############################################');
logger.info('### Layout ###');
logger.info('#############################################');
dagre.layout(graph);
// Move the nodes to the correct place
graph.nodes().forEach(function(v) {
logger.trace('Node ' + v + ': ' + JSON.stringify(graph.node(v)));
positionNode(graph.node(v));
const node = graph.node(v);
logger.info('Node ' + v + ': ' + JSON.stringify(graph.node(v)));
if (node.type !== 'group') {
positionNode(node);
} else {
insertCluster(clusters, node);
}
});
// 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));
logger.trace('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(edge));
insertEdge(edgePaths, edge);
positionEdgeLabel(edge);

View File

@ -140,6 +140,8 @@ export const addVertices = function(vert, g, svgId) {
class: classStr,
style: styles.style,
id: vertex.id,
width: vertex.type === 'group' ? 500 : undefined,
type: vertex.type,
padding: getConfig().flowchart.padding
});
});