mirror of
https://github.com/mermaid-js/mermaid.git
synced 2026-05-23 20:10:38 +00:00
fix(class): Self-referential class multiplicity labels rendered multiple times
Fixes #7560 where cardinality labels (e.g. "1", "0..1") were displayed 3x on self-referential class diagram relationships. Root cause: The dagre layout splits self-loops into 3 edges but structuredClone copied cardinality labels to all of them. Now each segment only carries its relevant cardinality label. Also fix DOM hierarchy bug in edge label creation where labels were appended to the wrong parent element. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -97,16 +97,10 @@ export const insertEdgeLabel = async (elem, edge) => {
|
||||
setTerminalWidth(fo, edge.startLabelLeft);
|
||||
}
|
||||
if (edge.startLabelRight) {
|
||||
// Create the actual text element
|
||||
const startEdgeLabelRight = elem.insert('g').attr('class', 'edgeTerminals');
|
||||
const inner = startEdgeLabelRight.insert('g').attr('class', 'inner');
|
||||
const startLabelElement = await createLabel(
|
||||
startEdgeLabelRight,
|
||||
edge.startLabelRight,
|
||||
edge.labelStyle
|
||||
);
|
||||
const startLabelElement = await createLabel(inner, edge.startLabelRight, edge.labelStyle);
|
||||
fo = startLabelElement;
|
||||
inner.node().appendChild(startLabelElement);
|
||||
let slBox = startLabelElement.getBBox();
|
||||
if (useHtmlLabels) {
|
||||
const div = startLabelElement.children[0];
|
||||
@@ -124,7 +118,6 @@ export const insertEdgeLabel = async (elem, edge) => {
|
||||
setTerminalWidth(fo, edge.startLabelRight);
|
||||
}
|
||||
if (edge.endLabelLeft) {
|
||||
// Create the actual text element
|
||||
const endEdgeLabelLeft = elem.insert('g').attr('class', 'edgeTerminals');
|
||||
const inner = endEdgeLabelLeft.insert('g').attr('class', 'inner');
|
||||
const endLabelElement = await createLabel(inner, edge.endLabelLeft, edge.labelStyle);
|
||||
@@ -139,8 +132,6 @@ export const insertEdgeLabel = async (elem, edge) => {
|
||||
}
|
||||
inner.attr('transform', computeLabelTransform(slBox, useHtmlLabels));
|
||||
|
||||
endEdgeLabelLeft.node().appendChild(endLabelElement);
|
||||
|
||||
if (!terminalLabels[edge.id]) {
|
||||
terminalLabels[edge.id] = {};
|
||||
}
|
||||
@@ -148,7 +139,6 @@ export const insertEdgeLabel = async (elem, edge) => {
|
||||
setTerminalWidth(fo, edge.endLabelLeft);
|
||||
}
|
||||
if (edge.endLabelRight) {
|
||||
// Create the actual text element
|
||||
const endEdgeLabelRight = elem.insert('g').attr('class', 'edgeTerminals');
|
||||
const inner = endEdgeLabelRight.insert('g').attr('class', 'inner');
|
||||
const endLabelElement = await createLabel(inner, edge.endLabelRight, edge.labelStyle);
|
||||
@@ -163,7 +153,6 @@ export const insertEdgeLabel = async (elem, edge) => {
|
||||
}
|
||||
inner.attr('transform', computeLabelTransform(slBox, useHtmlLabels));
|
||||
|
||||
endEdgeLabelRight.node().appendChild(endLabelElement);
|
||||
if (!terminalLabels[edge.id]) {
|
||||
terminalLabels[edge.id] = {};
|
||||
}
|
||||
|
||||
@@ -345,11 +345,17 @@ export const render = async (data4Layout, svg) => {
|
||||
const edge2 = structuredClone(edge);
|
||||
edge1.label = '';
|
||||
edge1.arrowTypeEnd = 'none';
|
||||
edge1.endLabelLeft = '';
|
||||
edge1.id = nodeId + '-cyclic-special-1';
|
||||
edgeMid.label = '';
|
||||
edgeMid.startLabelRight = '';
|
||||
edgeMid.endLabelLeft = '';
|
||||
edgeMid.arrowTypeStart = 'none';
|
||||
edgeMid.arrowTypeEnd = 'none';
|
||||
edgeMid.id = nodeId + '-cyclic-special-mid';
|
||||
edge2.label = '';
|
||||
edge2.startLabelRight = '';
|
||||
edge2.arrowTypeStart = 'none';
|
||||
if (node.isGroup) {
|
||||
edge1.fromCluster = nodeId;
|
||||
edge2.toCluster = nodeId;
|
||||
|
||||
@@ -148,7 +148,6 @@ export const insertEdgeLabel = async (elem, edge) => {
|
||||
setTerminalWidth(fo, edge.startLabelLeft);
|
||||
}
|
||||
if (edge.startLabelRight) {
|
||||
// Create the actual text element
|
||||
const startEdgeLabelRight = elem.insert('g').attr('class', 'edgeTerminals');
|
||||
const inner = startEdgeLabelRight.insert('g').attr('class', 'inner');
|
||||
const startLabelElement = await createLabel(
|
||||
@@ -159,7 +158,6 @@ export const insertEdgeLabel = async (elem, edge) => {
|
||||
false
|
||||
);
|
||||
fo = startLabelElement;
|
||||
inner.node().appendChild(startLabelElement);
|
||||
let slBox = startLabelElement.getBBox();
|
||||
if (useHtmlLabels) {
|
||||
const div = startLabelElement.children[0];
|
||||
@@ -177,7 +175,6 @@ export const insertEdgeLabel = async (elem, edge) => {
|
||||
setTerminalWidth(fo, edge.startLabelRight);
|
||||
}
|
||||
if (edge.endLabelLeft) {
|
||||
// Create the actual text element
|
||||
const endEdgeLabelLeft = elem.insert('g').attr('class', 'edgeTerminals');
|
||||
const inner = endEdgeLabelLeft.insert('g').attr('class', 'inner');
|
||||
const endLabelElement = await createLabel(
|
||||
@@ -198,8 +195,6 @@ export const insertEdgeLabel = async (elem, edge) => {
|
||||
}
|
||||
inner.attr('transform', computeLabelTransform(slBox, useHtmlLabels));
|
||||
|
||||
endEdgeLabelLeft.node().appendChild(endLabelElement);
|
||||
|
||||
if (!terminalLabels.get(edge.id)) {
|
||||
terminalLabels.set(edge.id, {});
|
||||
}
|
||||
@@ -207,10 +202,8 @@ export const insertEdgeLabel = async (elem, edge) => {
|
||||
setTerminalWidth(fo, edge.endLabelLeft);
|
||||
}
|
||||
if (edge.endLabelRight) {
|
||||
// Create the actual text element
|
||||
const endEdgeLabelRight = elem.insert('g').attr('class', 'edgeTerminals');
|
||||
const inner = endEdgeLabelRight.insert('g').attr('class', 'inner');
|
||||
|
||||
const endLabelElement = await createLabel(
|
||||
inner,
|
||||
edge.endLabelRight,
|
||||
@@ -229,7 +222,6 @@ export const insertEdgeLabel = async (elem, edge) => {
|
||||
}
|
||||
inner.attr('transform', computeLabelTransform(slBox, useHtmlLabels));
|
||||
|
||||
endEdgeLabelRight.node().appendChild(endLabelElement);
|
||||
if (!terminalLabels.get(edge.id)) {
|
||||
terminalLabels.set(edge.id, {});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user