mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-02-04 07:13:25 +08:00
Merge pull request #1489 from cmmoran/develop
noteModel generated during calculation of loop bounds
This commit is contained in:
commit
f95b5d05d7
@ -263,32 +263,26 @@ const drawLongText = (text, x, y, g, width) => {
|
|||||||
/**
|
/**
|
||||||
* Draws an note in the diagram with the attaced line
|
* Draws an note in the diagram with the attaced line
|
||||||
* @param elem - The diagram to draw to.
|
* @param elem - The diagram to draw to.
|
||||||
* @param startx - The x axis start position.
|
* @param noteModel:{x: number, y: number, message: string, width: number} - startx: x axis start position, verticalPos: y axis position, messsage: the message to be shown, width: Set this with a custom width to override the default configured width.
|
||||||
* @param verticalPos - The y axis position.
|
|
||||||
* @param msg - The message to be drawn.
|
|
||||||
* @param forceWidth - Set this with a custom width to override the default configured width.
|
|
||||||
*/
|
*/
|
||||||
const drawNote = function(elem, startx, verticalPos, msg, forceWidth) {
|
const drawNote = function(elem, noteModel) {
|
||||||
const rect = svgDraw.getNoteRect();
|
const rect = svgDraw.getNoteRect();
|
||||||
rect.x = startx;
|
rect.x = noteModel.x;
|
||||||
rect.y = verticalPos;
|
rect.y = noteModel.y;
|
||||||
rect.width = forceWidth || conf.width;
|
rect.width = noteModel.width || conf.width;
|
||||||
rect.class = 'note';
|
rect.class = 'note';
|
||||||
|
|
||||||
let g = elem.append('g');
|
let g = elem.append('g');
|
||||||
const rectElem = svgDraw.drawRect(g, rect);
|
const rectElem = svgDraw.drawRect(g, rect);
|
||||||
|
|
||||||
const textHeight = drawLongText(msg.message, startx, verticalPos, g, rect.width);
|
const textHeight = drawLongText(noteModel.message, noteModel.x, noteModel.y, g, rect.width);
|
||||||
|
|
||||||
bounds.insert(
|
noteModel.height = textHeight + 2 * conf.noteMargin;
|
||||||
startx,
|
|
||||||
verticalPos,
|
|
||||||
startx + rect.width,
|
|
||||||
verticalPos + 2 * conf.noteMargin + textHeight
|
|
||||||
);
|
|
||||||
|
|
||||||
rectElem.attr('height', textHeight + 2 * conf.noteMargin);
|
bounds.insert(noteModel.x, noteModel.y, noteModel.x + rect.width, noteModel.y + noteModel.height);
|
||||||
bounds.bumpVerticalPos(textHeight + 2 * conf.noteMargin);
|
|
||||||
|
rectElem.attr('height', noteModel.height);
|
||||||
|
bounds.bumpVerticalPos(noteModel.height);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -516,12 +510,7 @@ function adjustLoopHeightForWrap(loopWidths, msg, preMargin, postMargin, addLoop
|
|||||||
bounds.bumpVerticalPos(preMargin);
|
bounds.bumpVerticalPos(preMargin);
|
||||||
if (msg.message && loopWidths[msg.message]) {
|
if (msg.message && loopWidths[msg.message]) {
|
||||||
let loopWidth = loopWidths[msg.message].width;
|
let loopWidth = loopWidths[msg.message].width;
|
||||||
let minSize =
|
|
||||||
Math.round((3 * conf.messageFontSize) / 4) < 10
|
|
||||||
? conf.messageFontSize
|
|
||||||
: Math.round((3 * conf.messageFontSize) / 4);
|
|
||||||
let textConf = conf.messageFont();
|
let textConf = conf.messageFont();
|
||||||
textConf.fontSize = minSize;
|
|
||||||
msg.message = utils.wrapLabel(
|
msg.message = utils.wrapLabel(
|
||||||
`[${msg.message}]`,
|
`[${msg.message}]`,
|
||||||
loopWidth - 20 - 2 * conf.wrapPadding,
|
loopWidth - 20 - 2 * conf.wrapPadding,
|
||||||
@ -550,9 +539,6 @@ export const draw = function(text, id) {
|
|||||||
bounds.init();
|
bounds.init();
|
||||||
const diagram = select(`[id="${id}"]`);
|
const diagram = select(`[id="${id}"]`);
|
||||||
|
|
||||||
let startx;
|
|
||||||
let stopx;
|
|
||||||
|
|
||||||
// Fetch data from the parsing
|
// Fetch data from the parsing
|
||||||
const actors = parser.yy.getActors();
|
const actors = parser.yy.getActors();
|
||||||
const actorKeys = parser.yy.getActorKeys();
|
const actorKeys = parser.yy.getActorKeys();
|
||||||
@ -563,7 +549,7 @@ export const draw = function(text, id) {
|
|||||||
conf.height = calculateActorMargins(actors, maxMessageWidthPerActor);
|
conf.height = calculateActorMargins(actors, maxMessageWidthPerActor);
|
||||||
|
|
||||||
drawActors(diagram, actors, actorKeys, 0);
|
drawActors(diagram, actors, actorKeys, 0);
|
||||||
const loopWidths = calculateLoopMargins(messages, actors);
|
const loopWidths = calculateLoopBounds(messages, actors, maxMessageWidthPerActor);
|
||||||
|
|
||||||
// The arrow head definition is attached to the svg once
|
// The arrow head definition is attached to the svg once
|
||||||
svgDraw.insertArrowHead(diagram);
|
svgDraw.insertArrowHead(diagram);
|
||||||
@ -590,110 +576,15 @@ export const draw = function(text, id) {
|
|||||||
// Draw the messages/signals
|
// Draw the messages/signals
|
||||||
let sequenceIndex = 1;
|
let sequenceIndex = 1;
|
||||||
messages.forEach(function(msg) {
|
messages.forEach(function(msg) {
|
||||||
let loopData,
|
let loopData, noteModel, msgModel;
|
||||||
noteWidth,
|
|
||||||
noteStart,
|
|
||||||
noteEnd,
|
|
||||||
textWidth,
|
|
||||||
shouldWrap = msg.wrap && msg.message && !common.lineBreakRegex.test(msg.message);
|
|
||||||
|
|
||||||
switch (msg.type) {
|
switch (msg.type) {
|
||||||
case parser.yy.LINETYPE.NOTE:
|
case parser.yy.LINETYPE.NOTE:
|
||||||
bounds.bumpVerticalPos(conf.boxMargin);
|
bounds.bumpVerticalPos(conf.boxMargin);
|
||||||
|
noteModel = msg.noteModel;
|
||||||
startx = actors[msg.from].x;
|
noteModel.y = bounds.getVerticalPos();
|
||||||
stopx = actors[msg.to].x;
|
logger.debug('noteModel', noteModel);
|
||||||
noteStart = startx + actors[msg.from].width / 2;
|
drawNote(diagram, noteModel);
|
||||||
noteEnd = stopx + actors[msg.to].width / 2;
|
|
||||||
textWidth = utils.calculateTextWidth(
|
|
||||||
shouldWrap ? utils.wrapLabel(msg.message, conf.width, conf.noteFont()) : msg.message,
|
|
||||||
conf.noteFont()
|
|
||||||
);
|
|
||||||
noteWidth = shouldWrap ? conf.width : Math.max(conf.width, textWidth + 2 * conf.noteMargin);
|
|
||||||
|
|
||||||
if (msg.placement === parser.yy.PLACEMENT.RIGHTOF) {
|
|
||||||
noteWidth = shouldWrap
|
|
||||||
? conf.width
|
|
||||||
: Math.max(
|
|
||||||
actors[msg.from].width / 2 + actors[msg.to].width / 2,
|
|
||||||
textWidth + 2 * conf.noteMargin
|
|
||||||
);
|
|
||||||
if (shouldWrap) {
|
|
||||||
msg.message = utils.wrapLabel(
|
|
||||||
msg.message,
|
|
||||||
noteWidth - 2 * conf.wrapPadding,
|
|
||||||
conf.noteFont()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
drawNote(
|
|
||||||
diagram,
|
|
||||||
startx + (actors[msg.from].width + conf.actorMargin) / 2,
|
|
||||||
bounds.getVerticalPos(),
|
|
||||||
msg,
|
|
||||||
noteWidth
|
|
||||||
);
|
|
||||||
} else if (msg.placement === parser.yy.PLACEMENT.LEFTOF) {
|
|
||||||
noteWidth = shouldWrap
|
|
||||||
? conf.width
|
|
||||||
: Math.max(
|
|
||||||
actors[msg.from].width / 2 + actors[msg.to].width / 2,
|
|
||||||
textWidth + 2 * conf.noteMargin
|
|
||||||
);
|
|
||||||
if (shouldWrap) {
|
|
||||||
msg.message = utils.wrapLabel(
|
|
||||||
msg.message,
|
|
||||||
noteWidth - 2 * conf.wrapPadding,
|
|
||||||
conf.noteFont()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
drawNote(
|
|
||||||
diagram,
|
|
||||||
startx - noteWidth + (actors[msg.from].width - conf.actorMargin) / 2,
|
|
||||||
bounds.getVerticalPos(),
|
|
||||||
msg,
|
|
||||||
noteWidth
|
|
||||||
);
|
|
||||||
} else if (msg.to === msg.from) {
|
|
||||||
// Single-actor over
|
|
||||||
textWidth = utils.calculateTextWidth(
|
|
||||||
shouldWrap
|
|
||||||
? utils.wrapLabel(
|
|
||||||
msg.message,
|
|
||||||
Math.max(conf.width, actors[msg.to].width),
|
|
||||||
conf.noteFont()
|
|
||||||
)
|
|
||||||
: msg.message,
|
|
||||||
conf.noteFont()
|
|
||||||
);
|
|
||||||
noteWidth = shouldWrap
|
|
||||||
? Math.max(conf.width, actors[msg.to].width)
|
|
||||||
: Math.max(actors[msg.to].width, conf.width, textWidth + 2 * conf.noteMargin);
|
|
||||||
if (shouldWrap) {
|
|
||||||
msg.message = utils.wrapLabel(
|
|
||||||
msg.message,
|
|
||||||
noteWidth - 2 * conf.wrapPadding,
|
|
||||||
conf.noteFont()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
drawNote(
|
|
||||||
diagram,
|
|
||||||
startx + (actors[msg.to].width - noteWidth) / 2,
|
|
||||||
bounds.getVerticalPos(),
|
|
||||||
msg,
|
|
||||||
noteWidth
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Multi-actor over
|
|
||||||
noteWidth = Math.abs(noteStart - noteEnd) + conf.actorMargin;
|
|
||||||
if (shouldWrap) {
|
|
||||||
msg.message = utils.wrapLabel(msg.message, noteWidth, conf.noteFont());
|
|
||||||
}
|
|
||||||
let x =
|
|
||||||
startx < stopx
|
|
||||||
? startx + actors[msg.from].width / 2 - conf.actorMargin / 2
|
|
||||||
: stopx + actors[msg.to].width / 2 - conf.actorMargin / 2;
|
|
||||||
drawNote(diagram, x, bounds.getVerticalPos(), msg, noteWidth);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case parser.yy.LINETYPE.ACTIVE_START:
|
case parser.yy.LINETYPE.ACTIVE_START:
|
||||||
bounds.newActivation(msg, diagram, actors);
|
bounds.newActivation(msg, diagram, actors);
|
||||||
@ -780,32 +671,17 @@ export const draw = function(text, id) {
|
|||||||
try {
|
try {
|
||||||
// lastMsg = msg
|
// lastMsg = msg
|
||||||
bounds.bumpVerticalPos(conf.messageMargin);
|
bounds.bumpVerticalPos(conf.messageMargin);
|
||||||
const fromBounds = actorFlowVerticaBounds(msg.from);
|
msgModel = msg.msgModel;
|
||||||
const toBounds = actorFlowVerticaBounds(msg.to);
|
msgModel.starty = bounds.getVerticalPos();
|
||||||
const fromIdx = fromBounds[0] <= toBounds[0] ? 1 : 0;
|
drawMessage(
|
||||||
const toIdx = fromBounds[0] < toBounds[0] ? 0 : 1;
|
diagram,
|
||||||
startx = fromBounds[fromIdx];
|
msgModel.startx,
|
||||||
stopx = toBounds[toIdx];
|
msgModel.stopx,
|
||||||
if (shouldWrap) {
|
msgModel.starty,
|
||||||
msg.message = utils.wrapLabel(
|
msgModel,
|
||||||
msg.message,
|
sequenceIndex
|
||||||
Math.max(
|
|
||||||
Math.abs(stopx - startx) + conf.messageMargin * 2,
|
|
||||||
conf.width + conf.messageMargin * 2
|
|
||||||
),
|
|
||||||
conf.messageFont()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const verticalPos = bounds.getVerticalPos();
|
|
||||||
drawMessage(diagram, startx, stopx, verticalPos, msg, sequenceIndex);
|
|
||||||
const allBounds = fromBounds.concat(toBounds);
|
|
||||||
bounds.insert(
|
|
||||||
Math.min.apply(null, allBounds),
|
|
||||||
verticalPos,
|
|
||||||
Math.max.apply(null, allBounds),
|
|
||||||
verticalPos
|
|
||||||
);
|
);
|
||||||
|
bounds.insert(msgModel.fromBounds, msgModel.starty, msgModel.toBounds, msgModel.starty);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('error while drawing message', e);
|
logger.error('error while drawing message', e);
|
||||||
}
|
}
|
||||||
@ -934,10 +810,7 @@ const getMaxMessageWidthPerActor = function(actors, messages) {
|
|||||||
maxMessageWidthPerActor[msg.to] || 0,
|
maxMessageWidthPerActor[msg.to] || 0,
|
||||||
messageWidth
|
messageWidth
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (msg.placement === parser.yy.PLACEMENT.RIGHTOF) {
|
||||||
(isMessage && msg.from === actor.prevActor) ||
|
|
||||||
msg.placement === parser.yy.PLACEMENT.RIGHTOF
|
|
||||||
) {
|
|
||||||
maxMessageWidthPerActor[msg.from] = Math.max(
|
maxMessageWidthPerActor[msg.from] = Math.max(
|
||||||
maxMessageWidthPerActor[msg.from] || 0,
|
maxMessageWidthPerActor[msg.from] || 0,
|
||||||
messageWidth
|
messageWidth
|
||||||
@ -1022,10 +895,118 @@ const calculateActorMargins = function(actors, actorToMessageWidth) {
|
|||||||
return Math.max(maxHeight, conf.height);
|
return Math.max(maxHeight, conf.height);
|
||||||
};
|
};
|
||||||
|
|
||||||
const calculateLoopMargins = function(messages, actors) {
|
const buildNoteModel = function(msg, actors) {
|
||||||
|
let startx = actors[msg.from].x;
|
||||||
|
let stopx = actors[msg.to].x;
|
||||||
|
let shouldWrap = msg.wrap && msg.message && !common.lineBreakRegex.test(msg.message);
|
||||||
|
|
||||||
|
let textDimensions = utils.calculateTextDimensions(
|
||||||
|
shouldWrap ? utils.wrapLabel(msg.message, conf.width, conf.noteFont()) : msg.message,
|
||||||
|
conf.noteFont()
|
||||||
|
);
|
||||||
|
let noteModel = {
|
||||||
|
width: shouldWrap
|
||||||
|
? conf.width
|
||||||
|
: Math.max(conf.width, textDimensions.width + 2 * conf.noteMargin),
|
||||||
|
height: 0,
|
||||||
|
x: actors[msg.from].x,
|
||||||
|
y: 0,
|
||||||
|
message: msg.message
|
||||||
|
};
|
||||||
|
if (msg.placement === parser.yy.PLACEMENT.RIGHTOF) {
|
||||||
|
noteModel.width = shouldWrap
|
||||||
|
? conf.width
|
||||||
|
: Math.max(
|
||||||
|
actors[msg.from].width / 2 + actors[msg.to].width / 2,
|
||||||
|
textDimensions.width + 2 * conf.noteMargin
|
||||||
|
);
|
||||||
|
noteModel.x = startx + (actors[msg.from].width + conf.actorMargin) / 2;
|
||||||
|
} else if (msg.placement === parser.yy.PLACEMENT.LEFTOF) {
|
||||||
|
noteModel.width = shouldWrap
|
||||||
|
? conf.width
|
||||||
|
: Math.max(
|
||||||
|
actors[msg.from].width / 2 + actors[msg.to].width / 2,
|
||||||
|
textDimensions.width + 2 * conf.noteMargin
|
||||||
|
);
|
||||||
|
noteModel.x = startx - noteModel.width + (actors[msg.from].width - conf.actorMargin) / 2;
|
||||||
|
} else if (msg.to === msg.from) {
|
||||||
|
textDimensions = utils.calculateTextDimensions(
|
||||||
|
shouldWrap
|
||||||
|
? utils.wrapLabel(msg.message, Math.max(conf.width, actors[msg.to].width), conf.noteFont())
|
||||||
|
: msg.message,
|
||||||
|
conf.noteFont()
|
||||||
|
);
|
||||||
|
noteModel.width = shouldWrap
|
||||||
|
? Math.max(conf.width, actors[msg.to].width)
|
||||||
|
: Math.max(actors[msg.to].width, conf.width, textDimensions.width + 2 * conf.noteMargin);
|
||||||
|
noteModel.x = startx + (actors[msg.to].width - noteModel.width) / 2;
|
||||||
|
} else {
|
||||||
|
noteModel.width =
|
||||||
|
Math.abs(startx + actors[msg.from].width / 2 - (stopx + actors[msg.to].width / 2)) +
|
||||||
|
conf.actorMargin;
|
||||||
|
noteModel.x =
|
||||||
|
startx < stopx
|
||||||
|
? startx + actors[msg.from].width / 2 - conf.actorMargin / 2
|
||||||
|
: stopx + actors[msg.to].width / 2 - conf.actorMargin / 2;
|
||||||
|
}
|
||||||
|
if (shouldWrap) {
|
||||||
|
noteModel.message = utils.wrapLabel(
|
||||||
|
msg.message,
|
||||||
|
noteModel.width - 2 * conf.wrapPadding,
|
||||||
|
conf.noteFont()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return noteModel;
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildMessageModel = function(msg) {
|
||||||
|
let process = false;
|
||||||
|
if (
|
||||||
|
[
|
||||||
|
parser.yy.LINETYPE.SOLID_OPEN,
|
||||||
|
parser.yy.LINETYPE.DOTTED_OPEN,
|
||||||
|
parser.yy.LINETYPE.SOLID,
|
||||||
|
parser.yy.LINETYPE.DOTTED,
|
||||||
|
parser.yy.LINETYPE.SOLID_CROSS,
|
||||||
|
parser.yy.LINETYPE.DOTTED_CROSS
|
||||||
|
].includes(msg.type)
|
||||||
|
) {
|
||||||
|
process = true;
|
||||||
|
}
|
||||||
|
if (!process) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const fromBounds = actorFlowVerticaBounds(msg.from);
|
||||||
|
const toBounds = actorFlowVerticaBounds(msg.to);
|
||||||
|
const fromIdx = fromBounds[0] <= toBounds[0] ? 1 : 0;
|
||||||
|
const toIdx = fromBounds[0] < toBounds[0] ? 0 : 1;
|
||||||
|
const allBounds = fromBounds.concat(toBounds);
|
||||||
|
const msgModel = {
|
||||||
|
width: Math.abs(toBounds[toIdx] - fromBounds[fromIdx]) + conf.messageMargin * 2,
|
||||||
|
height: 0,
|
||||||
|
startx: fromBounds[fromIdx],
|
||||||
|
stopx: toBounds[toIdx],
|
||||||
|
starty: 0,
|
||||||
|
stopy: 0,
|
||||||
|
message: msg.message,
|
||||||
|
type: msg.type,
|
||||||
|
fromBounds: Math.min.apply(null, allBounds),
|
||||||
|
toBounds: Math.max.apply(null, allBounds)
|
||||||
|
};
|
||||||
|
if (msg.wrap && msg.message && !common.lineBreakRegex.test(msg.message)) {
|
||||||
|
msgModel.message = utils.wrapLabel(
|
||||||
|
msg.message,
|
||||||
|
Math.max(msgModel.width, conf.width + conf.messageMargin * 2),
|
||||||
|
conf.messageFont()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return msgModel;
|
||||||
|
};
|
||||||
|
|
||||||
|
const calculateLoopBounds = function(messages, actors) {
|
||||||
const loops = {};
|
const loops = {};
|
||||||
const stack = [];
|
const stack = [];
|
||||||
let current;
|
let current, noteModel, msgModel;
|
||||||
|
|
||||||
messages.forEach(function(msg) {
|
messages.forEach(function(msg) {
|
||||||
switch (msg.type) {
|
switch (msg.type) {
|
||||||
@ -1056,27 +1037,46 @@ const calculateLoopMargins = function(messages, actors) {
|
|||||||
loops[current.msg] = current;
|
loops[current.msg] = current;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (msg.from && msg.to && stack.length > 0) {
|
const isNote = msg.placement !== undefined;
|
||||||
|
if (isNote) {
|
||||||
|
noteModel = buildNoteModel(msg, actors);
|
||||||
|
msg.noteModel = noteModel;
|
||||||
stack.forEach(stk => {
|
stack.forEach(stk => {
|
||||||
current = stk;
|
current = stk;
|
||||||
let from = actors[msg.from];
|
current.from = Math.min(current.from, noteModel.x);
|
||||||
let to = actors[msg.to];
|
current.to = Math.max(current.to, noteModel.x + noteModel.width);
|
||||||
if (from.x === to.x) {
|
current.width = Math.max(current.width, Math.abs(current.from - current.to));
|
||||||
current.from = current.to = from.x;
|
});
|
||||||
current.width = from.width;
|
} else {
|
||||||
} else {
|
msgModel = buildMessageModel(msg);
|
||||||
if (from.x < to.x) {
|
msg.msgModel = msgModel;
|
||||||
|
if (msg.from && msg.to && stack.length > 0) {
|
||||||
|
stack.forEach(stk => {
|
||||||
|
current = stk;
|
||||||
|
let from = actors[msg.from];
|
||||||
|
let to = actors[msg.to];
|
||||||
|
if (from.x === to.x) {
|
||||||
current.from = Math.min(current.from, from.x);
|
current.from = Math.min(current.from, from.x);
|
||||||
current.to = Math.max(current.to, to.x);
|
current.to = Math.max(current.to, to.x);
|
||||||
|
current.width = Math.max(current.width, from.width);
|
||||||
} else {
|
} else {
|
||||||
current.from = Math.min(current.from, to.x);
|
if (from.x < to.x) {
|
||||||
current.to = Math.max(current.to, from.x);
|
current.from = Math.min(current.from, from.x);
|
||||||
|
current.to = Math.max(current.to, to.x);
|
||||||
|
} else {
|
||||||
|
current.from = Math.min(current.from, to.x);
|
||||||
|
current.to = Math.max(current.to, from.x);
|
||||||
|
}
|
||||||
|
current.width = Math.max(
|
||||||
|
current.width,
|
||||||
|
Math.abs(current.from - current.to) - 20 + 2 * conf.wrapPadding
|
||||||
|
);
|
||||||
}
|
}
|
||||||
current.width = Math.abs(current.from - current.to) - 20 + 2 * conf.wrapPadding;
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
logger.debug('Loop type widths:', loops);
|
||||||
return loops;
|
return loops;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user