#530 Started adding some tests around how flowchart shapes are rendered in SVG
This commit is contained in:
parent
9a0a5ca804
commit
dcbcbf40a0
|
@ -0,0 +1,162 @@
|
||||||
|
import dagreD3 from 'dagre-d3-renderer';
|
||||||
|
|
||||||
|
export function addToRender(render) {
|
||||||
|
render.shapes().question = function(parent, bbox, node) {
|
||||||
|
const w = bbox.width;
|
||||||
|
const h = bbox.height;
|
||||||
|
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 shapeSvg = insertPolygonShape(parent, s, s, points);
|
||||||
|
node.intersect = function(point) {
|
||||||
|
return dagreD3.intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
||||||
|
|
||||||
|
render.shapes().hexagon = function(parent, bbox, node) {
|
||||||
|
const f = 4;
|
||||||
|
const h = bbox.height;
|
||||||
|
const m = h / f;
|
||||||
|
const w = bbox.width + 2 * m;
|
||||||
|
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 shapeSvg = insertPolygonShape(parent, w, h, points);
|
||||||
|
node.intersect = function(point) {
|
||||||
|
return dagreD3.intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add custom shape for box with inverted arrow on left side
|
||||||
|
render.shapes().rect_left_inv_arrow = function(parent, bbox, node) {
|
||||||
|
const w = bbox.width;
|
||||||
|
const h = bbox.height;
|
||||||
|
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 shapeSvg = insertPolygonShape(parent, w, h, points);
|
||||||
|
node.intersect = function(point) {
|
||||||
|
return dagreD3.intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add custom shape for box with inverted arrow on left side
|
||||||
|
render.shapes().lean_right = function(parent, bbox, node) {
|
||||||
|
const w = bbox.width;
|
||||||
|
const h = bbox.height;
|
||||||
|
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 shapeSvg = insertPolygonShape(parent, w, h, points);
|
||||||
|
node.intersect = function(point) {
|
||||||
|
return dagreD3.intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add custom shape for box with inverted arrow on left side
|
||||||
|
render.shapes().lean_left = function(parent, bbox, node) {
|
||||||
|
const w = bbox.width;
|
||||||
|
const h = bbox.height;
|
||||||
|
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 shapeSvg = insertPolygonShape(parent, w, h, points);
|
||||||
|
node.intersect = function(point) {
|
||||||
|
return dagreD3.intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add custom shape for box with inverted arrow on left side
|
||||||
|
render.shapes().trapezoid = function(parent, bbox, node) {
|
||||||
|
const w = bbox.width;
|
||||||
|
const h = bbox.height;
|
||||||
|
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 shapeSvg = insertPolygonShape(parent, w, h, points);
|
||||||
|
node.intersect = function(point) {
|
||||||
|
return dagreD3.intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add custom shape for box with inverted arrow on left side
|
||||||
|
render.shapes().inv_trapezoid = function(parent, bbox, node) {
|
||||||
|
const w = bbox.width;
|
||||||
|
const h = bbox.height;
|
||||||
|
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 shapeSvg = insertPolygonShape(parent, w, h, points);
|
||||||
|
node.intersect = function(point) {
|
||||||
|
return dagreD3.intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add custom shape for box with inverted arrow on right side
|
||||||
|
render.shapes().rect_right_inv_arrow = function(parent, bbox, node) {
|
||||||
|
const w = bbox.width;
|
||||||
|
const h = bbox.height;
|
||||||
|
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 shapeSvg = insertPolygonShape(parent, w, h, points);
|
||||||
|
node.intersect = function(point) {
|
||||||
|
return dagreD3.intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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 + ')');
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
addToRender
|
||||||
|
};
|
|
@ -0,0 +1,89 @@
|
||||||
|
import { addToRender } from './flowChartShapes';
|
||||||
|
|
||||||
|
describe('flowchart shapes', function() {
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'question',
|
||||||
|
4,
|
||||||
|
function(w, h) {
|
||||||
|
return (w + h) * 0.9;
|
||||||
|
},
|
||||||
|
function(w, h) {
|
||||||
|
return (w + h) * 0.9;
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'hexagon',
|
||||||
|
6,
|
||||||
|
function(w, h) {
|
||||||
|
return w + h / 2;
|
||||||
|
},
|
||||||
|
function(w, h) {
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'rect_left_inv_arrow',
|
||||||
|
5,
|
||||||
|
function(w) {
|
||||||
|
return w;
|
||||||
|
},
|
||||||
|
function(w, h) {
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
]
|
||||||
|
].forEach(function([shapeType, expectedPointCount, getW, getH]) {
|
||||||
|
it(`should add a ${shapeType} shape that renders a properly translated polygon element`, function() {
|
||||||
|
const mockRender = MockRender();
|
||||||
|
const mockSvg = MockSvg();
|
||||||
|
addToRender(mockRender);
|
||||||
|
|
||||||
|
[[100, 100], [123, 45], [71, 300]].forEach(function([width, height]) {
|
||||||
|
const shape = mockRender.shapes()[shapeType](mockSvg, { width, height }, {});
|
||||||
|
const dx = -getW(width, height) / 2;
|
||||||
|
const dy = getH(width, height) / 2;
|
||||||
|
const points = shape.__attrs.points.split(' ');
|
||||||
|
expect(shape.__tag).toEqual('polygon');
|
||||||
|
expect(shape.__attrs).toHaveProperty('transform', `translate(${dx},${dy})`);
|
||||||
|
expect(points).toHaveLength(expectedPointCount);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function MockRender() {
|
||||||
|
const shapes = {};
|
||||||
|
return {
|
||||||
|
shapes() {
|
||||||
|
return shapes;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function MockSvg(tag, ...args) {
|
||||||
|
const children = [];
|
||||||
|
const attributes = {};
|
||||||
|
return {
|
||||||
|
get __args() {
|
||||||
|
return args;
|
||||||
|
},
|
||||||
|
get __tag() {
|
||||||
|
return tag;
|
||||||
|
},
|
||||||
|
get __children() {
|
||||||
|
return children;
|
||||||
|
},
|
||||||
|
get __attrs() {
|
||||||
|
return attributes;
|
||||||
|
},
|
||||||
|
insert: function(tag, ...args) {
|
||||||
|
const child = MockSvg(tag, ...args);
|
||||||
|
children.push(child);
|
||||||
|
return child;
|
||||||
|
},
|
||||||
|
attr(name, value) {
|
||||||
|
this.__attrs[name] = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import dagreD3 from 'dagre-d3-renderer';
|
||||||
import addHtmlLabel from 'dagre-d3-renderer/lib/label/add-html-label.js';
|
import addHtmlLabel from 'dagre-d3-renderer/lib/label/add-html-label.js';
|
||||||
import { logger } from '../../logger';
|
import { logger } from '../../logger';
|
||||||
import { interpolateToCurve } from '../../utils';
|
import { interpolateToCurve } from '../../utils';
|
||||||
|
import flowChartShapes from './flowChartShapes';
|
||||||
|
|
||||||
const conf = {};
|
const conf = {};
|
||||||
export const setConf = function(cnf) {
|
export const setConf = function(cnf) {
|
||||||
|
@ -331,147 +332,8 @@ export const draw = function(text, id) {
|
||||||
const Render = dagreD3.render;
|
const Render = dagreD3.render;
|
||||||
const render = new Render();
|
const render = new Render();
|
||||||
|
|
||||||
// Add custom shape for rhombus type of boc (decision)
|
// Add custom shapes
|
||||||
render.shapes().question = function(parent, bbox, node) {
|
flowChartShapes.addToRender(render);
|
||||||
const w = bbox.width;
|
|
||||||
const h = bbox.height;
|
|
||||||
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 shapeSvg = insertPolygonShape(parent, s, s, points);
|
|
||||||
node.intersect = function(point) {
|
|
||||||
return dagreD3.intersect.polygon(node, points, point);
|
|
||||||
};
|
|
||||||
return shapeSvg;
|
|
||||||
};
|
|
||||||
|
|
||||||
render.shapes().hexagon = function(parent, bbox, node) {
|
|
||||||
const f = 4;
|
|
||||||
const h = bbox.height;
|
|
||||||
const m = h / 4;
|
|
||||||
const w = bbox.width + 2 * m;
|
|
||||||
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 shapeSvg = insertPolygonShape(parent, w, h, points);
|
|
||||||
node.intersect = function(point) {
|
|
||||||
return dagreD3.intersect.polygon(node, points, point);
|
|
||||||
};
|
|
||||||
return shapeSvg;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add custom shape for box with inverted arrow on left side
|
|
||||||
render.shapes().rect_left_inv_arrow = function(parent, bbox, node) {
|
|
||||||
const w = bbox.width;
|
|
||||||
const h = bbox.height;
|
|
||||||
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 shapeSvg = insertPolygonShape(parent, w, h, points);
|
|
||||||
node.intersect = function(point) {
|
|
||||||
return dagreD3.intersect.polygon(node, points, point);
|
|
||||||
};
|
|
||||||
return shapeSvg;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add custom shape for box with inverted arrow on left side
|
|
||||||
render.shapes().lean_right = function(parent, bbox, node) {
|
|
||||||
const w = bbox.width;
|
|
||||||
const h = bbox.height;
|
|
||||||
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 shapeSvg = insertPolygonShape(parent, w, h, points);
|
|
||||||
node.intersect = function(point) {
|
|
||||||
return dagreD3.intersect.polygon(node, points, point);
|
|
||||||
};
|
|
||||||
return shapeSvg;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add custom shape for box with inverted arrow on left side
|
|
||||||
render.shapes().lean_left = function(parent, bbox, node) {
|
|
||||||
const w = bbox.width;
|
|
||||||
const h = bbox.height;
|
|
||||||
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 shapeSvg = insertPolygonShape(parent, w, h, points);
|
|
||||||
node.intersect = function(point) {
|
|
||||||
return dagreD3.intersect.polygon(node, points, point);
|
|
||||||
};
|
|
||||||
return shapeSvg;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add custom shape for box with inverted arrow on left side
|
|
||||||
render.shapes().trapezoid = function(parent, bbox, node) {
|
|
||||||
const w = bbox.width;
|
|
||||||
const h = bbox.height;
|
|
||||||
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 shapeSvg = insertPolygonShape(parent, w, h, points);
|
|
||||||
node.intersect = function(point) {
|
|
||||||
return dagreD3.intersect.polygon(node, points, point);
|
|
||||||
};
|
|
||||||
return shapeSvg;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add custom shape for box with inverted arrow on left side
|
|
||||||
render.shapes().inv_trapezoid = function(parent, bbox, node) {
|
|
||||||
const w = bbox.width;
|
|
||||||
const h = bbox.height;
|
|
||||||
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 shapeSvg = insertPolygonShape(parent, w, h, points);
|
|
||||||
node.intersect = function(point) {
|
|
||||||
return dagreD3.intersect.polygon(node, points, point);
|
|
||||||
};
|
|
||||||
return shapeSvg;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add custom shape for box with inverted arrow on right side
|
|
||||||
render.shapes().rect_right_inv_arrow = function(parent, bbox, node) {
|
|
||||||
const w = bbox.width;
|
|
||||||
const h = bbox.height;
|
|
||||||
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 shapeSvg = insertPolygonShape(parent, w, h, points);
|
|
||||||
node.intersect = function(point) {
|
|
||||||
return dagreD3.intersect.polygon(node, points, point);
|
|
||||||
};
|
|
||||||
return shapeSvg;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add our custom arrow - an empty arrowhead
|
// Add our custom arrow - an empty arrowhead
|
||||||
render.arrows().none = function normal(parent, id, edge, type) {
|
render.arrows().none = function normal(parent, id, edge, type) {
|
||||||
|
@ -572,20 +434,6 @@ export const draw = function(text, id) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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 + ')');
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
setConf,
|
setConf,
|
||||||
addVertices,
|
addVertices,
|
||||||
|
|
|
@ -2,7 +2,6 @@ import { addVertices } from './flowRenderer';
|
||||||
import { setConfig } from '../../config';
|
import { setConfig } from '../../config';
|
||||||
|
|
||||||
setConfig({
|
setConfig({
|
||||||
securityLevel: 'strict',
|
|
||||||
flowchart: {
|
flowchart: {
|
||||||
htmlLabels: false
|
htmlLabels: false
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue