mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-15 13:29:40 +02:00
addition: added bounds models for bounds checking in unit tests.
addition: bounds.init will clear models addition: added loop model widths id instead of using title as the id removed parseMessage debug message addition: added configuration labelBoxWidth and labelBoxHeight for loop label box width/height change: adjusted svgDraw drawText to support anchor and valign and whether to output a tspan change: drawText returns an array regardless of array size change: hardcoded label width/height uses conf.labelBoxWidth and conf.labelBoxHeight change: Math.round() on many of the calculations to clean up bounds values change: getTextObj anchor, width, height start as undefined
This commit is contained in:
@@ -508,7 +508,7 @@ context('Sequence diagram', () => {
|
|||||||
it('should overide config with directive settings', () => {
|
it('should overide config with directive settings', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
%%{init: { "sequence": { "mirrorActors": true }}}%%
|
%%{init: { "config": { "mirrorActors": true }}}%%
|
||||||
sequenceDiagram
|
sequenceDiagram
|
||||||
Alice->>Bob: I'm short
|
Alice->>Bob: I'm short
|
||||||
note left of Alice: config set to mirrorActors: false<br/>directive set to mirrorActors: true
|
note left of Alice: config set to mirrorActors: false<br/>directive set to mirrorActors: true
|
||||||
@@ -520,7 +520,7 @@ context('Sequence diagram', () => {
|
|||||||
it('should overide config with directive settings', () => {
|
it('should overide config with directive settings', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
%%{init: { "sequence": { "mirrorActors": false }}}%%
|
%%{init: { "config": { "mirrorActors": false }}}%%
|
||||||
sequenceDiagram
|
sequenceDiagram
|
||||||
%%{config: { "mirrorActors": false} }%%
|
%%{config: { "mirrorActors": false} }%%
|
||||||
Alice->>Bob: I'm short
|
Alice->>Bob: I'm short
|
||||||
|
@@ -202,7 +202,7 @@ export const clear = function() {
|
|||||||
|
|
||||||
export const parseMessage = function(str) {
|
export const parseMessage = function(str) {
|
||||||
const _str = str.trim();
|
const _str = str.trim();
|
||||||
const retVal = {
|
return {
|
||||||
text: _str.replace(/^[:]?(?:no)?wrap:/, '').trim(),
|
text: _str.replace(/^[:]?(?:no)?wrap:/, '').trim(),
|
||||||
wrap:
|
wrap:
|
||||||
_str.match(/^[:]?(?:no)?wrap:/) === null
|
_str.match(/^[:]?(?:no)?wrap:/) === null
|
||||||
@@ -213,8 +213,6 @@ export const parseMessage = function(str) {
|
|||||||
? false
|
? false
|
||||||
: autoWrap()
|
: autoWrap()
|
||||||
};
|
};
|
||||||
logger.debug(`ParseMessage[${str}] [${JSON.stringify(retVal, null, 2)}`);
|
|
||||||
return retVal;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const LINETYPE = {
|
export const LINETYPE = {
|
||||||
|
@@ -46,6 +46,8 @@ const conf = {
|
|||||||
|
|
||||||
// width of activation box
|
// width of activation box
|
||||||
activationWidth: 10,
|
activationWidth: 10,
|
||||||
|
labelBoxWidth: 50,
|
||||||
|
labelBoxHeight: 20,
|
||||||
|
|
||||||
// text placement as: tspan | fo | old only text as before
|
// text placement as: tspan | fo | old only text as before
|
||||||
textPlacement: 'tspan',
|
textPlacement: 'tspan',
|
||||||
@@ -91,9 +93,19 @@ export const bounds = {
|
|||||||
|
|
||||||
sequenceItems: [],
|
sequenceItems: [],
|
||||||
activations: [],
|
activations: [],
|
||||||
|
models: {
|
||||||
|
loops: [],
|
||||||
|
messages: [],
|
||||||
|
notes: []
|
||||||
|
},
|
||||||
init: function() {
|
init: function() {
|
||||||
this.sequenceItems = [];
|
this.sequenceItems = [];
|
||||||
this.activations = [];
|
this.activations = [];
|
||||||
|
this.models = {
|
||||||
|
loops: [],
|
||||||
|
messages: [],
|
||||||
|
notes: []
|
||||||
|
};
|
||||||
this.data = {
|
this.data = {
|
||||||
startx: undefined,
|
startx: undefined,
|
||||||
stopx: undefined,
|
stopx: undefined,
|
||||||
@@ -181,6 +193,7 @@ export const bounds = {
|
|||||||
title: title.message,
|
title: title.message,
|
||||||
wrap: title.wrap,
|
wrap: title.wrap,
|
||||||
width: title.width,
|
width: title.width,
|
||||||
|
height: 0,
|
||||||
fill: fill
|
fill: fill
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -194,7 +207,7 @@ export const bounds = {
|
|||||||
const loop = this.sequenceItems.pop();
|
const loop = this.sequenceItems.pop();
|
||||||
loop.sections = loop.sections || [];
|
loop.sections = loop.sections || [];
|
||||||
loop.sectionTitles = loop.sectionTitles || [];
|
loop.sectionTitles = loop.sectionTitles || [];
|
||||||
loop.sections.push(bounds.getVerticalPos());
|
loop.sections.push({ y: bounds.getVerticalPos(), height: 0 });
|
||||||
loop.sectionTitles.push(message);
|
loop.sectionTitles.push(message);
|
||||||
this.sequenceItems.push(loop);
|
this.sequenceItems.push(loop);
|
||||||
},
|
},
|
||||||
@@ -210,58 +223,8 @@ export const bounds = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const drawLongText = (text, x, y, g, width) => {
|
|
||||||
const alignmentToAnchor = {
|
|
||||||
left: 'start',
|
|
||||||
start: 'start',
|
|
||||||
center: 'middle',
|
|
||||||
middle: 'middle',
|
|
||||||
right: 'end',
|
|
||||||
end: 'end'
|
|
||||||
};
|
|
||||||
const alignment = alignmentToAnchor[conf.noteAlign] || 'middle';
|
|
||||||
const textObj = svgDraw.getTextObj();
|
|
||||||
switch (alignment) {
|
|
||||||
case 'start':
|
|
||||||
textObj.x = x + conf.noteMargin;
|
|
||||||
break;
|
|
||||||
case 'middle':
|
|
||||||
textObj.x = x + width / 2;
|
|
||||||
break;
|
|
||||||
case 'end':
|
|
||||||
textObj.x = x + width - conf.noteMargin;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
textObj.y = y;
|
|
||||||
textObj.dy = '1em';
|
|
||||||
textObj.text = text;
|
|
||||||
textObj.class = 'noteText';
|
|
||||||
textObj.fontFamily = conf.noteFontFamily;
|
|
||||||
textObj.fontSize = conf.noteFontSize;
|
|
||||||
textObj.fontWeight = conf.noteFontWeight;
|
|
||||||
textObj.anchor = alignment;
|
|
||||||
textObj.textMargin = conf.noteMargin;
|
|
||||||
textObj.valign = alignment;
|
|
||||||
textObj.wrap = true;
|
|
||||||
|
|
||||||
let textElem = drawText(g, textObj);
|
|
||||||
|
|
||||||
if (!Array.isArray(textElem)) {
|
|
||||||
textElem = [textElem];
|
|
||||||
}
|
|
||||||
|
|
||||||
textElem.forEach(te => {
|
|
||||||
te.attr('dominant-baseline', 'central').attr('alignment-baseline', 'central');
|
|
||||||
});
|
|
||||||
|
|
||||||
return textElem
|
|
||||||
.map(te => (te._groups || te)[0][0].getBBox().height)
|
|
||||||
.reduce((acc, curr) => acc + curr);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws an note in the diagram with the attaced line
|
* Draws an note in the diagram with the attached line
|
||||||
* @param elem - The diagram to draw to.
|
* @param elem - The diagram to draw to.
|
||||||
* @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 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.
|
||||||
*/
|
*/
|
||||||
@@ -274,8 +237,26 @@ const drawNote = function(elem, noteModel) {
|
|||||||
|
|
||||||
let g = elem.append('g');
|
let g = elem.append('g');
|
||||||
const rectElem = svgDraw.drawRect(g, rect);
|
const rectElem = svgDraw.drawRect(g, rect);
|
||||||
|
const textObj = svgDraw.getTextObj();
|
||||||
|
textObj.x = noteModel.x;
|
||||||
|
textObj.y = noteModel.y;
|
||||||
|
textObj.width = rect.width;
|
||||||
|
textObj.dy = '1em';
|
||||||
|
textObj.text = noteModel.message;
|
||||||
|
textObj.class = 'noteText';
|
||||||
|
textObj.fontFamily = conf.noteFontFamily;
|
||||||
|
textObj.fontSize = conf.noteFontSize;
|
||||||
|
textObj.fontWeight = conf.noteFontWeight;
|
||||||
|
textObj.anchor = conf.noteAlign;
|
||||||
|
textObj.textMargin = conf.noteMargin;
|
||||||
|
textObj.valign = conf.noteAlign;
|
||||||
|
textObj.wrap = true;
|
||||||
|
|
||||||
const textHeight = drawLongText(noteModel.message, noteModel.x, noteModel.y, g, rect.width);
|
let textElem = drawText(g, textObj);
|
||||||
|
|
||||||
|
let textHeight = Math.round(
|
||||||
|
textElem.map(te => (te._groups || te)[0][0].getBBox().height).reduce((acc, curr) => acc + curr)
|
||||||
|
);
|
||||||
|
|
||||||
noteModel.height = textHeight + 2 * conf.noteMargin;
|
noteModel.height = textHeight + 2 * conf.noteMargin;
|
||||||
|
|
||||||
@@ -287,52 +268,41 @@ const drawNote = function(elem, noteModel) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws a message
|
* Draws a message
|
||||||
* @param elem
|
* @param g - the parent of the message element
|
||||||
* @param startx
|
* @param msgModel - the model containing fields describing a message
|
||||||
* @param stopx
|
|
||||||
* @param verticalPos
|
|
||||||
* @param msg
|
|
||||||
* @param sequenceIndex
|
|
||||||
*/
|
*/
|
||||||
const drawMessage = function(elem, startx, stopx, verticalPos, msg, sequenceIndex) {
|
const drawMessage = function(g, msgModel) {
|
||||||
const g = elem.append('g');
|
const { startx, stopx, starty: verticalPos, message, type, sequenceIndex, wrap } = msgModel;
|
||||||
const txtCenter = startx + (stopx - startx) / 2;
|
const textObj = svgDraw.getTextObj();
|
||||||
|
textObj.x = startx;
|
||||||
|
textObj.y = verticalPos - (conf.messageFontSize + 7);
|
||||||
|
textObj.width = stopx - startx;
|
||||||
|
textObj.class = 'messageText';
|
||||||
|
textObj.dy = '1em';
|
||||||
|
textObj.text = message;
|
||||||
|
textObj.fontFamily = conf.messageFontFamily;
|
||||||
|
textObj.fontSize = conf.messageFontSize;
|
||||||
|
textObj.fontWeight = conf.messageFontWeight;
|
||||||
|
textObj.anchor = conf.messageAlign;
|
||||||
|
textObj.valign = conf.messageAlign;
|
||||||
|
textObj.textMargin = conf.wrapPadding;
|
||||||
|
textObj.tspan = false;
|
||||||
|
textObj.wrap = wrap;
|
||||||
|
|
||||||
let textElems = [];
|
let textElem = drawText(g, textObj);
|
||||||
|
|
||||||
let counterBreaklines = 0;
|
const lines = message.split(common.lineBreakRegex).length - 1 > 0 ? 1 : 0;
|
||||||
let breaklineOffset = conf.messageFontSize;
|
|
||||||
const breaklines = msg.message.split(common.lineBreakRegex);
|
|
||||||
for (const breakline of breaklines) {
|
|
||||||
textElems.push(
|
|
||||||
g
|
|
||||||
.append('text') // text label for the x axis
|
|
||||||
.attr('x', txtCenter)
|
|
||||||
.attr('y', verticalPos - 7 + counterBreaklines * breaklineOffset)
|
|
||||||
.style('font-size', conf.messageFontSize)
|
|
||||||
.style('font-family', conf.messageFontFamily)
|
|
||||||
.style('font-weight', conf.messageFontWeight)
|
|
||||||
.style('text-anchor', 'middle')
|
|
||||||
.attr('class', 'messageText')
|
|
||||||
.text(breakline.trim())
|
|
||||||
);
|
|
||||||
counterBreaklines++;
|
|
||||||
}
|
|
||||||
const offsetLineCounter = counterBreaklines - 1;
|
|
||||||
let totalOffset = offsetLineCounter * breaklineOffset;
|
|
||||||
let textWidths = textElems.map(function(textElem) {
|
|
||||||
return (textElem._groups || textElem)[0][0].getBBox().width;
|
|
||||||
});
|
|
||||||
let textWidth = Math.max(...textWidths);
|
|
||||||
for (const textElem of textElems) {
|
|
||||||
if (conf.messageAlign === 'left') {
|
|
||||||
textElem.attr('x', txtCenter - textWidth / 2).style('text-anchor', 'start');
|
|
||||||
} else if (conf.messageAlign === 'right') {
|
|
||||||
textElem.attr('x', txtCenter + textWidth / 2).style('text-anchor', 'end');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bounds.bumpVerticalPos(totalOffset);
|
let totalOffset = Math.round(
|
||||||
|
textElem.map(te => (te._groups || te)[0][0].getBBox().height).reduce((acc, curr) => acc + curr)
|
||||||
|
);
|
||||||
|
|
||||||
|
let textWidth = Math.max.apply(
|
||||||
|
null,
|
||||||
|
textElem.map(te => (te._groups || te)[0][0].getBBox().width)
|
||||||
|
);
|
||||||
|
|
||||||
|
bounds.bumpVerticalPos(totalOffset - lines * conf.messageFontSize);
|
||||||
|
|
||||||
let line;
|
let line;
|
||||||
if (startx === stopx) {
|
if (startx === stopx) {
|
||||||
@@ -371,7 +341,7 @@ const drawMessage = function(elem, startx, stopx, verticalPos, msg, sequenceInde
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bounds.bumpVerticalPos(30 + totalOffset);
|
bounds.bumpVerticalPos(30);
|
||||||
const dx = Math.max(textWidth / 2, 100);
|
const dx = Math.max(textWidth / 2, 100);
|
||||||
bounds.insert(
|
bounds.insert(
|
||||||
startx - dx,
|
startx - dx,
|
||||||
@@ -395,9 +365,9 @@ const drawMessage = function(elem, startx, stopx, verticalPos, msg, sequenceInde
|
|||||||
// Make an SVG Container
|
// Make an SVG Container
|
||||||
// Draw the line
|
// Draw the line
|
||||||
if (
|
if (
|
||||||
msg.type === parser.yy.LINETYPE.DOTTED ||
|
type === parser.yy.LINETYPE.DOTTED ||
|
||||||
msg.type === parser.yy.LINETYPE.DOTTED_CROSS ||
|
type === parser.yy.LINETYPE.DOTTED_CROSS ||
|
||||||
msg.type === parser.yy.LINETYPE.DOTTED_OPEN
|
type === parser.yy.LINETYPE.DOTTED_OPEN
|
||||||
) {
|
) {
|
||||||
line.style('stroke-dasharray', '3, 3');
|
line.style('stroke-dasharray', '3, 3');
|
||||||
line.attr('class', 'messageLine1');
|
line.attr('class', 'messageLine1');
|
||||||
@@ -420,11 +390,11 @@ const drawMessage = function(elem, startx, stopx, verticalPos, msg, sequenceInde
|
|||||||
line.attr('stroke-width', 2);
|
line.attr('stroke-width', 2);
|
||||||
line.attr('stroke', 'black');
|
line.attr('stroke', 'black');
|
||||||
line.style('fill', 'none'); // remove any fill colour
|
line.style('fill', 'none'); // remove any fill colour
|
||||||
if (msg.type === parser.yy.LINETYPE.SOLID || msg.type === parser.yy.LINETYPE.DOTTED) {
|
if (type === parser.yy.LINETYPE.SOLID || type === parser.yy.LINETYPE.DOTTED) {
|
||||||
line.attr('marker-end', 'url(' + url + '#arrowhead)');
|
line.attr('marker-end', 'url(' + url + '#arrowhead)');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg.type === parser.yy.LINETYPE.SOLID_CROSS || msg.type === parser.yy.LINETYPE.DOTTED_CROSS) {
|
if (type === parser.yy.LINETYPE.SOLID_CROSS || type === parser.yy.LINETYPE.DOTTED_CROSS) {
|
||||||
line.attr('marker-end', 'url(' + url + '#crosshead)');
|
line.attr('marker-end', 'url(' + url + '#crosshead)');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,8 +422,8 @@ export const drawActors = function(diagram, actors, actorKeys, verticalPos) {
|
|||||||
const actor = actors[actorKeys[i]];
|
const actor = actors[actorKeys[i]];
|
||||||
|
|
||||||
// Add some rendering data to the object
|
// Add some rendering data to the object
|
||||||
actor.width = actor.width ? actor.width : conf.width;
|
actor.width = actor.width || conf.width;
|
||||||
actor.height = conf.height;
|
actor.height = Math.max(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;
|
||||||
@@ -491,9 +461,9 @@ const actorActivations = function(actor) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const actorFlowVerticaBounds = function(actor) {
|
const actorFlowVerticaBounds = function(actor, actors) {
|
||||||
// handle multiple stacked activations for same actor
|
// handle multiple stacked activations for same actor
|
||||||
const actorObj = parser.yy.getActors()[actor];
|
const actorObj = actors[actor];
|
||||||
const activations = actorActivations(actor);
|
const activations = actorActivations(actor);
|
||||||
|
|
||||||
const left = activations.reduce(function(acc, activation) {
|
const left = activations.reduce(function(acc, activation) {
|
||||||
@@ -506,28 +476,23 @@ const actorFlowVerticaBounds = function(actor) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function adjustLoopHeightForWrap(loopWidths, msg, preMargin, postMargin, addLoopFn) {
|
function adjustLoopHeightForWrap(loopWidths, msg, preMargin, postMargin, addLoopFn) {
|
||||||
let heightAdjust = 0;
|
|
||||||
bounds.bumpVerticalPos(preMargin);
|
bounds.bumpVerticalPos(preMargin);
|
||||||
if (msg.message && loopWidths[msg.message]) {
|
let heightAdjust = postMargin;
|
||||||
let loopWidth = loopWidths[msg.message].width;
|
if (msg.id && msg.message && loopWidths[msg.id]) {
|
||||||
|
let loopWidth = loopWidths[msg.id].width;
|
||||||
let textConf = conf.messageFont();
|
let textConf = conf.messageFont();
|
||||||
msg.message = utils.wrapLabel(
|
msg.message = utils.wrapLabel(`[${msg.message}]`, loopWidth - 2 * conf.wrapPadding, textConf);
|
||||||
`[${msg.message}]`,
|
msg.width = loopWidth;
|
||||||
loopWidth - 20 - 2 * conf.wrapPadding,
|
|
||||||
textConf
|
|
||||||
);
|
|
||||||
|
|
||||||
heightAdjust = Math.max(
|
const textHeight = utils.calculateTextHeight(msg.message, textConf);
|
||||||
0,
|
heightAdjust += textHeight;
|
||||||
utils.calculateTextHeight(msg.message, textConf) - (preMargin + postMargin)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
addLoopFn(msg);
|
addLoopFn(msg);
|
||||||
bounds.bumpVerticalPos(heightAdjust + postMargin);
|
bounds.bumpVerticalPos(heightAdjust);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws a flowchart in the tag with id: id based on the graph definition in text.
|
* Draws a sequenceDiagram in the tag with id: id based on the graph definition in text.
|
||||||
* @param text
|
* @param text
|
||||||
* @param id
|
* @param id
|
||||||
*/
|
*/
|
||||||
@@ -576,15 +541,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, noteModel, msgModel;
|
let loopModel, noteModel, msgModel;
|
||||||
|
|
||||||
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;
|
noteModel = msg.noteModel;
|
||||||
noteModel.y = bounds.getVerticalPos();
|
noteModel.y = bounds.getVerticalPos();
|
||||||
logger.debug('noteModel', noteModel);
|
|
||||||
drawNote(diagram, noteModel);
|
drawNote(diagram, noteModel);
|
||||||
|
bounds.models.notes.push(noteModel);
|
||||||
break;
|
break;
|
||||||
case parser.yy.LINETYPE.ACTIVE_START:
|
case parser.yy.LINETYPE.ACTIVE_START:
|
||||||
bounds.newActivation(msg, diagram, actors);
|
bounds.newActivation(msg, diagram, actors);
|
||||||
@@ -602,18 +567,21 @@ export const draw = function(text, id) {
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case parser.yy.LINETYPE.LOOP_END:
|
case parser.yy.LINETYPE.LOOP_END:
|
||||||
loopData = bounds.endLoop();
|
loopModel = bounds.endLoop();
|
||||||
svgDraw.drawLoop(diagram, loopData, 'loop', conf);
|
svgDraw.drawLoop(diagram, loopModel, 'loop', conf);
|
||||||
bounds.bumpVerticalPos(conf.boxMargin);
|
bounds.models.loops.push(loopModel);
|
||||||
|
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
|
||||||
break;
|
break;
|
||||||
case parser.yy.LINETYPE.RECT_START:
|
case parser.yy.LINETYPE.RECT_START:
|
||||||
bounds.bumpVerticalPos(conf.boxMargin);
|
adjustLoopHeightForWrap(loopWidths, msg, conf.boxMargin, conf.boxMargin, message =>
|
||||||
bounds.newLoop(undefined, msg.message);
|
bounds.newLoop(undefined, message.message)
|
||||||
bounds.bumpVerticalPos(conf.boxMargin);
|
);
|
||||||
break;
|
break;
|
||||||
case parser.yy.LINETYPE.RECT_END:
|
case parser.yy.LINETYPE.RECT_END:
|
||||||
svgDraw.drawBackgroundRect(diagram, bounds.endLoop());
|
loopModel = bounds.endLoop();
|
||||||
bounds.bumpVerticalPos(conf.boxMargin);
|
svgDraw.drawBackgroundRect(diagram, loopModel);
|
||||||
|
bounds.models.loops.push(loopModel);
|
||||||
|
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
|
||||||
break;
|
break;
|
||||||
case parser.yy.LINETYPE.OPT_START:
|
case parser.yy.LINETYPE.OPT_START:
|
||||||
adjustLoopHeightForWrap(
|
adjustLoopHeightForWrap(
|
||||||
@@ -625,9 +593,10 @@ export const draw = function(text, id) {
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case parser.yy.LINETYPE.OPT_END:
|
case parser.yy.LINETYPE.OPT_END:
|
||||||
loopData = bounds.endLoop();
|
loopModel = bounds.endLoop();
|
||||||
svgDraw.drawLoop(diagram, loopData, 'opt', conf);
|
svgDraw.drawLoop(diagram, loopModel, 'opt', conf);
|
||||||
bounds.bumpVerticalPos(conf.boxMargin);
|
bounds.models.loops.push(loopModel);
|
||||||
|
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
|
||||||
break;
|
break;
|
||||||
case parser.yy.LINETYPE.ALT_START:
|
case parser.yy.LINETYPE.ALT_START:
|
||||||
adjustLoopHeightForWrap(
|
adjustLoopHeightForWrap(
|
||||||
@@ -639,14 +608,19 @@ export const draw = function(text, id) {
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case parser.yy.LINETYPE.ALT_ELSE:
|
case parser.yy.LINETYPE.ALT_ELSE:
|
||||||
adjustLoopHeightForWrap(loopWidths, msg, conf.boxMargin, conf.boxMargin, message =>
|
adjustLoopHeightForWrap(
|
||||||
bounds.addSectionToLoop(message)
|
loopWidths,
|
||||||
|
msg,
|
||||||
|
conf.boxMargin + conf.boxTextMargin,
|
||||||
|
conf.boxMargin,
|
||||||
|
message => bounds.addSectionToLoop(message)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case parser.yy.LINETYPE.ALT_END:
|
case parser.yy.LINETYPE.ALT_END:
|
||||||
loopData = bounds.endLoop();
|
loopModel = bounds.endLoop();
|
||||||
svgDraw.drawLoop(diagram, loopData, 'alt', conf);
|
svgDraw.drawLoop(diagram, loopModel, 'alt', conf);
|
||||||
bounds.bumpVerticalPos(conf.boxMargin);
|
bounds.models.loops.push(loopModel);
|
||||||
|
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
|
||||||
break;
|
break;
|
||||||
case parser.yy.LINETYPE.PAR_START:
|
case parser.yy.LINETYPE.PAR_START:
|
||||||
adjustLoopHeightForWrap(
|
adjustLoopHeightForWrap(
|
||||||
@@ -658,14 +632,19 @@ export const draw = function(text, id) {
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case parser.yy.LINETYPE.PAR_AND:
|
case parser.yy.LINETYPE.PAR_AND:
|
||||||
adjustLoopHeightForWrap(loopWidths, msg, conf.boxMargin, conf.boxMargin, message =>
|
adjustLoopHeightForWrap(
|
||||||
bounds.addSectionToLoop(message)
|
loopWidths,
|
||||||
|
msg,
|
||||||
|
conf.boxMargin + conf.boxTextMargin,
|
||||||
|
conf.boxMargin,
|
||||||
|
message => bounds.addSectionToLoop(message)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case parser.yy.LINETYPE.PAR_END:
|
case parser.yy.LINETYPE.PAR_END:
|
||||||
loopData = bounds.endLoop();
|
loopModel = bounds.endLoop();
|
||||||
svgDraw.drawLoop(diagram, loopData, 'par', conf);
|
svgDraw.drawLoop(diagram, loopModel, 'par', conf);
|
||||||
bounds.bumpVerticalPos(conf.boxMargin);
|
bounds.models.loops.push(loopModel);
|
||||||
|
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
try {
|
try {
|
||||||
@@ -673,14 +652,9 @@ export const draw = function(text, id) {
|
|||||||
bounds.bumpVerticalPos(conf.messageMargin);
|
bounds.bumpVerticalPos(conf.messageMargin);
|
||||||
msgModel = msg.msgModel;
|
msgModel = msg.msgModel;
|
||||||
msgModel.starty = bounds.getVerticalPos();
|
msgModel.starty = bounds.getVerticalPos();
|
||||||
drawMessage(
|
msgModel.sequenceIndex = sequenceIndex;
|
||||||
diagram,
|
drawMessage(diagram, msgModel);
|
||||||
msgModel.startx,
|
bounds.models.messages.push(msgModel);
|
||||||
msgModel.stopx,
|
|
||||||
msgModel.starty,
|
|
||||||
msgModel,
|
|
||||||
sequenceIndex
|
|
||||||
);
|
|
||||||
bounds.insert(msgModel.fromBounds, msgModel.starty, msgModel.toBounds, msgModel.starty);
|
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);
|
||||||
@@ -750,6 +724,7 @@ export const draw = function(text, id) {
|
|||||||
' ' +
|
' ' +
|
||||||
(height + extraVertForTitle)
|
(height + extraVertForTitle)
|
||||||
);
|
);
|
||||||
|
logger.debug('bounds', bounds);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -784,10 +759,10 @@ const getMaxMessageWidthPerActor = function(actors, messages) {
|
|||||||
|
|
||||||
const textFont = isNote ? conf.noteFont() : conf.messageFont();
|
const textFont = isNote ? conf.noteFont() : conf.messageFont();
|
||||||
let wrappedMessage = msg.wrap
|
let wrappedMessage = msg.wrap
|
||||||
? utils.wrapLabel(msg.message, conf.width - conf.noteMargin, textFont)
|
? utils.wrapLabel(msg.message, conf.width - 2 * conf.wrapPadding, textFont)
|
||||||
: msg.message;
|
: msg.message;
|
||||||
const messageDimensions = utils.calculateTextDimensions(wrappedMessage, textFont);
|
const messageDimensions = utils.calculateTextDimensions(wrappedMessage, textFont);
|
||||||
const messageWidth = messageDimensions.width;
|
const messageWidth = messageDimensions.width + 2 * conf.wrapPadding;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following scenarios should be supported:
|
* The following scenarios should be supported:
|
||||||
@@ -838,7 +813,7 @@ const getMaxMessageWidthPerActor = function(actors, messages) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
logger.debug('MaxMessages:', maxMessageWidthPerActor);
|
logger.debug('maxMessageWidthPerActor:', maxMessageWidthPerActor);
|
||||||
return maxMessageWidthPerActor;
|
return maxMessageWidthPerActor;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -915,7 +890,7 @@ const buildNoteModel = function(msg, actors) {
|
|||||||
};
|
};
|
||||||
if (msg.placement === parser.yy.PLACEMENT.RIGHTOF) {
|
if (msg.placement === parser.yy.PLACEMENT.RIGHTOF) {
|
||||||
noteModel.width = shouldWrap
|
noteModel.width = shouldWrap
|
||||||
? conf.width
|
? Math.max(conf.width, textDimensions.width)
|
||||||
: Math.max(
|
: Math.max(
|
||||||
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
|
||||||
@@ -923,7 +898,7 @@ const buildNoteModel = function(msg, actors) {
|
|||||||
noteModel.x = startx + (actors[msg.from].width + conf.actorMargin) / 2;
|
noteModel.x = startx + (actors[msg.from].width + conf.actorMargin) / 2;
|
||||||
} else if (msg.placement === parser.yy.PLACEMENT.LEFTOF) {
|
} else if (msg.placement === parser.yy.PLACEMENT.LEFTOF) {
|
||||||
noteModel.width = shouldWrap
|
noteModel.width = shouldWrap
|
||||||
? conf.width
|
? Math.max(conf.width, textDimensions.width + 2 * conf.noteMargin)
|
||||||
: Math.max(
|
: Math.max(
|
||||||
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
|
||||||
@@ -959,7 +934,7 @@ const buildNoteModel = function(msg, actors) {
|
|||||||
return noteModel;
|
return noteModel;
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildMessageModel = function(msg) {
|
const buildMessageModel = function(msg, actors) {
|
||||||
let process = false;
|
let process = false;
|
||||||
if (
|
if (
|
||||||
[
|
[
|
||||||
@@ -976,13 +951,13 @@ const buildMessageModel = function(msg) {
|
|||||||
if (!process) {
|
if (!process) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
const fromBounds = actorFlowVerticaBounds(msg.from);
|
const fromBounds = actorFlowVerticaBounds(msg.from, actors);
|
||||||
const toBounds = actorFlowVerticaBounds(msg.to);
|
const toBounds = actorFlowVerticaBounds(msg.to, actors);
|
||||||
const fromIdx = fromBounds[0] <= toBounds[0] ? 1 : 0;
|
const fromIdx = fromBounds[0] <= toBounds[0] ? 1 : 0;
|
||||||
const toIdx = fromBounds[0] < toBounds[0] ? 0 : 1;
|
const toIdx = fromBounds[0] < toBounds[0] ? 0 : 1;
|
||||||
const allBounds = fromBounds.concat(toBounds);
|
const allBounds = fromBounds.concat(toBounds);
|
||||||
const msgModel = {
|
const msgModel = {
|
||||||
width: Math.abs(toBounds[toIdx] - fromBounds[fromIdx]) + conf.messageMargin * 2,
|
width: Math.abs(toBounds[toIdx] - fromBounds[fromIdx]),
|
||||||
height: 0,
|
height: 0,
|
||||||
startx: fromBounds[fromIdx],
|
startx: fromBounds[fromIdx],
|
||||||
stopx: toBounds[toIdx],
|
stopx: toBounds[toIdx],
|
||||||
@@ -990,13 +965,14 @@ const buildMessageModel = function(msg) {
|
|||||||
stopy: 0,
|
stopy: 0,
|
||||||
message: msg.message,
|
message: msg.message,
|
||||||
type: msg.type,
|
type: msg.type,
|
||||||
|
wrap: msg.wrap,
|
||||||
fromBounds: Math.min.apply(null, allBounds),
|
fromBounds: Math.min.apply(null, allBounds),
|
||||||
toBounds: Math.max.apply(null, allBounds)
|
toBounds: Math.max.apply(null, allBounds)
|
||||||
};
|
};
|
||||||
if (msg.wrap && msg.message && !common.lineBreakRegex.test(msg.message)) {
|
if (msg.wrap && msg.message && !common.lineBreakRegex.test(msg.message)) {
|
||||||
msgModel.message = utils.wrapLabel(
|
msgModel.message = utils.wrapLabel(
|
||||||
msg.message,
|
msg.message,
|
||||||
Math.max(msgModel.width, conf.width + conf.messageMargin * 2),
|
Math.max(msgModel.width, conf.width),
|
||||||
conf.messageFont()
|
conf.messageFont()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1009,12 +985,14 @@ const calculateLoopBounds = function(messages, actors) {
|
|||||||
let current, noteModel, msgModel;
|
let current, noteModel, msgModel;
|
||||||
|
|
||||||
messages.forEach(function(msg) {
|
messages.forEach(function(msg) {
|
||||||
|
msg.id = utils.generateId();
|
||||||
switch (msg.type) {
|
switch (msg.type) {
|
||||||
case parser.yy.LINETYPE.LOOP_START:
|
case parser.yy.LINETYPE.LOOP_START:
|
||||||
case parser.yy.LINETYPE.ALT_START:
|
case parser.yy.LINETYPE.ALT_START:
|
||||||
case parser.yy.LINETYPE.OPT_START:
|
case parser.yy.LINETYPE.OPT_START:
|
||||||
case parser.yy.LINETYPE.PAR_START:
|
case parser.yy.LINETYPE.PAR_START:
|
||||||
stack.push({
|
stack.push({
|
||||||
|
id: msg.id,
|
||||||
msg: msg.message,
|
msg: msg.message,
|
||||||
from: Number.MAX_SAFE_INTEGER,
|
from: Number.MAX_SAFE_INTEGER,
|
||||||
to: Number.MIN_SAFE_INTEGER,
|
to: Number.MIN_SAFE_INTEGER,
|
||||||
@@ -1025,7 +1003,8 @@ const calculateLoopBounds = function(messages, actors) {
|
|||||||
case parser.yy.LINETYPE.PAR_AND:
|
case parser.yy.LINETYPE.PAR_AND:
|
||||||
if (msg.message) {
|
if (msg.message) {
|
||||||
current = stack.pop();
|
current = stack.pop();
|
||||||
loops[msg.message] = current;
|
loops[current.id] = current;
|
||||||
|
loops[msg.id] = current;
|
||||||
stack.push(current);
|
stack.push(current);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1034,23 +1013,52 @@ const calculateLoopBounds = function(messages, actors) {
|
|||||||
case parser.yy.LINETYPE.OPT_END:
|
case parser.yy.LINETYPE.OPT_END:
|
||||||
case parser.yy.LINETYPE.PAR_END:
|
case parser.yy.LINETYPE.PAR_END:
|
||||||
current = stack.pop();
|
current = stack.pop();
|
||||||
loops[current.msg] = current;
|
loops[current.id] = current;
|
||||||
|
break;
|
||||||
|
case parser.yy.LINETYPE.ACTIVE_START:
|
||||||
|
{
|
||||||
|
const actorRect = actors[msg.from.actor];
|
||||||
|
const stackedSize = actorActivations(msg.from.actor).length;
|
||||||
|
const x =
|
||||||
|
actorRect.x + actorRect.width / 2 + ((stackedSize - 1) * conf.activationWidth) / 2;
|
||||||
|
const toAdd = {
|
||||||
|
startx: x,
|
||||||
|
stopx: x + conf.activationWidth,
|
||||||
|
actor: msg.from.actor,
|
||||||
|
enabled: true
|
||||||
|
};
|
||||||
|
bounds.activations.push(toAdd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case parser.yy.LINETYPE.ACTIVE_END:
|
||||||
|
{
|
||||||
|
const lastActorActivationIdx = bounds.activations
|
||||||
|
.map(a => a.actor)
|
||||||
|
.lastIndexOf(msg.from.actor);
|
||||||
|
delete bounds.activations.splice(lastActorActivationIdx, 1)[0];
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const isNote = msg.placement !== undefined;
|
const isNote = msg.placement !== undefined;
|
||||||
if (isNote) {
|
if (isNote) {
|
||||||
noteModel = buildNoteModel(msg, actors);
|
noteModel = buildNoteModel(msg, actors);
|
||||||
msg.noteModel = noteModel;
|
msg.noteModel = noteModel;
|
||||||
|
let depth = 0;
|
||||||
stack.forEach(stk => {
|
stack.forEach(stk => {
|
||||||
current = stk;
|
current = stk;
|
||||||
current.from = Math.min(current.from, noteModel.x);
|
current.from = Math.min(current.from, noteModel.x);
|
||||||
current.to = Math.max(current.to, noteModel.x + noteModel.width);
|
current.to = Math.max(current.to, noteModel.x + noteModel.width);
|
||||||
current.width = Math.max(current.width, Math.abs(current.from - current.to));
|
current.width =
|
||||||
|
Math.max(current.width, Math.abs(current.from - current.to)) -
|
||||||
|
50 -
|
||||||
|
conf.boxMargin * depth;
|
||||||
|
depth++;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
msgModel = buildMessageModel(msg);
|
msgModel = buildMessageModel(msg, actors);
|
||||||
msg.msgModel = msgModel;
|
msg.msgModel = msgModel;
|
||||||
if (msg.from && msg.to && stack.length > 0) {
|
if (msg.from && msg.to && stack.length > 0) {
|
||||||
|
let depth = 0;
|
||||||
stack.forEach(stk => {
|
stack.forEach(stk => {
|
||||||
current = stk;
|
current = stk;
|
||||||
let from = actors[msg.from];
|
let from = actors[msg.from];
|
||||||
@@ -1058,7 +1066,7 @@ const calculateLoopBounds = function(messages, actors) {
|
|||||||
if (from.x === to.x) {
|
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);
|
current.width = Math.max(current.width, from.width) - 50 - conf.boxMargin * depth;
|
||||||
} else {
|
} else {
|
||||||
if (from.x < to.x) {
|
if (from.x < to.x) {
|
||||||
current.from = Math.min(current.from, from.x);
|
current.from = Math.min(current.from, from.x);
|
||||||
@@ -1067,15 +1075,17 @@ const calculateLoopBounds = function(messages, actors) {
|
|||||||
current.from = Math.min(current.from, to.x);
|
current.from = Math.min(current.from, to.x);
|
||||||
current.to = Math.max(current.to, from.x);
|
current.to = Math.max(current.to, from.x);
|
||||||
}
|
}
|
||||||
current.width = Math.max(
|
current.width =
|
||||||
current.width,
|
Math.max(current.width, Math.abs(current.from - current.to)) -
|
||||||
Math.abs(current.from - current.to) - 20 + 2 * conf.wrapPadding
|
50 -
|
||||||
);
|
conf.boxMargin * depth;
|
||||||
}
|
}
|
||||||
|
depth++;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
bounds.activations = [];
|
||||||
logger.debug('Loop type widths:', loops);
|
logger.debug('Loop type widths:', loops);
|
||||||
return loops;
|
return loops;
|
||||||
};
|
};
|
||||||
|
@@ -51,6 +51,35 @@ export const drawText = function(elem, textData) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
typeof textData.anchor !== 'undefined' &&
|
||||||
|
typeof textData.textMargin !== 'undefined' &&
|
||||||
|
typeof textData.width !== 'undefined'
|
||||||
|
) {
|
||||||
|
switch (textData.anchor) {
|
||||||
|
case 'left':
|
||||||
|
case 'start':
|
||||||
|
textData.x = textData.x + textData.textMargin;
|
||||||
|
textData.anchor = 'start';
|
||||||
|
textData.dominantBaseline = 'text-after-edge';
|
||||||
|
textData.alignmentBaseline = 'middle';
|
||||||
|
break;
|
||||||
|
case 'middle':
|
||||||
|
case 'center':
|
||||||
|
textData.x = textData.x + textData.width / 2;
|
||||||
|
textData.anchor = 'middle';
|
||||||
|
textData.dominantBaseline = 'middle';
|
||||||
|
textData.alignmentBaseline = 'middle';
|
||||||
|
break;
|
||||||
|
case 'right':
|
||||||
|
case 'end':
|
||||||
|
textData.x = textData.x + textData.width - textData.textMargin;
|
||||||
|
textData.anchor = 'end';
|
||||||
|
textData.dominantBaseline = 'text-before-edge';
|
||||||
|
textData.alignmentBaseline = 'middle';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
for (let i = 0; i < lines.length; i++) {
|
for (let i = 0; i < lines.length; i++) {
|
||||||
let line = lines[i];
|
let line = lines[i];
|
||||||
if (
|
if (
|
||||||
@@ -65,7 +94,10 @@ export const drawText = function(elem, textData) {
|
|||||||
textElem.attr('x', textData.x);
|
textElem.attr('x', textData.x);
|
||||||
textElem.attr('y', yfunc());
|
textElem.attr('y', yfunc());
|
||||||
if (typeof textData.anchor !== 'undefined') {
|
if (typeof textData.anchor !== 'undefined') {
|
||||||
textElem.style('text-anchor', textData.anchor);
|
textElem
|
||||||
|
.attr('text-anchor', textData.anchor)
|
||||||
|
.attr('dominant-baseline', textData.dominantBaseline)
|
||||||
|
.attr('alignment-baseline', textData.alignmentBaseline);
|
||||||
}
|
}
|
||||||
if (typeof textData.fontFamily !== 'undefined') {
|
if (typeof textData.fontFamily !== 'undefined') {
|
||||||
textElem.style('font-family', textData.fontFamily);
|
textElem.style('font-family', textData.fontFamily);
|
||||||
@@ -88,13 +120,16 @@ export const drawText = function(elem, textData) {
|
|||||||
textElem.attr('dy', dy);
|
textElem.attr('dy', dy);
|
||||||
}
|
}
|
||||||
|
|
||||||
const span = textElem.append('tspan');
|
if (textData.tspan) {
|
||||||
span.attr('x', textData.x);
|
const span = textElem.append('tspan');
|
||||||
if (typeof textData.fill !== 'undefined') {
|
span.attr('x', textData.x);
|
||||||
span.attr('fill', textData.fill);
|
if (typeof textData.fill !== 'undefined') {
|
||||||
|
span.attr('fill', textData.fill);
|
||||||
|
}
|
||||||
|
span.text(line);
|
||||||
|
} else {
|
||||||
|
textElem.text(line);
|
||||||
}
|
}
|
||||||
span.text(line);
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
typeof textData.valign !== 'undefined' &&
|
typeof textData.valign !== 'undefined' &&
|
||||||
typeof textData.textMargin !== 'undefined' &&
|
typeof textData.textMargin !== 'undefined' &&
|
||||||
@@ -107,7 +142,7 @@ export const drawText = function(elem, textData) {
|
|||||||
textElems.push(textElem);
|
textElems.push(textElem);
|
||||||
}
|
}
|
||||||
|
|
||||||
return textElems.length === 1 ? textElems[0] : textElems;
|
return textElems;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const drawLabel = function(elem, txtObject) {
|
export const drawLabel = function(elem, txtObject) {
|
||||||
@@ -135,17 +170,18 @@ export const drawLabel = function(elem, txtObject) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
const polygon = elem.append('polygon');
|
const polygon = elem.append('polygon');
|
||||||
polygon.attr('points', genPoints(txtObject.x, txtObject.y, 50, 20, 7));
|
polygon.attr('points', genPoints(txtObject.x, txtObject.y, txtObject.width, txtObject.height, 7));
|
||||||
polygon.attr('class', 'labelBox');
|
polygon.attr('class', 'labelBox');
|
||||||
|
|
||||||
txtObject.y = txtObject.y + txtObject.labelMargin;
|
txtObject.y = txtObject.y + txtObject.height / 2;
|
||||||
txtObject.x = txtObject.x + 0.5 * txtObject.labelMargin;
|
|
||||||
return drawText(elem, txtObject);
|
drawText(elem, txtObject);
|
||||||
|
return polygon;
|
||||||
};
|
};
|
||||||
|
|
||||||
let actorCnt = -1;
|
let actorCnt = -1;
|
||||||
/**
|
/**
|
||||||
* Draws an actor in the diagram with the attaced line
|
* Draws an actor in the diagram with the attached line
|
||||||
* @param elem - The diagram we'll draw to.
|
* @param elem - The diagram we'll draw to.
|
||||||
* @param actor - The actor to draw.
|
* @param actor - The actor to draw.
|
||||||
* @param conf - drawText implementation discriminator object
|
* @param conf - drawText implementation discriminator object
|
||||||
@@ -236,57 +272,67 @@ export const drawLoop = function(elem, bounds, labelText, conf) {
|
|||||||
drawLoopLine(bounds.startx, bounds.starty, bounds.startx, bounds.stopy);
|
drawLoopLine(bounds.startx, bounds.starty, bounds.startx, bounds.stopy);
|
||||||
if (typeof bounds.sections !== 'undefined') {
|
if (typeof bounds.sections !== 'undefined') {
|
||||||
bounds.sections.forEach(function(item) {
|
bounds.sections.forEach(function(item) {
|
||||||
drawLoopLine(bounds.startx, item, bounds.stopx, item).style('stroke-dasharray', '3, 3');
|
drawLoopLine(bounds.startx, item.y, bounds.stopx, item.y).style('stroke-dasharray', '3, 3');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let minSize =
|
|
||||||
Math.round((3 * conf.messageFontSize) / 4) < 10
|
|
||||||
? conf.messageFontSize
|
|
||||||
: Math.round((3 * conf.messageFontSize) / 4);
|
|
||||||
|
|
||||||
let txt = getTextObj();
|
let txt = getTextObj();
|
||||||
txt.text = labelText;
|
txt.text = labelText;
|
||||||
txt.x = bounds.startx;
|
txt.x = bounds.startx;
|
||||||
txt.y = bounds.starty;
|
txt.y = bounds.starty;
|
||||||
txt.labelMargin = 1.5 * 10; // This is the small box that says "loop"
|
const msgFont = conf.messageFont();
|
||||||
txt.fontFamily = conf.messageFontFamily;
|
txt.fontFamily = msgFont.fontFamily;
|
||||||
txt.fontSize = minSize;
|
txt.fontSize = msgFont.fontSize;
|
||||||
txt.fontWeight = conf.messageFontWeight;
|
txt.fontWeight = msgFont.fontWeight;
|
||||||
txt.class = 'labelText'; // Its size & position are fixed.
|
txt.anchor = 'middle';
|
||||||
|
txt.valign = 'middle';
|
||||||
|
txt.tspan = false;
|
||||||
|
txt.width = conf.labelBoxWidth || 50;
|
||||||
|
txt.height = conf.labelBoxHeight || 20;
|
||||||
|
txt.textMargin = conf.boxTextMargin;
|
||||||
|
txt.class = 'labelText';
|
||||||
|
|
||||||
let labelElem = drawLabel(g, txt);
|
drawLabel(g, txt);
|
||||||
let labelBoxWidth = (labelElem._groups || labelElem)[0][0].getBBox().width;
|
|
||||||
txt = getTextObj();
|
txt = getTextObj();
|
||||||
txt.text = bounds.title;
|
txt.text = bounds.title;
|
||||||
txt.x = bounds.startx + (bounds.stopx - bounds.startx) / 2 + labelBoxWidth;
|
txt.x = bounds.startx + conf.labelBoxWidth / 2 + (bounds.stopx - bounds.startx) / 2;
|
||||||
txt.y = bounds.starty + conf.boxMargin + conf.boxTextMargin;
|
txt.y = bounds.starty + conf.boxMargin + conf.boxTextMargin;
|
||||||
txt.anchor = 'middle';
|
txt.anchor = 'middle';
|
||||||
txt.class = 'loopText';
|
txt.class = 'loopText';
|
||||||
txt.fontFamily = conf.messageFontFamily;
|
txt.fontFamily = msgFont.fontFamily;
|
||||||
txt.fontSize = minSize;
|
txt.fontSize = msgFont.fontSize;
|
||||||
txt.fontWeight = conf.messageFontWeight;
|
txt.fontWeight = msgFont.fontWeight;
|
||||||
txt.wrap = true;
|
txt.wrap = true;
|
||||||
|
|
||||||
drawText(g, txt);
|
let textElem = drawText(g, txt);
|
||||||
|
|
||||||
if (typeof bounds.sectionTitles !== 'undefined') {
|
if (typeof bounds.sectionTitles !== 'undefined') {
|
||||||
bounds.sectionTitles.forEach(function(item, idx) {
|
bounds.sectionTitles.forEach(function(item, idx) {
|
||||||
if (item.message) {
|
if (item.message) {
|
||||||
txt.text = item.message;
|
txt.text = item.message;
|
||||||
txt.x = bounds.startx + (bounds.stopx - bounds.startx) / 2;
|
txt.x = bounds.startx + (bounds.stopx - bounds.startx) / 2;
|
||||||
txt.y = bounds.sections[idx] + conf.boxMargin + conf.boxTextMargin;
|
txt.y = bounds.sections[idx].y + conf.boxMargin + conf.boxTextMargin;
|
||||||
txt.class = 'loopText';
|
txt.class = 'loopText';
|
||||||
txt.anchor = 'middle';
|
txt.anchor = 'middle';
|
||||||
txt.fontFamily = conf.messageFontFamily;
|
txt.valign = 'middle';
|
||||||
txt.fontSize = minSize;
|
txt.tspan = false;
|
||||||
txt.fontWeight = conf.messageFontWeight;
|
txt.fontFamily = msgFont.fontFamily;
|
||||||
|
txt.fontSize = msgFont.fontSize;
|
||||||
|
txt.fontWeight = msgFont.fontWeight;
|
||||||
txt.wrap = bounds.wrap;
|
txt.wrap = bounds.wrap;
|
||||||
drawText(g, txt);
|
textElem = drawText(g, txt);
|
||||||
|
let sectionHeight = Math.round(
|
||||||
|
textElem
|
||||||
|
.map(te => (te._groups || te)[0][0].getBBox().height)
|
||||||
|
.reduce((acc, curr) => acc + curr)
|
||||||
|
);
|
||||||
|
bounds.sections[idx].height += sectionHeight - (conf.boxMargin + conf.boxTextMargin);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bounds.height = Math.round(bounds.stopy - bounds.starty);
|
||||||
|
|
||||||
return g;
|
return g;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -380,13 +426,14 @@ export const getTextObj = function() {
|
|||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
fill: undefined,
|
fill: undefined,
|
||||||
anchor: 'start',
|
anchor: undefined,
|
||||||
style: '#666',
|
style: '#666',
|
||||||
width: 100,
|
width: undefined,
|
||||||
height: 100,
|
height: undefined,
|
||||||
textMargin: 0,
|
textMargin: 0,
|
||||||
rx: 0,
|
rx: 0,
|
||||||
ry: 0,
|
ry: 0,
|
||||||
|
tspan: true,
|
||||||
valign: undefined
|
valign: undefined
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@@ -335,7 +335,17 @@ const config = {
|
|||||||
* This sets the auto-wrap padding for the diagram (sides only)
|
* This sets the auto-wrap padding for the diagram (sides only)
|
||||||
* **Default value 15.
|
* **Default value 15.
|
||||||
*/
|
*/
|
||||||
wrapPadding: 15
|
wrapPadding: 15,
|
||||||
|
/**
|
||||||
|
* This sets the width of the loop-box (loop, alt, opt, par)
|
||||||
|
* **Default value 50.
|
||||||
|
*/
|
||||||
|
labelBoxWidth: 50,
|
||||||
|
/**
|
||||||
|
* This sets the height of the loop-box (loop, alt, opt, par)
|
||||||
|
* **Default value 20.
|
||||||
|
*/
|
||||||
|
labelBoxHeight: 20
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user