Merge pull request #1238 from GDFaber/feature/962_flowchart_line_label_color_from_linkstyle

Set text color for flowchart link labels according to linkStyle definitions
This commit is contained in:
Knut Sveidqvist
2020-02-05 19:36:12 +01:00
committed by GitHub
6 changed files with 123 additions and 83 deletions

View File

@@ -512,7 +512,7 @@ describe('Flowchart', () => {
);
});
it('24.1: Keep node label text (if already defined) when a style is applied', () => {
it('24: Keep node label text (if already defined) when a style is applied', () => {
imgSnapshotTest(
`graph LR
A(( )) -->|step 1| B(( ))
@@ -524,7 +524,7 @@ describe('Flowchart', () => {
{ flowchart: { htmlLabels: false } }
);
});
it('24.2: Handle link click events (link, anchor, mailto, other protocol, script)', () => {
it('25: Handle link click events (link, anchor, mailto, other protocol, script)', () => {
imgSnapshotTest(
`graph TB
TITLE["Link Click Events<br>(click the nodes below)"]
@@ -544,11 +544,15 @@ it('24.2: Handle link click events (link, anchor, mailto, other protocol, script
);
});
it('25: Set node text color according to style when html labels are enabled', () => {
it('26: Set text color of nodes and links according to styles when html labels are enabled', () => {
imgSnapshotTest(
`graph LR
A[red<br>text] --> B(blue<br>text)
C[/red<br/>text/] --> D{blue<br/>text}
A[red<br>text] -->|red<br>text| B(blue<br>text)
C[/red<br/>text/] -->|blue<br/>text| D{blue<br/>text}
E{{default<br />style}} -->|default<br />style| F([default<br />style])
linkStyle default color:Sienna;
linkStyle 0 color:red;
linkStyle 1 stroke:DarkGray,stroke-width:2px,color:#0000ff
style A color:red;
style B color:blue;
style C stroke:#ff0000,fill:#ffcccc,color:#ff0000
@@ -560,11 +564,15 @@ it('24.2: Handle link click events (link, anchor, mailto, other protocol, script
);
});
it('26: Set node text color according to style when html labels are disabled', () => {
it('27: Set text color of nodes and links according to styles when html labels are disabled', () => {
imgSnapshotTest(
`graph LR
A[red<br>text] --> B(blue<br>text)
C[/red<br/>text/] --> D{blue<br/>text}
A[red<br>text] -->|red<br>text| B(blue<br>text)
C[/red<br/>text/] -->|blue<br/>text| D{blue<br/>text}
E{{default<br />style}} -->|default<br />style| F([default<br />style])
linkStyle default color:Sienna;
linkStyle 0 color:red;
linkStyle 1 stroke:DarkGray,stroke-width:2px,color:#0000ff
style A color:red;
style B color:blue;
style C stroke:#ff0000,fill:#ffcccc,color:#ff0000

8
dist/index.html vendored
View File

@@ -371,8 +371,12 @@ graph TB
<hr/>
<div class="mermaid">
graph LR
A[red<br>text] --> B(blue<br>text)
C[/red<br/>text/] --> D{blue<br/>text}
A[red<br>text] -->|red<br>text| B(blue<br>text)
C[/red<br/>text/] -->|blue<br/>text| D{blue<br/>text}
E{{default<br />style}} -->|default<br />style| F([default<br />style])
linkStyle default color:Sienna;
linkStyle 0 color:red;
linkStyle 1 stroke:DarkGray,stroke-width:2px,color:#0000ff
style A color:red;
style B color:blue;
style C stroke:#ff0000,fill:#ffcccc,color:#ff0000

View File

@@ -497,7 +497,7 @@ Instead of ids, the order number of when the link was defined in the graph is us
defined in the linkStyle statement will belong to the fourth link in the graph:
```
linkStyle 3 stroke:#ff3,stroke-width:4px;
linkStyle 3 stroke:#ff3,stroke-width:4px,color:red;
```

View File

@@ -8,7 +8,7 @@ import { getConfig } from '../../config';
import dagreD3 from 'dagre-d3';
import addHtmlLabel from 'dagre-d3/lib/label/add-html-label.js';
import { logger } from '../../logger';
import { interpolateToCurve } from '../../utils';
import { interpolateToCurve, getStylesFromArray } from '../../utils';
import flowChartShapes from './flowChartShapes';
const conf = {};
@@ -28,25 +28,6 @@ export const addVertices = function(vert, g, svgId) {
const svg = d3.select(`[id="${svgId}"]`);
const keys = Object.keys(vert);
const styleFromStyleArr = function(styleStr, arr, { label }) {
if (!label) {
// Create a compound style definition from the style definitions found for the node in the graph definition
for (let i = 0; i < arr.length; i++) {
if (typeof arr[i] !== 'undefined') {
styleStr = styleStr + arr[i] + ';';
}
}
} else {
// create the style definition for the text, if property is a text-property
for (let i = 0; i < arr.length; i++) {
if (typeof arr[i] !== 'undefined') {
if (arr[i].match('^color:|^text-align:')) styleStr = styleStr + arr[i] + ';';
}
}
}
return styleStr;
};
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
keys.forEach(function(id) {
const vertex = vert[id];
@@ -60,15 +41,7 @@ export const addVertices = function(vert, g, svgId) {
classStr = vertex.classes.join(' ');
}
/**
* Variable for storing the extracted style for the vertex
* @type {string}
*/
let style = '';
// Create a compound style definition from the style definitions found for the node in the graph definition
style = styleFromStyleArr(style, vertex.styles, { label: false });
let labelStyle = '';
labelStyle = styleFromStyleArr(labelStyle, vertex.styles, { label: true });
const styles = getStylesFromArray(vertex.styles);
// Use vertex id as text in the box if no text is provided by the graph definition
let vertexText = vertex.text !== undefined ? vertex.text : vertex.id;
@@ -87,7 +60,7 @@ export const addVertices = function(vert, g, svgId) {
vertexNode.parentNode.removeChild(vertexNode);
} else {
const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text');
svgLabel.setAttribute('style', labelStyle.replace('color:', 'fill:'));
svgLabel.setAttribute('style', styles.labelStyle.replace('color:', 'fill:'));
const rows = vertexText.split(/<br\s*\/?>/gi);
@@ -158,13 +131,13 @@ export const addVertices = function(vert, g, svgId) {
// Add the node
g.setNode(vertex.id, {
labelType: 'svg',
labelStyle: labelStyle,
labelStyle: styles.labelStyle,
shape: _shape,
label: vertexNode,
rx: radious,
ry: radious,
class: classStr,
style: style,
style: styles.style,
id: vertex.id
});
});
@@ -179,8 +152,12 @@ export const addEdges = function(edges, g) {
let cnt = 0;
let defaultStyle;
let defaultLabelStyle;
if (typeof edges.defaultStyle !== 'undefined') {
defaultStyle = edges.defaultStyle.toString().replace(/,/g, ';');
const defaultStyles = getStylesFromArray(edges.defaultStyle);
defaultStyle = defaultStyles.style;
defaultLabelStyle = defaultStyles.labelStyle;
}
edges.forEach(function(edge) {
@@ -195,10 +172,12 @@ export const addEdges = function(edges, g) {
}
let style = '';
let labelStyle = '';
if (typeof edge.style !== 'undefined') {
edge.style.forEach(function(s) {
style = style + s + ';';
});
const styles = getStylesFromArray(edge.style);
style = styles.style;
labelStyle = styles.labelStyle;
} else {
switch (edge.stroke) {
case 'normal':
@@ -206,6 +185,9 @@ export const addEdges = function(edges, g) {
if (typeof defaultStyle !== 'undefined') {
style = defaultStyle;
}
if (typeof defaultLabelStyle !== 'undefined') {
labelStyle = defaultLabelStyle;
}
break;
case 'dotted':
style = 'fill:none;stroke-width:2px;stroke-dasharray:3;';
@@ -215,7 +197,9 @@ export const addEdges = function(edges, g) {
break;
}
}
edgeData.style = style;
edgeData.labelStyle = labelStyle;
if (typeof edge.interpolate !== 'undefined') {
edgeData.curve = interpolateToCurve(edge.interpolate, d3.curveLinear);
@@ -243,6 +227,8 @@ export const addEdges = function(edges, g) {
if (typeof edge.style === 'undefined') {
edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none';
}
edgeData.labelStyle = edgeData.labelStyle.replace('color:', 'fill:');
}
}
// Add the edge to the graph

View File

@@ -92,17 +92,12 @@ describe('the flowchart renderer', function() {
expect(addedNodes[0][1].label.lastChild.innerHTML).toEqual('Line'); // <tspan> node, line 2
});
});
});
[
[['fill:#fff'], 'fill:#fff;', ''],
[['color:#ccc'], 'color:#ccc;', 'color:#ccc;'],
[['fill:#fff', 'color:#ccc'], 'fill:#fff;color:#ccc;', 'color:#ccc;'],
[
['fill:#fff', 'color:#ccc', 'text-align:center'],
'fill:#fff;color:#ccc;text-align:center;',
'color:#ccc;text-align:center;'
]
[['color:#ccc'], '', 'color:#ccc;'],
[['fill:#fff', 'color:#ccc'], 'fill:#fff;', 'color:#ccc;'],
[['fill:#fff', 'color:#ccc', 'text-align:center'], 'fill:#fff;', 'color:#ccc;text-align:center;']
].forEach(function([style, expectedStyle, expectedLabelStyle]) {
it(`should add the styles to style and/or labelStyle for style ${style}`, function() {
const addedNodes = [];
@@ -132,6 +127,7 @@ describe('the flowchart renderer', function() {
expect(addedNodes[0][1]).toHaveProperty('labelStyle', expectedLabelStyle);
});
});
});
describe('when adding edges to a graph', function() {
it('should handle multiline texts and set centered label position', function() {
@@ -161,5 +157,32 @@ describe('the flowchart renderer', function() {
expect(edge).toHaveProperty('labelpos', 'c');
});
});
[
[['stroke:DarkGray'], 'stroke:DarkGray;', ''],
[['color:red'], '', 'fill:red;'],
[['stroke:DarkGray', 'color:red'], 'stroke:DarkGray;', 'fill:red;'],
[['stroke:DarkGray', 'color:red', 'stroke-width:2px'], 'stroke:DarkGray;stroke-width:2px;', 'fill:red;']
].forEach(function([style, expectedStyle, expectedLabelStyle]) {
it(`should add the styles to style and/or labelStyle for style ${style}`, function() {
const addedEdges = [];
const mockG = {
setEdge: function(s, e, data, c) {
addedEdges.push(data);
}
};
addEdges(
[
{ style: style, text: 'styling' }
],
mockG,
'svg-id'
);
expect(addedEdges).toHaveLength(1);
expect(addedEdges[0]).toHaveProperty('style', expectedStyle);
expect(addedEdges[0]).toHaveProperty('labelStyle', expectedLabelStyle);
});
});
});
});

View File

@@ -201,6 +201,24 @@ const calcCardinalityPosition = (isRelationTypePresent, points, initialPosition)
return cardinalityPosition;
};
export const getStylesFromArray = arr => {
let style = '';
let labelStyle = '';
for (let i = 0; i < arr.length; i++) {
if (typeof arr[i] !== 'undefined') {
// add text properties to label style definition
if (arr[i].startsWith('color:') || arr[i].startsWith('text-align:')) {
labelStyle = labelStyle + arr[i] + ';';
} else {
style = style + arr[i] + ';';
}
}
}
return { style: style, labelStyle: labelStyle };
};
export default {
detectType,
isSubstringInArray,
@@ -208,5 +226,6 @@ export default {
calcLabelPosition,
calcCardinalityPosition,
sanitize,
formatUrl
formatUrl,
getStylesFromArray
};