Allow overlapping notes

This commit is contained in:
Justin Greywolf
2023-05-03 22:15:59 -07:00
parent 2216bbad25
commit 06fdb95389
8 changed files with 187 additions and 49 deletions

View File

@@ -59,6 +59,7 @@
"knsv", "knsv",
"knut", "knut",
"laganeckas", "laganeckas",
"linetype",
"lintstagedrc", "lintstagedrc",
"logmsg", "logmsg",
"lucida", "lucida",

View File

@@ -123,6 +123,29 @@ context('Sequence diagram', () => {
} }
); );
}); });
it('should render a sequence diagram with par_over', () => {
imgSnapshotTest(
`
sequenceDiagram
participant Alice
participant Bob
participant John
par_over Section title
Alice ->> Bob: Message 1<br>Second line
Bob ->> John: Message 2
end
par_over Two line<br>section title
Note over Alice: Alice note
Note over Bob: Bob note<br>Second line
Note over John: John note
end
par_over Mixed section
Alice ->> Bob: Message 1
Note left of Bob: Alice/Bob Note
end
`
);
});
context('font settings', () => { context('font settings', () => {
it('should render different note fonts when configured', () => { it('should render different note fonts when configured', () => {
imgSnapshotTest( imgSnapshotTest(

View File

@@ -144,6 +144,26 @@
> >
<hr /> <hr />
<pre class="mermaid">
sequenceDiagram
participant Alice
participant Bob
participant John
par_over Section title
Alice ->> Bob: Message 1<br>Second line
Bob ->> John: Message 2
end
par_over Two line<br>section title
Note over Alice: Alice note
Note over Bob: Bob note<br>Second line
Note over John: John note
end
par_over Mixed section
Alice ->> Bob: Message 1
Note left of Bob: Alice/Bob Note
end
</pre>
<script type="module"> <script type="module">
import mermaid from './mermaid.esm.mjs'; import mermaid from './mermaid.esm.mjs';
mermaid.initialize({ mermaid.initialize({

View File

@@ -138,6 +138,32 @@ const getUrl = (useAbsolute: boolean): string => {
export const evaluate = (val?: string | boolean): boolean => export const evaluate = (val?: string | boolean): boolean =>
val === false || ['false', 'null', '0'].includes(String(val).trim().toLowerCase()) ? false : true; val === false || ['false', 'null', '0'].includes(String(val).trim().toLowerCase()) ? false : true;
/**
* Wrapper around Math.max which removes non-numeric values
* Returns the larger of a set of supplied numeric expressions.
* @param values - Numeric expressions to be evaluated
* @returns The smaller value
*/
export const getMax = function (...values: number[]): number {
const newValues: number[] = values.filter((value) => {
return !isNaN(value);
});
return Math.max(...newValues);
};
/**
* Wrapper around Math.min which removes non-numeric values
* Returns the smaller of a set of supplied numeric expressions.
* @param values - Numeric expressions to be evaluated
* @returns The smaller value
*/
export const getMin = function (...values: number[]): number {
const newValues: number[] = values.filter((value) => {
return !isNaN(value);
});
return Math.min(...newValues);
};
/** /**
* Makes generics in typescript syntax * Makes generics in typescript syntax
* *
@@ -180,4 +206,6 @@ export default {
removeScript, removeScript,
getUrl, getUrl,
evaluate, evaluate,
getMax,
getMin,
}; };

View File

@@ -47,6 +47,7 @@
"alt" { this.begin('LINE'); return 'alt'; } "alt" { this.begin('LINE'); return 'alt'; }
"else" { this.begin('LINE'); return 'else'; } "else" { this.begin('LINE'); return 'else'; }
"par" { this.begin('LINE'); return 'par'; } "par" { this.begin('LINE'); return 'par'; }
"par_over" { this.begin('LINE'); return 'par_over'; }
"and" { this.begin('LINE'); return 'and'; } "and" { this.begin('LINE'); return 'and'; }
"critical" { this.begin('LINE'); return 'critical'; } "critical" { this.begin('LINE'); return 'critical'; }
"option" { this.begin('LINE'); return 'option'; } "option" { this.begin('LINE'); return 'option'; }
@@ -190,6 +191,14 @@ statement
// End // End
$3.push({type: 'parEnd', signalType: yy.LINETYPE.PAR_END}); $3.push({type: 'parEnd', signalType: yy.LINETYPE.PAR_END});
$$=$3;} $$=$3;}
| par_over restOfLine par_sections end
{
// Parallel (overlapped) start
$3.unshift({type: 'parStart', parText:yy.parseMessage($2), signalType: yy.LINETYPE.PAR_OVER_START});
// Content in par is already in $3
// End
$3.push({type: 'parEnd', signalType: yy.LINETYPE.PAR_END});
$$=$3;}
| critical restOfLine option_sections end | critical restOfLine option_sections end
{ {
// critical start // critical start

View File

@@ -286,6 +286,7 @@ export const LINETYPE = {
CRITICAL_END: 29, CRITICAL_END: 29,
BREAK_START: 30, BREAK_START: 30,
BREAK_END: 31, BREAK_END: 31,
PAR_OVER_START: 32,
}; };
export const ARROWTYPE = { export const ARROWTYPE = {

View File

@@ -1126,6 +1126,29 @@ end`;
expect(messages[1].from).toBe('Alice'); expect(messages[1].from).toBe('Alice');
expect(messages[2].from).toBe('Bob'); expect(messages[2].from).toBe('Bob');
}); });
it('it should handle par_over statements', async () => {
const str = `
sequenceDiagram
par_over Parallel overlap
Alice ->> Bob: Message
Note left of Alice: Alice note
Note right of Bob: Bob note
end`;
await mermaidAPI.parse(str);
const actors = diagram.db.getActors();
expect(actors.Alice.description).toBe('Alice');
expect(actors.Bob.description).toBe('Bob');
const messages = diagram.db.getMessages();
expect(messages.length).toBe(5);
expect(messages[0].message).toBe('Parallel overlap');
expect(messages[1].from).toBe('Alice');
expect(messages[2].from).toBe('Alice');
expect(messages[3].from).toBe('Bob');
});
it('should handle special characters in signals', async () => { it('should handle special characters in signals', async () => {
const str = 'sequenceDiagram\n' + 'Alice->Bob: -:<>,;# comment'; const str = 'sequenceDiagram\n' + 'Alice->Bob: -:<>,;# comment';

View File

@@ -131,10 +131,10 @@ export const bounds = {
this.activations.forEach(updateFn('activation')); this.activations.forEach(updateFn('activation'));
}, },
insert: function (startx, starty, stopx, stopy) { insert: function (startx, starty, stopx, stopy) {
const _startx = Math.min(startx, stopx); const _startx = common.getMin(startx, stopx);
const _stopx = Math.max(startx, stopx); const _stopx = common.getMax(startx, stopx);
const _starty = Math.min(starty, stopy); const _starty = common.getMin(starty, stopy);
const _stopy = Math.max(starty, stopy); const _stopy = common.getMax(starty, stopy);
this.updateVal(bounds.data, 'startx', _startx, Math.min); this.updateVal(bounds.data, 'startx', _startx, Math.min);
this.updateVal(bounds.data, 'starty', _starty, Math.min); this.updateVal(bounds.data, 'starty', _starty, Math.min);
@@ -184,6 +184,11 @@ export const bounds = {
endLoop: function () { endLoop: function () {
return this.sequenceItems.pop(); return this.sequenceItems.pop();
}, },
isLoopOverlap: function () {
return this.sequenceItems.length
? this.sequenceItems[this.sequenceItems.length - 1].overlap
: false;
},
addSectionToLoop: function (message) { addSectionToLoop: function (message) {
const loop = this.sequenceItems.pop(); const loop = this.sequenceItems.pop();
loop.sections = loop.sections || []; loop.sections = loop.sections || [];
@@ -192,9 +197,19 @@ export const bounds = {
loop.sectionTitles.push(message); loop.sectionTitles.push(message);
this.sequenceItems.push(loop); this.sequenceItems.push(loop);
}, },
saveVerticalPos: function () {
if (this.isLoopOverlap()) {
this.savedVerticalPos = this.verticalPos;
}
},
resetVerticalPos: function () {
if (this.isLoopOverlap()) {
this.verticalPos = this.savedVerticalPos;
}
},
bumpVerticalPos: function (bump) { bumpVerticalPos: function (bump) {
this.verticalPos = this.verticalPos + bump; this.verticalPos = this.verticalPos + bump;
this.data.stopy = this.verticalPos; this.data.stopy = common.getMax(this.data.stopy, this.verticalPos);
}, },
getVerticalPos: function () { getVerticalPos: function () {
return this.verticalPos; return this.verticalPos;
@@ -317,7 +332,7 @@ function boundMessage(_diagram, msgModel): number {
lineStartY = bounds.getVerticalPos() + totalOffset; lineStartY = bounds.getVerticalPos() + totalOffset;
} }
totalOffset += 30; totalOffset += 30;
const dx = Math.max(textWidth / 2, conf.width / 2); const dx = common.getMax(textWidth / 2, conf.width / 2);
bounds.insert( bounds.insert(
startx - dx, startx - dx,
bounds.getVerticalPos() - 10 + totalOffset, bounds.getVerticalPos() - 10 + totalOffset,
@@ -374,9 +389,9 @@ const drawMessage = function (diagram, msgModel, lineStartY: number, diagObj: Di
.append('path') .append('path')
.attr( .attr(
'd', 'd',
`M ${startx},${lineStartY} H ${startx + Math.max(conf.width / 2, textWidth / 2)} V ${ `M ${startx},${lineStartY} H ${
lineStartY + 25 startx + common.getMax(conf.width / 2, textWidth / 2)
} H ${startx}` } V ${lineStartY + 25} H ${startx}`
); );
} else { } else {
line = diagram line = diagram
@@ -510,7 +525,7 @@ export const drawActors = function (
// Add some rendering data to the object // Add some rendering data to the object
actor.width = actor.width || conf.width; actor.width = actor.width || conf.width;
actor.height = Math.max(actor.height || conf.height, conf.height); actor.height = common.getMax(actor.height || conf.height, conf.height);
actor.margin = actor.margin || conf.actorMargin; actor.margin = actor.margin || conf.actorMargin;
actor.x = prevWidth + prevMargin; actor.x = prevWidth + prevMargin;
@@ -518,7 +533,7 @@ export const drawActors = function (
// Draw the box with the attached line // Draw the box with the attached line
const height = svgDraw.drawActor(diagram, actor, conf, isFooter); const height = svgDraw.drawActor(diagram, actor, conf, isFooter);
maxHeight = Math.max(maxHeight, height); maxHeight = common.getMax(maxHeight, height);
bounds.insert(actor.x, verticalPos, actor.x + actor.width, actor.height); bounds.insert(actor.x, verticalPos, actor.x + actor.width, actor.height);
prevWidth += actor.width + prevMargin; prevWidth += actor.width + prevMargin;
@@ -590,10 +605,10 @@ const activationBounds = function (actor, actors) {
const activations = actorActivations(actor); const activations = actorActivations(actor);
const left = activations.reduce(function (acc, activation) { const left = activations.reduce(function (acc, activation) {
return Math.min(acc, activation.startx); return common.getMin(acc, activation.startx);
}, actorObj.x + actorObj.width / 2); }, actorObj.x + actorObj.width / 2);
const right = activations.reduce(function (acc, activation) { const right = activations.reduce(function (acc, activation) {
return Math.max(acc, activation.stopx); return common.getMax(acc, activation.stopx);
}, actorObj.x + actorObj.width / 2); }, actorObj.x + actorObj.width / 2);
return [left, right]; return [left, right];
}; };
@@ -610,7 +625,7 @@ function adjustLoopHeightForWrap(loopWidths, msg, preMargin, postMargin, addLoop
// const lines = common.splitBreaks(msg.message).length; // const lines = common.splitBreaks(msg.message).length;
const textDims = utils.calculateTextDimensions(msg.message, textConf); const textDims = utils.calculateTextDimensions(msg.message, textConf);
const totalOffset = Math.max(textDims.height, conf.labelBoxHeight); const totalOffset = common.getMax(textDims.height, conf.labelBoxHeight);
heightAdjust = postMargin + totalOffset; heightAdjust = postMargin + totalOffset;
log.debug(`${totalOffset} - ${msg.message}`); log.debug(`${totalOffset} - ${msg.message}`);
} }
@@ -710,6 +725,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
switch (msg.type) { switch (msg.type) {
case diagObj.db.LINETYPE.NOTE: case diagObj.db.LINETYPE.NOTE:
bounds.resetVerticalPos();
noteModel = msg.noteModel; noteModel = msg.noteModel;
drawNote(diagram, noteModel); drawNote(diagram, noteModel);
break; break;
@@ -785,6 +801,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
bounds.models.addLoop(loopModel); bounds.models.addLoop(loopModel);
break; break;
case diagObj.db.LINETYPE.PAR_START: case diagObj.db.LINETYPE.PAR_START:
case diagObj.db.LINETYPE.PAR_OVER_START:
adjustLoopHeightForWrap( adjustLoopHeightForWrap(
loopWidths, loopWidths,
msg, msg,
@@ -792,6 +809,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
conf.boxMargin + conf.boxTextMargin, conf.boxMargin + conf.boxTextMargin,
(message) => bounds.newLoop(message) (message) => bounds.newLoop(message)
); );
bounds.saveVerticalPos();
break; break;
case diagObj.db.LINETYPE.PAR_AND: case diagObj.db.LINETYPE.PAR_AND:
adjustLoopHeightForWrap( adjustLoopHeightForWrap(
@@ -859,6 +877,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
default: default:
try { try {
// lastMsg = msg // lastMsg = msg
bounds.resetVerticalPos();
msgModel = msg.msgModel; msgModel = msg.msgModel;
msgModel.starty = bounds.getVerticalPos(); msgModel.starty = bounds.getVerticalPos();
msgModel.sequenceIndex = sequenceIndex; msgModel.sequenceIndex = sequenceIndex;
@@ -1026,45 +1045,45 @@ function getMaxMessageWidthPerActor(
* margin * margin
*/ */
if (isMessage && msg.from === actor.nextActor) { if (isMessage && msg.from === actor.nextActor) {
maxMessageWidthPerActor[msg.to] = Math.max( maxMessageWidthPerActor[msg.to] = common.getMax(
maxMessageWidthPerActor[msg.to] || 0, maxMessageWidthPerActor[msg.to] || 0,
messageWidth messageWidth
); );
} else if (isMessage && msg.from === actor.prevActor) { } else if (isMessage && msg.from === actor.prevActor) {
maxMessageWidthPerActor[msg.from] = Math.max( maxMessageWidthPerActor[msg.from] = common.getMax(
maxMessageWidthPerActor[msg.from] || 0, maxMessageWidthPerActor[msg.from] || 0,
messageWidth messageWidth
); );
} else if (isMessage && msg.from === msg.to) { } else if (isMessage && msg.from === msg.to) {
maxMessageWidthPerActor[msg.from] = Math.max( maxMessageWidthPerActor[msg.from] = common.getMax(
maxMessageWidthPerActor[msg.from] || 0, maxMessageWidthPerActor[msg.from] || 0,
messageWidth / 2 messageWidth / 2
); );
maxMessageWidthPerActor[msg.to] = Math.max( maxMessageWidthPerActor[msg.to] = common.getMax(
maxMessageWidthPerActor[msg.to] || 0, maxMessageWidthPerActor[msg.to] || 0,
messageWidth / 2 messageWidth / 2
); );
} else if (msg.placement === diagObj.db.PLACEMENT.RIGHTOF) { } else if (msg.placement === diagObj.db.PLACEMENT.RIGHTOF) {
maxMessageWidthPerActor[msg.from] = Math.max( maxMessageWidthPerActor[msg.from] = common.getMax(
maxMessageWidthPerActor[msg.from] || 0, maxMessageWidthPerActor[msg.from] || 0,
messageWidth messageWidth
); );
} else if (msg.placement === diagObj.db.PLACEMENT.LEFTOF) { } else if (msg.placement === diagObj.db.PLACEMENT.LEFTOF) {
maxMessageWidthPerActor[actor.prevActor] = Math.max( maxMessageWidthPerActor[actor.prevActor] = common.getMax(
maxMessageWidthPerActor[actor.prevActor] || 0, maxMessageWidthPerActor[actor.prevActor] || 0,
messageWidth messageWidth
); );
} else if (msg.placement === diagObj.db.PLACEMENT.OVER) { } else if (msg.placement === diagObj.db.PLACEMENT.OVER) {
if (actor.prevActor) { if (actor.prevActor) {
maxMessageWidthPerActor[actor.prevActor] = Math.max( maxMessageWidthPerActor[actor.prevActor] = common.getMax(
maxMessageWidthPerActor[actor.prevActor] || 0, maxMessageWidthPerActor[actor.prevActor] || 0,
messageWidth / 2 messageWidth / 2
); );
} }
if (actor.nextActor) { if (actor.nextActor) {
maxMessageWidthPerActor[msg.from] = Math.max( maxMessageWidthPerActor[msg.from] = common.getMax(
maxMessageWidthPerActor[msg.from] || 0, maxMessageWidthPerActor[msg.from] || 0,
messageWidth / 2 messageWidth / 2
); );
@@ -1120,10 +1139,10 @@ function calculateActorMargins(
const actDims = utils.calculateTextDimensions(actor.description, actorFont(conf)); const actDims = utils.calculateTextDimensions(actor.description, actorFont(conf));
actor.width = actor.wrap actor.width = actor.wrap
? conf.width ? conf.width
: Math.max(conf.width, actDims.width + 2 * conf.wrapPadding); : common.getMax(conf.width, actDims.width + 2 * conf.wrapPadding);
actor.height = actor.wrap ? Math.max(actDims.height, conf.height) : conf.height; actor.height = actor.wrap ? common.getMax(actDims.height, conf.height) : conf.height;
maxHeight = Math.max(maxHeight, actor.height); maxHeight = common.getMax(maxHeight, actor.height);
}); });
for (const actorKey in actorToMessageWidth) { for (const actorKey in actorToMessageWidth) {
@@ -1139,14 +1158,14 @@ function calculateActorMargins(
if (!nextActor) { if (!nextActor) {
const messageWidth = actorToMessageWidth[actorKey]; const messageWidth = actorToMessageWidth[actorKey];
const actorWidth = messageWidth + conf.actorMargin - actor.width / 2; const actorWidth = messageWidth + conf.actorMargin - actor.width / 2;
actor.margin = Math.max(actorWidth, conf.actorMargin); actor.margin = common.getMax(actorWidth, conf.actorMargin);
continue; continue;
} }
const messageWidth = actorToMessageWidth[actorKey]; const messageWidth = actorToMessageWidth[actorKey];
const actorWidth = messageWidth + conf.actorMargin - actor.width / 2 - nextActor.width / 2; const actorWidth = messageWidth + conf.actorMargin - actor.width / 2 - nextActor.width / 2;
actor.margin = Math.max(actorWidth, conf.actorMargin); actor.margin = common.getMax(actorWidth, conf.actorMargin);
} }
let maxBoxHeight = 0; let maxBoxHeight = 0;
@@ -1162,8 +1181,8 @@ function calculateActorMargins(
} }
const boxMsgDimensions = utils.calculateTextDimensions(box.name, textFont); const boxMsgDimensions = utils.calculateTextDimensions(box.name, textFont);
maxBoxHeight = Math.max(boxMsgDimensions.height, maxBoxHeight); maxBoxHeight = common.getMax(boxMsgDimensions.height, maxBoxHeight);
const minWidth = Math.max(totalWidth, boxMsgDimensions.width + 2 * conf.wrapPadding); const minWidth = common.getMax(totalWidth, boxMsgDimensions.width + 2 * conf.wrapPadding);
box.margin = conf.boxTextMargin; box.margin = conf.boxTextMargin;
if (totalWidth < minWidth) { if (totalWidth < minWidth) {
const missing = (minWidth - totalWidth) / 2; const missing = (minWidth - totalWidth) / 2;
@@ -1172,7 +1191,7 @@ function calculateActorMargins(
}); });
boxes.forEach((box) => (box.textMaxHeight = maxBoxHeight)); boxes.forEach((box) => (box.textMaxHeight = maxBoxHeight));
return Math.max(maxHeight, conf.height); return common.getMax(maxHeight, conf.height);
} }
const buildNoteModel = function (msg, actors, diagObj) { const buildNoteModel = function (msg, actors, diagObj) {
@@ -1187,7 +1206,7 @@ const buildNoteModel = function (msg, actors, diagObj) {
const noteModel = { const noteModel = {
width: shouldWrap width: shouldWrap
? conf.width ? conf.width
: Math.max(conf.width, textDimensions.width + 2 * conf.noteMargin), : common.getMax(conf.width, textDimensions.width + 2 * conf.noteMargin),
height: 0, height: 0,
startx: actors[msg.from].x, startx: actors[msg.from].x,
stopx: 0, stopx: 0,
@@ -1197,16 +1216,16 @@ const buildNoteModel = function (msg, actors, diagObj) {
}; };
if (msg.placement === diagObj.db.PLACEMENT.RIGHTOF) { if (msg.placement === diagObj.db.PLACEMENT.RIGHTOF) {
noteModel.width = shouldWrap noteModel.width = shouldWrap
? Math.max(conf.width, textDimensions.width) ? common.getMax(conf.width, textDimensions.width)
: Math.max( : common.getMax(
actors[msg.from].width / 2 + actors[msg.to].width / 2, actors[msg.from].width / 2 + actors[msg.to].width / 2,
textDimensions.width + 2 * conf.noteMargin textDimensions.width + 2 * conf.noteMargin
); );
noteModel.startx = startx + (actors[msg.from].width + conf.actorMargin) / 2; noteModel.startx = startx + (actors[msg.from].width + conf.actorMargin) / 2;
} else if (msg.placement === diagObj.db.PLACEMENT.LEFTOF) { } else if (msg.placement === diagObj.db.PLACEMENT.LEFTOF) {
noteModel.width = shouldWrap noteModel.width = shouldWrap
? Math.max(conf.width, textDimensions.width + 2 * conf.noteMargin) ? common.getMax(conf.width, textDimensions.width + 2 * conf.noteMargin)
: Math.max( : common.getMax(
actors[msg.from].width / 2 + actors[msg.to].width / 2, actors[msg.from].width / 2 + actors[msg.to].width / 2,
textDimensions.width + 2 * conf.noteMargin textDimensions.width + 2 * conf.noteMargin
); );
@@ -1214,13 +1233,21 @@ const buildNoteModel = function (msg, actors, diagObj) {
} else if (msg.to === msg.from) { } else if (msg.to === msg.from) {
textDimensions = utils.calculateTextDimensions( textDimensions = utils.calculateTextDimensions(
shouldWrap shouldWrap
? utils.wrapLabel(msg.message, Math.max(conf.width, actors[msg.from].width), noteFont(conf)) ? utils.wrapLabel(
msg.message,
common.getMax(conf.width, actors[msg.from].width),
noteFont(conf)
)
: msg.message, : msg.message,
noteFont(conf) noteFont(conf)
); );
noteModel.width = shouldWrap noteModel.width = shouldWrap
? Math.max(conf.width, actors[msg.from].width) ? common.getMax(conf.width, actors[msg.from].width)
: Math.max(actors[msg.from].width, conf.width, textDimensions.width + 2 * conf.noteMargin); : common.getMax(
actors[msg.from].width,
conf.width,
textDimensions.width + 2 * conf.noteMargin
);
noteModel.startx = startx + (actors[msg.from].width - noteModel.width) / 2; noteModel.startx = startx + (actors[msg.from].width - noteModel.width) / 2;
} else { } else {
noteModel.width = noteModel.width =
@@ -1272,14 +1299,14 @@ const buildMessageModel = function (msg, actors, diagObj) {
if (msg.wrap && msg.message) { if (msg.wrap && msg.message) {
msg.message = utils.wrapLabel( msg.message = utils.wrapLabel(
msg.message, msg.message,
Math.max(boundedWidth + 2 * conf.wrapPadding, conf.width), common.getMax(boundedWidth + 2 * conf.wrapPadding, conf.width),
messageFont(conf) messageFont(conf)
); );
} }
const msgDims = utils.calculateTextDimensions(msg.message, messageFont(conf)); const msgDims = utils.calculateTextDimensions(msg.message, messageFont(conf));
return { return {
width: Math.max( width: common.getMax(
msg.wrap ? 0 : msgDims.width + 2 * conf.wrapPadding, msg.wrap ? 0 : msgDims.width + 2 * conf.wrapPadding,
boundedWidth + 2 * conf.wrapPadding, boundedWidth + 2 * conf.wrapPadding,
conf.width conf.width
@@ -1309,6 +1336,7 @@ const calculateLoopBounds = function (messages, actors, _maxWidthPerActor, diagO
case diagObj.db.LINETYPE.ALT_START: case diagObj.db.LINETYPE.ALT_START:
case diagObj.db.LINETYPE.OPT_START: case diagObj.db.LINETYPE.OPT_START:
case diagObj.db.LINETYPE.PAR_START: case diagObj.db.LINETYPE.PAR_START:
case diagObj.db.LINETYPE.PAR_OVER_START:
case diagObj.db.LINETYPE.CRITICAL_START: case diagObj.db.LINETYPE.CRITICAL_START:
case diagObj.db.LINETYPE.BREAK_START: case diagObj.db.LINETYPE.BREAK_START:
stack.push({ stack.push({
@@ -1368,10 +1396,10 @@ const calculateLoopBounds = function (messages, actors, _maxWidthPerActor, diagO
msg.noteModel = noteModel; msg.noteModel = noteModel;
stack.forEach((stk) => { stack.forEach((stk) => {
current = stk; current = stk;
current.from = Math.min(current.from, noteModel.startx); current.from = common.getMin(current.from, noteModel.startx);
current.to = Math.max(current.to, noteModel.startx + noteModel.width); current.to = common.getMax(current.to, noteModel.startx + noteModel.width);
current.width = current.width =
Math.max(current.width, Math.abs(current.from - current.to)) - conf.labelBoxWidth; common.getMax(current.width, Math.abs(current.from - current.to)) - conf.labelBoxWidth;
}); });
} else { } else {
msgModel = buildMessageModel(msg, actors, diagObj); msgModel = buildMessageModel(msg, actors, diagObj);
@@ -1382,18 +1410,23 @@ const calculateLoopBounds = function (messages, actors, _maxWidthPerActor, diagO
if (msgModel.startx === msgModel.stopx) { if (msgModel.startx === msgModel.stopx) {
const from = actors[msg.from]; const from = actors[msg.from];
const to = actors[msg.to]; const to = actors[msg.to];
current.from = Math.min( current.from = common.getMin(
from.x - msgModel.width / 2, from.x - msgModel.width / 2,
from.x - from.width / 2, from.x - from.width / 2,
current.from current.from
); );
current.to = Math.max(to.x + msgModel.width / 2, to.x + from.width / 2, current.to); current.to = common.getMax(
to.x + msgModel.width / 2,
to.x + from.width / 2,
current.to
);
current.width = current.width =
Math.max(current.width, Math.abs(current.to - current.from)) - conf.labelBoxWidth; common.getMax(current.width, Math.abs(current.to - current.from)) -
conf.labelBoxWidth;
} else { } else {
current.from = Math.min(msgModel.startx, current.from); current.from = common.getMin(msgModel.startx, current.from);
current.to = Math.max(msgModel.stopx, current.to); current.to = common.getMax(msgModel.stopx, current.to);
current.width = Math.max(current.width, msgModel.width) - conf.labelBoxWidth; current.width = common.getMax(current.width, msgModel.width) - conf.labelBoxWidth;
} }
}); });
} }