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: Prevent Legend Labels from Overlapping Diagram Elements in Journey Diagrams #6274

Open
wants to merge 11 commits into
base: develop
Choose a base branch
from
78 changes: 78 additions & 0 deletions cypress/integration/rendering/journey.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,82 @@ section Checkout from website
{ journey: { useMaxWidth: false } }
);
});

it('should maintain sufficient space between legend labels and diagram elements', () => {
renderGraph(
`journey
title Web hook life cycle
section Darkoob
Make preBuilt:5: Darkoob user
register slug : 5: Darkoob userf
Map slug to a Prebuilt Job:5: Darkoob user
section External Service
set Darkoob slug as hook for an Event : 5 : admin Exjjjnjjjj qwerty
listen to the events : 5 : External Service
call darkoob endpoint : 5 : External Service
section Darkoob
check for inputs : 5 : DarkoobAPI
run the prebuilt job : 5 : DarkoobAPI
`,
{ journey: { useMaxWidth: true } }
);

let LabelEndX, diagramStartX;

// Get right edge of the legend
cy.contains('tspan', 'admin Exjjjnjjjj qwerty').then((textBox) => {
const bbox = textBox[0].getBBox();
LabelEndX = bbox.x + bbox.width;
});

// Get left edge of the diagram
cy.contains('foreignobject', 'Make preBuilt').then((rect) => {
diagramStartX = parseFloat(rect.attr('x'));
});

// Assert right edge of the diagram is greater than or equal to the right edge of the label
cy.then(() => {
expect(diagramStartX).to.be.gte(LabelEndX);
});
});

it('should maintain sufficient space between legend and diagram when legend labels are longer', () => {
renderGraph(
`journey
title Web hook life cycle
section Darkoob
Make preBuilt:5: Darkoob user
register slug : 5: Darkoob userf deliberately increasing the size of this label to check if distance between legend and diagram is maintained
Map slug to a Prebuilt Job:5: Darkoob user
section External Service
set Darkoob slug as hook for an Event : 5 : admin Exjjjnjjjj qwerty
listen to the events : 5 : External Service
call darkoob endpoint : 5 : External Service
section Darkoob
check for inputs : 5 : DarkoobAPI
run the prebuilt job : 5 : DarkoobAPI
`,
{ journey: { useMaxWidth: true } }
);

let LabelEndX, diagramStartX;

// Get right edge of the legend
cy.contains('tspan', 'Darkoob userf deliberately increasing the size of this label').then(
(textBox) => {
const bbox = textBox[0].getBBox();
LabelEndX = bbox.x + bbox.width;
}
);

// Get left edge of the diagram
cy.contains('foreignobject', 'Make preBuilt').then((rect) => {
diagramStartX = parseFloat(rect.attr('x'));
});

// Assert right edge of the diagram is greater than or equal to the right edge of the label
cy.then(() => {
expect(diagramStartX).to.be.gte(LabelEndX);
});
});
});
25 changes: 16 additions & 9 deletions packages/mermaid/src/diagrams/user-journey/journeyRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ export const setConf = function (cnf) {
};

const actors = {};
let maxWidth = 0;

/** @param diagram - The diagram to draw to. */
function drawActorLegend(diagram) {
const conf = getConfig().journey;
maxWidth = 0;
// Draw the actors
let yPos = 60;
Object.keys(actors).forEach((person) => {
Expand All @@ -39,14 +41,18 @@ function drawActorLegend(diagram) {
text: person,
textMargin: conf.boxTextMargin | 5,
};
svgDraw.drawText(diagram, labelData);

const textElement = svgDraw.drawText(diagram, labelData);
const textLength = textElement.node().getBBox().width;
if (textLength > maxWidth && textLength > conf?.leftMargin - textLength) {
maxWidth = textLength;
}
yPos += 20;
});
}
// TODO: Cleanup?
const conf = getConfig().journey;
const LEFT_MARGIN = conf.leftMargin;
let leftMargin = 0;
export const draw = function (text, id, version, diagObj) {
const conf = getConfig().journey;

Expand Down Expand Up @@ -84,31 +90,32 @@ export const draw = function (text, id, version, diagObj) {
});

drawActorLegend(diagram);
bounds.insert(0, 0, LEFT_MARGIN, Object.keys(actors).length * 50);
leftMargin = conf.leftMargin + maxWidth;
bounds.insert(0, 0, leftMargin, Object.keys(actors).length * 50);
drawTasks(diagram, tasks, 0);

const box = bounds.getBounds();
if (title) {
diagram
.append('text')
.text(title)
.attr('x', LEFT_MARGIN)
.attr('x', leftMargin)
.attr('font-size', '4ex')
.attr('font-weight', 'bold')
.attr('y', 25);
}

const height = box.stopy - box.starty + 2 * conf.diagramMarginY;
const width = LEFT_MARGIN + box.stopx + 2 * conf.diagramMarginX;
const width = leftMargin + box.stopx + 2 * conf.diagramMarginX;

configureSvgSize(diagram, height, width, conf.useMaxWidth);

// Draw activity line
diagram
.append('line')
.attr('x1', LEFT_MARGIN)
.attr('x1', leftMargin)
.attr('y1', conf.height * 4) // One section head + one task + margins
.attr('x2', width - LEFT_MARGIN - 4) // Subtract stroke width so arrow point is retained
.attr('x2', width - leftMargin - 4) // Subtract stroke width so arrow point is retained
.attr('y2', conf.height * 4)
.attr('stroke-width', 4)
.attr('stroke', 'black')
Expand Down Expand Up @@ -234,7 +241,7 @@ export const drawTasks = function (diagram, tasks, verticalPos) {
}

const section = {
x: i * conf.taskMargin + i * conf.width + LEFT_MARGIN,
x: i * conf.taskMargin + i * conf.width + leftMargin,
y: 50,
text: task.section,
fill,
Expand All @@ -258,7 +265,7 @@ export const drawTasks = function (diagram, tasks, verticalPos) {
}, {});

// Add some rendering data to the object
task.x = i * conf.taskMargin + i * conf.width + LEFT_MARGIN;
task.x = i * conf.taskMargin + i * conf.width + leftMargin;
task.y = taskPos;
task.width = conf.diagramMarginX;
task.height = conf.diagramMarginY;
Expand Down
Loading