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

3952 - lexical ids #4785

Closed
wants to merge 12 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 @@ -461,6 +461,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 @@ -543,6 +544,9 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph
'url(' + url + '#' + id + '_' + diagramType + '-extensionStart' + ')'
);
break;
case 'realization':
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-realizationStart' + ')');
break;
case 'composition':
svgPath.attr(
'marker-start',
Expand Down Expand Up @@ -588,6 +592,9 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph
'url(' + url + '#' + id + '_' + diagramType + '-extensionEnd' + ')'
);
break;
case 'realization':
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-realizationEnd' + ')');
break;
case 'composition':
svgPath.attr(
'marker-end',
Expand Down
95 changes: 93 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,59 @@

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;
};

/**
* Finds the parent background color of an SVG element.
*
* Used to make a "hollow" arrowhead for an arrow.
*
* We can't use a transparent fill,
* because the arrow line is behind the arrowhead
* (ideally we'd stop drawing the line behind the arrowhead,
* but this is pretty complicated to do).
*
* **Limitations**:
* - If the parent background color is a partial transparency,
* the arrowhead will also be partially transparent.
* - More complicated backgrounds like pictures/animations won't work.
* @param elem
*/
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 +64,8 @@ const insertMarkers = (elem, markerArray, type, id) => {

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

elem
.append('defs')
.append('marker')
Expand All @@ -22,7 +77,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')
.attr('fill', backgroundColor);

elem
.append('defs')
Expand All @@ -35,7 +91,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, id) => {
Expand Down Expand Up @@ -282,6 +372,7 @@ const barb = (elem, type, id) => {
// 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 @@ -360,6 +360,7 @@ export const relationType = {
COMPOSITION: 2,
DEPENDENCY: 3,
LOLLIPOP: 4,
REALIZATION: 5,
};

const setupToolTips = function (element: Element) {
Expand Down
10 changes: 6 additions & 4 deletions packages/mermaid/src/diagrams/class/classDiagram.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1193,16 +1193,18 @@ describe('given a class diagram with relationships, ', function () {
});

it('should handle relation definitions with type only on right side', function () {
const str = 'classDiagram\n' + 'Class1 --|> Class02';
const str = 'classDiagram\n' + 'Class1 --|> Class2';

parser.parse(str);

const relations = parser.yy.getRelations();
const class1 = parser.yy.getClass('Class1');
const class2 = parser.yy.getClass('Class2');

expect(parser.yy.getClass('Class1').id).toBe('Class1');
expect(parser.yy.getClass('Class02').id).toBe('Class02');
expect(class1.id).toBe('Class1');
expect(class2.id).toBe('Class2');
expect(relations[0].relation.type1).toBe('none');
expect(relations[0].relation.type2).toBe(classDb.relationType.EXTENSION);
expect(relations[0].relation.type2).toBe(classDb.relationType.REALIZATION);
expect(relations[0].relation.lineType).toBe(classDb.lineType.LINE);
});

Expand Down
7 changes: 5 additions & 2 deletions packages/mermaid/src/diagrams/class/classRenderer-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ export const addRelations = function (relations: ClassRelation[], g: graphlib.Gr
//Set relationship style and line type
classes: 'relation',
pattern: edge.relation.lineType == 1 ? 'dashed' : 'solid',
id: 'id' + cnt,
id: 'id_' + edge.id1 + '_' + edge.id2,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the only relevant part for lexical IDs?
If so, can you reset your branch to develop and only have this in the PR?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the cnt should also be in the ID.

Otherwise, id of [a, b_c] and [a_b, c] will both be id_a_b_c, leading to a conflict.

// Set link type for rendering
arrowhead: edge.type === 'arrow_open' ? 'none' : 'normal',
//Set edge extra labels
Expand Down Expand Up @@ -355,7 +355,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 @@ -407,6 +407,9 @@ function getArrowMarker(type: number) {
case 4:
marker = 'lollipop';
break;
case 5:
marker = 'realization';
break;
default:
marker = 'none';
}
Expand Down
54 changes: 32 additions & 22 deletions packages/mermaid/src/diagrams/class/parser/classDiagram.jison
Original file line number Diff line number Diff line change
Expand Up @@ -113,28 +113,37 @@ line was introduced with 'click'.
<*>"_parent" return 'LINK_TARGET';
<*>"_top" return 'LINK_TARGET';

<*>\s*\<\| return 'EXTENSION';
<*>\s*\|\> return 'EXTENSION';
<*>\s*\> return 'DEPENDENCY';
<*>\s*\< return 'DEPENDENCY';
<*>\s*\* return 'COMPOSITION';
<*>\s*o return 'AGGREGATION';
<*>\s*\(\) return 'LOLLIPOP';
<*>\-\- return 'LINE';
<*>\.\. return 'DOTTED_LINE';
<*>":"{1}[^:\n;]+ return 'LABEL';
<*>":"{3} return 'STYLE_SEPARATOR';
<*>\- return 'MINUS';
<*>"." return 'DOT';
<*>\+ return 'PLUS';
<*>\% return 'PCT';
<*>"=" return 'EQUALS';
<*>\= return 'EQUALS';
<*>\w+ return 'ALPHA';
<*>"[" return 'SQS';
<*>"]" return 'SQE';
<*>[!"#$%&'*+,-.`?\\/] return 'PUNCTUATION';
<*>[0-9]+ return 'NUM';
<bqstring>[`] this.popState();
<bqstring>[^`]+ return "BQUOTE_STR";
<*>[`] this.begin("bqstring");

<*>"_self" return 'LINK_TARGET';
<*>"_blank" return 'LINK_TARGET';
<*>"_parent" return 'LINK_TARGET';
<*>"_top" return 'LINK_TARGET';

<*>\s*\<\| return 'EXTENSION';
<*>\s*\|\> return 'REALIZATION';
<*>\s*\> return 'DEPENDENCY';
<*>\s*\< return 'DEPENDENCY';
<*>\s*\* return 'COMPOSITION';
<*>\s*o return 'AGGREGATION';
<*>\s*\(\) return 'LOLLIPOP';
<*>\-\- return 'LINE';
<*>\.\. return 'DOTTED_LINE';
<*>":"{1}[^:\n;]+ return 'LABEL';
<*>":"{3} return 'STYLE_SEPARATOR';
<*>\- return 'MINUS';
<*>"." return 'DOT';
<*>\+ return 'PLUS';
<*>\% return 'PCT';
<*>"=" return 'EQUALS';
<*>\= return 'EQUALS';
<*>\w+ return 'ALPHA';
<*>"[" return 'SQS';
<*>"]" return 'SQE';
<*>[!"#$%&'*+,-.`?\\/] return 'PUNCTUATION';
<*>[0-9]+ return 'NUM';
<*>[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|
[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|
[\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5]|
Expand Down Expand Up @@ -338,6 +347,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
Loading