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

Fix edge handling and arrow type #4582

Closed
wants to merge 11 commits into from
7 changes: 7 additions & 0 deletions packages/mermaid/src/dagre-wrapper/edges.js
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph
default:
strokeClasses = '';
}

switch (edge.pattern) {
case 'solid':
strokeClasses += ' edge-pattern-solid';
Expand Down Expand Up @@ -533,6 +534,9 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph
case 'extension':
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-extensionStart' + ')');
break;
case 'realization':
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-realizationStart' + ')');
break;
case 'composition':
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-compositionStart' + ')');
break;
Expand Down Expand Up @@ -563,6 +567,9 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph
case 'extension':
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-extensionEnd' + ')');
break;
case 'realization':
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-realizationEnd' + ')');
break;
case 'composition':
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-compositionEnd' + ')');
break;
Expand Down
79 changes: 77 additions & 2 deletions packages/mermaid/src/dagre-wrapper/markers.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,43 @@

import { log } from '../logger.js';

const getSvgParent = (elem) => {
let container = elem;

// the intent here is to find the first parent element that is NOT part of the SVG element
// I know there has to be a better way, but could not find one that worked
// tried using checking if elem was instanceof SVGGraphicsElement or SVGElement, but it failed to detect correctly
if (container._groups) {
container = container._groups[0][0];
}
if (container.tagName.toLowerCase() === 'g') {
container = container.parentElement;
}
if (container.localName.toLowerCase() === 'svg') {
container = container.parentElement;
}
return container;
sidharthv96 marked this conversation as resolved.
Show resolved Hide resolved
};

const getBackgroundColor = (elem) => {
let parent = getSvgParent(elem);

let backgroundColor;
while (parent && parent.tagName.toLowerCase() !== 'body') {
if(parent instanceof Element) {
const computedStyle = getComputedStyle(parent);
backgroundColor = computedStyle.backgroundColor;

if (backgroundColor !== 'rgba(0, 0, 0, 0)') {
break;
}
parent = parent.parentNode;
}
}

return backgroundColor === 'rgba(0, 0, 0, 0)' ? 'white' : backgroundColor;
};

// Only add the number of markers that the diagram needs
const insertMarkers = (elem, markerArray, type, id) => {
markerArray.forEach((markerName) => {
Expand All @@ -11,6 +48,8 @@ const insertMarkers = (elem, markerArray, type, id) => {

const extension = (elem, type, id) => {
log.trace('Making markers for ', id);
let backgroundColor = getBackgroundColor(elem);
jgreywolf marked this conversation as resolved.
Show resolved Hide resolved

elem
.append('defs')
.append('marker')
Expand All @@ -22,7 +61,8 @@ const extension = (elem, type, id) => {
.attr('markerHeight', 240)
.attr('orient', 'auto')
.append('path')
.attr('d', 'M 1,7 L18,13 V 1 Z');
.attr('d', 'M 1,7 L18,13 V 2 Z')
jgreywolf marked this conversation as resolved.
Show resolved Hide resolved
.attr('fill', backgroundColor);

elem
.append('defs')
Expand All @@ -35,7 +75,41 @@ const extension = (elem, type, id) => {
.attr('markerHeight', 28)
.attr('orient', 'auto')
.append('path')
.attr('d', 'M 1,1 V 13 L18,7 Z'); // this is actual shape for arrowhead
.attr('d', 'M 1,1 V 13 L18,7 Z')
.attr('fill', backgroundColor); // this is actual shape for arrowhead
};

const realization = (elem, type, id) => {
log.trace('Making markers for ', id);
let backgroundColor = getBackgroundColor(elem);

elem
.append('defs')
.append('marker')
.attr('id', type + '-realizationStart')
.attr('class', 'marker realization ' + type)
.attr('refX', 0)
.attr('refY', 7)
.attr('markerWidth', 190)
.attr('markerHeight', 240)
.attr('orient', 'auto')
.append('path')
.attr('d', 'M 1,7 L18,13 V 2 Z')
.attr('fill', backgroundColor);

elem
.append('defs')
.append('marker')
.attr('id', type + '-realizationEnd')
.attr('class', 'marker realization ' + type)
.attr('refX', 19)
.attr('refY', 7)
.attr('markerWidth', 20)
.attr('markerHeight', 28)
.attr('orient', 'auto')
.append('path')
.attr('d', 'M 1,1 V 13 L18,7 Z')
.attr('fill', backgroundColor); // this is actual shape for arrowhead
};

const composition = (elem, type) => {
Expand Down Expand Up @@ -265,6 +339,7 @@ const barb = (elem, type) => {
// TODO rename the class diagram markers to something shape descriptive and semantic free
const markers = {
extension,
realization,
composition,
aggregation,
dependency,
Expand Down
1 change: 1 addition & 0 deletions packages/mermaid/src/diagrams/class/classDb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ export const relationType = {
COMPOSITION: 2,
DEPENDENCY: 3,
LOLLIPOP: 4,
REALIZATION: 5,
};

const setupToolTips = function (element: Element) {
Expand Down
5 changes: 4 additions & 1 deletion packages/mermaid/src/diagrams/class/classRenderer-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ export const draw = async function (text: string, id: string, _version: string,
await render(
element,
g,
['aggregation', 'extension', 'composition', 'dependency', 'lollipop'],
['aggregation', 'extension', 'realization', 'composition', 'dependency', 'lollipop'],
'classDiagram',
id
);
Expand Down Expand Up @@ -413,6 +413,9 @@ function getArrowMarker(type: number) {
case 4:
marker = 'lollipop';
break;
case 5:
marker = 'realization';
break;
default:
marker = 'none';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ Function arguments are optional: 'call <callback_name>()' simply executes 'callb
<*>"_top" return 'LINK_TARGET';

<*>\s*\<\| return 'EXTENSION';
<*>\s*\|\> return 'EXTENSION';
<*>\s*\|\> return 'REALIZATION';
<*>\s*\> return 'DEPENDENCY';
<*>\s*\< return 'DEPENDENCY';
<*>\s*\* return 'COMPOSITION';
Expand Down Expand Up @@ -370,6 +370,7 @@ relation
relationType
: AGGREGATION { $$=yy.relationType.AGGREGATION;}
| EXTENSION { $$=yy.relationType.EXTENSION;}
| REALIZATION { $$=yy.relationType.REALIZATION;}
| COMPOSITION { $$=yy.relationType.COMPOSITION;}
| DEPENDENCY { $$=yy.relationType.DEPENDENCY;}
| LOLLIPOP { $$=yy.relationType.LOLLIPOP;}
Expand Down
2 changes: 2 additions & 0 deletions packages/mermaid/src/diagrams/class/svgDraw.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export const drawEdge = function (elem, path, relation, conf, diagObj) {
switch (type) {
case diagObj.db.relationType.AGGREGATION:
return 'aggregation';
case diagObj.db.relationType.REALIZATION:
return 'realization';
case diagObj.db.relationType.EXTENSION:
return 'extension';
case diagObj.db.relationType.COMPOSITION:
Expand Down