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}"]`);