Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/4935 subgraph title margin config option #5041

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b134766
Add subgraph title margin config options to schema.
mathbraga Nov 11, 2023
0bcd5d2
Create helper function for subgraph title margin fetching.
mathbraga Nov 11, 2023
52ed387
Fix nesting of getSubGraphTitleMargins test.
mathbraga Nov 11, 2023
8b0a5be
Include subgraph margin into label positioning
mathbraga Nov 11, 2023
56c3809
Add logic to add subgraph title margin on layout
mathbraga Nov 12, 2023
453c16d
Remove unnecessary code
mathbraga Nov 17, 2023
7e77433
Add tests for subgraph title margin
mathbraga Nov 17, 2023
42ac630
Merge branch 'develop' into feature/4935_subgraph-title-margin-config…
mathbraga Nov 18, 2023
ad6c761
Modify getSubGraphTitleMargins to use null coalescing operator
mathbraga Nov 20, 2023
c0a43f5
Change getSubGraphTitleMargins to accept config object as parameter
mathbraga Nov 20, 2023
63c2d36
Rename file and update imports
mathbraga Nov 20, 2023
fc3018e
Move subgraph title margin tests to independent file
mathbraga Nov 20, 2023
d61bfde
Replace string concat with string templates
mathbraga Nov 21, 2023
a935380
Merge branch 'feature/4935_subgraph-title-margin-config-option' of ht…
mathbraga Nov 21, 2023
d79671e
Resolve lint issue
mathbraga Nov 21, 2023
997a377
Merge branch 'develop' into feature/4935_subgraph-title-margin-config…
mathbraga Nov 21, 2023
3489fc4
Replace multiple calls of getConfig() for a single at top of the scope
mathbraga Nov 25, 2023
904be16
Merge branch 'develop' into feature/4935_subgraph-title-margin-config…
mathbraga Nov 25, 2023
ce875c9
Move getConfig() call out of recursiveRender to its parent caller
mathbraga Nov 26, 2023
a807a58
Modify margin logic to avoid creating unnecessary space in subgraph
mathbraga Nov 28, 2023
7979b28
Add test for subgraphs with title margins and edge labels
mathbraga Nov 28, 2023
8e794e3
Merge branch 'feature/4935_subgraph-title-margin-config-option' of ht…
mathbraga Nov 28, 2023
5718be5
Merge branch 'develop' into feature/4935_subgraph-title-margin-config…
mathbraga Nov 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions cypress/integration/rendering/flowchart-v2.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -886,4 +886,93 @@ end
});
});
});
describe('Subgraph title margins', () => {
it('Should render subgraphs with title margins set (LR)', () => {
imgSnapshotTest(
`flowchart LR

subgraph TOP
direction TB
subgraph B1
direction RL
i1 -->f1
end
subgraph B2
direction BT
i2 -->f2
end
end
A --> TOP --> B
B1 --> B2
`,
{ flowchart: { subGraphTitleMargin: { top: 10, bottom: 5 } } }
);
});
it('Should render subgraphs with title margins set (TD)', () => {
imgSnapshotTest(
`flowchart TD

subgraph TOP
direction LR
subgraph B1
direction RL
i1 -->f1
end
subgraph B2
direction BT
i2 -->f2
end
end
A --> TOP --> B
B1 --> B2
`,
{ flowchart: { subGraphTitleMargin: { top: 8, bottom: 16 } } }
);
});
it('Should render subgraphs with title margins set (LR) and htmlLabels set to false', () => {
imgSnapshotTest(
`flowchart LR

subgraph TOP
direction TB
subgraph B1
direction RL
i1 -->f1
end
subgraph B2
direction BT
i2 -->f2
end
end
A --> TOP --> B
B1 --> B2
`,
{
htmlLabels: false,
flowchart: { htmlLabels: false, subGraphTitleMargin: { top: 10, bottom: 5 } },
}
);
});
it('Should render subgraphs with title margins and edge labels', () => {
imgSnapshotTest(
`flowchart LR

subgraph TOP
direction TB
subgraph B1
direction RL
i1 --lb1-->f1
end
subgraph B2
direction BT
i2 --lb2-->f2
end
end
A --lb3--> TOP --lb4--> B
B1 --lb5--> B2
`,
{ flowchart: { subGraphTitleMargin: { top: 10, bottom: 5 } } }
);
});
});
});
8 changes: 8 additions & 0 deletions packages/mermaid/src/config.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1411,6 +1411,14 @@ export interface FlowchartDiagramConfig extends BaseDiagramConfig {
* Margin top for the text over the diagram
*/
titleTopMargin?: number;
/**
* Defines a top/bottom margin for subgraph titles
*
*/
subGraphTitleMargin?: {
top?: number;
bottom?: number;
};
arrowMarkerAbsolute?: boolean;
/**
* The amount of padding around the diagram as a whole so that embedded
Expand Down
19 changes: 13 additions & 6 deletions packages/mermaid/src/dagre-wrapper/clusters.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import { createText } from '../rendering-util/createText.js';
import { select } from 'd3';
import { getConfig } from '../diagram-api/diagramAPI.js';
import { evaluate } from '../diagrams/common/common.js';
import { getSubGraphTitleMargins } from '../utils/subGraphTitleMargins.js';

const rect = (parent, node) => {
log.info('Creating subgraph rect for ', node.id, node);
const siteConfig = getConfig();

// Add outer g element
const shapeSvg = parent
Expand All @@ -18,7 +20,7 @@ const rect = (parent, node) => {
// add the rect
const rect = shapeSvg.insert('rect', ':first-child');

const useHtmlLabels = evaluate(getConfig().flowchart.htmlLabels);
const useHtmlLabels = evaluate(siteConfig.flowchart.htmlLabels);

// Create the label and insert it after the rect
const label = shapeSvg.insert('g').attr('class', 'cluster-label');
Expand All @@ -34,7 +36,7 @@ const rect = (parent, node) => {
// Get the size of the label
let bbox = text.getBBox();

if (evaluate(getConfig().flowchart.htmlLabels)) {
if (evaluate(siteConfig.flowchart.htmlLabels)) {
const div = text.children[0];
const dv = select(text);
bbox = div.getBoundingClientRect();
Expand Down Expand Up @@ -63,17 +65,18 @@ const rect = (parent, node) => {
.attr('width', width)
.attr('height', node.height + padding);

const { subGraphTitleTopMargin } = getSubGraphTitleMargins(siteConfig);
if (useHtmlLabels) {
label.attr(
'transform',
// This puts the labal on top of the box instead of inside it
'translate(' + (node.x - bbox.width / 2) + ', ' + (node.y - node.height / 2) + ')'
`translate(${node.x - bbox.width / 2}, ${node.y - node.height / 2 + subGraphTitleTopMargin})`
);
} else {
label.attr(
'transform',
// This puts the labal on top of the box instead of inside it
'translate(' + node.x + ', ' + (node.y - node.height / 2) + ')'
`translate(${node.x}, ${node.y - node.height / 2 + subGraphTitleTopMargin})`
);
}
// Center the label
Expand Down Expand Up @@ -127,6 +130,8 @@ const noteGroup = (parent, node) => {
return shapeSvg;
};
const roundedWithTitle = (parent, node) => {
const siteConfig = getConfig();

// Add outer g element
const shapeSvg = parent.insert('g').attr('class', node.classes).attr('id', node.id);

Expand All @@ -143,7 +148,7 @@ const roundedWithTitle = (parent, node) => {

// Get the size of the label
let bbox = text.getBBox();
if (evaluate(getConfig().flowchart.htmlLabels)) {
if (evaluate(siteConfig.flowchart.htmlLabels)) {
const div = text.children[0];
const dv = select(text);
bbox = div.getBoundingClientRect();
Expand Down Expand Up @@ -175,6 +180,7 @@ const roundedWithTitle = (parent, node) => {
.attr('width', width + padding)
.attr('height', node.height + padding - bbox.height - 3);

const { subGraphTitleTopMargin } = getSubGraphTitleMargins(siteConfig);
// Center the label
label.attr(
'transform',
Expand All @@ -184,7 +190,8 @@ const roundedWithTitle = (parent, node) => {
(node.y -
node.height / 2 -
node.padding / 3 +
(evaluate(getConfig().flowchart.htmlLabels) ? 5 : 3)) +
(evaluate(siteConfig.flowchart.htmlLabels) ? 5 : 3)) +
subGraphTitleTopMargin +
')'
);

Expand Down
13 changes: 8 additions & 5 deletions packages/mermaid/src/dagre-wrapper/edges.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import utils from '../utils.js';
import { evaluate } from '../diagrams/common/common.js';
import { getLineFunctionsWithOffset } from '../utils/lineWithOffset.js';
import { getSubGraphTitleMargins } from '../utils/subGraphTitleMargins.js';
import { addEdgeMarkers } from './edgeMarker.js';

let edgeLabels = {};
Expand Down Expand Up @@ -136,6 +137,8 @@
export const positionEdgeLabel = (edge, paths) => {
log.info('Moving label abc78 ', edge.id, edge.label, edgeLabels[edge.id]);
let path = paths.updatedPath ? paths.updatedPath : paths.originalPath;
const siteConfig = getConfig();
const { subGraphTitleTotalMargin } = getSubGraphTitleMargins(siteConfig);
if (edge.label) {
const el = edgeLabels[edge.id];
let x = edge.x;
Expand All @@ -159,7 +162,7 @@
y = pos.y;
}
}
el.attr('transform', 'translate(' + x + ', ' + y + ')');
el.attr('transform', `translate(${x}, ${y + subGraphTitleTotalMargin / 2})`);
}

//let path = paths.updatedPath ? paths.updatedPath : paths.originalPath;
Expand All @@ -173,7 +176,7 @@
x = pos.x;
y = pos.y;
}
el.attr('transform', 'translate(' + x + ', ' + y + ')');
el.attr('transform', `translate(${x}, ${y})`);

Check warning on line 179 in packages/mermaid/src/dagre-wrapper/edges.js

View check run for this annotation

Codecov / codecov/patch

packages/mermaid/src/dagre-wrapper/edges.js#L179

Added line #L179 was not covered by tests
}
if (edge.startLabelRight) {
const el = terminalLabels[edge.id].startRight;
Expand All @@ -189,7 +192,7 @@
x = pos.x;
y = pos.y;
}
el.attr('transform', 'translate(' + x + ', ' + y + ')');
el.attr('transform', `translate(${x}, ${y})`);
}
if (edge.endLabelLeft) {
const el = terminalLabels[edge.id].endLeft;
Expand All @@ -201,7 +204,7 @@
x = pos.x;
y = pos.y;
}
el.attr('transform', 'translate(' + x + ', ' + y + ')');
el.attr('transform', `translate(${x}, ${y})`);
}
if (edge.endLabelRight) {
const el = terminalLabels[edge.id].endRight;
Expand All @@ -213,7 +216,7 @@
x = pos.x;
y = pos.y;
}
el.attr('transform', 'translate(' + x + ', ' + y + ')');
el.attr('transform', `translate(${x}, ${y})`);

Check warning on line 219 in packages/mermaid/src/dagre-wrapper/edges.js

View check run for this annotation

Codecov / codecov/patch

packages/mermaid/src/dagre-wrapper/edges.js#L219

Added line #L219 was not covered by tests
}
};

Expand Down
22 changes: 18 additions & 4 deletions packages/mermaid/src/dagre-wrapper/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ import { insertNode, positionNode, clear as clearNodes, setNodeElem } from './no
import { insertCluster, clear as clearClusters } from './clusters.js';
import { insertEdgeLabel, positionEdgeLabel, insertEdge, clear as clearEdges } from './edges.js';
import { log } from '../logger.js';
import { getSubGraphTitleMargins } from '../utils/subGraphTitleMargins.js';
import { getConfig } from '../diagram-api/diagramAPI.js';

const recursiveRender = async (_elem, graph, diagramtype, id, parentCluster) => {
const recursiveRender = async (_elem, graph, diagramtype, id, parentCluster, siteConfig) => {
log.info('Graph in recursive render: XXX', graphlibJson.write(graph), parentCluster);
const dir = graph.graph().rankdir;
log.trace('Dir in recursive render - dir:', dir);
Expand Down Expand Up @@ -52,7 +54,14 @@ const recursiveRender = async (_elem, graph, diagramtype, id, parentCluster) =>
if (node && node.clusterNode) {
// const children = graph.children(v);
log.info('Cluster identified', v, node.width, graph.node(v));
const o = await recursiveRender(nodes, node.graph, diagramtype, id, graph.node(v));
const o = await recursiveRender(
nodes,
node.graph,
diagramtype,
id,
graph.node(v),
siteConfig
);
const newEl = o.elem;
updateNodeBounds(node, newEl);
node.diff = o.diff || 0;
Expand Down Expand Up @@ -101,6 +110,7 @@ const recursiveRender = async (_elem, graph, diagramtype, id, parentCluster) =>
log.info('Graph after layout:', graphlibJson.write(graph));
// Move the nodes to the correct place
let diff = 0;
const { subGraphTitleTotalMargin } = getSubGraphTitleMargins(siteConfig);
sortNodesByHierarchy(graph).forEach(function (v) {
const node = graph.node(v);
log.info('Position ' + v + ': ' + JSON.stringify(graph.node(v)));
Expand All @@ -114,16 +124,18 @@ const recursiveRender = async (_elem, graph, diagramtype, id, parentCluster) =>
);
if (node && node.clusterNode) {
// clusterDb[node.id].node = node;

node.y += subGraphTitleTotalMargin;
positionNode(node);
} else {
// Non cluster node
if (graph.children(v).length > 0) {
// A cluster in the non-recursive way
// positionCluster(node);
node.height += subGraphTitleTotalMargin;
insertCluster(clusters, node);
clusterDb[node.id].node = node;
} else {
node.y += subGraphTitleTotalMargin / 2;
positionNode(node);
}
}
Expand All @@ -134,6 +146,7 @@ const recursiveRender = async (_elem, graph, diagramtype, id, parentCluster) =>
const edge = graph.edge(e);
log.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(edge), edge);

edge.points.forEach((point) => (point.y += subGraphTitleTotalMargin / 2));
const paths = insertEdge(edgePaths, e, edge, clusterDb, diagramtype, graph, id);
positionEdgeLabel(edge, paths);
});
Expand All @@ -159,7 +172,8 @@ export const render = async (elem, graph, markers, diagramtype, id) => {
adjustClustersAndEdges(graph);
log.warn('Graph after:', JSON.stringify(graphlibJson.write(graph)));
// log.warn('Graph ever after:', graphlibJson.write(graph.node('A').graph));
await recursiveRender(elem, graph, diagramtype, id);
const siteConfig = getConfig();
await recursiveRender(elem, graph, diagramtype, id, undefined, siteConfig);
};

// const shapeDefinitions = {};
Expand Down
15 changes: 15 additions & 0 deletions packages/mermaid/src/schemas/config.schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1863,6 +1863,7 @@ $defs: # JSON Schema definition (maybe we should move these to a separate file)
unevaluatedProperties: false
required:
- titleTopMargin
- subGraphTitleMargin
- diagramPadding
- htmlLabels
- nodeSpacing
Expand All @@ -1875,6 +1876,20 @@ $defs: # JSON Schema definition (maybe we should move these to a separate file)
titleTopMargin:
$ref: '#/$defs/GitGraphDiagramConfig/properties/titleTopMargin'
default: 25
subGraphTitleMargin:
description: |
Defines a top/bottom margin for subgraph titles
type: object
properties:
top:
type: integer
minimum: 0
bottom:
type: integer
minimum: 0
default:
top: 0
bottom: 0
arrowMarkerAbsolute:
type: boolean # TODO, is this actually used here (it has no default value but was in types)
diagramPadding:
Expand Down
22 changes: 22 additions & 0 deletions packages/mermaid/src/utils/subGraphTitleMargins.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { getSubGraphTitleMargins } from './subGraphTitleMargins.js';
import * as configApi from '../config.js';

describe('getSubGraphTitleMargins', () => {
it('should get subgraph title margins after config has been set', () => {
const config_0 = {
flowchart: {
subGraphTitleMargin: {
top: 10,
bottom: 5,
},
},
};

configApi.setSiteConfig(config_0);
expect(getSubGraphTitleMargins(config_0)).toEqual({
subGraphTitleTopMargin: 10,
subGraphTitleBottomMargin: 5,
subGraphTitleTotalMargin: 15,
});
});
});
Loading
Loading