mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-03 23:56:44 +02:00
Initial implementation for cardinality position.
This commit is contained in:
@@ -20,7 +20,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>info below</h1>
|
<h1>info below</h1>
|
||||||
<div class="mermaid" style="width: 100%; height: 20%;">
|
<div class="mermaid2" style="width: 100%; height: 20%;">
|
||||||
classDiagram-v2
|
classDiagram-v2
|
||||||
class BankAccount{
|
class BankAccount{
|
||||||
+String owner
|
+String owner
|
||||||
@@ -42,6 +42,15 @@
|
|||||||
<<interface>> classB
|
<<interface>> classB
|
||||||
classB : method2() int
|
classB : method2() int
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mermaid" style="width: 100%; height: 20%;">
|
||||||
|
classDiagram-v2
|
||||||
|
|
||||||
|
classA -- classB : Inheritance
|
||||||
|
classA -- classC : link
|
||||||
|
classC -- classD : link
|
||||||
|
classB -- classD
|
||||||
|
</div>
|
||||||
<script src="./mermaid.js"></script>
|
<script src="./mermaid.js"></script>
|
||||||
<script>
|
<script>
|
||||||
mermaid.parseError = function (err, hash) {
|
mermaid.parseError = function (err, hash) {
|
||||||
|
@@ -6,9 +6,11 @@ import utils from '../utils';
|
|||||||
// import { calcLabelPosition } from '../utils';
|
// import { calcLabelPosition } from '../utils';
|
||||||
|
|
||||||
let edgeLabels = {};
|
let edgeLabels = {};
|
||||||
|
let terminalLabels = {};
|
||||||
|
|
||||||
export const clear = () => {
|
export const clear = () => {
|
||||||
edgeLabels = {};
|
edgeLabels = {};
|
||||||
|
terminalLabels = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const insertEdgeLabel = (elem, edge) => {
|
export const insertEdgeLabel = (elem, edge) => {
|
||||||
@@ -39,6 +41,66 @@ export const insertEdgeLabel = (elem, edge) => {
|
|||||||
// Update the abstract data of the edge with the new information about its width and height
|
// Update the abstract data of the edge with the new information about its width and height
|
||||||
edge.width = bbox.width;
|
edge.width = bbox.width;
|
||||||
edge.height = bbox.height;
|
edge.height = bbox.height;
|
||||||
|
|
||||||
|
if (edge.startLabelLeft) {
|
||||||
|
// Create the actual text element
|
||||||
|
const startLabelElement = createLabel(edge.startLabelLeft, edge.labelStyle);
|
||||||
|
const startEdgeLabelLeft = elem.insert('g').attr('class', 'edgeTerminals');
|
||||||
|
const inner = startEdgeLabelLeft.insert('g').attr('class', 'inner');
|
||||||
|
inner.node().appendChild(startLabelElement);
|
||||||
|
const slBox = startLabelElement.getBBox();
|
||||||
|
inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')');
|
||||||
|
if (!terminalLabels[edge.id]) {
|
||||||
|
terminalLabels[edge.id] = {};
|
||||||
|
}
|
||||||
|
terminalLabels[edge.id].startLeft = startEdgeLabelLeft;
|
||||||
|
}
|
||||||
|
if (edge.startLabelRight) {
|
||||||
|
// Create the actual text element
|
||||||
|
const startLabelElement = createLabel(edge.startLabelRight, edge.labelStyle);
|
||||||
|
const startEdgeLabelRight = elem.insert('g').attr('class', 'edgeTerminals');
|
||||||
|
const inner = startEdgeLabelRight.insert('g').attr('class', 'inner');
|
||||||
|
startEdgeLabelRight.node().appendChild(startLabelElement);
|
||||||
|
inner.node().appendChild(startLabelElement);
|
||||||
|
const slBox = startLabelElement.getBBox();
|
||||||
|
inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')');
|
||||||
|
|
||||||
|
if (!terminalLabels[edge.id]) {
|
||||||
|
terminalLabels[edge.id] = {};
|
||||||
|
}
|
||||||
|
terminalLabels[edge.id].startRight = startEdgeLabelRight;
|
||||||
|
}
|
||||||
|
if (edge.endLabelLeft) {
|
||||||
|
// Create the actual text element
|
||||||
|
const endLabelElement = createLabel(edge.endLabelLeft, edge.labelStyle);
|
||||||
|
const endEdgeLabelLeft = elem.insert('g').attr('class', 'edgeTerminals');
|
||||||
|
const inner = endEdgeLabelLeft.insert('g').attr('class', 'inner');
|
||||||
|
inner.node().appendChild(endLabelElement);
|
||||||
|
const slBox = endLabelElement.getBBox();
|
||||||
|
inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')');
|
||||||
|
|
||||||
|
endEdgeLabelLeft.node().appendChild(endLabelElement);
|
||||||
|
if (!terminalLabels[edge.id]) {
|
||||||
|
terminalLabels[edge.id] = {};
|
||||||
|
}
|
||||||
|
terminalLabels[edge.id].endLeft = endEdgeLabelLeft;
|
||||||
|
}
|
||||||
|
if (edge.endLabelRight) {
|
||||||
|
// Create the actual text element
|
||||||
|
const endLabelElement = createLabel(edge.endLabelRight, edge.labelStyle);
|
||||||
|
const endEdgeLabelRight = elem.insert('g').attr('class', 'edgeTerminals');
|
||||||
|
const inner = endEdgeLabelRight.insert('g').attr('class', 'inner');
|
||||||
|
|
||||||
|
inner.node().appendChild(endLabelElement);
|
||||||
|
const slBox = endLabelElement.getBBox();
|
||||||
|
inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')');
|
||||||
|
|
||||||
|
endEdgeLabelRight.node().appendChild(endLabelElement);
|
||||||
|
if (!terminalLabels[edge.id]) {
|
||||||
|
terminalLabels[edge.id] = {};
|
||||||
|
}
|
||||||
|
terminalLabels[edge.id].endRight = endEdgeLabelRight;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const positionEdgeLabel = (edge, points) => {
|
export const positionEdgeLabel = (edge, points) => {
|
||||||
@@ -55,6 +117,55 @@ export const positionEdgeLabel = (edge, points) => {
|
|||||||
}
|
}
|
||||||
el.attr('transform', 'translate(' + x + ', ' + y + ')');
|
el.attr('transform', 'translate(' + x + ', ' + y + ')');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (edge.startLabelLeft) {
|
||||||
|
const el = terminalLabels[edge.id].startLeft;
|
||||||
|
let x = edge.x;
|
||||||
|
let y = edge.y;
|
||||||
|
if (points) {
|
||||||
|
// debugger;
|
||||||
|
const pos = utils.calcTerminalLabelPosition(0, 'start_left', points);
|
||||||
|
x = pos.x;
|
||||||
|
y = pos.y;
|
||||||
|
}
|
||||||
|
el.attr('transform', 'translate(' + x + ', ' + y + ')');
|
||||||
|
}
|
||||||
|
if (edge.startLabelRight) {
|
||||||
|
const el = terminalLabels[edge.id].startRight;
|
||||||
|
let x = edge.x;
|
||||||
|
let y = edge.y;
|
||||||
|
if (points) {
|
||||||
|
// debugger;
|
||||||
|
const pos = utils.calcTerminalLabelPosition(0, 'start_right', points);
|
||||||
|
x = pos.x;
|
||||||
|
y = pos.y;
|
||||||
|
}
|
||||||
|
el.attr('transform', 'translate(' + x + ', ' + y + ')');
|
||||||
|
}
|
||||||
|
if (edge.endLabelLeft) {
|
||||||
|
const el = terminalLabels[edge.id].endLeft;
|
||||||
|
let x = edge.x;
|
||||||
|
let y = edge.y;
|
||||||
|
if (points) {
|
||||||
|
// debugger;
|
||||||
|
const pos = utils.calcTerminalLabelPosition(0, 'end_left', points);
|
||||||
|
x = pos.x;
|
||||||
|
y = pos.y;
|
||||||
|
}
|
||||||
|
el.attr('transform', 'translate(' + x + ', ' + y + ')');
|
||||||
|
}
|
||||||
|
if (edge.endLabelRight) {
|
||||||
|
const el = terminalLabels[edge.id].endRight;
|
||||||
|
let x = edge.x;
|
||||||
|
let y = edge.y;
|
||||||
|
if (points) {
|
||||||
|
// debugger;
|
||||||
|
const pos = utils.calcTerminalLabelPosition(0, 'end_right', points);
|
||||||
|
x = pos.x;
|
||||||
|
y = pos.y;
|
||||||
|
}
|
||||||
|
el.attr('transform', 'translate(' + x + ', ' + y + ')');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// const getRelationType = function(type) {
|
// const getRelationType = function(type) {
|
||||||
@@ -357,5 +468,7 @@ export const insertEdge = function(elem, e, edge, clusterDb, diagramType, graph)
|
|||||||
|
|
||||||
if (pointsHasChanged) {
|
if (pointsHasChanged) {
|
||||||
return points;
|
return points;
|
||||||
|
} else {
|
||||||
|
return edge.points;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -155,6 +155,13 @@ export const addRelations = function(relations, g) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.info(edgeData, edge);
|
logger.info(edgeData, edge);
|
||||||
|
|
||||||
|
//Set edge extra labels
|
||||||
|
edgeData.startLabelLeft = 'TL';
|
||||||
|
edgeData.startLabelRight = 'TR';
|
||||||
|
edgeData.endLabelLeft = 'BL';
|
||||||
|
edgeData.endLabelRight = 'BR';
|
||||||
|
|
||||||
//Set relation arrow types
|
//Set relation arrow types
|
||||||
edgeData.arrowTypeStart = getArrowMarker(edge.relation.type1);
|
edgeData.arrowTypeStart = getArrowMarker(edge.relation.type1);
|
||||||
edgeData.arrowTypeEnd = getArrowMarker(edge.relation.type2);
|
edgeData.arrowTypeEnd = getArrowMarker(edge.relation.type2);
|
||||||
|
@@ -109,6 +109,11 @@ g.classGroup line {
|
|||||||
stroke: ${options.lineColor} !important;
|
stroke: ${options.lineColor} !important;
|
||||||
stroke-width: 1;
|
stroke-width: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.edgeTerminals {
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default getStyles;
|
export default getStyles;
|
||||||
|
73
src/utils.js
73
src/utils.js
@@ -334,6 +334,7 @@ const calcLabelPosition = points => {
|
|||||||
const calcCardinalityPosition = (isRelationTypePresent, points, initialPosition) => {
|
const calcCardinalityPosition = (isRelationTypePresent, points, initialPosition) => {
|
||||||
let prevPoint;
|
let prevPoint;
|
||||||
let totalDistance = 0; // eslint-disable-line
|
let totalDistance = 0; // eslint-disable-line
|
||||||
|
logger.info('our points', points);
|
||||||
if (points[0] !== initialPosition) {
|
if (points[0] !== initialPosition) {
|
||||||
points = points.reverse();
|
points = points.reverse();
|
||||||
}
|
}
|
||||||
@@ -380,6 +381,77 @@ const calcCardinalityPosition = (isRelationTypePresent, points, initialPosition)
|
|||||||
return cardinalityPosition;
|
return cardinalityPosition;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* position ['start_left', 'start_right', 'end_left', 'end_right']
|
||||||
|
*/
|
||||||
|
const calcTerminalLabelPosition = (terminalMarkerSize, position, _points) => {
|
||||||
|
// Todo looking to faster cloning method
|
||||||
|
let points = JSON.parse(JSON.stringify(_points));
|
||||||
|
let prevPoint;
|
||||||
|
let totalDistance = 0; // eslint-disable-line
|
||||||
|
logger.info('our points', points);
|
||||||
|
if (position !== 'start_left' && position !== 'start_right') {
|
||||||
|
points = points.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
points.forEach(point => {
|
||||||
|
totalDistance += distance(point, prevPoint);
|
||||||
|
prevPoint = point;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Traverse only 25 total distance along points to find cardinality point
|
||||||
|
const distanceToCardinalityPoint = 25;
|
||||||
|
|
||||||
|
let remainingDistance = distanceToCardinalityPoint;
|
||||||
|
let center;
|
||||||
|
prevPoint = undefined;
|
||||||
|
points.forEach(point => {
|
||||||
|
if (prevPoint && !center) {
|
||||||
|
const vectorDistance = distance(point, prevPoint);
|
||||||
|
if (vectorDistance < remainingDistance) {
|
||||||
|
remainingDistance -= vectorDistance;
|
||||||
|
} else {
|
||||||
|
// The point is remainingDistance from prevPoint in the vector between prevPoint and point
|
||||||
|
// Calculate the coordinates
|
||||||
|
const distanceRatio = remainingDistance / vectorDistance;
|
||||||
|
if (distanceRatio <= 0) center = prevPoint;
|
||||||
|
if (distanceRatio >= 1) center = { x: point.x, y: point.y };
|
||||||
|
if (distanceRatio > 0 && distanceRatio < 1) {
|
||||||
|
center = {
|
||||||
|
x: (1 - distanceRatio) * prevPoint.x + distanceRatio * point.x,
|
||||||
|
y: (1 - distanceRatio) * prevPoint.y + distanceRatio * point.y
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevPoint = point;
|
||||||
|
});
|
||||||
|
// if relation is present (Arrows will be added), change cardinality point off-set distance (d)
|
||||||
|
let d = 10;
|
||||||
|
//Calculate Angle for x and y axis
|
||||||
|
let angle = Math.atan2(points[0].y - center.y, points[0].x - center.x);
|
||||||
|
|
||||||
|
let cardinalityPosition = { x: 0, y: 0 };
|
||||||
|
|
||||||
|
//Calculation cardinality position using angle, center point on the line/curve but pendicular and with offset-distance
|
||||||
|
|
||||||
|
cardinalityPosition.x = Math.sin(angle) * d + (points[0].x + center.x) / 2;
|
||||||
|
cardinalityPosition.y = -Math.cos(angle) * d + (points[0].y + center.y) / 2;
|
||||||
|
if (position === 'start_left') {
|
||||||
|
cardinalityPosition.x = Math.sin(angle + Math.PI) * d + (points[0].x + center.x) / 2;
|
||||||
|
cardinalityPosition.y = -Math.cos(angle + Math.PI) * d + (points[0].y + center.y) / 2;
|
||||||
|
}
|
||||||
|
if (position === 'end_right') {
|
||||||
|
cardinalityPosition.x = Math.sin(angle - Math.PI) * d + (points[0].x + center.x) / 2 - 5;
|
||||||
|
cardinalityPosition.y = -Math.cos(angle - Math.PI) * d + (points[0].y + center.y) / 2 - 5;
|
||||||
|
}
|
||||||
|
if (position === 'end_left') {
|
||||||
|
cardinalityPosition.x = Math.sin(angle) * d + (points[0].x + center.x) / 2 - 5;
|
||||||
|
cardinalityPosition.y = -Math.cos(angle) * d + (points[0].y + center.y) / 2 - 5;
|
||||||
|
}
|
||||||
|
return cardinalityPosition;
|
||||||
|
};
|
||||||
|
|
||||||
export const getStylesFromArray = arr => {
|
export const getStylesFromArray = arr => {
|
||||||
let style = '';
|
let style = '';
|
||||||
let labelStyle = '';
|
let labelStyle = '';
|
||||||
@@ -708,6 +780,7 @@ export default {
|
|||||||
interpolateToCurve,
|
interpolateToCurve,
|
||||||
calcLabelPosition,
|
calcLabelPosition,
|
||||||
calcCardinalityPosition,
|
calcCardinalityPosition,
|
||||||
|
calcTerminalLabelPosition,
|
||||||
formatUrl,
|
formatUrl,
|
||||||
getStylesFromArray,
|
getStylesFromArray,
|
||||||
generateId,
|
generateId,
|
||||||
|
Reference in New Issue
Block a user