From aa32d454c9d964afe8ad8aaeb4fa9e531806972b Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Sun, 8 Mar 2020 09:49:41 +0100 Subject: [PATCH 01/22] #1295 First draft of generic renderer applied to flowcharts. --- cypress/platform/current.html | 26 +- src/dagre-wrapper/createLabel.js | 18 + src/dagre-wrapper/edges.js | 84 +++ src/dagre-wrapper/index.js | 54 ++ src/dagre-wrapper/intersect.js | 7 + src/dagre-wrapper/intersect/index.js | 17 + .../intersect/intersect-circle.js | 7 + .../intersect/intersect-ellipse.js | 25 + src/dagre-wrapper/intersect/intersect-line.js | 70 ++ src/dagre-wrapper/intersect/intersect-node.js | 5 + .../intersect/intersect-polygon.js | 57 ++ src/dagre-wrapper/intersect/intersect-rect.js | 32 + src/dagre-wrapper/markers.js | 106 +++ src/dagre-wrapper/nodes.js | 59 ++ src/diagrams/flowchart-v2/flowChartShapes.js | 261 ------- .../flowchart-v2/flowChartShapes.spec.js | 131 ---- src/diagrams/flowchart-v2/flowDb.js | 644 ------------------ src/diagrams/flowchart/flowChartShapes.js | 28 +- .../flowRenderer-v2.js} | 87 ++- src/logger.js | 1 + src/mermaidAPI.js | 7 +- 21 files changed, 639 insertions(+), 1087 deletions(-) create mode 100644 src/dagre-wrapper/createLabel.js create mode 100644 src/dagre-wrapper/edges.js create mode 100644 src/dagre-wrapper/index.js create mode 100644 src/dagre-wrapper/intersect.js create mode 100644 src/dagre-wrapper/intersect/index.js create mode 100644 src/dagre-wrapper/intersect/intersect-circle.js create mode 100644 src/dagre-wrapper/intersect/intersect-ellipse.js create mode 100644 src/dagre-wrapper/intersect/intersect-line.js create mode 100644 src/dagre-wrapper/intersect/intersect-node.js create mode 100644 src/dagre-wrapper/intersect/intersect-polygon.js create mode 100644 src/dagre-wrapper/intersect/intersect-rect.js create mode 100644 src/dagre-wrapper/markers.js create mode 100644 src/dagre-wrapper/nodes.js delete mode 100644 src/diagrams/flowchart-v2/flowChartShapes.js delete mode 100644 src/diagrams/flowchart-v2/flowChartShapes.spec.js delete mode 100644 src/diagrams/flowchart-v2/flowDb.js rename src/diagrams/{flowchart-v2/flowRenderer.js => flowchart/flowRenderer-v2.js} (88%) diff --git a/cypress/platform/current.html b/cypress/platform/current.html index 2f5ec32b4..3074517a9 100644 --- a/cypress/platform/current.html +++ b/cypress/platform/current.html @@ -8,7 +8,7 @@ @@ -33,14 +36,72 @@ C --> D C --> D -
- flowchart LR - G-->H - G-->H + +
+ flowchart TB + a --> b + + subgraph id1 [Test] + a --apa--> c + b + c-->b + b-->H + end + G-->H + G-->id1 + id1 --> I + I --> G +
+
+ flowchart RL + a --> b + + subgraph id1 [Test] + a --apa--> c + b + c-->b + b-->H + end + G-->H + G-->id1 + id1 --> I + I --> G +
+
+ flowchart RL + + subgraph id1 [Test] + a + end + b-->id1 +
+
+ flowchart RL + + subgraph id1 [Test1] + a + end + subgraph id2 [Test2] + b + end + a --> id2 + a --> b + b-->id1 + id1 --> id2 +
+
diff --git a/src/dagre-wrapper/clusters.js b/src/dagre-wrapper/clusters.js index 74947b46d..4d0322192 100644 --- a/src/dagre-wrapper/clusters.js +++ b/src/dagre-wrapper/clusters.js @@ -32,7 +32,7 @@ const rect = (parent, node) => { .attr('width', node.width + padding) .attr('height', node.height + padding); - logger.info('bbox', bbox.width, node.x, node.width); + // logger.info('bbox', bbox.width, node.x, node.width); // Center the label // label.attr('transform', 'translate(' + adj + ', ' + (node.y - node.height / 2) + ')'); label.attr( @@ -57,7 +57,7 @@ const rect = (parent, node) => { const shapes = { rect }; -const clusterElems = {}; +let clusterElems = {}; export const insertCluster = (elem, node) => { clusterElems[node.id] = shapes[node.shape](elem, node); @@ -70,6 +70,10 @@ export const getClusterTitleWidth = (elem, node) => { return width; }; +export const clear = () => { + clusterElems = {}; +}; + export const positionCluster = node => { const el = clusterElems[node.id]; el.attr('transform', 'translate(' + node.x + ', ' + node.y + ')'); diff --git a/src/dagre-wrapper/edges.js b/src/dagre-wrapper/edges.js index 8ba6a64a2..c2135abf0 100644 --- a/src/dagre-wrapper/edges.js +++ b/src/dagre-wrapper/edges.js @@ -1,9 +1,14 @@ import { logger } from '../logger'; // eslint-disable-line import createLabel from './createLabel'; import * as d3 from 'd3'; +import inter from './intersect/index.js'; import { getConfig } from '../config'; -const edgeLabels = {}; +let edgeLabels = {}; + +export const clear = () => { + edgeLabels = {}; +}; export const insertEdgeLabel = (elem, edge) => { // Create the actual text element @@ -30,7 +35,6 @@ export const insertEdgeLabel = (elem, edge) => { export const positionEdgeLabel = edge => { const el = edgeLabels[edge.id]; - logger.info(edge.id, el); el.attr('transform', 'translate(' + edge.x + ', ' + edge.y + ')'); }; @@ -47,9 +51,128 @@ export const positionEdgeLabel = edge => { // } // }; -export const insertEdge = function(elem, edge) { +const outsideNode = (node, point) => { + const x = node.x; + const y = node.y; + const dx = Math.abs(point.x - x); + const dy = Math.abs(point.y - y); + const w = node.width / 2; + const h = node.height / 2; + if (dx > w || dy > h) { + return true; + } + return false; +}; + +// const intersection = (node, outsidePoint, insidePoint) => { +// const x = node.x; +// const y = node.y; + +// const dx = Math.abs(x - insidePoint.x); +// const w = node.width / 2; +// let r = w - dx; +// const dy = Math.abs(y - insidePoint.y); +// const h = node.height / 2; +// const q = h - dy; + +// const Q = Math.abs(outsidePoint.y - insidePoint.y); +// const R = Math.abs(outsidePoint.x - insidePoint.x); +// r = (R * q) / Q; + +// return { x: insidePoint.x + r, y: insidePoint.y + q }; +// }; +const intersection = (node, outsidePoint, insidePoint) => { + const x = node.x; + const y = node.y; + + const dx = Math.abs(x - insidePoint.x); + const w = node.width / 2; + let r = w - dx; + const dy = Math.abs(y - insidePoint.y); + const h = node.height / 2; + let q = h - dy; + + logger.info('q och r', q, r); + + const Q = Math.abs(outsidePoint.y - insidePoint.y); + const R = Math.abs(outsidePoint.x - insidePoint.x); + // if (Math.abs(y - outsidePoint.y) * w > Math.abs(x - outsidePoint.x) * h || false) { // eslint-disable-line + // // Intersection is top or bottom of rect. + + // r = (R * q) / Q; + + // return { + // x: insidePoint.x < outsidePoint.x ? insidePoint.x + r : insidePoint.x - r, + // y: insidePoint.y + q + // }; + // } else { + q = (Q * r) / R; + + return { + x: insidePoint.x < outsidePoint.x ? insidePoint.x + r : insidePoint.x - r, + y: insidePoint.y < outsidePoint.y ? insidePoint.y + q : insidePoint.y - q + }; + // } +}; + +export const insertEdge = function(elem, edge, clusterDb) { + let points = edge.points; + if (edge.toCluster) { + logger.trace('edge', edge); + logger.trace('cluster', clusterDb[edge.toCluster]); + points = []; + let lastPointOutside; + let isInside = false; + edge.points.forEach(point => { + const node = clusterDb[edge.toCluster].node; + + if (!outsideNode(node, point) && !isInside) { + logger.info('inside', edge.toCluster, point); + + // First point inside the rect + const insterection = intersection(node, lastPointOutside, point); + logger.info('intersect', inter.rect(node, lastPointOutside)); + points.push(insterection); + // points.push(insterection); + isInside = true; + } else { + if (!isInside) points.push(point); + } + lastPointOutside = point; + }); + } + + if (edge.fromCluster) { + logger.info('edge', edge); + logger.info('cluster', clusterDb[edge.toCluster]); + const updatedPoints = []; + let lastPointOutside; + let isInside = false; + for (let i = points.length - 1; i >= 0; i--) { + const point = points[i]; + const node = clusterDb[edge.fromCluster].node; + + if (!outsideNode(node, point) && !isInside) { + logger.info('inside', edge.toCluster, point); + + // First point inside the rect + const insterection = intersection(node, lastPointOutside, point); + logger.info('intersect', inter.rect(node, lastPointOutside)); + updatedPoints.unshift(insterection); + // points.push(insterection); + isInside = true; + } else { + if (!isInside) updatedPoints.unshift(point); + } + lastPointOutside = point; + } + points = updatedPoints; + } + + logger.info('Points', points); + // The data for our line - const lineData = edge.points.filter(p => !Number.isNaN(p.y)); + const lineData = points.filter(p => !Number.isNaN(p.y)); // This is the accessor function we talked about above const lineFunction = d3 @@ -59,14 +182,25 @@ export const insertEdge = function(elem, edge) { }) .y(function(d) { return d.y; - }) - .curve(d3.curveBasis); + }); + // .curve(d3.curveBasis); const svgPath = elem .append('path') .attr('d', lineFunction(lineData)) .attr('id', edge.id) .attr('class', 'transition'); + + // edge.points.forEach(point => { + // elem + // .append('circle') + // .style('stroke', 'red') + // .style('fill', 'red') + // .attr('r', 1) + // .attr('cx', point.x) + // .attr('cy', point.y); + // }); + let url = ''; if (getConfig().state.arrowMarkerAbsolute) { url = @@ -79,6 +213,6 @@ export const insertEdge = function(elem, edge) { url = url.replace(/\)/g, '\\)'); } - svgPath.attr('marker-end', 'url(' + url + '#' + 'extensionEnd' + ')'); - svgPath.attr('marker-start', 'url(' + url + '#' + 'extensionStart' + ')'); + svgPath.attr('marker-end', 'url(' + url + '#' + 'normalEnd' + ')'); + // svgPath.attr('marker-start', 'url(' + url + '#' + 'normalStart' + ')'); }; diff --git a/src/dagre-wrapper/index.js b/src/dagre-wrapper/index.js index d2f12c491..1ad515236 100644 --- a/src/dagre-wrapper/index.js +++ b/src/dagre-wrapper/index.js @@ -1,12 +1,23 @@ import dagre from 'dagre'; import insertMarkers from './markers'; -import { insertNode, positionNode } from './nodes'; -import { insertCluster } from './clusters'; -import { insertEdgeLabel, positionEdgeLabel, insertEdge } from './edges'; +import { insertNode, positionNode, clearNodes } from './nodes'; +import { insertCluster, clearClusters } from './clusters'; +import { insertEdgeLabel, positionEdgeLabel, insertEdge, clearEdges } from './edges'; import { logger } from '../logger'; +let clusterDb = {}; + +const translateClusterId = id => { + if (clusterDb[id]) return clusterDb[id].id; + return id; +}; + export const render = (elem, graph) => { insertMarkers(elem); + clusterDb = {}; + clearNodes(); + clearEdges(); + clearClusters(); const clusters = elem.insert('g').attr('class', 'clusters'); // eslint-disable-line const edgePaths = elem.insert('g').attr('class', 'edgePaths'); @@ -17,27 +28,41 @@ export const render = (elem, graph) => { // to the abstract node and is later used by dagre for the layout graph.nodes().forEach(function(v) { const node = graph.node(v); - logger.info('Node ' + v + ': ' + JSON.stringify(graph.node(v))); + logger.trace('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); + const children = graph.children(v); + logger.info('Cluster identified', node.id, children[0]); // nodes2expand.push({ id: children[0], width }); + clusterDb[node.id] = { id: children[0] }; + logger.info('Clusters ', clusterDb); } }); - // 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 + // Insert labels, this will insert them into the dom so that the width can be calculated + // Also figure out which edges point to/from clusters and adjust them accordingly + // Edges from/to clusters really points to the first child in the cluster. + // TODO: pick optimal child in the cluster to us as link anchor graph.edges().forEach(function(e) { - logger.trace('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(graph.edge(e))); - insertEdgeLabel(edgeLabels, graph.edge(e)); + const edge = graph.edge(e); + // logger.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(e)); + // logger.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(graph.edge(e))); + const v = translateClusterId(e.v); + const w = translateClusterId(e.w); + if (v !== e.v || w !== e.w) { + graph.removeEdge(e.v, e.w, e.name); + if (v !== e.v) edge.fromCluster = e.v; + if (w !== e.w) edge.toCluster = e.w; + graph.setEdge(v, w, edge, e.name); + } + insertEdgeLabel(edgeLabels, edge); }); + // graph.edges().forEach(function(e) { + // logger.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(e)); + // }); logger.info('#############################################'); logger.info('### Layout ###'); logger.info('#############################################'); @@ -46,11 +71,12 @@ export const render = (elem, graph) => { // Move the nodes to the correct place graph.nodes().forEach(function(v) { const node = graph.node(v); - logger.info('Node ' + v + ': ' + JSON.stringify(graph.node(v))); + logger.trace('Node ' + v + ': ' + JSON.stringify(graph.node(v))); if (node.type !== 'group') { positionNode(node); } else { insertCluster(clusters, node); + clusterDb[node.id].node = node; } }); @@ -59,7 +85,7 @@ export const render = (elem, graph) => { const edge = graph.edge(e); logger.trace('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(edge)); - insertEdge(edgePaths, edge); + insertEdge(edgePaths, edge, clusterDb); positionEdgeLabel(edge); }); }; diff --git a/src/dagre-wrapper/intersect/index.js b/src/dagre-wrapper/intersect/index.js index a68ea0bfa..5cf3a259c 100644 --- a/src/dagre-wrapper/intersect/index.js +++ b/src/dagre-wrapper/intersect/index.js @@ -8,7 +8,7 @@ import ellipse from './intersect-ellipse'; import polygon from './intersect-polygon'; import rect from './intersect-rect'; -module.exports = { +export default { node, circle, ellipse, diff --git a/src/dagre-wrapper/intersect/intersect-rect.js b/src/dagre-wrapper/intersect/intersect-rect.js index f8c03a2af..9847f9897 100644 --- a/src/dagre-wrapper/intersect/intersect-rect.js +++ b/src/dagre-wrapper/intersect/intersect-rect.js @@ -2,6 +2,7 @@ const intersectRect = (node, point) => { var x = node.x; var y = node.y; + console.log(node, point); // Rectangle intersection algorithm from: // http://math.stackexchange.com/questions/108113/find-edge-between-two-boxes var dx = point.x - x; diff --git a/src/dagre-wrapper/markers.js b/src/dagre-wrapper/markers.js index d81babf0d..c9c6cd703 100644 --- a/src/dagre-wrapper/markers.js +++ b/src/dagre-wrapper/markers.js @@ -101,6 +101,37 @@ const insertMarkers = elem => { .attr('orient', 'auto') .append('path') .attr('d', 'M 18,7 L9,13 L14,7 L9,1 Z'); + + elem + .append('marker') + .attr('id', 'normalEnd') + .attr('viewBox', '0 0 10 10') + .attr('refX', 9) + .attr('refY', 5) + .attr('markerUnits', 'strokeWidth') + .attr('markerWidth', 8) + .attr('markerHeight', 6) + .attr('orient', 'auto') + .append('path') + .attr('d', 'M 0 0 L 10 5 L 0 10 z') + .attr('class', 'arrowheadPath') + .style('stroke-width', 1) + .style('stroke-dasharray', '1,0'); + elem + .append('marker') + .attr('id', 'normalStart') + .attr('viewBox', '0 0 10 10') + .attr('refX', 9) + .attr('refY', 5) + .attr('markerUnits', 'strokeWidth') + .attr('markerWidth', 8) + .attr('markerHeight', 6) + .attr('orient', 'auto') + .append('path') + .attr('d', 'M 0 0 L 10 5 L 0 10 z') + .attr('class', 'arrowheadPath') + .style('stroke-width', 1) + .style('stroke-dasharray', '1,0'); }; export default insertMarkers; diff --git a/src/dagre-wrapper/nodes.js b/src/dagre-wrapper/nodes.js index 95d146da1..06e947dad 100644 --- a/src/dagre-wrapper/nodes.js +++ b/src/dagre-wrapper/nodes.js @@ -47,11 +47,14 @@ const rect = (parent, node) => { const shapes = { rect }; -const nodeElems = {}; +let nodeElems = {}; export const insertNode = (elem, node) => { nodeElems[node.id] = shapes[node.shape](elem, node); }; +export const clear = () => { + nodeElems = {}; +}; export const positionNode = node => { const el = nodeElems[node.id]; diff --git a/src/diagrams/flowchart/flowDb.js b/src/diagrams/flowchart/flowDb.js index 4917a54a7..d6d766da6 100644 --- a/src/diagrams/flowchart/flowDb.js +++ b/src/diagrams/flowchart/flowDb.js @@ -1,5 +1,5 @@ import * as d3 from 'd3'; -import { logger } from '../../logger'; +import { logger } from '../../logger'; // eslint-disable-line import utils from '../../utils'; import { getConfig } from '../../config'; import common from '../common/common'; @@ -88,7 +88,7 @@ export const addSingleLink = function(_start, _end, type, linktext) { let end = _end; if (start[0].match(/\d/)) start = MERMAID_DOM_ID_PREFIX + start; if (end[0].match(/\d/)) end = MERMAID_DOM_ID_PREFIX + end; - logger.info('Got edge...', start, end); + // logger.info('Got edge...', start, end); const edge = { start: start, end: end, type: undefined, text: '' }; linktext = type.text; From 9266eaef16495e3ce691fe95767b4183009dc96e Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Sat, 14 Mar 2020 17:49:02 +0100 Subject: [PATCH 08/22] #1295 Small fix for import --- src/dagre-wrapper/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dagre-wrapper/index.js b/src/dagre-wrapper/index.js index 1ad515236..bf3127a76 100644 --- a/src/dagre-wrapper/index.js +++ b/src/dagre-wrapper/index.js @@ -1,8 +1,8 @@ import dagre from 'dagre'; import insertMarkers from './markers'; -import { insertNode, positionNode, clearNodes } from './nodes'; -import { insertCluster, clearClusters } from './clusters'; -import { insertEdgeLabel, positionEdgeLabel, insertEdge, clearEdges } from './edges'; +import { insertNode, positionNode, clear as clearNodes } from './nodes'; +import { insertCluster, clear as clearClusters } from './clusters'; +import { insertEdgeLabel, positionEdgeLabel, insertEdge, clear as clearEdges } from './edges'; import { logger } from '../logger'; let clusterDb = {}; From 5b74d75011ec59264f0070f779f07df8aca834a7 Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Sat, 14 Mar 2020 18:13:34 +0100 Subject: [PATCH 09/22] #1295 Arrow head start --- cypress/platform/current.html | 6 +++- src/dagre-wrapper/GraphObjects.md | 5 +++ src/dagre-wrapper/edges.js | 14 ++++++--- src/dagre-wrapper/markers.js | 37 +++++++++++++++++++++++ src/diagrams/flowchart/flowRenderer-v2.js | 2 ++ 5 files changed, 59 insertions(+), 5 deletions(-) diff --git a/cypress/platform/current.html b/cypress/platform/current.html index 0f5d69915..56f2c3257 100644 --- a/cypress/platform/current.html +++ b/cypress/platform/current.html @@ -87,7 +87,7 @@ end b-->id1 -
+
flowchart RL subgraph id1 [Test1] @@ -101,6 +101,10 @@ b-->id1 id1 --> id2
+
+ flowchart LR + a o--o b +
diff --git a/src/dagre-wrapper/GraphObjects.md b/src/dagre-wrapper/GraphObjects.md index 9a982feb8..d073515b8 100644 --- a/src/dagre-wrapper/GraphObjects.md +++ b/src/dagre-wrapper/GraphObjects.md @@ -36,3 +36,8 @@ This is set by the renderer of the diagram and insert the data that the wrapper | 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. | + + +#edge + +arrowType sets the type of arrows to use diff --git a/src/dagre-wrapper/edges.js b/src/dagre-wrapper/edges.js index c2135abf0..e3c372220 100644 --- a/src/dagre-wrapper/edges.js +++ b/src/dagre-wrapper/edges.js @@ -169,7 +169,7 @@ export const insertEdge = function(elem, edge, clusterDb) { points = updatedPoints; } - logger.info('Points', points); + logger.info('Edge', edge); // The data for our line const lineData = points.filter(p => !Number.isNaN(p.y)); @@ -212,7 +212,13 @@ export const insertEdge = function(elem, edge, clusterDb) { url = url.replace(/\(/g, '\\('); url = url.replace(/\)/g, '\\)'); } - - svgPath.attr('marker-end', 'url(' + url + '#' + 'normalEnd' + ')'); - // svgPath.attr('marker-start', 'url(' + url + '#' + 'normalStart' + ')'); + switch (edge.arrowType) { + case 'double_arrow_circle': + svgPath.attr('marker-end', 'url(' + url + '#' + 'circleEnd' + ')'); + svgPath.attr('marker-start', 'url(' + url + '#' + 'circleStart' + ')'); + break; + case 'arrow_circle': + svgPath.attr('marker-end', 'url(' + url + '#' + 'circleEnd' + ')'); + break; + } }; diff --git a/src/dagre-wrapper/markers.js b/src/dagre-wrapper/markers.js index c9c6cd703..0515defc4 100644 --- a/src/dagre-wrapper/markers.js +++ b/src/dagre-wrapper/markers.js @@ -132,6 +132,43 @@ const insertMarkers = elem => { .attr('class', 'arrowheadPath') .style('stroke-width', 1) .style('stroke-dasharray', '1,0'); + elem + .append('marker') + .attr('id', 'circleEnd') + .attr('viewBox', '0 0 10 10') + .attr('refX', 10) + .attr('refY', 5) + .attr('markerUnits', 'strokeWidth') + .attr('markerWidth', 7) + .attr('markerHeight', 7) + .attr('orient', 'auto') + .append('circle') + .attr('cx', '5') + .attr('cy', '5') + .attr('r', '5') + .attr('fill', 'red') + .attr('class', 'arrowheadPath') + .style('stroke-width', 1) + .style('stroke-dasharray', '1,0'); + + elem + .append('marker') + .attr('id', 'circleStart') + .attr('viewBox', '0 0 10 10') + .attr('refX', 0) + .attr('refY', 5) + .attr('markerUnits', 'strokeWidth') + .attr('markerWidth', 7) + .attr('markerHeight', 7) + .attr('orient', 'auto') + .append('circle') + .attr('cx', '5') + .attr('cy', '5') + .attr('r', '5') + .attr('fill', 'red') + .attr('class', 'arrowheadPath') + .style('stroke-width', 1) + .style('stroke-dasharray', '1,0'); }; export default insertMarkers; diff --git a/src/diagrams/flowchart/flowRenderer-v2.js b/src/diagrams/flowchart/flowRenderer-v2.js index 29f599fe8..b4a278bcd 100644 --- a/src/diagrams/flowchart/flowRenderer-v2.js +++ b/src/diagrams/flowchart/flowRenderer-v2.js @@ -174,6 +174,7 @@ export const addEdges = function(edges, g) { } else { edgeData.arrowhead = 'normal'; } + edgeData.arrowType = edge.type; let style = ''; let labelStyle = ''; @@ -311,6 +312,7 @@ export const draw = function(text, id) { const edges = flowDb.getEdges(); + logger.info(edges); let i = 0; for (i = subGraphs.length - 1; i >= 0; i--) { subG = subGraphs[i]; From 215e930da4a374f70589fa5d7d90d70a950ded41 Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Mon, 16 Mar 2020 07:55:02 +0100 Subject: [PATCH 10/22] #1295 Markers implmented, the gereric pattern and diagram specific for flowcharts. --- cypress/platform/current.html | 13 +++- src/dagre-wrapper/GraphObjects.md | 28 +++++++- src/dagre-wrapper/edges.js | 23 +++++- src/dagre-wrapper/index.js | 4 +- src/dagre-wrapper/markers.js | 87 +++++++++++++++++++---- src/diagrams/flowchart/flowDb.js | 14 ++-- src/diagrams/flowchart/flowRenderer-v2.js | 2 +- 7 files changed, 140 insertions(+), 31 deletions(-) diff --git a/cypress/platform/current.html b/cypress/platform/current.html index 56f2c3257..b987d1b08 100644 --- a/cypress/platform/current.html +++ b/cypress/platform/current.html @@ -101,9 +101,20 @@ b-->id1 id1 --> id2 + new:
flowchart LR - a o--o b + a <--> b + b o--o c + c x--x d + a2 --> b2 + b2 --o c2 + c2 --x d2 +
+ old: +
+ graph LR + a --> b
diff --git a/src/dagre-wrapper/GraphObjects.md b/src/dagre-wrapper/GraphObjects.md index d073515b8..d6fd87648 100644 --- a/src/dagre-wrapper/GraphObjects.md +++ b/src/dagre-wrapper/GraphObjects.md @@ -38,6 +38,30 @@ This is set by the renderer of the diagram and insert the data that the wrapper | padding | Padding. Passed from the renderr as this might differ between react for different diagrams. Maybe obsolete. | -#edge +# edge -arrowType sets the type of arrows to use +arrowType sets the type of arrows to use. The following arrow types are currently supported: + +arrow_cross +double_arrow_cross +arrow_point +double_arrow_point +arrow_circle +double_arrow_circle + +Lets try to make these types semantic free so that diagram type semantics does not find its way in to this more generic layer. + + +# Markers + +Define what markers that should be included in the diagram with the insert markers function. The function takes two arguments, first the element in which the markers should be included and a list of the markers that should be added. + +Ex: +insertMarkers(el, ['point', 'circle']) + +The example above adds the markers point and cross. This means that edges with the arrowTypes arrow_cross, double_arrow_cross, arrow_point and double_arrow_cross will get the corresponding markers but arrowType arrow_cross will have no impact. + +Current markers: +* point - the standard arrow from flowcharts +* circle - Arrows ending with circle +* cross - arrows starting and ending with a cross \ No newline at end of file diff --git a/src/dagre-wrapper/edges.js b/src/dagre-wrapper/edges.js index e3c372220..d81f1c13f 100644 --- a/src/dagre-wrapper/edges.js +++ b/src/dagre-wrapper/edges.js @@ -191,6 +191,7 @@ export const insertEdge = function(elem, edge, clusterDb) { .attr('id', edge.id) .attr('class', 'transition'); + // DEBUG code, adds a red circle at each edge coordinate // edge.points.forEach(point => { // elem // .append('circle') @@ -212,13 +213,29 @@ export const insertEdge = function(elem, edge, clusterDb) { url = url.replace(/\(/g, '\\('); url = url.replace(/\)/g, '\\)'); } + logger.info('arrowType', edge.arrowType); switch (edge.arrowType) { - case 'double_arrow_circle': - svgPath.attr('marker-end', 'url(' + url + '#' + 'circleEnd' + ')'); - svgPath.attr('marker-start', 'url(' + url + '#' + 'circleStart' + ')'); + case 'arrow_cross': + svgPath.attr('marker-end', 'url(' + url + '#' + 'crossEnd' + ')'); + break; + case 'double_arrow_cross': + svgPath.attr('marker-end', 'url(' + url + '#' + 'crossEnd' + ')'); + svgPath.attr('marker-start', 'url(' + url + '#' + 'crossStart' + ')'); + break; + case 'arrow_point': + svgPath.attr('marker-end', 'url(' + url + '#' + 'pointEnd' + ')'); + break; + case 'double_arrow_point': + svgPath.attr('marker-end', 'url(' + url + '#' + 'pointEnd' + ')'); + svgPath.attr('marker-start', 'url(' + url + '#' + 'pointStart' + ')'); break; case 'arrow_circle': svgPath.attr('marker-end', 'url(' + url + '#' + 'circleEnd' + ')'); break; + case 'double_arrow_circle': + svgPath.attr('marker-end', 'url(' + url + '#' + 'circleEnd' + ')'); + svgPath.attr('marker-start', 'url(' + url + '#' + 'circleStart' + ')'); + break; + default: } }; diff --git a/src/dagre-wrapper/index.js b/src/dagre-wrapper/index.js index bf3127a76..dbfbcc3ee 100644 --- a/src/dagre-wrapper/index.js +++ b/src/dagre-wrapper/index.js @@ -12,8 +12,8 @@ const translateClusterId = id => { return id; }; -export const render = (elem, graph) => { - insertMarkers(elem); +export const render = (elem, graph, markers) => { + insertMarkers(elem, markers); clusterDb = {}; clearNodes(); clearEdges(); diff --git a/src/dagre-wrapper/markers.js b/src/dagre-wrapper/markers.js index 0515defc4..2850b6714 100644 --- a/src/dagre-wrapper/markers.js +++ b/src/dagre-wrapper/markers.js @@ -1,7 +1,14 @@ /** * Setup arrow head and define the marker. The result is appended to the svg. */ -const insertMarkers = elem => { +// Only add the number of markers that the diagram needs +const insertMarkers = (elem, markerArray) => { + markerArray.forEach(markerName => { + markers[markerName](elem); + }); +}; + +const extension = elem => { elem .append('defs') .append('marker') @@ -26,7 +33,9 @@ const insertMarkers = elem => { .attr('orient', 'auto') .append('path') .attr('d', 'M 1,1 V 13 L18,7 Z'); // this is actual shape for arrowhead +}; +const composition = elem => { elem .append('defs') .append('marker') @@ -51,7 +60,8 @@ const insertMarkers = elem => { .attr('orient', 'auto') .append('path') .attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z'); - +}; +const aggregation = elem => { elem .append('defs') .append('marker') @@ -76,7 +86,8 @@ const insertMarkers = elem => { .attr('orient', 'auto') .append('path') .attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z'); - +}; +const dependency = elem => { elem .append('defs') .append('marker') @@ -101,16 +112,17 @@ const insertMarkers = elem => { .attr('orient', 'auto') .append('path') .attr('d', 'M 18,7 L9,13 L14,7 L9,1 Z'); - +}; +const point = elem => { elem .append('marker') - .attr('id', 'normalEnd') + .attr('id', 'pointEnd') .attr('viewBox', '0 0 10 10') - .attr('refX', 9) + .attr('refX', 10) .attr('refY', 5) .attr('markerUnits', 'strokeWidth') .attr('markerWidth', 8) - .attr('markerHeight', 6) + .attr('markerHeight', 8) .attr('orient', 'auto') .append('path') .attr('d', 'M 0 0 L 10 5 L 0 10 z') @@ -119,24 +131,26 @@ const insertMarkers = elem => { .style('stroke-dasharray', '1,0'); elem .append('marker') - .attr('id', 'normalStart') + .attr('id', 'pointStart') .attr('viewBox', '0 0 10 10') - .attr('refX', 9) + .attr('refX', 0) .attr('refY', 5) .attr('markerUnits', 'strokeWidth') .attr('markerWidth', 8) - .attr('markerHeight', 6) + .attr('markerHeight', 8) .attr('orient', 'auto') .append('path') - .attr('d', 'M 0 0 L 10 5 L 0 10 z') + .attr('d', 'M 0 5 L 10 10 L 10 0 z') .attr('class', 'arrowheadPath') .style('stroke-width', 1) .style('stroke-dasharray', '1,0'); +}; +const circle = elem => { elem .append('marker') .attr('id', 'circleEnd') .attr('viewBox', '0 0 10 10') - .attr('refX', 10) + .attr('refX', 11) .attr('refY', 5) .attr('markerUnits', 'strokeWidth') .attr('markerWidth', 7) @@ -146,7 +160,6 @@ const insertMarkers = elem => { .attr('cx', '5') .attr('cy', '5') .attr('r', '5') - .attr('fill', 'red') .attr('class', 'arrowheadPath') .style('stroke-width', 1) .style('stroke-dasharray', '1,0'); @@ -155,7 +168,7 @@ const insertMarkers = elem => { .append('marker') .attr('id', 'circleStart') .attr('viewBox', '0 0 10 10') - .attr('refX', 0) + .attr('refX', -1) .attr('refY', 5) .attr('markerUnits', 'strokeWidth') .attr('markerWidth', 7) @@ -165,10 +178,54 @@ const insertMarkers = elem => { .attr('cx', '5') .attr('cy', '5') .attr('r', '5') - .attr('fill', 'red') .attr('class', 'arrowheadPath') .style('stroke-width', 1) .style('stroke-dasharray', '1,0'); }; +const cross = elem => { + elem + .append('marker') + .attr('id', 'crossEnd') + .attr('viewBox', '0 0 11 11') + .attr('refX', 12) + .attr('refY', 5.2) + .attr('markerUnits', 'strokeWidth') + .attr('markerWidth', 7) + .attr('markerHeight', 7) + .attr('orient', 'auto') + .append('path') + .attr('stroke', 'black') + .attr('d', 'M 1,1 l 9,9 M 10,1 l -9,9') + .attr('class', 'arrowheadPath') + .style('stroke-width', 2) + .style('stroke-dasharray', '1,0'); + elem + .append('marker') + .attr('id', 'crossStart') + .attr('viewBox', '0 0 11 11') + .attr('refX', -1) + .attr('refY', 5.2) + .attr('markerUnits', 'strokeWidth') + .attr('markerWidth', 7) + .attr('markerHeight', 7) + .attr('orient', 'auto') + .append('path') + .attr('stroke', 'black') + .attr('d', 'M 1,1 l 9,9 M 10,1 l -9,9') + .attr('class', 'arrowheadPath') + .style('stroke-width', 2) + .style('stroke-dasharray', '1,0'); +}; + +// TODO rename the class diagram markers to something shape descriptive and semanitc free +const markers = { + extension, + composition, + aggregation, + dependency, + point, + circle, + cross +}; export default insertMarkers; diff --git a/src/diagrams/flowchart/flowDb.js b/src/diagrams/flowchart/flowDb.js index d6d766da6..375b1b8ae 100644 --- a/src/diagrams/flowchart/flowDb.js +++ b/src/diagrams/flowchart/flowDb.js @@ -496,19 +496,19 @@ const destructStartLink = _str => { switch (str) { case '<--': - return { type: 'arrow', stroke: 'normal' }; + return { type: 'arrow_point', stroke: 'normal' }; case 'x--': return { type: 'arrow_cross', stroke: 'normal' }; case 'o--': return { type: 'arrow_circle', stroke: 'normal' }; case '<-.': - return { type: 'arrow', stroke: 'dotted' }; + return { type: 'arrow_point', stroke: 'dotted' }; case 'x-.': return { type: 'arrow_cross', stroke: 'dotted' }; case 'o-.': return { type: 'arrow_circle', stroke: 'dotted' }; case '<==': - return { type: 'arrow', stroke: 'thick' }; + return { type: 'arrow_point', stroke: 'thick' }; case 'x==': return { type: 'arrow_cross', stroke: 'thick' }; case 'o==': @@ -529,7 +529,7 @@ const destructEndLink = _str => { case '--x': return { type: 'arrow_cross', stroke: 'normal' }; case '-->': - return { type: 'arrow', stroke: 'normal' }; + return { type: 'arrow_point', stroke: 'normal' }; case '<-->': return { type: 'double_arrow_point', stroke: 'normal' }; case 'x--x': @@ -561,7 +561,7 @@ const destructEndLink = _str => { case '-.-x': return { type: 'arrow_cross', stroke: 'dotted' }; case '-.->': - return { type: 'arrow', stroke: 'dotted' }; + return { type: 'arrow_point', stroke: 'dotted' }; case '-.-o': return { type: 'arrow_circle', stroke: 'dotted' }; case '-.-': @@ -569,7 +569,7 @@ const destructEndLink = _str => { case '.-x': return { type: 'arrow_cross', stroke: 'dotted' }; case '.->': - return { type: 'arrow', stroke: 'dotted' }; + return { type: 'arrow_point', stroke: 'dotted' }; case '.-o': return { type: 'arrow_circle', stroke: 'dotted' }; case '.-': @@ -577,7 +577,7 @@ const destructEndLink = _str => { case '==x': return { type: 'arrow_cross', stroke: 'thick' }; case '==>': - return { type: 'arrow', stroke: 'thick' }; + return { type: 'arrow_point', stroke: 'thick' }; case '==o': return { type: 'arrow_circle', stroke: 'thick' }; case '===': diff --git a/src/diagrams/flowchart/flowRenderer-v2.js b/src/diagrams/flowchart/flowRenderer-v2.js index b4a278bcd..e1866d396 100644 --- a/src/diagrams/flowchart/flowRenderer-v2.js +++ b/src/diagrams/flowchart/flowRenderer-v2.js @@ -372,7 +372,7 @@ export const draw = function(text, id) { // Run the renderer. This is what draws the final graph. const element = d3.select('#' + id + ' g'); - render(element, g); + render(element, g, ['point', 'circle', 'cross']); dagre.layout(g); element.selectAll('g.node').attr('title', function() { From 4010c89899dc77cc8c568e98ab41529c60d3ce14 Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Mon, 16 Mar 2020 08:02:32 +0100 Subject: [PATCH 11/22] #1295 'arrow' renamed to 'arrow_point' --- .../flowchart/parser/flow-arrows.spec.js | 16 +++---- .../flowchart/parser/flow-comments.spec.js | 18 +++---- .../flowchart/parser/flow-huge.spec.js | 2 +- .../flowchart/parser/flow-style.spec.js | 8 ++-- .../flowchart/parser/flow-text.spec.js | 6 +-- .../parser/flow-vertice-chaining.spec.js | 48 +++++++++---------- src/diagrams/flowchart/parser/flow.spec.js | 2 +- .../flowchart/parser/subgraph.spec.js | 24 +++++----- 8 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/diagrams/flowchart/parser/flow-arrows.spec.js b/src/diagrams/flowchart/parser/flow-arrows.spec.js index 511dadda6..5f27457e7 100644 --- a/src/diagrams/flowchart/parser/flow-arrows.spec.js +++ b/src/diagrams/flowchart/parser/flow-arrows.spec.js @@ -23,7 +23,7 @@ describe('[Arrows] when parsing', () => { expect(edges.length).toBe(1); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); }); @@ -41,7 +41,7 @@ describe('[Arrows] when parsing', () => { expect(edges.length).toBe(1); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); }); @@ -59,7 +59,7 @@ describe('[Arrows] when parsing', () => { expect(edges.length).toBe(1); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); }); @@ -77,7 +77,7 @@ describe('[Arrows] when parsing', () => { expect(edges.length).toBe(1); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); }); @@ -95,7 +95,7 @@ describe('[Arrows] when parsing', () => { expect(edges.length).toBe(1); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); }); @@ -110,7 +110,7 @@ describe('[Arrows] when parsing', () => { expect(edges.length).toBe(1); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); }); @@ -125,7 +125,7 @@ describe('[Arrows] when parsing', () => { expect(edges.length).toBe(1); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); }); @@ -140,7 +140,7 @@ describe('[Arrows] when parsing', () => { expect(edges.length).toBe(2); expect(edges[1].start).toBe('B'); expect(edges[1].end).toBe('C'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); }); diff --git a/src/diagrams/flowchart/parser/flow-comments.spec.js b/src/diagrams/flowchart/parser/flow-comments.spec.js index e05caadd0..3b3a2da3c 100644 --- a/src/diagrams/flowchart/parser/flow-comments.spec.js +++ b/src/diagrams/flowchart/parser/flow-comments.spec.js @@ -23,7 +23,7 @@ describe('[Comments] when parsing', () => { expect(edges.length).toBe(1); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); }); @@ -38,7 +38,7 @@ describe('[Comments] when parsing', () => { expect(edges.length).toBe(1); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); }); @@ -53,7 +53,7 @@ describe('[Comments] when parsing', () => { expect(edges.length).toBe(1); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); }); @@ -68,7 +68,7 @@ describe('[Comments] when parsing', () => { expect(edges.length).toBe(1); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); }); @@ -83,7 +83,7 @@ describe('[Comments] when parsing', () => { expect(edges.length).toBe(1); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); }); @@ -98,7 +98,7 @@ describe('[Comments] when parsing', () => { expect(edges.length).toBe(1); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); }); @@ -113,7 +113,7 @@ describe('[Comments] when parsing', () => { expect(edges.length).toBe(1); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); }); @@ -128,7 +128,7 @@ describe('[Comments] when parsing', () => { expect(edges.length).toBe(1); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); }); @@ -145,7 +145,7 @@ describe('[Comments] when parsing', () => { expect(edges.length).toBe(1); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); }); }); diff --git a/src/diagrams/flowchart/parser/flow-huge.spec.js b/src/diagrams/flowchart/parser/flow-huge.spec.js index 901a615a2..8cdfd7593 100644 --- a/src/diagrams/flowchart/parser/flow-huge.spec.js +++ b/src/diagrams/flowchart/parser/flow-huge.spec.js @@ -19,7 +19,7 @@ describe('[Text] when parsing', () => { const vert = flow.parser.yy.getVertices(); const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges.length).toBe(47917); console.log(vert); expect(Object.keys(vert).length).toBe(2); diff --git a/src/diagrams/flowchart/parser/flow-style.spec.js b/src/diagrams/flowchart/parser/flow-style.spec.js index db92660ae..fc388aa8f 100644 --- a/src/diagrams/flowchart/parser/flow-style.spec.js +++ b/src/diagrams/flowchart/parser/flow-style.spec.js @@ -273,7 +273,7 @@ describe('[Style] when parsing', () => { const vert = flow.parser.yy.getVertices(); const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); }); it('should handle multi-numbered style definitons with more then 1 digit in a row', function() { @@ -297,7 +297,7 @@ describe('[Style] when parsing', () => { const vert = flow.parser.yy.getVertices(); const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); }); it('should handle classDefs with style in classes', function() { @@ -306,7 +306,7 @@ describe('[Style] when parsing', () => { const vert = flow.parser.yy.getVertices(); const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); }); it('should handle classDefs with % in classes', function() { @@ -317,6 +317,6 @@ describe('[Style] when parsing', () => { const vert = flow.parser.yy.getVertices(); const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); }); }); diff --git a/src/diagrams/flowchart/parser/flow-text.spec.js b/src/diagrams/flowchart/parser/flow-text.spec.js index 29979ce54..61703000a 100644 --- a/src/diagrams/flowchart/parser/flow-text.spec.js +++ b/src/diagrams/flowchart/parser/flow-text.spec.js @@ -74,7 +74,7 @@ describe('[Text] when parsing', () => { const vert = flow.parser.yy.getVertices(); const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe('text including URL space and send'); }); it('should handle space and send', function() { @@ -83,7 +83,7 @@ describe('[Text] when parsing', () => { const vert = flow.parser.yy.getVertices(); const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe('text including URL space and send'); }); @@ -380,7 +380,7 @@ describe('[Text] when parsing', () => { const edges = flow.parser.yy.getEdges(); expect(edges[0].type).toBe('arrow_circle'); - expect(edges[1].type).toBe('arrow'); + expect(edges[1].type).toBe('arrow_point'); expect(vert['A'].id).toBe('A'); expect(vert['B'].id).toBe('B'); expect(vert['C'].id).toBe('C'); diff --git a/src/diagrams/flowchart/parser/flow-vertice-chaining.spec.js b/src/diagrams/flowchart/parser/flow-vertice-chaining.spec.js index 64259ea1d..796075996 100644 --- a/src/diagrams/flowchart/parser/flow-vertice-chaining.spec.js +++ b/src/diagrams/flowchart/parser/flow-vertice-chaining.spec.js @@ -27,11 +27,11 @@ describe('when parsing flowcharts', function() { expect(edges.length).toBe(2); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); expect(edges[1].start).toBe('B'); expect(edges[1].end).toBe('C'); - expect(edges[1].type).toBe('arrow'); + expect(edges[1].type).toBe('arrow_point'); expect(edges[1].text).toBe(''); }); it('should handle chaining of vertices', function() { @@ -49,11 +49,11 @@ describe('when parsing flowcharts', function() { expect(edges.length).toBe(2); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('C'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); expect(edges[1].start).toBe('B'); expect(edges[1].end).toBe('C'); - expect(edges[1].type).toBe('arrow'); + expect(edges[1].type).toBe('arrow_point'); expect(edges[1].text).toBe(''); }); it('should multiple vertices in link statement in the begining', function() { @@ -71,11 +71,11 @@ describe('when parsing flowcharts', function() { expect(edges.length).toBe(2); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); expect(edges[1].start).toBe('A'); expect(edges[1].end).toBe('C'); - expect(edges[1].type).toBe('arrow'); + expect(edges[1].type).toBe('arrow_point'); expect(edges[1].text).toBe(''); }); it('should multiple vertices in link statement at the end', function() { @@ -94,19 +94,19 @@ describe('when parsing flowcharts', function() { expect(edges.length).toBe(4); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('C'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); expect(edges[1].start).toBe('A'); expect(edges[1].end).toBe('D'); - expect(edges[1].type).toBe('arrow'); + expect(edges[1].type).toBe('arrow_point'); expect(edges[1].text).toBe(''); expect(edges[2].start).toBe('B'); expect(edges[2].end).toBe('C'); - expect(edges[2].type).toBe('arrow'); + expect(edges[2].type).toBe('arrow_point'); expect(edges[2].text).toBe(''); expect(edges[3].start).toBe('B'); expect(edges[3].end).toBe('D'); - expect(edges[3].type).toBe('arrow'); + expect(edges[3].type).toBe('arrow_point'); expect(edges[3].text).toBe(''); }); it('should handle chaining of vertices at both ends at once', function() { @@ -125,19 +125,19 @@ describe('when parsing flowcharts', function() { expect(edges.length).toBe(4); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('C'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); expect(edges[1].start).toBe('A'); expect(edges[1].end).toBe('D'); - expect(edges[1].type).toBe('arrow'); + expect(edges[1].type).toBe('arrow_point'); expect(edges[1].text).toBe(''); expect(edges[2].start).toBe('B'); expect(edges[2].end).toBe('C'); - expect(edges[2].type).toBe('arrow'); + expect(edges[2].type).toBe('arrow_point'); expect(edges[2].text).toBe(''); expect(edges[3].start).toBe('B'); expect(edges[3].end).toBe('D'); - expect(edges[3].type).toBe('arrow'); + expect(edges[3].type).toBe('arrow_point'); expect(edges[3].text).toBe(''); }); it('should handle chaining and multiple nodes in in link statement FVC ', function() { @@ -157,27 +157,27 @@ describe('when parsing flowcharts', function() { expect(edges.length).toBe(6); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); expect(edges[1].start).toBe('A'); expect(edges[1].end).toBe('B2'); - expect(edges[1].type).toBe('arrow'); + expect(edges[1].type).toBe('arrow_point'); expect(edges[1].text).toBe(''); expect(edges[2].start).toBe('A'); expect(edges[2].end).toBe('C'); - expect(edges[2].type).toBe('arrow'); + expect(edges[2].type).toBe('arrow_point'); expect(edges[2].text).toBe(''); expect(edges[3].start).toBe('B'); expect(edges[3].end).toBe('D2'); - expect(edges[3].type).toBe('arrow'); + expect(edges[3].type).toBe('arrow_point'); expect(edges[3].text).toBe(''); expect(edges[4].start).toBe('B2'); expect(edges[4].end).toBe('D2'); - expect(edges[4].type).toBe('arrow'); + expect(edges[4].type).toBe('arrow_point'); expect(edges[4].text).toBe(''); expect(edges[5].start).toBe('C'); expect(edges[5].end).toBe('D2'); - expect(edges[5].type).toBe('arrow'); + expect(edges[5].type).toBe('arrow_point'); expect(edges[5].text).toBe(''); }); it('should handle chaining and multiple nodes in in link statement with extra info in statements', function() { @@ -203,19 +203,19 @@ describe('when parsing flowcharts', function() { expect(edges.length).toBe(4); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe('hello'); expect(edges[1].start).toBe('A'); expect(edges[1].end).toBe('C'); - expect(edges[1].type).toBe('arrow'); + expect(edges[1].type).toBe('arrow_point'); expect(edges[1].text).toBe('hello'); expect(edges[2].start).toBe('B'); expect(edges[2].end).toBe('D'); - expect(edges[2].type).toBe('arrow'); + expect(edges[2].type).toBe('arrow_point'); expect(edges[2].text).toBe(''); expect(edges[3].start).toBe('C'); expect(edges[3].end).toBe('D'); - expect(edges[3].type).toBe('arrow'); + expect(edges[3].type).toBe('arrow_point'); expect(edges[3].text).toBe(''); }); }); diff --git a/src/diagrams/flowchart/parser/flow.spec.js b/src/diagrams/flowchart/parser/flow.spec.js index 20899fbce..8c844cfc4 100644 --- a/src/diagrams/flowchart/parser/flow.spec.js +++ b/src/diagrams/flowchart/parser/flow.spec.js @@ -23,7 +23,7 @@ describe('when parsing ', function() { expect(edges.length).toBe(2); expect(edges[0].start).toBe('A'); expect(edges[0].end).toBe('B'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); expect(edges[0].text).toBe(''); }); diff --git a/src/diagrams/flowchart/parser/subgraph.spec.js b/src/diagrams/flowchart/parser/subgraph.spec.js index 3f9a83b67..e2e412b40 100644 --- a/src/diagrams/flowchart/parser/subgraph.spec.js +++ b/src/diagrams/flowchart/parser/subgraph.spec.js @@ -93,7 +93,7 @@ describe('when parsing subgraphs', function() { const vert = flow.parser.yy.getVertices(); const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); }); it('should handle subgraphs with title in quotes', function() { const res = flow.parser.parse('graph TD;A-->B;subgraph "title in quotes";c-->d;end;'); @@ -107,7 +107,7 @@ describe('when parsing subgraphs', function() { expect(subgraph.title).toBe('title in quotes'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); }); it('should handle subgraphs in old style that was broken', function() { const res = flow.parser.parse('graph TD;A-->B;subgraph old style that is broken;c-->d;end;'); @@ -121,7 +121,7 @@ describe('when parsing subgraphs', function() { expect(subgraph.title).toBe('old style that is broken'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); }); it('should handle subgraphs with dashes in the title', function() { const res = flow.parser.parse('graph TD;A-->B;subgraph a-b-c;c-->d;end;'); @@ -135,7 +135,7 @@ describe('when parsing subgraphs', function() { expect(subgraph.title).toBe('a-b-c'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); }); it('should handle subgraphs with id and title in brackets', function() { const res = flow.parser.parse('graph TD;A-->B;subgraph uid1[text of doom];c-->d;end;'); @@ -150,7 +150,7 @@ describe('when parsing subgraphs', function() { expect(subgraph.title).toBe('text of doom'); expect(subgraph.id).toBe('uid1'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); }); it('should handle subgraphs with id and title in brackets and quotes', function() { const res = flow.parser.parse('graph TD;A-->B;subgraph uid2["text of doom"];c-->d;end;'); @@ -165,7 +165,7 @@ describe('when parsing subgraphs', function() { expect(subgraph.title).toBe('text of doom'); expect(subgraph.id).toBe('uid2'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); }); it('should handle subgraphs with id and title in brackets without spaces', function() { const res = flow.parser.parse('graph TD;A-->B;subgraph uid2[textofdoom];c-->d;end;'); @@ -180,7 +180,7 @@ describe('when parsing subgraphs', function() { expect(subgraph.title).toBe('textofdoom'); expect(subgraph.id).toBe('uid2'); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); }); it('should handle subgraphs2', function() { @@ -189,7 +189,7 @@ describe('when parsing subgraphs', function() { const vert = flow.parser.yy.getVertices(); const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); }); it('should handle subgraphs3', function() { @@ -198,7 +198,7 @@ describe('when parsing subgraphs', function() { const vert = flow.parser.yy.getVertices(); const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); }); it('should handle nested subgraphs', function() { @@ -219,7 +219,7 @@ describe('when parsing subgraphs', function() { const vert = flow.parser.yy.getVertices(); const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); }); it('should handle subgraphs5', function() { @@ -228,7 +228,7 @@ describe('when parsing subgraphs', function() { const vert = flow.parser.yy.getVertices(); const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); }); it('should handle subgraphs with multi node statements in it', function() { const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\na & b --> c & e\n end;'); @@ -236,6 +236,6 @@ describe('when parsing subgraphs', function() { const vert = flow.parser.yy.getVertices(); const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow'); + expect(edges[0].type).toBe('arrow_point'); }); }); From 17f06564a287cecaddee0324ed28ba9a9b4f7b68 Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Wed, 18 Mar 2020 22:08:19 +0100 Subject: [PATCH 12/22] #1295 Added the flowchart shapes --- cypress/platform/current.html | 9 +- src/dagre-wrapper/intersect/index.js | 10 +- src/dagre-wrapper/nodes.js | 350 +++++++++++++++++++++- src/diagrams/flowchart/flowRenderer-v2.js | 38 --- 4 files changed, 346 insertions(+), 61 deletions(-) diff --git a/cypress/platform/current.html b/cypress/platform/current.html index b987d1b08..e48303f0e 100644 --- a/cypress/platform/current.html +++ b/cypress/platform/current.html @@ -107,14 +107,15 @@ a <--> b b o--o c c x--x d - a2 --> b2 - b2 --o c2 - c2 --x d2 + a21([In the box]) --> b2 + b2((b2)) --o c2 + c2(c2) --x d2 --> id1{{This is the text in the box}} --> A[(cylindrical
shape
test)] old:
graph LR - a --> b + a((a)) --> b --> id1{{This is the text in the box}} + A[(cylindrical
shape
test)]
diff --git a/src/dagre-wrapper/intersect/index.js b/src/dagre-wrapper/intersect/index.js index 5cf3a259c..20c3a8ccb 100644 --- a/src/dagre-wrapper/intersect/index.js +++ b/src/dagre-wrapper/intersect/index.js @@ -2,11 +2,11 @@ * Borrowed with love from from dagrge-d3. Many thanks to cpettitt! */ -import node from './intersect-node'; -import circle from './intersect-circle'; -import ellipse from './intersect-ellipse'; -import polygon from './intersect-polygon'; -import rect from './intersect-rect'; +import node from './intersect-node.js'; +import circle from './intersect-circle.js'; +import ellipse from './intersect-ellipse.js'; +import polygon from './intersect-polygon.js'; +import rect from './intersect-rect.js'; export default { node, diff --git a/src/dagre-wrapper/nodes.js b/src/dagre-wrapper/nodes.js index 06e947dad..78c8d98c8 100644 --- a/src/dagre-wrapper/nodes.js +++ b/src/dagre-wrapper/nodes.js @@ -1,17 +1,14 @@ -import intersectRect from './intersect/intersect-rect'; +import intersect from './intersect/index.js'; import { logger } from '../logger'; // eslint-disable-line import createLabel from './createLabel'; -const rect = (parent, node) => { +const labelHelper = (parent, node) => { // Add outer g element const shapeSvg = parent .insert('g') .attr('class', 'node default') .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', 'label'); @@ -22,7 +19,279 @@ const rect = (parent, node) => { const halfPadding = node.padding / 2; - // center the rect around its coordinate + // Center the label + label.attr('transform', 'translate(' + -bbox.width / 2 + ', ' + -bbox.height / 2 + ')'); + + return { shapeSvg, bbox, halfPadding, label }; +}; + +const updateNodeBounds = (node, element) => { + const bbox = element.node().getBBox(); + node.width = bbox.width; + node.height = bbox.height; +}; + +function insertPolygonShape(parent, w, h, points) { + return parent + .insert('polygon', ':first-child') + .attr( + 'points', + points + .map(function(d) { + return d.x + ',' + d.y; + }) + .join(' ') + ) + .attr('transform', 'translate(' + -w / 2 + ',' + h / 2 + ')'); +} +const question = (parent, node) => { + const { shapeSvg, bbox } = labelHelper(parent, node); + + const w = bbox.width + node.padding; + const h = bbox.height + node.padding; + const s = (w + h) * 0.9; + const points = [ + { x: s / 2, y: 0 }, + { x: s, y: -s / 2 }, + { x: s / 2, y: -s }, + { x: 0, y: -s / 2 } + ]; + + const questionElem = insertPolygonShape(shapeSvg, s, s, points); + updateNodeBounds(node, questionElem); + node.intersect = function(point) { + return intersect.polugon(node, points, point); + }; + + return shapeSvg; +}; + +const hexagon = (parent, node) => { + const { shapeSvg, bbox } = labelHelper(parent, node); + + const f = 4; + const h = bbox.height + node.padding; + const m = h / f; + const w = bbox.width + 2 * m + node.padding; + const points = [ + { x: m, y: 0 }, + { x: w - m, y: 0 }, + { x: w, y: -h / 2 }, + { x: w - m, y: -h }, + { x: m, y: -h }, + { x: 0, y: -h / 2 } + ]; + const hex = insertPolygonShape(shapeSvg, w, h, points); + updateNodeBounds(node, hex); + + node.intersect = function(point) { + return intersect.polygon(node, point); + }; + + return shapeSvg; +}; + +const rect_left_inv_arrow = (parent, node) => { + const { shapeSvg, bbox } = labelHelper(parent, node); + + const w = bbox.width + node.padding; + const h = bbox.height + node.padding; + const points = [ + { x: -h / 2, y: 0 }, + { x: w, y: 0 }, + { x: w, y: -h }, + { x: -h / 2, y: -h }, + { x: 0, y: -h / 2 } + ]; + + const el = insertPolygonShape(shapeSvg, w, h, points); + updateNodeBounds(node, el); + + node.intersect = function(point) { + return intersect.polygon(node, point); + }; + + return shapeSvg; +}; +const lean_right = (parent, node) => { + const { shapeSvg, bbox } = labelHelper(parent, node); + + const w = bbox.width + node.padding; + const h = bbox.height + node.padding; + const points = [ + { x: (-2 * h) / 6, y: 0 }, + { x: w - h / 6, y: 0 }, + { x: w + (2 * h) / 6, y: -h }, + { x: h / 6, y: -h } + ]; + + const el = insertPolygonShape(shapeSvg, w, h, points); + updateNodeBounds(node, el); + + node.intersect = function(point) { + return intersect.polygon(node, point); + }; + + return shapeSvg; +}; + +const lean_left = (parent, node) => { + const { shapeSvg, bbox } = labelHelper(parent, node); + + const w = bbox.width + node.padding; + const h = bbox.height + node.padding; + const points = [ + { x: (2 * h) / 6, y: 0 }, + { x: w + h / 6, y: 0 }, + { x: w - (2 * h) / 6, y: -h }, + { x: -h / 6, y: -h } + ]; + + const el = insertPolygonShape(shapeSvg, w, h, points); + updateNodeBounds(node, el); + + node.intersect = function(point) { + return intersect.polygon(node, point); + }; + + return shapeSvg; +}; + +const trapezoid = (parent, node) => { + const { shapeSvg, bbox } = labelHelper(parent, node); + + const w = bbox.width + node.padding; + const h = bbox.height + node.padding; + const points = [ + { x: (-2 * h) / 6, y: 0 }, + { x: w + (2 * h) / 6, y: 0 }, + { x: w - h / 6, y: -h }, + { x: h / 6, y: -h } + ]; + const el = insertPolygonShape(shapeSvg, w, h, points); + updateNodeBounds(node, el); + + node.intersect = function(point) { + return intersect.polygon(node, point); + }; + + return shapeSvg; +}; + +const inv_trapezoid = (parent, node) => { + const { shapeSvg, bbox } = labelHelper(parent, node); + + const w = bbox.width + node.padding; + const h = bbox.height + node.padding; + const points = [ + { x: h / 6, y: 0 }, + { x: w - h / 6, y: 0 }, + { x: w + (2 * h) / 6, y: -h }, + { x: (-2 * h) / 6, y: -h } + ]; + const el = insertPolygonShape(shapeSvg, w, h, points); + updateNodeBounds(node, el); + + node.intersect = function(point) { + return intersect.polygon(node, point); + }; + + return shapeSvg; +}; +const rect_right_inv_arrow = (parent, node) => { + const { shapeSvg, bbox } = labelHelper(parent, node); + + const w = bbox.width + node.padding; + const h = bbox.height + node.padding; + const points = [ + { x: 0, y: 0 }, + { x: w + h / 2, y: 0 }, + { x: w, y: -h / 2 }, + { x: w + h / 2, y: -h }, + { x: 0, y: -h } + ]; + const el = insertPolygonShape(shapeSvg, w, h, points); + updateNodeBounds(node, el); + + node.intersect = function(point) { + return intersect.polygon(node, point); + }; + + return shapeSvg; +}; +const cylinder = (parent, node) => { + const { shapeSvg, bbox } = labelHelper(parent, node); + + const w = bbox.width + node.padding; + const rx = w / 2; + const ry = rx / (2.5 + w / 50); + const h = bbox.height + ry + node.padding; + + const shape = + 'M 0,' + + ry + + ' a ' + + rx + + ',' + + ry + + ' 0,0,0 ' + + w + + ' 0 a ' + + rx + + ',' + + ry + + ' 0,0,0 ' + + -w + + ' 0 l 0,' + + h + + ' a ' + + rx + + ',' + + ry + + ' 0,0,0 ' + + w + + ' 0 l 0,' + + -h; + + const el = shapeSvg + .attr('label-offset-y', ry) + .insert('path', ':first-child') + .attr('d', shape) + .attr('transform', 'translate(' + -w / 2 + ',' + -(h / 2 + ry) + ')'); + + updateNodeBounds(node, el); + + node.intersect = function(point) { + const pos = intersect.rect(node, point); + const x = pos.x - node.x; + + if ( + rx != 0 && + (Math.abs(x) < node.width / 2 || + (Math.abs(x) == node.width / 2 && Math.abs(pos.y - node.y) > node.height / 2 - ry)) + ) { + // ellipsis equation: x*x / a*a + y*y / b*b = 1 + // solve for y to get adjustion value for pos.y + let y = ry * ry * (1 - (x * x) / (rx * rx)); + if (y != 0) y = Math.sqrt(y); + y = ry - y; + if (point.y - node.y > 0) y = -y; + + pos.y += y; + } + + return pos; + }; + + return shapeSvg; +}; + +const rect = (parent, node) => { + const { shapeSvg, bbox, halfPadding } = labelHelper(parent, node); + + // add the rect + const rect = shapeSvg.insert('rect', ':first-child'); + rect .attr('rx', node.rx) .attr('ry', node.ry) @@ -31,21 +300,74 @@ const rect = (parent, node) => { .attr('width', bbox.width + node.padding) .attr('height', bbox.height + node.padding); - // Center the label - label.attr('transform', 'translate(' + -bbox.width / 2 + ', ' + -bbox.height / 2 + ')'); - - const rectBox = rect.node().getBBox(); - node.width = rectBox.width; - node.height = rectBox.height; + updateNodeBounds(node, rect); node.intersect = function(point) { - return intersectRect(node, point); + return intersect.rect(node, point); }; return shapeSvg; }; -const shapes = { rect }; +const stadium = (parent, node) => { + const { shapeSvg, bbox } = labelHelper(parent, node); + + const h = bbox.height + node.padding; + const w = bbox.width + h / 4 + node.padding; + + // add the rect + const rect = shapeSvg + .insert('rect', ':first-child') + .attr('rx', h / 2) + .attr('ry', h / 2) + .attr('x', -w / 2) + .attr('y', -h / 2) + .attr('width', w) + .attr('height', h); + + updateNodeBounds(node, rect); + + node.intersect = function(point) { + return intersect.rect(node, point); + }; + + return shapeSvg; +}; +const circle = (parent, node) => { + const { shapeSvg, bbox, halfPadding } = labelHelper(parent, node); + const circle = shapeSvg.insert('circle', ':first-child'); + + // center the circle around its coordinate + circle + .attr('rx', node.rx) + .attr('ry', node.ry) + .attr('r', bbox.width / 2 + halfPadding) + .attr('width', bbox.width + node.padding) + .attr('height', bbox.height + node.padding); + + updateNodeBounds(node, circle); + + node.intersect = function(point) { + return intersect.circle(node, point); + }; + + return shapeSvg; +}; + +const shapes = { + question, + rect, + circle, + stadium, + hexagon, + rect_left_inv_arrow, + lean_right, + lean_left, + trapezoid, + inv_trapezoid, + rect_right_inv_arrow, + cylinder +}; let nodeElems = {}; diff --git a/src/diagrams/flowchart/flowRenderer-v2.js b/src/diagrams/flowchart/flowRenderer-v2.js index e1866d396..17c532a6f 100644 --- a/src/diagrams/flowchart/flowRenderer-v2.js +++ b/src/diagrams/flowchart/flowRenderer-v2.js @@ -329,44 +329,6 @@ export const draw = function(text, id) { // Add custom shapes // flowChartShapes.addToRenderV2(addShape); - // Add our custom arrow - an empty arrowhead - // render.arrows().none = function normal(parent, id, edge, type) { - // const marker = parent - // .append('marker') - // .attr('id', id) - // .attr('viewBox', '0 0 10 10') - // .attr('refX', 9) - // .attr('refY', 5) - // .attr('markerUnits', 'strokeWidth') - // .attr('markerWidth', 8) - // .attr('markerHeight', 6) - // .attr('orient', 'auto'); - - // // const path = marker.append('path').attr('d', 'M 0 0 L 0 0 L 0 0 z'); - // dagreD3.util.applyStyle(path, edge[type + 'Style']); - // }; - - // Override normal arrowhead defined in d3. Remove style & add class to allow css styling. - // render.arrows().normal = function normal(parent, id) { - // const marker = parent - // .append('marker') - // .attr('id', id) - // .attr('viewBox', '0 0 10 10') - // .attr('refX', 9) - // .attr('refY', 5) - // .attr('markerUnits', 'strokeWidth') - // .attr('markerWidth', 8) - // .attr('markerHeight', 6) - // .attr('orient', 'auto'); - - // marker - // .append('path') - // .attr('d', 'M 0 0 L 10 5 L 0 10 z') - // .attr('class', 'arrowheadPath') - // .style('stroke-width', 1) - // .style('stroke-dasharray', '1,0'); - // }; - // Set up an SVG group so that we can translate the final graph. const svg = d3.select(`[id="${id}"]`); From df2925e51ceb472e9f1fe02d0889a603d9bf9a0b Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Sun, 22 Mar 2020 16:08:57 +0100 Subject: [PATCH 13/22] #1295 Fix for edges form clusters --- src/dagre-wrapper/edges.js | 42 ++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/dagre-wrapper/edges.js b/src/dagre-wrapper/edges.js index d81f1c13f..2a7c6fd34 100644 --- a/src/dagre-wrapper/edges.js +++ b/src/dagre-wrapper/edges.js @@ -82,6 +82,7 @@ const outsideNode = (node, point) => { // return { x: insidePoint.x + r, y: insidePoint.y + q }; // }; const intersection = (node, outsidePoint, insidePoint) => { + logger.info('intersection', outsidePoint, insidePoint, node); const x = node.x; const y = node.y; @@ -96,30 +97,31 @@ const intersection = (node, outsidePoint, insidePoint) => { const Q = Math.abs(outsidePoint.y - insidePoint.y); const R = Math.abs(outsidePoint.x - insidePoint.x); - // if (Math.abs(y - outsidePoint.y) * w > Math.abs(x - outsidePoint.x) * h || false) { // eslint-disable-line - // // Intersection is top or bottom of rect. + if (Math.abs(y - outsidePoint.y) * w > Math.abs(x - outsidePoint.x) * h || false) { // eslint-disable-line + // Intersection is top or bottom of rect. - // r = (R * q) / Q; + r = (R * q) / Q; - // return { - // x: insidePoint.x < outsidePoint.x ? insidePoint.x + r : insidePoint.x - r, - // y: insidePoint.y + q - // }; - // } else { - q = (Q * r) / R; + return { + x: insidePoint.x < outsidePoint.x ? insidePoint.x + r : insidePoint.x - r, + y: insidePoint.y + q + }; + } else { + q = (Q * r) / R; - return { - x: insidePoint.x < outsidePoint.x ? insidePoint.x + r : insidePoint.x - r, - y: insidePoint.y < outsidePoint.y ? insidePoint.y + q : insidePoint.y - q - }; - // } + return { + x: insidePoint.x < outsidePoint.x ? insidePoint.x + r : insidePoint.x - r, + y: insidePoint.y < outsidePoint.y ? insidePoint.y + q : insidePoint.y - q + }; + } }; export const insertEdge = function(elem, edge, clusterDb) { + logger.info('\n\n\n\n'); let points = edge.points; if (edge.toCluster) { - logger.trace('edge', edge); - logger.trace('cluster', clusterDb[edge.toCluster]); + logger.info('edge', edge); + logger.info('to cluster', clusterDb[edge.toCluster]); points = []; let lastPointOutside; let isInside = false; @@ -144,7 +146,7 @@ export const insertEdge = function(elem, edge, clusterDb) { if (edge.fromCluster) { logger.info('edge', edge); - logger.info('cluster', clusterDb[edge.toCluster]); + logger.info('from cluster', clusterDb[edge.toCluster]); const updatedPoints = []; let lastPointOutside; let isInside = false; @@ -157,11 +159,13 @@ export const insertEdge = function(elem, edge, clusterDb) { // First point inside the rect const insterection = intersection(node, lastPointOutside, point); - logger.info('intersect', inter.rect(node, lastPointOutside)); + // logger.info('intersect', intersection(node, lastPointOutside, point)); updatedPoints.unshift(insterection); // points.push(insterection); isInside = true; } else { + // at the outside + logger.info('Outside point', point); if (!isInside) updatedPoints.unshift(point); } lastPointOutside = point; @@ -169,6 +173,8 @@ export const insertEdge = function(elem, edge, clusterDb) { points = updatedPoints; } + logger.info('Poibts', points); + logger.info('Edge', edge); // The data for our line From 5b302ae2e6d3a78fac8d84b4016eebe3a71c0346 Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Sun, 22 Mar 2020 21:45:14 +0100 Subject: [PATCH 14/22] #1295 Applying new rendering engine for stateDiagrams --- cypress/platform/current.html | 53 +- src/dagre-wrapper/GraphObjects.md | 11 +- src/dagre-wrapper/index.js | 13 +- src/diagrams/flowchart/flowRenderer-v2.js | 16 + src/diagrams/state/parser/stateDiagram.jison | 1 + src/diagrams/state/stateDb.js | 10 +- src/diagrams/state/stateRenderer-v2.js | 552 +++++++++++++++++++ src/mermaidAPI.js | 10 + src/utils.js | 3 + 9 files changed, 643 insertions(+), 26 deletions(-) create mode 100644 src/diagrams/state/stateRenderer-v2.js diff --git a/cypress/platform/current.html b/cypress/platform/current.html index e48303f0e..cb7b67f70 100644 --- a/cypress/platform/current.html +++ b/cypress/platform/current.html @@ -21,23 +21,8 @@

info below

-
-