Revert of PR #1482

This commit is contained in:
Knut Sveidqvist
2020-06-19 10:52:20 +02:00
parent 8e1e7fb314
commit 44d5009538
26 changed files with 593 additions and 1195 deletions

View File

@@ -1,4 +1,5 @@
import { logger } from '../../logger';
import { getConfig, setConfig } from '../../config';
import mermaidAPI from '../../mermaidAPI';
let prevActor = undefined;
@@ -9,6 +10,7 @@ let title = '';
let titleWrapped = false;
let sequenceNumbersEnabled = false;
let wrapEnabled = false;
let configUpdated = false;
let currentDirective = {};
export const parseDirective = function(statement, context) {
@@ -44,24 +46,18 @@ const handleDirective = function(directive) {
switch (directive.type) {
case 'init':
case 'initialize':
['config'].forEach(prop => {
if (typeof directive.args[prop] !== 'undefined') {
directive.args.sequence = directive.args[prop];
delete directive.args[prop];
}
});
mermaidAPI.initialize(directive.args);
break;
case 'config':
updateConfig(directive.args);
break;
case 'wrap':
case 'nowrap':
wrapEnabled = directive.type === 'wrap';
break;
default:
logger.warn(
`Unhandled directive: source: '%%{${directive.type}: ${JSON.stringify(
directive.args ? directive.args : {}
)}}%%`,
`Unrecognized directive: source: '%%{${directive.type}: ${directive.args}}%%`,
directive
);
break;
@@ -81,7 +77,7 @@ export const addActor = function(id, name, description) {
actors[id] = {
name: name,
description: description.text,
wrap: (description.wrap === undefined && autoWrap()) || !!description.wrap,
wrap: (description.wrap === null && autoWrap()) || !!description.wrap,
prevActor: prevActor
};
if (prevActor && actors[prevActor]) {
@@ -115,17 +111,12 @@ export const addMessage = function(idFrom, idTo, message, answer) {
from: idFrom,
to: idTo,
message: message.text,
wrap: (message.wrap === undefined && autoWrap()) || !!message.wrap,
wrap: (message.wrap === null && autoWrap()) || !!message.wrap,
answer: answer
});
};
export const addSignal = function(
idFrom,
idTo,
message = { text: undefined, wrap: undefined },
messageType
) {
export const addSignal = function(idFrom, idTo, message = { text: null, wrap: null }, messageType) {
logger.debug(
'Adding message from=' +
idFrom +
@@ -159,7 +150,7 @@ export const addSignal = function(
from: idFrom,
to: idTo,
message: message.text,
wrap: (message.wrap === undefined && autoWrap()) || !!message.wrap,
wrap: (message.wrap === null && autoWrap()) || !!message.wrap,
type: messageType
});
return true;
@@ -189,8 +180,12 @@ export const enableSequenceNumbers = function() {
};
export const showSequenceNumbers = () => sequenceNumbersEnabled;
export const setWrap = function(wrapSetting) {
wrapEnabled = wrapSetting;
export const enableWrap = function() {
wrapEnabled = true;
};
export const disableWrap = function() {
wrapEnabled = false;
};
export const autoWrap = () => wrapEnabled;
@@ -198,11 +193,12 @@ export const autoWrap = () => wrapEnabled;
export const clear = function() {
actors = {};
messages = [];
configUpdated = false;
};
export const parseMessage = function(str) {
const _str = str.trim();
const retVal = {
return {
text: _str.replace(/^[:]?(?:no)?wrap:/, '').trim(),
wrap:
_str.match(/^[:]?(?:no)?wrap:/) === null
@@ -213,8 +209,6 @@ export const parseMessage = function(str) {
? false
: autoWrap()
};
logger.debug(`ParseMessage[${str}] [${JSON.stringify(retVal, null, 2)}`);
return retVal;
};
export const LINETYPE = {
@@ -257,7 +251,7 @@ export const addNote = function(actor, placement, message) {
actor: actor,
placement: placement,
message: message.text,
wrap: (message.wrap === undefined && autoWrap()) || !!message.wrap
wrap: (message.wrap === null && autoWrap()) || !!message.wrap
};
// Coerce actor into a [to, from, ...] array
@@ -268,7 +262,7 @@ export const addNote = function(actor, placement, message) {
from: actors[0],
to: actors[1],
message: message.text,
wrap: (message.wrap === undefined && autoWrap()) || !!message.wrap,
wrap: (message.wrap === null && autoWrap()) || !!message.wrap,
type: LINETYPE.NOTE,
placement: placement
});
@@ -276,7 +270,20 @@ export const addNote = function(actor, placement, message) {
export const setTitle = function(titleWrap) {
title = titleWrap.text;
titleWrapped = (titleWrap.wrap === undefined && autoWrap()) || !!titleWrap.wrap;
titleWrapped = (titleWrap.wrap === null && autoWrap()) || !!titleWrap.wrap;
};
export const updateConfig = function(config = getConfig()) {
try {
setConfig(config);
configUpdated = true;
} catch (error) {
logger.error('Error: unable to parse config');
}
};
export const hasConfigChange = function() {
return configUpdated;
};
export const apply = function(param) {
@@ -348,16 +355,20 @@ export default {
addActor,
addMessage,
addSignal,
autoWrap,
setWrap,
enableWrap,
disableWrap,
enableSequenceNumbers,
showSequenceNumbers,
autoWrap,
getMessages,
getActors,
getActor,
getActorKeys,
getTitle,
parseDirective,
hasConfigChange,
getConfig,
updateConfig,
getTitleWrapped,
clear,
parseMessage,

View File

@@ -1,7 +1,7 @@
/* eslint-env jasmine */
import { parser } from './parser/sequenceDiagram';
import sequenceDb from './sequenceDb';
import renderer from './sequenceRenderer';
import renderer, { calculateTextHeight, calculateTextWidth } from './sequenceRenderer';
import mermaidAPI from '../../mermaidAPI';
function addConf(conf, key, value) {
@@ -10,6 +10,7 @@ function addConf(conf, key, value) {
}
return conf;
}
describe('when parsing a sequenceDiagram', function() {
beforeEach(function() {
parser.yy = sequenceDb;
@@ -773,7 +774,6 @@ end`;
describe('when checking the bounds in a sequenceDiagram', function() {
let conf;
beforeEach(function() {
mermaidAPI.reset();
parser.yy = sequenceDb;
parser.yy.clear();
conf = {
@@ -788,11 +788,10 @@ describe('when checking the bounds in a sequenceDiagram', function() {
boxTextMargin: 15,
noteMargin: 25
};
mermaidAPI.initialize({ sequence: conf });
renderer.bounds.init();
renderer.setConf(conf);
});
it('it should handle a simple bound call', function() {
renderer.bounds.init();
renderer.bounds.insert(100, 100, 200, 200);
@@ -803,6 +802,7 @@ describe('when checking the bounds in a sequenceDiagram', function() {
expect(bounds.stopy).toBe(200);
});
it('it should handle an expanding bound', function() {
renderer.bounds.init();
renderer.bounds.insert(100, 100, 200, 200);
renderer.bounds.insert(25, 50, 300, 400);
@@ -814,6 +814,7 @@ describe('when checking the bounds in a sequenceDiagram', function() {
expect(bounds.stopy).toBe(400);
});
it('it should handle inserts within the bound without changing the outer bounds', function() {
renderer.bounds.init();
renderer.bounds.insert(100, 100, 200, 200);
renderer.bounds.insert(25, 50, 300, 400);
@@ -826,6 +827,7 @@ describe('when checking the bounds in a sequenceDiagram', function() {
expect(bounds.stopy).toBe(400);
});
it('it should handle a loop without expanding the area', function() {
renderer.bounds.init();
renderer.bounds.insert(25, 50, 300, 400);
renderer.bounds.verticalPos = 150;
@@ -848,6 +850,7 @@ describe('when checking the bounds in a sequenceDiagram', function() {
expect(bounds.stopy).toBe(400);
});
it('it should handle multiple loops withtout expanding the bounds', function() {
renderer.bounds.init();
renderer.bounds.insert(100, 100, 1000, 1000);
renderer.bounds.verticalPos = 200;
@@ -880,6 +883,7 @@ describe('when checking the bounds in a sequenceDiagram', function() {
expect(bounds.stopy).toBe(1000);
});
it('it should handle a loop that expands the area', function() {
renderer.bounds.init();
renderer.bounds.insert(100, 100, 200, 200);
renderer.bounds.verticalPos = 200;
@@ -906,7 +910,6 @@ describe('when checking the bounds in a sequenceDiagram', function() {
describe('when rendering a sequenceDiagram', function() {
let conf;
beforeEach(function() {
mermaidAPI.reset();
parser.yy = sequenceDb;
parser.yy.clear();
@@ -920,22 +923,19 @@ describe('when rendering a sequenceDiagram', function() {
boxMargin: 10,
messageMargin: 40,
boxTextMargin: 15,
noteMargin: 25,
wrapEnabled: false,
mirrorActors: false
noteMargin: 25
};
mermaidAPI.initialize({ sequence: conf });
renderer.bounds.init();
renderer.setConf(conf);
});
['tspan', 'fo', 'old', undefined].forEach(function(textPlacement) {
it(`
it should handle one actor, when textPlacement is ${textPlacement}`, function() {
renderer.setConf(addConf(conf, 'textPlacement', textPlacement));
renderer.bounds.init();
const str = `
sequenceDiagram
participant Alice`;
mermaidAPI.initialize(addConf(conf, 'textPlacement', textPlacement));
renderer.bounds.init();
parser.parse(str);
renderer.draw(str, 'tst');
@@ -947,6 +947,8 @@ participant Alice`;
});
});
it('it should handle same actor with different whitespace properly', function() {
renderer.bounds.init();
const str = `
sequenceDiagram
participant Alice
@@ -960,6 +962,7 @@ participant Alice
expect(Object.keys(actors)).toEqual(['Alice']);
});
it('it should handle one actor and a centered note', function() {
renderer.bounds.init();
const str = `
sequenceDiagram
participant Alice
@@ -977,6 +980,7 @@ Note over Alice: Alice thinks
expect(bounds.stopy).toBe(conf.height + conf.boxMargin + 2 * conf.noteMargin + 10);
});
it('it should handle one actor and a note to the left', function() {
renderer.bounds.init();
const str = `
sequenceDiagram
participant Alice
@@ -993,6 +997,7 @@ Note left of Alice: Alice thinks`;
expect(bounds.stopy).toBe(conf.height + conf.boxMargin + 2 * conf.noteMargin + 10);
});
it('it should handle one actor and a note to the right', function() {
renderer.bounds.init();
const str = `
sequenceDiagram
participant Alice
@@ -1009,6 +1014,7 @@ Note right of Alice: Alice thinks`;
expect(bounds.stopy).toBe(conf.height + conf.boxMargin + 2 * conf.noteMargin + 10);
});
it('it should handle two actors', function() {
renderer.bounds.init();
const str = `
sequenceDiagram
Alice->Bob: Hello Bob, how are you?`;
@@ -1020,9 +1026,10 @@ Alice->Bob: Hello Bob, how are you?`;
expect(bounds.startx).toBe(0);
expect(bounds.starty).toBe(0);
expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin);
expect(bounds.stopy).toBe(conf.messageMargin + conf.height);
expect(bounds.stopy).toBe(0 + conf.messageMargin + conf.height);
});
it('it should handle two actors with init directive', function() {
renderer.bounds.init();
const str = `
%%{init: {'logLevel': 0}}%%
sequenceDiagram
@@ -1037,9 +1044,10 @@ Alice->Bob: Hello Bob, how are you?`;
expect(bounds.startx).toBe(0);
expect(bounds.starty).toBe(0);
expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin);
expect(bounds.stopy).toBe(conf.height + conf.messageMargin + (conf.mirrorActors ? 2 * conf.boxMargin + conf.height : 0));
expect(bounds.stopy).toBe(0 + conf.messageMargin + conf.height);
});
it('it should handle two actors with init directive with multiline directive', function() {
renderer.bounds.init();
const str = `
%%{init: { 'logLevel': 0}}%%
sequenceDiagram
@@ -1051,18 +1059,16 @@ Alice->Bob: Hello Bob, how are you?`;
parser.parse(str);
renderer.draw(str, 'tst');
const msgs = parser.yy.getMessages();
const bounds = renderer.bounds.getBounds();
const mermaid = mermaidAPI.getConfig();
expect(mermaid.logLevel).toBe(0);
expect(bounds.startx).toBe(0);
expect(bounds.starty).toBe(0);
expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin);
expect(bounds.stopy).toBe(conf.messageMargin + conf.height);
expect(msgs.every(v => v.wrap)).toBe(true);
expect(bounds.stopy).toBe(0 + conf.messageMargin + conf.height);
});
it('it should handle two actors and two centered shared notes', function() {
renderer.bounds.init();
const str = `
sequenceDiagram
Alice->Bob: Hello Bob, how are you?
@@ -1082,6 +1088,7 @@ Note over Bob,Alice: Looks back
);
});
it('it should draw two actors and two messages', function() {
renderer.bounds.init();
const str = `
sequenceDiagram
Alice->Bob: Hello Bob, how are you?
@@ -1097,6 +1104,7 @@ Bob->Alice: Fine!`;
expect(bounds.stopy).toBe(0 + 2 * conf.messageMargin + conf.height);
});
it('it should draw two actors notes to the right', function() {
renderer.bounds.init();
const str = `
sequenceDiagram
Alice->Bob: Hello Bob, how are you?
@@ -1118,6 +1126,7 @@ Bob->Alice: Fine!`;
);
});
it('it should draw two actors notes to the left', function() {
renderer.bounds.init();
const str = `
sequenceDiagram
Alice->Bob: Hello Bob, how are you?
@@ -1137,6 +1146,7 @@ Bob->Alice: Fine!`;
);
});
it('it should draw two actors notes to the left with text wrapped (inline)', function() {
renderer.bounds.init();
const str = `
sequenceDiagram
Alice->>Bob:wrap: Hello Bob, how are you? If you are not available right now, I can leave you a message. Please get back to me as soon as you can!
@@ -1158,6 +1168,7 @@ Bob->>Alice: Fine!`;
);
});
it('it should draw two actors notes to the left with text wrapped (directive)', function() {
renderer.bounds.init();
const str = `
%%{init: { 'theme': 'dark' } }%%
sequenceDiagram
@@ -1183,6 +1194,7 @@ Bob->>Alice: Fine!`;
);
});
it('it should draw two actors notes to the left with text wrapped and the init directive sets the theme to dark', function() {
renderer.bounds.init();
const str = `
%%{init:{'theme':'dark'}}%%
sequenceDiagram
@@ -1190,7 +1202,6 @@ sequenceDiagram
Alice->>Bob: Hello Bob, how are you? If you are not available right now, I can leave you a message. Please get back to me as soon as you can!
Note left of Alice: Bob thinks
Bob->>Alice: Fine!`;
parser.parse(str);
renderer.draw(str, 'tst');
@@ -1207,16 +1218,17 @@ Bob->>Alice: Fine!`;
2 * conf.messageMargin + conf.height + conf.boxMargin + 10 + 2 * conf.noteMargin
);
});
it('it should draw two actors, notes to the left with text wrapped and the init directive sets the theme to dark and fontFamily to Menlo, fontSize to 18, and fontWeight to 800', function() {
it('it should draw two actors notes to the left with text wrapped and the init directive sets the theme to dark and fontFamily to Menlo, fontSize to 18, and fontWeight to 800', function() {
renderer.bounds.init();
const str = `
%%{init: { "theme": "dark", 'config': { "fontFamily": "Menlo", "fontSize": 18, "fontWeight": 400, "wrapEnabled": true }}}%%
%%{init: { "theme": "dark" }}%%
sequenceDiagram
%%{config: { "fontFamily": "Menlo", "fontSize": 18, "fontWeight": 400 } }%%
%%{wrap}%%
Alice->>Bob: Hello Bob, how are you? If you are not available right now, I can leave you a message. Please get back to me as soon as you can!
Note left of Alice: Bob thinks
Bob->>Alice: Fine!`;
parser.parse(str);
// renderer.setConf(mermaidAPI.getConfig().sequence);
renderer.draw(str, 'tst');
const bounds = renderer.bounds.getBounds();
@@ -1225,9 +1237,9 @@ Bob->>Alice: Fine!`;
expect(bounds.startx).toBe(-(conf.width / 2) - conf.actorMargin / 2);
expect(bounds.starty).toBe(0);
expect(mermaid.theme).toBe('dark');
expect(mermaid.sequence.fontFamily).toBe('Menlo');
expect(mermaid.sequence.fontSize).toBe(18);
expect(mermaid.sequence.fontWeight).toBe(400);
expect(mermaid.fontFamily).toBe('Menlo');
expect(mermaid.fontSize).toBe(18);
expect(mermaid.fontWeight).toBe(400);
expect(msgs.every(v => v.wrap)).toBe(true);
expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin);
@@ -1236,13 +1248,13 @@ Bob->>Alice: Fine!`;
);
});
it('it should draw two loops', function() {
renderer.bounds.init();
const str = `
sequenceDiagram
Alice->Bob: Hello Bob, how are you?
loop Cheers
Bob->Alice: Fine!
end`;
parser.parse(str);
renderer.draw(str, 'tst');
@@ -1256,6 +1268,7 @@ end`;
);
});
it('it should draw background rect', function() {
renderer.bounds.init();
const str = `
sequenceDiagram
Alice->Bob: Hello Bob, are you alright?
@@ -1277,7 +1290,6 @@ end`;
describe('when rendering a sequenceDiagram with actor mirror activated', function() {
let conf;
beforeEach(function() {
mermaidAPI.reset();
parser.yy = sequenceDb;
parser.yy.clear();
@@ -1297,12 +1309,11 @@ describe('when rendering a sequenceDiagram with actor mirror activated', functio
// Prolongs the edge of the diagram downwards
bottomMarginAdj: 1
};
mermaidAPI.initialize({ sequence: conf });
renderer.bounds.init();
renderer.setConf(conf);
});
['tspan', 'fo', 'old', undefined].forEach(function(textPlacement) {
it('it should handle one actor, when textPlacement is' + textPlacement, function() {
mermaidAPI.initialize(addConf(conf, 'textPlacement', textPlacement));
renderer.setConf(addConf(conf, 'textPlacement', textPlacement));
renderer.bounds.init();
const str = `
sequenceDiagram
@@ -1323,7 +1334,6 @@ participant Alice`;
describe('when rendering a sequenceDiagram with directives', function() {
let conf;
beforeEach(function() {
mermaidAPI.reset();
parser.yy = sequenceDb;
parser.yy.clear();
conf = {
@@ -1338,11 +1348,11 @@ describe('when rendering a sequenceDiagram with directives', function() {
boxTextMargin: 15,
noteMargin: 25
};
mermaidAPI.initialize({ sequence: conf });
renderer.bounds.init();
renderer.setConf(conf);
});
it('it should handle one actor, when theme is dark and logLevel is 1 DX1', function() {
it('it should handle one actor, when theme is dark and logLevel is 1', function() {
renderer.bounds.init();
const str = `
%%{init: { "theme": "dark", "logLevel": 1 } }%%
sequenceDiagram
@@ -1363,6 +1373,7 @@ participant Alice
expect(bounds.stopy).toBe(2 * conf.height + 2 * conf.boxMargin);
});
it('it should handle one actor, when logLevel is 3', function() {
renderer.bounds.init();
const str = `
%%{initialize: { "logLevel": 3 }}%%
sequenceDiagram

View File

@@ -1,10 +1,10 @@
import { select, selectAll } from 'd3';
import svgDraw, { drawText } from './svgDraw';
import svgDraw from './svgDraw';
import { logger } from '../../logger';
import { parser } from './parser/sequenceDiagram';
import common from '../common/common';
import sequenceDb from './sequenceDb';
import utils, { assignWithDepth } from '../../utils';
import { getConfig } from '../../config';
parser.yy = sequenceDb;
@@ -79,6 +79,9 @@ export const bounds = {
stopy: undefined
};
this.verticalPos = 0;
if (parser.yy.hasConfigChange()) {
setConf(getConfig());
}
},
updateVal: function(obj, key, val, fun) {
if (typeof obj[key] === 'undefined') {
@@ -150,20 +153,15 @@ export const bounds = {
.lastIndexOf(message.from.actor);
return this.activations.splice(lastActorActivationIdx, 1)[0];
},
createLoop: function(title = { message: undefined, wrap: false, width: undefined }, fill) {
return {
newLoop: function(title, fill) {
this.sequenceItems.push({
startx: undefined,
starty: this.verticalPos,
stopx: undefined,
stopy: undefined,
title: title.message,
wrap: title.wrap,
width: title.width,
title: title,
fill: fill
};
},
newLoop: function(title = { message: undefined, wrap: false, width: undefined }, fill) {
this.sequenceItems.push(this.createLoop(title, fill));
});
},
endLoop: function() {
return this.sequenceItems.pop();
@@ -188,7 +186,59 @@ export const bounds = {
}
};
const drawLongText = (text, x, y, g, width) => {
const wrapLabel = (label, maxWidth, joinWith = '<br/>') => {
if (common.lineBreakRegex.test(label)) {
return label;
}
const words = label.split(' ');
const completedLines = [];
let nextLine = '';
words.forEach((word, index) => {
const wordLength = calculateTextWidth(`${word} `);
const nextLineLength = calculateTextWidth(nextLine);
if (wordLength > maxWidth) {
const { hyphenatedStrings, remainingWord } = breakString(word, maxWidth);
completedLines.push(nextLine, ...hyphenatedStrings);
nextLine = remainingWord;
} else if (nextLineLength + wordLength >= maxWidth) {
completedLines.push(nextLine);
nextLine = word;
} else {
nextLine = [nextLine, word].filter(Boolean).join(' ');
}
const currentWord = index + 1;
const isLastWord = currentWord === words.length;
if (isLastWord) {
completedLines.push(nextLine);
}
});
return completedLines.filter(line => line !== '').join(joinWith);
};
const breakString = (word, maxWidth, hyphenCharacter = '-') => {
const characters = word.split('');
const lines = [];
let currentLine = '';
characters.forEach((character, index) => {
const nextLine = `${currentLine}${character}`;
const lineWidth = calculateTextWidth(nextLine);
if (lineWidth >= maxWidth) {
const currentCharacter = index + 1;
const isLastLine = characters.length === currentCharacter;
const hyphenatedNextLine = `${nextLine}${hyphenCharacter}`;
lines.push(isLastLine ? nextLine : hyphenatedNextLine);
currentLine = '';
} else {
currentLine = nextLine;
}
});
return { hyphenatedStrings: lines, remainingWord: currentLine };
};
const _drawLongText = (text, x, y, g, width) => {
let textHeight = 0;
let prevTextHeight = 0;
const alignmentToAnchor = {
left: 'start',
start: 'start',
@@ -197,45 +247,43 @@ const drawLongText = (text, x, y, g, width) => {
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;
const lines = text.split(common.lineBreakRegex);
for (const line of lines) {
const textObj = svgDraw.getTextObj();
const alignment = alignmentToAnchor[conf.noteAlign] || 'middle';
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 + textHeight;
textObj.dy = '1em';
textObj.text = line;
textObj.class = 'noteText';
const textElem = svgDraw
.drawText(g, textObj)
.style('text-anchor', alignment)
.style('font-size', conf.noteFontSize)
.style('font-family', conf.noteFontFamily)
.style('font-weight', conf.noteFontWeight)
.attr('dominant-baseline', 'central')
.attr('alignment-baseline', 'central');
textHeight += (textElem._groups || textElem)[0][0].getBBox().height;
textElem.attr('y', y + (prevTextHeight + textHeight + 2 * conf.noteMargin) / 2);
prevTextHeight = textHeight;
}
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);
return textHeight;
};
/**
@@ -256,7 +304,7 @@ const drawNote = function(elem, startx, verticalPos, msg, forceWidth) {
let g = elem.append('g');
const rectElem = svgDraw.drawRect(g, rect);
const textHeight = drawLongText(msg.message, startx, verticalPos, g, rect.width);
const textHeight = _drawLongText(msg.message, startx, verticalPos, g, rect.width);
bounds.insert(
startx,
@@ -283,15 +331,36 @@ const drawMessage = function(elem, startx, stopx, verticalPos, msg, sequenceInde
const txtCenter = startx + (stopx - startx) / 2;
let textElems = [];
/*
let textHeight = 0;
const breaklines = msg.message.split(common.lineBreakRegex);
for (const breakline of breaklines) {
let textElem = g
.append('text') // text label for the x axis
.attr('x', txtCenter)
.attr('y', verticalPos + textHeight)
.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());
textElems.push(textElem);
textHeight += (textElem._groups || textElem)[0][0].getBBox().height;
}
let totalOffset = textHeight;
*/
let counterBreaklines = 0;
let breaklineOffset = conf.messageFontSize;
let breaklineOffset = conf.messageFontSize + 4;
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 - breaklineVerticalOffset + counterBreaklines * breaklineOffset)
.attr('y', verticalPos - 7 + counterBreaklines * breaklineOffset)
.style('font-size', conf.messageFontSize)
.style('font-family', conf.messageFontFamily)
@@ -431,18 +500,32 @@ export const drawActors = function(diagram, actors, actorKeys, verticalPos) {
// Draw the actors
let prevWidth = 0;
let prevMargin = 0;
let maxActorHeight = conf.height;
for (let i = 0; i < actorKeys.length; i++) {
const actor = actors[actorKeys[i]];
// Add some rendering data to the object
actor.width = typeof actor.width === 'undefined' ? calculateActorWidth(actor) : actor.width;
actor.height = conf.height;
actor.margin = conf.actorMargin;
actor.width = actor.width || calculateActorWidth(actor);
actor.height = actor.wrap
? calculateTextHeight(
actor.message,
conf.height,
actor.width,
conf.wrapPadding,
actor.wrap,
conf.actorFontSize
)
: conf.height;
maxActorHeight = Math.max(maxActorHeight, actor.height);
actor.margin = actor.margin || conf.actorMargin;
actor.x = prevWidth + prevMargin;
actor.y = verticalPos;
if (actor.wrap) {
actor.description = wrapLabel(actor.description, actor.width);
}
// Draw the box with the attached line
svgDraw.drawActor(diagram, actor, conf);
bounds.insert(actor.x, verticalPos, actor.x + actor.width, actor.height);
@@ -452,17 +535,22 @@ export const drawActors = function(diagram, actors, actorKeys, verticalPos) {
}
// Add a margin between the actor boxes and the first arrow
bounds.bumpVerticalPos(conf.height);
bounds.bumpVerticalPos(maxActorHeight);
};
export const setConf = function(cnf) {
assignWithDepth(conf, cnf);
const keys = Object.keys(cnf);
keys.forEach(function(key) {
conf[key] = cnf[key];
});
if (cnf.fontFamily) {
conf.actorFontFamily = conf.noteFontFamily = conf.messageFontFamily = cnf.fontFamily;
}
if (cnf.fontSize) {
conf.actorFontSize = conf.noteFontSize = conf.messageFontSize = cnf.fontSize;
// conf.height = cnf.fontSize * (65 / 14);
}
if (cnf.fontWeight) {
conf.actorFontWeight = conf.noteFontWeight = conf.messageFontWeight = cnf.fontWeight;
@@ -508,41 +596,100 @@ const calculateActorWidth = function(actor) {
? conf.width
: Math.max(
conf.width,
utils.calculateTextWidth(actor.description, {
fontSize: conf.actorFontSize,
fontFamily: conf.actorFontFamily,
fontWeight: conf.actorFontWeight,
margin: conf.wrapPadding
})
calculateTextWidth(
actor.description,
conf.actorFontSize,
conf.actorFontFamily,
conf.actorFontWeight
)
);
};
function adjustLoopHeightForWrap(loopWidths, msg, preMargin, postMargin, addLoopFn) {
let heightAdjust = 0;
bounds.bumpVerticalPos(preMargin);
if (msg.message && msg.wrap && loopWidths[msg.message]) {
let loopWidth = loopWidths[msg.message].width;
let minSize =
Math.round((3 * conf.fontSize) / 4) < 10
? conf.fontSize
: Math.round((3 * conf.fontSize) / 4);
let textConf = {
fontSize: minSize,
fontFamily: conf.messageFontFamily,
fontWeight: conf.messageFontWeight,
margin: conf.wrapPadding
};
msg.message = msg.message
? utils.wrapLabel(`[${msg.message}]`, loopWidth, textConf)
: msg.message;
heightAdjust = Math.max(
0,
utils.calculateTextHeight(msg.message, textConf) - (preMargin + postMargin)
);
/**
* This calculates the text's height, taking into account the wrap value and
* both the statically configured height, width, and the length of the text (in pixels).
*
* If the wrapped text text has greater height, we extend the height, so it's
* value won't overflow.
*
* @return - The height for the given actor
* @param message the text to measure
* @param elementHeight the height of the default bounding box containing the text
* @param elementWidth the width of the default bounding box containing the text
* @param margin space above and below
* @param wrap wrap the text based on: elementWidth - 2 * margin
* @param fontSize
*/
export const calculateTextHeight = function(
message,
elementHeight,
elementWidth,
margin,
wrap,
fontSize
) {
if (!message) {
return elementHeight;
}
addLoopFn(msg);
bounds.bumpVerticalPos(heightAdjust + postMargin);
}
let lineHeightFactor = wrap
? wrapLabel(message, elementWidth - 2 * margin).split(common.lineBreakRegex).length
: 1;
return wrap ? Math.max(elementHeight, lineHeightFactor * fontSize) : elementHeight;
};
/**
* This calculates the width of the given text, font size and family.
*
* @param text - The text to calculate the width of
* @param fontSize - The font size of the given text
* @param fontFamily - The font family (one, or more fonts) to render
* @param fontWeight - The font weight (normal, bold, italics)
*/
export const calculateTextWidth = function(text, fontSize, fontFamily, fontWeight) {
if (!text) {
return 0;
}
fontSize = fontSize ? fontSize : conf.actorFontSize;
fontFamily = fontFamily ? fontFamily : conf.actorFontFamily;
fontWeight = fontWeight ? fontWeight : conf.actorFontWeight;
// We can't really know if the user supplied font family will render on the user agent;
// thus, we'll take the max width between the user supplied font family, and a default
// of sans-serif.
const fontFamilies = ['sans-serif', fontFamily];
const lines = text.split(common.lineBreakRegex);
let maxWidth = 0;
const body = select('body');
// We don't want to leak DOM elements - if a removal operation isn't available
// for any reason, do not continue.
if (!body.remove) {
return 0;
}
const g = body.append('svg');
for (let line of lines) {
for (let fontFamily of fontFamilies) {
const textObj = svgDraw.getTextObj();
textObj.text = line;
const textElem = svgDraw
.drawText(g, textObj)
.style('font-size', fontSize)
.style('font-weight', fontWeight)
.style('font-family', fontFamily);
maxWidth = Math.max(maxWidth, (textElem._groups || textElem)[0][0].getBBox().width);
}
}
g.remove();
// Adds some padding, so the text won't sit exactly within the actor's borders
return maxWidth + conf.wrapPadding * 2;
};
/**
* Draws a flowchart in the tag with id: id based on the graph definition in text.
@@ -551,7 +698,6 @@ function adjustLoopHeightForWrap(loopWidths, msg, preMargin, postMargin, addLoop
*/
export const draw = function(text, id) {
parser.yy.clear();
parser.yy.setWrap(conf.wrapEnabled);
parser.parse(text + '\n');
bounds.init();
@@ -568,10 +714,15 @@ export const draw = function(text, id) {
const title = parser.yy.getTitle();
const maxMessageWidthPerActor = getMaxMessageWidthPerActor(actors, messages);
conf.height = calculateActorMargins(actors, maxMessageWidthPerActor);
const maxActorHeight = calculateActorMargins(actors, maxMessageWidthPerActor);
drawActors(diagram, actors, actorKeys, 0);
const loopWidths = calculateLoopMargins(messages, actors);
bounds.bumpVerticalPos(
maxActorHeight > conf.height
? Math.min(conf.boxMargin, Math.abs(maxActorHeight - conf.height))
: 0
);
// The arrow head definition is attached to the svg once
svgDraw.insertArrowHead(diagram);
@@ -601,7 +752,6 @@ export const draw = function(text, id) {
let loopData,
noteWidth,
textWidth,
textConf,
shouldWrap = msg.wrap && msg.message && !common.lineBreakRegex.test(msg.message);
switch (msg.type) {
@@ -610,18 +760,17 @@ export const draw = function(text, id) {
startx = actors[msg.from].x;
stopx = actors[msg.to].x;
textConf = {
fontSize: conf.noteFontSize,
fontFamily: conf.noteFontFamily,
fontWeight: conf.noteFontWeight,
margin: conf.wrapPadding
};
textWidth = utils.calculateTextWidth(msg.message, textConf);
textWidth = calculateTextWidth(
msg.message,
conf.noteFontSize,
conf.noteFontFamily,
conf.noteFontWeight
);
noteWidth = shouldWrap ? conf.width : Math.max(conf.width, textWidth);
if (msg.placement === parser.yy.PLACEMENT.RIGHTOF) {
if (shouldWrap) {
msg.message = utils.wrapLabel(msg.message, noteWidth, textConf);
msg.message = wrapLabel(msg.message, noteWidth);
}
drawNote(
diagram,
@@ -632,7 +781,7 @@ export const draw = function(text, id) {
);
} else if (msg.placement === parser.yy.PLACEMENT.LEFTOF) {
if (shouldWrap) {
msg.message = utils.wrapLabel(msg.message, noteWidth, textConf);
msg.message = wrapLabel(msg.message, noteWidth);
}
drawNote(
diagram,
@@ -644,7 +793,7 @@ export const draw = function(text, id) {
} else if (msg.to === msg.from) {
// Single-actor over
if (shouldWrap) {
msg.message = utils.wrapLabel(msg.message, noteWidth, textConf);
msg.message = wrapLabel(msg.message, noteWidth);
}
drawNote(
diagram,
@@ -658,7 +807,7 @@ export const draw = function(text, id) {
forceWidth = Math.abs(startx - stopx) + conf.actorMargin / 2;
if (shouldWrap) {
noteWidth = forceWidth;
msg.message = utils.wrapLabel(msg.message, noteWidth, textConf);
msg.message = wrapLabel(msg.message, noteWidth);
} else {
noteWidth = Math.max(forceWidth, textWidth - 2 * conf.noteMargin);
}
@@ -677,16 +826,13 @@ export const draw = function(text, id) {
activeEnd(msg, bounds.getVerticalPos());
break;
case parser.yy.LINETYPE.LOOP_START:
adjustLoopHeightForWrap(
loopWidths,
msg,
conf.boxMargin,
conf.boxMargin + conf.boxTextMargin,
message => bounds.newLoop(message)
);
bounds.bumpVerticalPos(conf.boxMargin);
bounds.newLoop(msg.message);
bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin);
break;
case parser.yy.LINETYPE.LOOP_END:
loopData = bounds.endLoop();
svgDraw.drawLoop(diagram, loopData, 'loop', conf);
bounds.bumpVerticalPos(conf.boxMargin);
break;
@@ -695,56 +841,51 @@ export const draw = function(text, id) {
bounds.newLoop(undefined, msg.message);
bounds.bumpVerticalPos(conf.boxMargin);
break;
case parser.yy.LINETYPE.RECT_END:
svgDraw.drawBackgroundRect(diagram, bounds.endLoop());
case parser.yy.LINETYPE.RECT_END: {
const rectData = bounds.endLoop();
svgDraw.drawBackgroundRect(diagram, rectData);
bounds.bumpVerticalPos(conf.boxMargin);
break;
}
case parser.yy.LINETYPE.OPT_START:
adjustLoopHeightForWrap(
loopWidths,
msg,
conf.boxMargin,
conf.boxMargin + conf.boxTextMargin,
message => bounds.newLoop(message)
);
bounds.bumpVerticalPos(conf.boxMargin);
bounds.newLoop(msg.message);
bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin);
break;
case parser.yy.LINETYPE.OPT_END:
loopData = bounds.endLoop();
svgDraw.drawLoop(diagram, loopData, 'opt', conf);
bounds.bumpVerticalPos(conf.boxMargin);
break;
case parser.yy.LINETYPE.ALT_START:
adjustLoopHeightForWrap(
loopWidths,
msg,
conf.boxMargin,
conf.boxMargin + conf.boxTextMargin,
message => bounds.newLoop(message)
);
bounds.bumpVerticalPos(conf.boxMargin);
bounds.newLoop(msg.message);
bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin);
break;
case parser.yy.LINETYPE.ALT_ELSE:
adjustLoopHeightForWrap(loopWidths, msg, conf.boxMargin, conf.boxMargin, message =>
bounds.addSectionToLoop(message)
);
bounds.bumpVerticalPos(conf.boxMargin);
loopData = bounds.addSectionToLoop(msg.message);
bounds.bumpVerticalPos(conf.boxMargin);
break;
case parser.yy.LINETYPE.ALT_END:
loopData = bounds.endLoop();
svgDraw.drawLoop(diagram, loopData, 'alt', conf);
bounds.bumpVerticalPos(conf.boxMargin);
break;
case parser.yy.LINETYPE.PAR_START:
adjustLoopHeightForWrap(
loopWidths,
msg,
conf.boxMargin,
conf.boxMargin + conf.boxTextMargin,
message => bounds.newLoop(message)
);
bounds.bumpVerticalPos(conf.boxMargin);
if (shouldWrap) {
msg.message = wrapLabel(msg.message, conf.boxMargin);
}
bounds.newLoop(msg.message);
bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin);
break;
case parser.yy.LINETYPE.PAR_AND:
adjustLoopHeightForWrap(loopWidths, msg, conf.boxMargin, conf.boxMargin, message =>
bounds.addSectionToLoop(message)
);
bounds.bumpVerticalPos(conf.boxMargin);
loopData = bounds.addSectionToLoop(msg.message);
bounds.bumpVerticalPos(conf.boxMargin);
break;
case parser.yy.LINETYPE.PAR_END:
loopData = bounds.endLoop();
@@ -761,20 +902,13 @@ export const draw = function(text, id) {
const toIdx = fromBounds[0] < toBounds[0] ? 0 : 1;
startx = fromBounds[fromIdx];
stopx = toBounds[toIdx];
textConf = {
fontSize: conf.messageFontSize,
fontFamily: conf.messageFontFamily,
fontWeight: conf.messageFontWeight,
margin: conf.wrapPadding
};
if (shouldWrap) {
msg.message = utils.wrapLabel(
msg.message = wrapLabel(
msg.message,
Math.max(
Math.abs(stopx - startx) + conf.messageMargin * 2,
conf.width + conf.messageMargin * 2
),
textConf
)
);
}
@@ -838,7 +972,6 @@ export const draw = function(text, id) {
diagram.attr('height', '100%');
diagram.attr('width', '100%');
diagram.attr('style', 'max-width:' + width + 'px;');
// diagram.attr('style', 'max-width:100%;');
} else {
diagram.attr('height', height);
diagram.attr('width', width);
@@ -890,17 +1023,12 @@ const getMaxMessageWidthPerActor = function(actors, messages) {
const fontSize = isNote ? conf.noteFontSize : conf.messageFontSize;
const fontFamily = isNote ? conf.noteFontFamily : conf.messageFontFamily;
const fontWeight = isNote ? conf.noteFontWeight : conf.messageFontWeight;
const textConf = { fontFamily, fontSize, fontWeight, margin: conf.wrapPadding };
let wrappedMessage = msg.wrap
? utils.wrapLabel(msg.message, conf.width - conf.noteMargin, textConf)
: msg.message;
const messageDimensions = utils.calculateTextDimensions(wrappedMessage, {
const messageWidth = calculateTextWidth(
msg.wrap ? wrapLabel(msg.message, conf.width - conf.noteMargin) : msg.message,
fontSize,
fontFamily,
fontWeight,
margin: conf.wrapPadding
});
const messageWidth = messageDimensions.width;
fontWeight
);
/*
* The following scenarios should be supported:
@@ -976,13 +1104,6 @@ const calculateActorMargins = function(actors, actorToMessageWidth) {
continue;
}
const textConf = {
fontSize: conf.actorFontSize,
fontFamily: conf.actorFontFamily,
fontWeight: conf.actorFontWeight,
margin: conf.wrapPadding
};
const nextActor = actors[actor.nextActor];
// No need to space out an actor that doesn't have a next link
@@ -991,14 +1112,28 @@ const calculateActorMargins = function(actors, actorToMessageWidth) {
}
[actor, nextActor].forEach(function(act) {
if (act.wrap) {
act.description = utils.wrapLabel(act.description, conf.width, textConf);
}
const actDims = utils.calculateTextDimensions(act.description, textConf);
act.width = act.wrap ? conf.width : Math.max(conf.width, actDims.width);
act.width = act.wrap
? conf.width
: Math.max(
conf.width,
calculateTextWidth(
act.description,
conf.actorFontSize,
conf.actorFontFamily,
conf.actorFontWeight
)
);
act.height = act.wrap ? Math.max(actDims.height, conf.height) : conf.height;
logger.debug(`Actor h:${act.height} ${actDims.height} d:${act.description}`);
act.height = act.wrap
? calculateTextHeight(
act.description,
conf.height,
actor.width,
conf.actorMargin,
act.wrap,
conf.actorFontSize
)
: conf.height;
maxHeight = Math.max(maxHeight, act.height);
});
@@ -1007,62 +1142,11 @@ const calculateActorMargins = function(actors, actorToMessageWidth) {
actor.margin = Math.max(actorWidth, conf.actorMargin);
}
return Math.max(maxHeight, conf.height);
};
const calculateLoopMargins = function(messages, actors) {
const loops = {};
const stack = [];
let current;
messages.forEach(function(msg) {
switch (msg.type) {
case parser.yy.LINETYPE.LOOP_START:
case parser.yy.LINETYPE.ALT_START:
case parser.yy.LINETYPE.OPT_START:
case parser.yy.LINETYPE.PAR_START:
stack.push({
msg: msg.message,
from: Number.MAX_SAFE_INTEGER,
to: Number.MIN_SAFE_INTEGER,
width: 0
});
break;
case parser.yy.LINETYPE.ALT_ELSE:
case parser.yy.LINETYPE.PAR_AND:
if (msg.message) {
current = stack.pop();
loops[msg.message] = current;
stack.push(current);
}
break;
case parser.yy.LINETYPE.LOOP_END:
case parser.yy.LINETYPE.ALT_END:
case parser.yy.LINETYPE.OPT_END:
case parser.yy.LINETYPE.PAR_END:
current = stack.pop();
loops[current.msg] = current;
break;
}
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.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.abs(current.from - current.to) - 20 + 2 * conf.wrapPadding;
});
}
Object.keys(actors).forEach(function(key) {
actors[key].height = maxHeight;
});
logger.debug('LoopWidths:', { loops, actors });
return loops;
return maxHeight;
};
export default {

View File

@@ -19,95 +19,27 @@ export const drawRect = function(elem, rectData) {
};
export const drawText = function(elem, textData) {
let prevTextHeight = 0,
textHeight = 0;
const lines = textData.wrap
? textData.text.split(common.lineBreakRegex)
: [textData.text.replace(common.lineBreakRegex, ' ')];
// Remove and ignore br:s
const nText = textData.text.replace(common.lineBreakRegex, ' ');
let textElems = [];
let dy = 0;
let yfunc = () => textData.y;
if (
typeof textData.valign !== 'undefined' &&
typeof textData.textMargin !== 'undefined' &&
textData.textMargin > 0
) {
switch (textData.valign) {
case 'top':
case 'start':
yfunc = () => textData.y + textData.textMargin;
break;
case 'middle':
case 'center':
yfunc = () => textData.y + (prevTextHeight + textHeight + textData.textMargin) / 2;
break;
case 'bottom':
case 'end':
yfunc = () =>
textData.y +
(prevTextHeight + textHeight + 2 * textData.textMargin) -
textData.textMargin;
break;
}
}
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
if (
typeof textData.textMargin !== 'undefined' &&
textData.textMargin === 0 &&
typeof textData.fontSize !== 'undefined'
) {
dy = i * textData.fontSize;
}
const textElem = elem.append('text');
textElem.attr('x', textData.x);
textElem.attr('y', yfunc());
if (typeof textData.anchor !== 'undefined') {
textElem.style('text-anchor', textData.anchor);
}
if (typeof textData.fontFamily !== 'undefined') {
textElem.style('font-family', textData.fontFamily);
}
if (typeof textData.fontSize !== 'undefined') {
textElem.style('font-size', textData.fontSize);
}
if (typeof textData.fontWeight !== 'undefined') {
textElem.style('font-weight', textData.fontWeight);
}
if (typeof textData.fill !== 'undefined') {
textElem.attr('fill', textData.fill);
}
if (typeof textData.class !== 'undefined') {
textElem.attr('class', textData.class);
}
if (typeof textData.dy !== 'undefined') {
textElem.attr('dy', textData.dy);
} else if (dy !== 0) {
textElem.attr('dy', dy);
}
const span = textElem.append('tspan');
span.attr('x', textData.x);
if (typeof textData.fill !== 'undefined') {
span.attr('fill', textData.fill);
}
span.text(line);
if (
typeof textData.valign !== 'undefined' &&
typeof textData.textMargin !== 'undefined' &&
textData.textMargin > 0
) {
textHeight += (textElem._groups || textElem)[0][0].getBBox().height;
prevTextHeight = textHeight;
}
textElems.push(textElem);
const textElem = elem.append('text');
textElem.attr('x', textData.x);
textElem.attr('y', textData.y);
textElem.style('text-anchor', textData.anchor);
textElem.style('font-family', textData.fontFamily);
textElem.style('font-size', textData.fontSize);
textElem.style('font-weight', textData.fontWeight);
textElem.attr('fill', textData.fill);
if (typeof textData.class !== 'undefined') {
textElem.attr('class', textData.class);
}
return textElems.length === 1 ? textElems[0] : textElems;
const span = textElem.append('tspan');
span.attr('x', textData.x + textData.textMargin * 2);
span.attr('fill', textData.fill);
span.text(nText);
return textElem;
};
export const drawLabel = function(elem, txtObject) {
@@ -140,7 +72,7 @@ export const drawLabel = function(elem, txtObject) {
txtObject.y = txtObject.y + txtObject.labelMargin;
txtObject.x = txtObject.x + 0.5 * txtObject.labelMargin;
return drawText(elem, txtObject);
drawText(elem, txtObject);
};
let actorCnt = -1;
@@ -148,7 +80,7 @@ let actorCnt = -1;
* Draws an actor in the diagram with the attaced line
* @param elem - The diagram we'll draw to.
* @param actor - The actor to draw.
* @param conf - utils.drawText implementation discriminator object
* @param conf - drawText implementation discriminator object
*/
export const drawActor = function(elem, actor, conf) {
const center = actor.x + actor.width / 2;
@@ -253,39 +185,33 @@ export const drawLoop = function(elem, bounds, labelText, conf) {
txt.fontWeight = conf.fontWeight;
txt.class = 'labelText'; // Its size & position are fixed.
let labelElem = drawLabel(g, txt);
let labelBoxWidth = (labelElem._groups || labelElem)[0][0].getBBox().width;
drawLabel(g, txt);
txt = getTextObj();
txt.text = bounds.title;
txt.x = bounds.startx + (bounds.stopx - bounds.startx) / 2 + labelBoxWidth;
txt.y = bounds.starty + conf.boxMargin + conf.boxTextMargin;
txt.text = '[ ' + bounds.title + ' ]';
txt.x = bounds.startx + (bounds.stopx - bounds.startx) / 2;
txt.y = bounds.starty + 1.5 * conf.boxMargin;
txt.anchor = 'middle';
txt.class = 'loopText';
txt.fontFamily = conf.fontFamily;
txt.fontSize = minSize;
txt.fontWeight = conf.fontWeight;
txt.wrap = bounds.wrap;
drawText(g, txt);
let textElem = drawText(g, txt);
let textHeight = (textElem._groups || textElem)[0][0].getBBox().height;
if (typeof bounds.sectionTitles !== 'undefined') {
bounds.sectionTitles.forEach(function(item, idx) {
if (item.message) {
txt.text = item.message;
txt.x = bounds.startx + (bounds.stopx - bounds.startx) / 2;
if (item !== '') {
txt.text = '[ ' + item + ' ]';
txt.y = bounds.sections[idx] + 1.5 * conf.boxMargin;
txt.class = 'loopText';
txt.anchor = 'middle';
txt.fontFamily = conf.fontFamily;
txt.fontSize = minSize;
txt.fontWeight = conf.fontWeight;
txt.wrap = bounds.wrap;
drawText(g, txt);
textElem = drawText(g, txt);
textHeight += (textElem._groups || textElem)[0][0].getBBox().height;
}
});
}
return g;
return textHeight + 4;
};
/**
@@ -374,23 +300,23 @@ export const insertArrowCrossHead = function(elem) {
};
export const getTextObj = function() {
return {
const txt = {
x: 0,
y: 0,
fill: undefined,
anchor: 'start',
'text-anchor': 'start',
style: '#666',
width: 100,
height: 100,
textMargin: 0,
rx: 0,
ry: 0,
valign: undefined
ry: 0
};
return txt;
};
export const getNoteRect = function() {
return {
const rect = {
x: 0,
y: 0,
fill: '#EDF2AE',
@@ -401,6 +327,7 @@ export const getNoteRect = function() {
rx: 0,
ry: 0
};
return rect;
};
const _drawTextCandidateFunc = (function() {