diff --git a/cypress/integration/rendering/flowchart.spec.js b/cypress/integration/rendering/flowchart.spec.js index 591f0f8db..bc6c68f6e 100644 --- a/cypress/integration/rendering/flowchart.spec.js +++ b/cypress/integration/rendering/flowchart.spec.js @@ -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
(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
text] --> B(blue
text) - C[/red
text/] --> D{blue
text} + A[red
text] -->|red
text| B(blue
text) + C[/red
text/] -->|blue
text| D{blue
text} + E{{default
style}} -->|default
style| F([default
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
text] --> B(blue
text) - C[/red
text/] --> D{blue
text} + A[red
text] -->|red
text| B(blue
text) + C[/red
text/] -->|blue
text| D{blue
text} + E{{default
style}} -->|default
style| F([default
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 diff --git a/dist/index.html b/dist/index.html index 47293b4b6..e28890ce7 100644 --- a/dist/index.html +++ b/dist/index.html @@ -371,8 +371,12 @@ graph TB
graph LR - A[red
text] --> B(blue
text) - C[/red
text/] --> D{blue
text} + A[red
text] -->|red
text| B(blue
text) + C[/red
text/] -->|blue
text| D{blue
text} + E{{default
style}} -->|default
style| F([default
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 diff --git a/docs/flowchart.md b/docs/flowchart.md index b6bdabc2f..ee4f0e130 100644 --- a/docs/flowchart.md +++ b/docs/flowchart.md @@ -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; ``` diff --git a/src/diagrams/flowchart/flowRenderer.js b/src/diagrams/flowchart/flowRenderer.js index 9ee23aea8..924e8dd03 100644 --- a/src/diagrams/flowchart/flowRenderer.js +++ b/src/diagrams/flowchart/flowRenderer.js @@ -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(//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 diff --git a/src/diagrams/flowchart/flowRenderer.spec.js b/src/diagrams/flowchart/flowRenderer.spec.js index d691840ed..e3980ef1f 100644 --- a/src/diagrams/flowchart/flowRenderer.spec.js +++ b/src/diagrams/flowchart/flowRenderer.spec.js @@ -92,44 +92,40 @@ describe('the flowchart renderer', function() { expect(addedNodes[0][1].label.lastChild.innerHTML).toEqual('Line'); // 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;' - ] - ].forEach(function([style, expectedStyle, expectedLabelStyle]) { - it(`should add the styles to style and/or labelStyle for style ${style}`, function() { - const addedNodes = []; - const mockG = { - setNode: function(id, object) { - addedNodes.push([id, object]); - } - }; - addVertices( - { - v1: { - type: 'rect', - id: 'my-node-id', - classes: [], - styles: style, - text: 'my vertex text' + [['fill:#fff'], 'fill:#fff;', ''], + [['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 = []; + const mockG = { + setNode: function(id, object) { + addedNodes.push([id, object]); } - }, - mockG, - 'svg-id' - ); - expect(addedNodes).toHaveLength(1); - expect(addedNodes[0][0]).toEqual('my-node-id'); - expect(addedNodes[0][1]).toHaveProperty('id', 'my-node-id'); - expect(addedNodes[0][1]).toHaveProperty('labelType', 'svg'); - expect(addedNodes[0][1]).toHaveProperty('style', expectedStyle); - expect(addedNodes[0][1]).toHaveProperty('labelStyle', expectedLabelStyle); + }; + addVertices( + { + v1: { + type: 'rect', + id: 'my-node-id', + classes: [], + styles: style, + text: 'my vertex text' + } + }, + mockG, + 'svg-id' + ); + expect(addedNodes).toHaveLength(1); + expect(addedNodes[0][0]).toEqual('my-node-id'); + expect(addedNodes[0][1]).toHaveProperty('id', 'my-node-id'); + expect(addedNodes[0][1]).toHaveProperty('labelType', 'svg'); + expect(addedNodes[0][1]).toHaveProperty('style', expectedStyle); + expect(addedNodes[0][1]).toHaveProperty('labelStyle', expectedLabelStyle); + }); }); }); @@ -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); + }); + }); }); }); diff --git a/src/utils.js b/src/utils.js index 38010c41f..002dcc8b7 100644 --- a/src/utils.js +++ b/src/utils.js @@ -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 };