Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hex shape for flow charts #970

Merged
merged 13 commits into from
Oct 8, 2019
Merged
4 changes: 2 additions & 2 deletions dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@
<div class="mermaid">
graph TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> C{{Let me think...<br />Do I want something for work,<br />something to spend every free second with,<br />or something to get around?}}
C -->|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[Car]
Expand Down Expand Up @@ -443,7 +443,7 @@
const testLineEndings = (test, input) => {
try {
mermaid.render(test, input, () => {});
} catch (err) {
} catch (err) {
console.error("Error in %s:\n\n%s", test, err);
}
};
Expand Down
15 changes: 13 additions & 2 deletions docs/flowchart.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,17 @@ graph LR
id1{This is the text in the box}
```

### A hexagon node

```
graph LR
id1{{This is the text in the box}}
```
```mermaid
graph LR
id1{{This is the text in the box}}
```

### Trapezoid

```mermaid
Expand Down Expand Up @@ -350,7 +361,7 @@ Beginners tip, a full example using interactive links in a html context:
click A callback "Tooltip"
click B "http://www.github.com" "This is a link"
</div>

<script>
var callback = function(){
alert('A callback was triggered');
Expand All @@ -364,7 +375,7 @@ Beginners tip, a full example using interactive links in a html context:
},
securityLevel:'loose',
};

mermaid.initialize(config);
</script>
</body>
Expand Down
2 changes: 1 addition & 1 deletion docs/mermaidAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ This option decides the amount of logging to be used.

Sets the level of trust to be used on the parsed diagrams.

- **strict**: (**default**) tags in text are encoded, click functionality is disabled
- **strict**: (**default**) tags in text are encoded, click functionality is disabeled
- **loose**: tags in text are allowed, click functionality is enabled

## startOnLoad
Expand Down
177 changes: 177 additions & 0 deletions src/diagrams/flowchart/flowChartShapes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import dagreD3 from 'dagre-d3-renderer';

function question(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;
}

function hexagon(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;
}

function rect_left_inv_arrow(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;
}

function lean_right(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;
}

function lean_left(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;
}

function trapezoid(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;
}

function inv_trapezoid(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;
}

function rect_right_inv_arrow(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;
}

export function addToRender(render) {
render.shapes().question = question;
render.shapes().hexagon = hexagon;

// Add custom shape for box with inverted arrow on left side
render.shapes().rect_left_inv_arrow = rect_left_inv_arrow;

// Add custom shape for box with inverted arrow on left side
render.shapes().lean_right = lean_right;

// Add custom shape for box with inverted arrow on left side
render.shapes().lean_left = lean_left;

// Add custom shape for box with inverted arrow on left side
render.shapes().trapezoid = trapezoid;

// Add custom shape for box with inverted arrow on left side
render.shapes().inv_trapezoid = inv_trapezoid;

// Add custom shape for box with inverted arrow on right side
render.shapes().rect_right_inv_arrow = rect_right_inv_arrow;
}

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
};
91 changes: 91 additions & 0 deletions src/diagrams/flowchart/flowChartShapes.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
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;
},
useHeight
],
['rect_left_inv_arrow', 5, useWidth, useHeight],
['rect_right_inv_arrow', 5, useWidth, useHeight],
['lean_right', 4, useWidth, useHeight],
['lean_left', 4, useWidth, useHeight],
['trapezoid', 4, useWidth, useHeight],
['inv_trapezoid', 4, useWidth, useHeight]
].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;
}
};
}

function useWidth(w, h) {
return w;
}

function useHeight(w, h) {
return h;
}
Loading