From bb9b0b015e85be9d229e54c9c745febc1013ca10 Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Fri, 16 Dec 2022 16:28:24 +0100 Subject: [PATCH] #815 Styling subgraphs with color shades --- cSpell.json | 1 + cypress/platform/knsv2.html | 35 ++- .../src/flowRenderer-v3.js | 233 ++++++++++-------- .../mermaid-flowchart-v3/src/render-utils.js | 119 +++++++++ .../src/render-utils.spec.js | 39 +++ packages/mermaid-flowchart-v3/src/styles.ts | 23 ++ packages/mermaid/src/dagre-wrapper/edges.js | 3 +- packages/mermaid/src/themes/theme-base.js | 11 +- packages/mermaid/src/themes/theme-dark.js | 7 + packages/mermaid/src/themes/theme-default.js | 5 + packages/mermaid/src/themes/theme-forest.js | 7 + packages/mermaid/src/themes/theme-neutral.js | 6 + 12 files changed, 374 insertions(+), 115 deletions(-) create mode 100644 packages/mermaid-flowchart-v3/src/render-utils.js create mode 100644 packages/mermaid-flowchart-v3/src/render-utils.spec.js diff --git a/cSpell.json b/cSpell.json index c7630d7ee..cfffbcdb7 100644 --- a/cSpell.json +++ b/cSpell.json @@ -83,6 +83,7 @@ "treemap", "ts-nocheck", "tuleap", + "ugge", "unist", "verdana", "viewports", diff --git a/cypress/platform/knsv2.html b/cypress/platform/knsv2.html index d6af0549b..ae9de8fca 100644 --- a/cypress/platform/knsv2.html +++ b/cypress/platform/knsv2.html @@ -56,7 +56,7 @@
Security check
-cyto TD
+cyto TB
   %% I could not figure out how to use double quotes in labels in Mermaid
   subgraph ibm[IBM Espresso CPU]
     core0[IBM PowerPC Broadway Core 0]
@@ -111,8 +111,35 @@ cyto TD
     >
     
 cyto LR
-  B1 --be be--> B2
-  B1 --bo bo--> B3
+  B1 --be be--x B2
+  B1 --bo bo--o B3
+  subgraph Ugge
+      B2
+      B3
+      subgraph inner
+          B4
+          B5
+      end
+      subgraph inner2
+        subgraph deeper
+          C4
+          C5
+        end
+        C6
+      end
+
+      B4 --> C4
+
+      B3 -- X --> B4
+      B2 --> inner
+
+      C4 --> C5
+  end
+
+  subgraph outer
+      B6
+  end
+  B6 --> B5
   
inside1 --> inside2 & inside3 & inside4 & inside5 & inside6 a(letter a
a) ---> b(letter @@ -159,7 +186,7 @@ cyto LR // console.error('Mermaid error: ', err); }; mermaid.initialize({ - theme: 'base', + theme: 'dark', startOnLoad: true, logLevel: 0, flowchart: { diff --git a/packages/mermaid-flowchart-v3/src/flowRenderer-v3.js b/packages/mermaid-flowchart-v3/src/flowRenderer-v3.js index a799a35bf..677d97724 100644 --- a/packages/mermaid-flowchart-v3/src/flowRenderer-v3.js +++ b/packages/mermaid-flowchart-v3/src/flowRenderer-v3.js @@ -4,7 +4,8 @@ import { log, getConfig, setupGraphViewbox } from './mermaidUtils'; import { insertNode } from '../../mermaid/src/dagre-wrapper/nodes.js'; import insertMarkers from '../../mermaid/src/dagre-wrapper/markers.js'; import createLabel from '../../mermaid/src/dagre-wrapper/createLabel'; -import dagre from 'cytoscape-dagre'; +import { insertEdgeLabel, positionEdgeLabel } from '../../mermaid/src/dagre-wrapper/edges.js'; +import { findCommonAncestor } from './render-utils'; // Replace with other function to avoid dependency to dagre-d3 import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js'; @@ -26,7 +27,7 @@ export const setConf = function (cnf) { } }; -const nodeDb = {}; +let nodeDb = {}; // /** // * Function that adds the vertices found during parsing to the graph to be rendered. @@ -381,10 +382,9 @@ export const addEdges = function (edges, diagObj, graph, svg) { edgeData.id = linkId; edgeData.classes = 'flowchart-link ' + linkNameStart + ' ' + linkNameEnd; - const labelEl = createLabel(edgeData.label, edgeData.labelStyle); - labelsEl.node().appendChild(labelEl); - const labelBox = labelEl.firstChild.getBoundingClientRect(); - // console.log('labelEl', labelEl); + const edgesNode = select(edges); + const labelEl = insertEdgeLabel(labelsEl, edgeData); + // console.log('labelEl', labelEl, edgeData.width); // Add the edge to the graph graph.edges.push({ id: 'e' + edge.start + edge.end, @@ -393,11 +393,11 @@ export const addEdges = function (edges, diagObj, graph, svg) { labelEl: labelEl, labels: [ { - width: labelBox.width, + width: edgeData.width, // width: 80, - height: labelBox.height, - orgWidth: labelBox.width, - orgHeight: labelBox.height, + height: edgeData.height, + orgWidth: edgeData.width, + orgHeight: edgeData.height, text: edgeData.label, layoutOptions: { 'edgeLabels.inline': 'true', @@ -413,9 +413,19 @@ export const addEdges = function (edges, diagObj, graph, svg) { return graph; }; -const addmarkers = function (svgPath, edgeData, diagramType, arrowMarkerAbsolute) { - // // TODO: Can we load this config only from the rendered graph type? - let url; +// TODO: break out and share with dagre wrapper. The current code in dagre wrapper also adds +// adds the line to the graph, but we don't need that here. This is why we cant use the dagre +// wrapper directly for this +/** + * Add the markers to the edge depending on the type of arrow is + * @param svgPath + * @param edgeData + * @param diagramType + * @param arrowMarkerAbsolute + */ +const addMarkersToEdge = function (svgPath, edgeData, diagramType, arrowMarkerAbsolute) { + let url = ''; + // Check configuration for absolute path if (arrowMarkerAbsolute) { url = window.location.protocol + @@ -426,6 +436,8 @@ const addmarkers = function (svgPath, edgeData, diagramType, arrowMarkerAbsolute url = url.replace(/\(/g, '\\('); url = url.replace(/\)/g, '\\)'); } + + // look in edge data and decide which marker to use switch (edgeData.arrowTypeStart) { case 'arrow_cross': svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-crossStart' + ')'); @@ -526,114 +538,104 @@ const addSubGraphs = function (db) { if (parentLookupDb.parentById[subgraph.id] !== undefined) { data.parent = parentLookupDb.parentById[subgraph.id]; } - // cy.add({ - // group: 'nodes', - // data, - // }); }); return parentLookupDb; }; /* Reverse engineered with trial and error */ -const calcOffset = function (src, dest, sourceId, targetId) { - if (src === dest) { +const calcOffsetOld = function (src, dest, sourceId, targetId, srcDepth, targetDepth, so, to) { + // if (src === dest) { + // return src; + // } + // if (sourceId === 'B6') { + // return 0; + // } + // if (sourceId === 'B4') { + // return 318; + // } + if (srcDepth < targetDepth) { return src; } + if (srcDepth > targetDepth) { + return dest; + } + if (srcDepth === targetDepth) { + return src; + } + // if (src < dest) { + // return dest + src; + // } return 0; }; -const insertEdge = function (edgesEl, edge, edgeData, diagObj) { +const calcOffset = function (src, dest, parentLookupDb) { + const ancestor = findCommonAncestor(src, dest, parentLookupDb); + if (ancestor === undefined || ancestor === 'root') { + return { x: 0, y: 0 }; + } + + const ancestoprOffset = nodeDb[ancestor].offset; + return { x: ancestoprOffset.posX, y: ancestoprOffset.posY }; +}; + +const insertEdge = function (edgesEl, edge, edgeData, diagObj, parentLookupDb) { const srcOffset = nodeDb[edge.sources[0]].offset; const targetOffset = nodeDb[edge.targets[0]].offset; - const offset = { - x: calcOffset( - srcOffset.x, - targetOffset.x, - nodeDb[edge.sources[0]].id, - nodeDb[edge.targets[0]].id - ), - y: calcOffset( - srcOffset.y, - targetOffset.y, - nodeDb[edge.sources[0]].id, - nodeDb[edge.targets[0]].id - ), - }; - // console.log('srcOffset', srcOffset.x, targetOffset.x, srcOffset.y, targetOffset.y); + const offset = calcOffset(edge.sources[0], edge.targets[0], parentLookupDb); + const src = edge.sections[0].startPoint; const dest = edge.sections[0].endPoint; const segments = edge.sections[0].bendPoints ? edge.sections[0].bendPoints : []; - // const dest = edge.target().position(); - // const dest = edge.targetEndpoint(); + const segPoints = segments.map((segment) => [segment.x + offset.x, segment.y + offset.y]); const points = [ [src.x + offset.x, src.y + offset.y], ...segPoints, [dest.x + offset.x, dest.y + offset.y], ]; - // console.log('Edge ctrl points:', edge.segmentPoints(), 'Bounds:', bounds, edge.source(), points); - // console.log('Edge ctrl points:', points); - // const curve = line().curve(curveCardinal); + + // const curve = line().curve(curveBasis); const curve = line().curve(curveLinear); const edgePath = edgesEl .insert('path') .attr('d', curve(points)) - // .attr('d', points)) .attr('class', 'path') .attr('fill', 'none'); const edgeG = edgesEl.insert('g').attr('class', 'edgeLabel'); - const edgeEl = select(edgeG.node().appendChild(edge.labelEl)); - // console.log('Edge label', edgeEl, edge); - const box = edgeEl.node().firstChild.getBoundingClientRect(); - edgeEl.attr('width', box.width); - edgeEl.attr('height', box.height); - // edgeEl.height = 24; + const edgeWithLabel = select(edgeG.node().appendChild(edge.labelEl)); + const box = edgeWithLabel.node().firstChild.getBoundingClientRect(); + edgeWithLabel.attr('width', box.width); + edgeWithLabel.attr('height', box.height); + edgeG.attr( 'transform', - `translate(${edge.labels[0].x - box.width / 2}, ${edge.labels[0].y - box.height / 2})` + `translate(${edge.labels[0].x + offset.x}, ${edge.labels[0].y + offset.y})` ); - addmarkers(edgesEl, edgeData, diagObj.type, diagObj.arrowMarkerAbsolute); - // edgesEl - // .append('circle') - // .style('stroke', 'red') - // .style('fill', 'red') - // .attr('r', 1) - // .attr('cx', src.x) - // .attr('cy', src.y); - // edgesEl - // .append('circle') - // .style('stroke', 'white') - // .style('fill', 'white') - // .attr('r', 1) - // .attr('cx', segments[0].x) - // .attr('cy', segments[0].y); - // edgesEl - // .append('circle') - // .style('stroke', 'pink') - // .style('fill', 'pink') - // .attr('r', 1) - // .attr('cx', dest.x) - // .attr('cy', dest.y); + addMarkersToEdge(edgePath, edgeData, diagObj.type, diagObj.arrowMarkerAbsolute); }; /** - * + * Recursive function that iterates over an array of nodes and inserts the children of each node. + * It also recursively populates the inserts the children of the children and so on. * @param {*} graph * @param nodeArray * @param parentLookupDb */ const insertChildren = (nodeArray, parentLookupDb) => { nodeArray.forEach((node) => { + // Check if we have reached the end of the tree if (!node.children) { node.children = []; } + // Check if the node has children const childIds = parentLookupDb.childrenById[node.id]; - // console.log('UGH', node.id, childIds); + // If the node has children, add them to the node if (childIds) { childIds.forEach((childId) => { node.children.push(nodeDb[childId]); }); } + // Recursive call insertChildren(node.children, parentLookupDb); }); }; @@ -648,6 +650,7 @@ const insertChildren = (nodeArray, parentLookupDb) => { export const draw = function (text, id, _version, diagObj) { // Add temporary render element diagObj.db.clear(); + nodeDb = {}; diagObj.db.setGen('gen-2'); // Parse the graph definition diagObj.parser.parse(text); @@ -659,12 +662,13 @@ export const draw = function (text, id, _version, diagObj) { id: 'root', layoutOptions: { 'elk.hierarchyHandling': 'INCLUDE_CHILDREN', + // 'elk.hierarchyHandling': 'SEPARATE_CHILDREN', 'org.eclipse.elk.padding': '[top=100, left=100, bottom=110, right=110]', // 'org.eclipse.elk.layered.spacing.nodeNodeBetweenLayers': 120, // 'elk.layered.spacing.nodeNodeBetweenLayers': '140', 'elk.layered.spacing.edgeNodeBetweenLayers': '30', // 'elk.algorithm': 'layered', - 'elk.direction': 'WEST', + 'elk.direction': 'DOWN', // 'elk.port.side': 'SOUTH', // 'nodePlacement.strategy': 'SIMPLE', // 'org.eclipse.elk.spacing.labelLabel': 120, @@ -679,14 +683,27 @@ export const draw = function (text, id, _version, diagObj) { edges: [], }; log.info('Drawing flowchart using v3 renderer'); + + // Set the direction, // Fetch the default direction, use TD if none was found let dir = diagObj.db.getDirection(); - if (dir === undefined) { - dir = 'TD'; + switch (dir) { + case 'BT': + graph.layoutOptions['elk.direction'] = 'UP'; + break; + case 'TB': + graph.layoutOptions['elk.direction'] = 'DOWN'; + break; + case 'LR': + graph.layoutOptions['elk.direction'] = 'RIGHT'; + break; + case 'RL': + graph.layoutOptions['elk.direction'] = 'LEFT'; + break; } - const { securityLevel, flowchart: conf } = getConfig(); + // Find the root dom node to ne used in rendering // Handle root and document for when rendering in sandbox mode let sandboxElement; if (securityLevel === 'sandbox') { @@ -699,25 +716,46 @@ export const draw = function (text, id, _version, diagObj) { const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document; const svg = root.select(`[id="${id}"]`); + + // Define the supported markers for the diagram const markers = ['point', 'circle', 'cross']; + + // Add the marker definitions to the svg as marker tags insertMarkers(svg, markers, diagObj.type, diagObj.arrowMarkerAbsolute); + // Fetch the vertices/nodes and edges/links from the parsed graph definition const vert = diagObj.db.getVertices(); + // Setup nodes from the subgraphs with type group, these will be used + // as nodes with children in the subgraph let subG; const subGraphs = diagObj.db.getSubGraphs(); log.info('Subgraphs - ', subGraphs); for (let i = subGraphs.length - 1; i >= 0; i--) { subG = subGraphs[i]; - log.info('Subgraph - ', subG); diagObj.db.addVertex(subG.id, subG.title, 'group', undefined, subG.classes, subG.dir); } + + // Add an element in the svg to be used to hold the subgraphs container + // elements const subGraphsEl = svg.insert('g').attr('class', 'subgraphs'); + // Create the lookup db for the subgraphs and their children to used when creating + // the tree structured graph const parentLookupDb = addSubGraphs(diagObj.db); + + // Add the nodes to the graph, this will entail creating the actual nodes + // in order to get the size of the node. You can't get the size of a node + // that is not in the dom so we need to add it to the dom, get the size + // we will position the nodes when we get the layout from elkjs graph = addVertices(vert, id, root, doc, diagObj, parentLookupDb, graph); + + // Time for the edges, we start with adding an element in the node to hold the edges const edgesEl = svg.insert('g').attr('class', 'edges edgePath'); + // Fetch the edges form the parsed graph definition const edges = diagObj.db.getEdges(); + + // Add the edges to the graph, this will entail creating the actual edges graph = addEdges(edges, diagObj, graph, svg); // Iterate through all nodes and add the top level nodes to the graph @@ -748,46 +786,21 @@ export const draw = function (text, id, _version, diagObj) { } }); insertChildren(graph.children, parentLookupDb); - // console.log('Graph (UGH)- ', JSON.parse(JSON.stringify(graph)), JSON.stringify(graph)); - // const graph2 = { - // id: 'root', - // layoutOptions: { 'elk.algorithm': 'layered' }, - // children: [ - // { - // id: 'N1', - // width: 30, - // height: 30, - // padding: 12, - // children: [ - // { id: 'n1', width: 30, height: 30 }, - // { id: 'n2', width: 30, height: 30 }, - // { id: 'n3', width: 30, height: 30 }, - // ], - // }, - // ], - // edges: [ - // { id: 'e1', sources: ['n1'], targets: ['n2'] }, - // { id: 'e2', sources: ['n1'], targets: ['n3'] }, - // ], - // }; elk.layout(graph).then(function (g) { - // elk.layout(graph2).then(function (g) { - // console.log('Layout (UGH)- ', g, JSON.stringify(g)); - drawNodes(0, 0, g.children, svg, subGraphsEl, diagObj); + drawNodes(0, 0, g.children, svg, subGraphsEl, diagObj, 0); g.edges.map((edge, id) => { - // console.log('Edge (UGH)- ', edge); - insertEdge(edgesEl, edge, edge.edgeData, diagObj); + insertEdge(edgesEl, edge, edge.edgeData, diagObj, parentLookupDb); }); setupGraphViewbox({}, svg, conf.diagramPadding, conf.useMaxWidth); resolve(); }); // Remove element after layout - // renderEl.remove(); + renderEl.remove(); }); }; -const drawNodes = (relX, relY, nodeArray, svg, subgraphsEl, diagObj) => { +const drawNodes = (relX, relY, nodeArray, svg, subgraphsEl, diagObj, depth) => { nodeArray.forEach(function (node) { if (node) { nodeDb[node.id].offset = { @@ -795,13 +808,15 @@ const drawNodes = (relX, relY, nodeArray, svg, subgraphsEl, diagObj) => { posY: node.y + relY, x: relX, y: relY, + depth, + width: node.width, + height: node.height, }; if (node.type === 'group') { const subgraphEl = subgraphsEl.insert('g').attr('class', 'subgraph'); subgraphEl .insert('rect') - .attr('class', 'subgraph node') - .attr('style', 'fill:#ccc;stroke:black;stroke-width:1') + .attr('class', 'subgraph subgraph-lvl-' + (depth % 5) + ' node') .attr('x', node.x + relX) .attr('y', node.y + relY) .attr('width', node.width) @@ -825,7 +840,7 @@ const drawNodes = (relX, relY, nodeArray, svg, subgraphsEl, diagObj) => { }); nodeArray.forEach(function (node) { if (node && node.type === 'group') { - drawNodes(relX + node.x, relY + node.y, node.children, svg, subgraphsEl, diagObj); + drawNodes(relX + node.x, relY + node.y, node.children, svg, subgraphsEl, diagObj, depth + 1); } }); }; diff --git a/packages/mermaid-flowchart-v3/src/render-utils.js b/packages/mermaid-flowchart-v3/src/render-utils.js new file mode 100644 index 000000000..20f6483d2 --- /dev/null +++ b/packages/mermaid-flowchart-v3/src/render-utils.js @@ -0,0 +1,119 @@ +export const findCommonAncestorCoPilot = (id1, id2, treeData) => { + const { parentById, childrenById } = treeData; + const parents1 = []; + const parents2 = []; + let cnt = 0; + let currentId = id1; + while (currentId) { + parents1.push(currentId); + currentId = parentById[currentId]; + cnt++; + if (cnt > 200) { + throw new Error('Infinite loop detected!'); + } + } + currentId = id2; + while (currentId) { + parents2.push(currentId); + currentId = parentById[currentId]; + cnt++; + if (cnt > 200) { + throw new Error('Infinite loop detected!'); + } + } + let commonAncestor = 'root'; + while (parents1.length && parents2.length) { + cnt++; + if (cnt > 200) { + throw new Error('Infinite loop detected!'); + } + const p1 = parents1.pop(); + const p2 = parents2.pop(); + if (p1 === p2) { + commonAncestor = p1; + } else { + break; + } + } + return commonAncestor; +}; + +export const findCommonAncestor = (id1, id2, treeData) => { + const { parentById } = treeData; + const visited = new Set(); + let currentId = id1; + while (currentId) { + visited.add(currentId); + if (currentId === id2) { + return currentId; + } + currentId = parentById[currentId]; + } + currentId = id2; + while (currentId) { + if (visited.has(currentId)) { + return currentId; + } + currentId = parentById[currentId]; + } + return 'root'; +}; + +export const findCommonAncestorKnut = (id1, id2, treeData) => { + const { parentById, childrenById } = treeData; + const parents1 = []; + const parents2 = []; + let cnt = 0; + let currentId = id1; + while (currentId) { + parents1.push(currentId); + currentId = parentById[currentId]; + cnt++; + if (cnt > 200) { + throw new Error('Infinite loop detected!'); + } + } + currentId = id2; + while (currentId) { + parents2.push(currentId); + currentId = parentById[currentId]; + if (currentId === 'root') { + return 'root'; + } + + if (parents1.includes(currentId)) { + return currentId; + } + + cnt++; + if (cnt > 200) { + throw new Error('Infinite loop detected!'); + } + } + return 'root'; +}; + +export const findCommonAncestorRecursive = (id1, id2, treeData) => { + const { parentById, childrenById } = treeData; + + // Base case: return the current node if it is the common ancestor + if (id1 === id2) { + return id1; + } + + // Recursive case: search for the common ancestor in the parent nodes + const parent1 = parentById[id1]; + const parent2 = parentById[id2]; + if (parent1 && parent2) { + return findCommonAncestor(parent1, parent2, treeData); + } + + // Edge case: one of the nodes is the root of the tree + if (parent1) { + return parent1; + } + if (parent2) { + return parent2; + } + return 'root'; +}; diff --git a/packages/mermaid-flowchart-v3/src/render-utils.spec.js b/packages/mermaid-flowchart-v3/src/render-utils.spec.js new file mode 100644 index 000000000..fcc04b4ee --- /dev/null +++ b/packages/mermaid-flowchart-v3/src/render-utils.spec.js @@ -0,0 +1,39 @@ +import { findCommonAncestor } from './render-utils'; +describe('when rendering a flowchart using elk ', function () { + let lookupDb; + beforeEach(function () { + /** + * root: + * B1 + * outer + * B6 + * Ugge + * B2 + * B3 + * inner + * B4 + * B5 + * inner2 + * C4 + * C5 + */ + lookupDb = JSON.parse( + '{"parentById":{"B4":"inner","B5":"inner","C4":"inner2","C5":"inner2","B2":"Ugge","B3":"Ugge","inner":"Ugge","inner2":"Ugge","B6":"outer"},"childrenById":{"inner":["B4","B5"],"inner2":["C4","C5"],"Ugge":["B2","B3","inner","inner2"],"outer":["B6"]}}' + ); + }); + it('Sieblings in a subgraph', function () { + expect(findCommonAncestor('B4', 'B5', lookupDb)).toBe('inner'); + }); + it('Find an uncle', function () { + expect(findCommonAncestor('B4', 'B2', lookupDb)).toBe('Ugge'); + }); + it('Find a cousin', function () { + expect(findCommonAncestor('B4', 'C4', lookupDb)).toBe('Ugge'); + }); + it('Find a grandparent', function () { + expect(findCommonAncestor('B4', 'B6', lookupDb)).toBe('root'); + }); + it('Sieblings in the root', function () { + expect(findCommonAncestor('B1', 'outer', lookupDb)).toBe('root'); + }); +}); diff --git a/packages/mermaid-flowchart-v3/src/styles.ts b/packages/mermaid-flowchart-v3/src/styles.ts index a89d33d3d..1f76ff435 100644 --- a/packages/mermaid-flowchart-v3/src/styles.ts +++ b/packages/mermaid-flowchart-v3/src/styles.ts @@ -15,6 +15,20 @@ export interface FlowChartStyleOptions { titleColor: string; } +const genSections = (options) => { + let sections = ''; + + for (let i = 0; i < 5; i++) { + sections += ` + .subgraph-lvl-${i} { + fill: ${options[`surface${i}`]}; + stroke: ${options[`surfacePeer${i}`]}; + } + `; + } + return sections; +}; + const getStyles = (options: FlowChartStyleOptions) => `.label { font-family: ${options.fontFamily}; @@ -109,6 +123,15 @@ const getStyles = (options: FlowChartStyleOptions) => font-size: 18px; fill: ${options.textColor}; } + .subgraph { + stroke-width:2; + rx:3; + } + // .subgraph-lvl-1 { + // fill:#ccc; + // // stroke:black; + // } + ${genSections(options)} `; export default getStyles; diff --git a/packages/mermaid/src/dagre-wrapper/edges.js b/packages/mermaid/src/dagre-wrapper/edges.js index 5213d0684..8f78403c0 100644 --- a/packages/mermaid/src/dagre-wrapper/edges.js +++ b/packages/mermaid/src/dagre-wrapper/edges.js @@ -107,6 +107,7 @@ export const insertEdgeLabel = (elem, edge) => { terminalLabels[edge.id].endRight = endEdgeLabelRight; setTerminalWidth(fo, edge.endLabelRight); } + return labelElement; }; /** @@ -463,7 +464,7 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph .attr('style', edge.style); // DEBUG code, adds a red circle at each edge coordinate - // edge.points.forEach(point => { + // edge.points.forEach((point) => { // elem // .append('circle') // .style('stroke', 'red') diff --git a/packages/mermaid/src/themes/theme-base.js b/packages/mermaid/src/themes/theme-base.js index c940a0055..8ff544feb 100644 --- a/packages/mermaid/src/themes/theme-base.js +++ b/packages/mermaid/src/themes/theme-base.js @@ -13,7 +13,6 @@ class Theme { * deducing colors for instance line color. Default value is #f4f4f4. */ this.background = '#f4f4f4'; - this.darkMode = false; this.primaryColor = '#fff4dd'; @@ -169,6 +168,16 @@ class Theme { this['cScaleLabel' + i] = this['cScaleLabel' + i] || this.scaleLabelColor; } + const multiplier = this.darkMode ? -4 : -1; + for (let i = 0; i < 5; i++) { + this['surface' + i] = + this['surface' + i] || + adjust(this.mainBkg, { h: 180, s: -15, l: multiplier * (5 + i * 3) }); + this['surfacePeer' + i] = + this['surfacePeer' + i] || + adjust(this.mainBkg, { h: 180, s: -15, l: multiplier * (8 + i * 3) }); + } + /* class */ this.classText = this.classText || this.textColor; diff --git a/packages/mermaid/src/themes/theme-dark.js b/packages/mermaid/src/themes/theme-dark.js index 5ba63e155..af21b4f13 100644 --- a/packages/mermaid/src/themes/theme-dark.js +++ b/packages/mermaid/src/themes/theme-dark.js @@ -196,6 +196,13 @@ class Theme { this['cScalePeer' + i] = this['cScalePeer' + i] || lighten(this['cScale' + i], 10); } + for (let i = 0; i < 5; i++) { + this['surface' + i] = + this['surface' + i] || adjust(this.mainBkg, { h: 30, s: -30, l: -(-10 + i * 4) }); + this['surfacePeer' + i] = + this['surfacePeer' + i] || adjust(this.mainBkg, { h: 30, s: -30, l: -(-7 + i * 4) }); + } + // Setup teh label color for the set this.scaleLabelColor = this.scaleLabelColor || (this.darkMode ? 'black' : this.labelTextColor); diff --git a/packages/mermaid/src/themes/theme-default.js b/packages/mermaid/src/themes/theme-default.js index 95710629b..969551ee6 100644 --- a/packages/mermaid/src/themes/theme-default.js +++ b/packages/mermaid/src/themes/theme-default.js @@ -147,6 +147,11 @@ class Theme { this['cScaleInv' + i] = this['cScaleInv' + i] || adjust(this['cScale' + i], { h: 180 }); } + for (let i = 0; i < 5; i++) { + this['surface' + i] = this['surface' + i] || adjust(this.mainBkg, { h: 30, l: -(5 + i * 5) }); + this['surfacePeer' + i] = + this['surfacePeer' + i] || adjust(this.mainBkg, { h: 30, l: -(7 + i * 5) }); + } // Setup the label color for the set this.scaleLabelColor = this.scaleLabelColor !== 'calculated' && this.scaleLabelColor diff --git a/packages/mermaid/src/themes/theme-forest.js b/packages/mermaid/src/themes/theme-forest.js index 860326dea..59adc9139 100644 --- a/packages/mermaid/src/themes/theme-forest.js +++ b/packages/mermaid/src/themes/theme-forest.js @@ -130,6 +130,13 @@ class Theme { this['cScaleLabel' + i] = this['cScaleLabel' + i] || this.scaleLabelColor; } + for (let i = 0; i < 5; i++) { + this['surface' + i] = + this['surface' + i] || adjust(this.mainBkg, { h: 30, s: -30, l: -(5 + i * 5) }); + this['surfacePeer' + i] = + this['surfacePeer' + i] || adjust(this.mainBkg, { h: 30, s: -30, l: -(8 + i * 5) }); + } + /* Flowchart variables */ this.nodeBkg = this.mainBkg; diff --git a/packages/mermaid/src/themes/theme-neutral.js b/packages/mermaid/src/themes/theme-neutral.js index f22710387..e7a136c6b 100644 --- a/packages/mermaid/src/themes/theme-neutral.js +++ b/packages/mermaid/src/themes/theme-neutral.js @@ -147,6 +147,12 @@ class Theme { this['cScaleLabel' + i] = this['cScaleLabel' + i] || this.scaleLabelColor; } + for (let i = 0; i < 5; i++) { + this['surface' + i] = this['surface' + i] || adjust(this.mainBkg, { l: -(5 + i * 5) }); + this['surfacePeer' + i] = + this['surfacePeer' + i] || adjust(this.mainBkg, { l: -(8 + i * 5) }); + } + /* Flowchart variables */ this.nodeBkg = this.mainBkg;