Fixed test cases for sequence diagrams

Updated config to match a conversation knut and i had about the relationship between global, site, and integrator configuration
(Will update docs)
Renamed wrapEnabled to wrap
Poor man's caching for calculateTextDimensions, wrapLabel, and breakString (actually makes a huge difference)
This commit is contained in:
chris moran
2020-06-26 09:26:56 -04:00
parent 7d9bf83f66
commit 217bd1f4bf
13 changed files with 1156 additions and 1370 deletions

View File

@@ -230,7 +230,7 @@ argDirective
;
closeDirective
: close_directive { yy.parseDirective('}%%', 'close_directive'); }
: close_directive { yy.parseDirective('}%%', 'close_directive', 'sequence'); }
;
%%

View File

@@ -1,5 +1,5 @@
import { logger } from '../../logger';
import mermaidAPI from '../../mermaidAPI';
import configApi from '../../config';
let prevActor = undefined;
let actors = {};
@@ -9,63 +9,9 @@ let title = '';
let titleWrapped = false;
let sequenceNumbersEnabled = false;
let wrapEnabled = false;
let currentDirective = {};
export const parseDirective = function(statement, context) {
try {
if (statement !== undefined) {
statement = statement.trim();
switch (context) {
case 'open_directive':
currentDirective = {};
break;
case 'type_directive':
currentDirective.type = statement.toLowerCase();
break;
case 'arg_directive':
currentDirective.args = JSON.parse(statement);
break;
case 'close_directive':
handleDirective(currentDirective);
currentDirective = null;
break;
}
}
} catch (error) {
logger.error(
`Error while rendering sequenceDiagram directive: ${statement} jison context: ${context}`
);
logger.error(error.message);
}
};
const handleDirective = function(directive) {
logger.debug(`Directive type=${directive.type} with args:`, directive.args);
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 'wrap':
case 'nowrap':
wrapEnabled = directive.type === 'wrap';
break;
default:
logger.warn(
`Unhandled directive: source: '%%{${directive.type}: ${JSON.stringify(
directive.args ? directive.args : {}
)}}%%`,
directive
);
break;
}
export const parseDirective = function(statement, context, type) {
mermaidAPI.parseDirective(statement, context, type);
};
export const addActor = function(id, name, description) {
@@ -126,22 +72,8 @@ export const addSignal = function(
message = { text: undefined, wrap: undefined },
messageType
) {
logger.debug(
'Adding message from=' +
idFrom +
' to=' +
idTo +
' message=' +
message.text +
' wrap=' +
message.wrap +
' type=' +
messageType
);
if (messageType === LINETYPE.ACTIVE_END) {
const cnt = activationCount(idFrom.actor);
logger.debug('Adding message from=', messages, cnt);
if (cnt < 1) {
// Bail out as there is an activation signal from an inactive participant
let error = new Error('Trying to inactivate an inactive participant (' + idFrom.actor + ')');
@@ -356,6 +288,7 @@ export default {
getActorKeys,
getTitle,
parseDirective,
getConfig: () => configApi.getConfig().sequence,
getTitleWrapped,
clear,
parseMessage,

View File

@@ -23,7 +23,7 @@ Alice->Bob:Hello Bob, how are you?
Note right of Bob: Bob thinks
Bob-->Alice: I am good thanks!`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
@@ -41,7 +41,7 @@ Alice->Bob:Hello Bob, how are you?
Note right of Bob: Bob thinks
Bob-->Alice: I am good thanks!`;
parser.parse(str);
mermaidAPI.parse(str);
expect(parser.yy.showSequenceNumbers()).toBe(false);
});
it('it should show sequence numbers when autonumber is enabled', function() {
@@ -52,7 +52,7 @@ Alice->Bob:Hello Bob, how are you?
Note right of Bob: Bob thinks
Bob-->Alice: I am good thanks!`;
parser.parse(str);
mermaidAPI.parse(str);
expect(parser.yy.showSequenceNumbers()).toBe(true);
});
it('it should handle a sequenceDiagram definition with a title', function() {
@@ -63,7 +63,7 @@ Alice->Bob:Hello Bob, how are you?
Note right of Bob: Bob thinks
Bob-->Alice: I am good thanks!`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
@@ -82,7 +82,7 @@ sequenceDiagram
Alice->Bob:Hello Bob, how are - you?
Bob-->Alice: I am good thanks!`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
@@ -101,7 +101,7 @@ participant B as Bob
A->B:Hello Bob, how are you?
B-->A: I am good thanks!`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(Object.keys(actors)).toEqual(['A', 'B']);
@@ -118,7 +118,7 @@ B-->A: I am good thanks!`;
sequenceDiagram
Alice-xBob:Hello Bob, how are you?`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
expect(actors.Bob.description).toBe('Bob');
@@ -133,7 +133,7 @@ Alice-xBob:Hello Bob, how are you?`;
sequenceDiagram
Alice--xBob:Hello Bob, how are you?`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
expect(actors.Bob.description).toBe('Bob');
@@ -148,7 +148,7 @@ Alice--xBob:Hello Bob, how are you?`;
sequenceDiagram
Alice->>Bob:Hello Bob, how are you?`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
expect(actors.Bob.description).toBe('Bob');
@@ -161,7 +161,7 @@ Alice->>Bob:Hello Bob, how are you?`;
it('it should handle in arrow messages', function() {
const str = 'sequenceDiagram\n' + 'Alice-->>Bob:Hello Bob, how are you?';
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
expect(actors.Bob.description).toBe('Bob');
@@ -179,7 +179,7 @@ activate Bob
Bob-->>Alice:Hello Alice, I'm fine and you?
deactivate Bob`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
expect(actors.Bob.description).toBe('Bob');
@@ -200,7 +200,7 @@ deactivate Bob`;
Alice-->>+Bob:Hello Bob, how are you?
Bob-->>- Alice:Hello Alice, I'm fine and you?`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
expect(actors.Bob.description).toBe('Bob');
@@ -223,7 +223,7 @@ deactivate Bob`;
Bob-->>- Alice:Hello Alice, please meet Carol?
Carol->>- Bob:Oh Bob, I'm so happy to be here!`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
expect(actors.Bob.description).toBe('Bob');
@@ -261,7 +261,7 @@ deactivate Bob`;
let error = false;
try {
parser.parse(str);
mermaidAPI.parse(str);
} catch (e) {
console.log(e.hash);
error = true;
@@ -277,7 +277,7 @@ deactivate Bob`;
Note right of Bob: Bob thinks
Bob-->Alice: I am good thanks!`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
@@ -298,7 +298,7 @@ deactivate Bob`;
Bob-->Alice: I am good thanks!
`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
@@ -313,7 +313,7 @@ deactivate Bob`;
const str = `
sequenceDiagram;Alice->Bob: Hello Bob, how are you?;Note right of Bob: Bob thinks;Bob-->Alice: I am good thanks!;`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
@@ -333,7 +333,7 @@ sequenceDiagram
Note right of Bob: Bob thinks
Bob-->Alice: I am good thanks!`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
@@ -353,7 +353,7 @@ sequenceDiagram
Note right of Bob: Bob thinks
Bob-->Alice: I am good thanks!`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
@@ -378,7 +378,7 @@ Note right of John: Rational thoughts<br/>prevail...
John->Bob: How about you?
Bob-->John: Jolly good!`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
@@ -406,7 +406,7 @@ note right of 4: multiline<br />text
note right of 1: multiline<br \t/>text
`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors['1'].description).toBe('multiline<br>text');
@@ -431,7 +431,7 @@ Alice->Bob: Hello Bob, how are you?
Note over Bob: Bob thinks
`;
parser.parse(str);
mermaidAPI.parse(str);
const messages = parser.yy.getMessages();
expect(messages[1].from).toBe('Bob');
@@ -445,7 +445,7 @@ Note over Alice,Bob: confusion
Note over Bob,Alice: resolution
`;
parser.parse(str);
mermaidAPI.parse(str);
const messages = parser.yy.getMessages();
expect(messages[1].from).toBe('Alice');
@@ -465,7 +465,7 @@ loop Multiple happy responses
Bob-->Alice: I am good thanks!
end`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
@@ -487,7 +487,7 @@ end`;
end
`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
@@ -512,7 +512,7 @@ end`;
Bob-->Alice: I am good thanks
end
`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
@@ -539,7 +539,7 @@ opt Perhaps a happy response
Bob-->Alice: I am good thanks!
end`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
@@ -564,7 +564,7 @@ else isSick
Bob-->Alice: Feel sick...
end`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
@@ -591,7 +591,7 @@ Bob-->Alice: Feel sick...
else default
Bob-->Alice: :-)
end`;
parser.parse(str);
mermaidAPI.parse(str);
const messages = parser.yy.getMessages();
expect(messages.length).toBe(9);
expect(messages[1].from).toBe('Bob');
@@ -617,7 +617,7 @@ Alice->>Bob: What do you think about it?
Bob-->>Alice: It's good!
end`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
@@ -633,7 +633,7 @@ end`;
it('it should handle special characters in signals', function() {
const str = 'sequenceDiagram\n' + 'Alice->Bob: -:<>,;# comment';
parser.parse(str);
mermaidAPI.parse(str);
const messages = parser.yy.getMessages();
expect(messages[0].message).toBe('-:<>,');
@@ -644,7 +644,7 @@ sequenceDiagram
Alice->Bob: Hello Bob, how are you?
Note right of Bob: -:<>,;# comment`;
parser.parse(str);
mermaidAPI.parse(str);
const messages = parser.yy.getMessages();
expect(messages[1].message).toBe('-:<>,');
@@ -657,7 +657,7 @@ loop -:<>,;# comment
Bob-->Alice: I am good thanks!
end`;
parser.parse(str);
mermaidAPI.parse(str);
const messages = parser.yy.getMessages();
expect(messages[1].message).toBe('-:<>,');
@@ -670,7 +670,7 @@ opt -:<>,;# comment
Bob-->Alice: I am good thanks!
end`;
parser.parse(str);
mermaidAPI.parse(str);
const messages = parser.yy.getMessages();
expect(messages[1].message).toBe('-:<>,');
@@ -685,7 +685,7 @@ else ,<>:-#; comment
Bob-->Alice: I am good thanks!
end`;
parser.parse(str);
mermaidAPI.parse(str);
const messages = parser.yy.getMessages();
expect(messages[1].message).toBe('-:<>,');
@@ -701,7 +701,7 @@ and ,<>:-#; comment
Bob-->Alice: I am good thanks!
end`;
parser.parse(str);
mermaidAPI.parse(str);
const messages = parser.yy.getMessages();
expect(messages[1].message).toBe('-:<>,');
@@ -715,7 +715,7 @@ loop
Bob-->Alice: I am good thanks!
end`;
parser.parse(str);
mermaidAPI.parse(str);
const messages = parser.yy.getMessages();
expect(messages[1].message).toBe('');
@@ -729,7 +729,7 @@ opt # comment
Bob-->Alice: I am good thanks!
end`;
parser.parse(str);
mermaidAPI.parse(str);
const messages = parser.yy.getMessages();
expect(messages[1].message).toBe('');
@@ -744,7 +744,7 @@ else # comment
Bob-->Alice: I am good thanks!
end`;
parser.parse(str);
mermaidAPI.parse(str);
const messages = parser.yy.getMessages();
expect(messages[1].message).toBe('');
@@ -761,7 +761,7 @@ and # comment
Bob-->Alice: I am good thanks!
end`;
parser.parse(str);
mermaidAPI.parse(str);
const messages = parser.yy.getMessages();
expect(messages[1].message).toBe('');
@@ -772,12 +772,8 @@ end`;
});
describe('when checking the bounds in a sequenceDiagram', function() {
let conf;
beforeEach(function() {
mermaidAPI.reset();
parser.yy = sequenceDb;
parser.yy.clear();
conf = {
beforeAll(() => {
let conf = {
diagramMarginX: 50,
diagramMarginY: 10,
actorMargin: 50,
@@ -791,13 +787,21 @@ describe('when checking the bounds in a sequenceDiagram', function() {
};
mermaidAPI.initialize({ sequence: conf });
});
let conf;
beforeEach(function() {
mermaidAPI.reset();
parser.yy = sequenceDb;
parser.yy.clear();
renderer.bounds.init();
conf = parser.yy.getConfig();
});
it('it should handle a simple bound call', function() {
renderer.bounds.insert(100, 100, 200, 200);
const bounds = renderer.bounds.getBounds();
const { bounds } = renderer.bounds.getBounds();
expect(bounds.startx).toBe(100);
expect(bounds.starty).toBe(100);
expect(bounds.stopx).toBe(200);
@@ -808,7 +812,7 @@ describe('when checking the bounds in a sequenceDiagram', function() {
renderer.bounds.insert(100, 100, 200, 200);
renderer.bounds.insert(25, 50, 300, 400);
const bounds = renderer.bounds.getBounds();
const { bounds } = renderer.bounds.getBounds();
expect(bounds.startx).toBe(25);
expect(bounds.starty).toBe(50);
expect(bounds.stopx).toBe(300);
@@ -820,7 +824,7 @@ describe('when checking the bounds in a sequenceDiagram', function() {
renderer.bounds.insert(25, 50, 300, 400);
renderer.bounds.insert(125, 150, 150, 200);
const bounds = renderer.bounds.getBounds();
const { bounds } = renderer.bounds.getBounds();
expect(bounds.startx).toBe(25);
expect(bounds.starty).toBe(50);
expect(bounds.stopx).toBe(300);
@@ -841,7 +845,7 @@ describe('when checking the bounds in a sequenceDiagram', function() {
expect(loop.stopy).toBe(200 + conf.boxMargin);
// Check bounds of first loop
const bounds = renderer.bounds.getBounds();
const { bounds } = renderer.bounds.getBounds();
expect(bounds.startx).toBe(25);
expect(bounds.starty).toBe(50);
@@ -873,7 +877,7 @@ describe('when checking the bounds in a sequenceDiagram', function() {
expect(loop.stopy).toBe(300 + 2 * conf.boxMargin);
// Check bounds of first loop
const bounds = renderer.bounds.getBounds();
const { bounds } = renderer.bounds.getBounds();
expect(bounds.startx).toBe(100);
expect(bounds.starty).toBe(100);
@@ -895,7 +899,7 @@ describe('when checking the bounds in a sequenceDiagram', function() {
expect(loop.stopy).toBe(300 + conf.boxMargin);
// Check bounds after the loop
const bounds = renderer.bounds.getBounds();
const { bounds } = renderer.bounds.getBounds();
expect(bounds.startx).toBe(loop.startx);
expect(bounds.starty).toBe(loop.starty);
@@ -905,13 +909,8 @@ 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();
conf = {
beforeAll(() => {
let conf = {
diagramMarginX: 50,
diagramMarginY: 10,
actorMargin: 50,
@@ -922,10 +921,17 @@ describe('when rendering a sequenceDiagram', function() {
messageMargin: 40,
boxTextMargin: 15,
noteMargin: 25,
wrapEnabled: false,
wrap: false,
mirrorActors: false
};
mermaidAPI.initialize({ sequence: conf });
});
let conf;
beforeEach(function() {
mermaidAPI.reset();
parser.yy = sequenceDb;
parser.yy.clear();
conf = parser.yy.getConfig();
renderer.bounds.init();
});
['tspan', 'fo', 'old', undefined].forEach(function(textPlacement) {
@@ -935,12 +941,12 @@ it should handle one actor, when textPlacement is ${textPlacement}`, function()
sequenceDiagram
participant Alice`;
mermaidAPI.initialize(addConf(conf, 'textPlacement', textPlacement));
renderer.bounds.init();
parser.parse(str);
mermaidAPI.reinitialize({sequence: { textPlacement: textPlacement}});
mermaidAPI.parse(str);
// renderer.setConf(mermaidAPI.getConfig().sequence);
renderer.draw(str, 'tst');
const bounds = renderer.bounds.getBounds();
const { bounds } = renderer.bounds.getBounds();
expect(bounds.startx).toBe(0);
expect(bounds.starty).toBe(0);
expect(bounds.stopx).toBe(conf.width);
@@ -955,7 +961,7 @@ participant Alice
participant Alice
`;
parser.parse(str);
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(Object.keys(actors)).toEqual(['Alice']);
@@ -967,15 +973,16 @@ participant Alice
Note over Alice: Alice thinks
`;
parser.parse(str);
expect(mermaidAPI.getConfig().sequence.mirrorActors).toBeFalsy();
mermaidAPI.parse(str);
renderer.draw(str, 'tst');
const bounds = renderer.bounds.getBounds();
const { bounds, models } = renderer.bounds.getBounds();
expect(bounds.startx).toBe(0);
expect(bounds.starty).toBe(0);
expect(bounds.stopx).toBe(conf.width);
// 10 comes from mock of text height
expect(bounds.stopy).toBe(conf.height + conf.boxMargin + 2 * conf.noteMargin + 10);
expect(bounds.stopy).toBe(models.lastNote().stopy);
});
it('it should handle one actor and a note to the left', function() {
const str = `
@@ -983,15 +990,15 @@ sequenceDiagram
participant Alice
Note left of Alice: Alice thinks`;
parser.parse(str);
mermaidAPI.parse(str);
renderer.draw(str, 'tst');
const bounds = renderer.bounds.getBounds();
const { bounds, models } = renderer.bounds.getBounds();
expect(bounds.startx).toBe(-(conf.width / 2) - conf.actorMargin / 2);
expect(bounds.starty).toBe(0);
expect(bounds.stopx).toBe(conf.width);
// 10 comes from mock of text height
expect(bounds.stopy).toBe(conf.height + conf.boxMargin + 2 * conf.noteMargin + 10);
expect(bounds.stopy).toBe(models.lastNote().stopy);
});
it('it should handle one actor and a note to the right', function() {
const str = `
@@ -999,29 +1006,29 @@ sequenceDiagram
participant Alice
Note right of Alice: Alice thinks`;
parser.parse(str);
mermaidAPI.parse(str);
renderer.draw(str, 'tst');
const bounds = renderer.bounds.getBounds();
const { bounds, models } = renderer.bounds.getBounds();
expect(bounds.startx).toBe(0);
expect(bounds.starty).toBe(0);
expect(bounds.stopx).toBe(conf.width / 2 + conf.actorMargin / 2 + conf.width);
// 10 comes from mock of text height
expect(bounds.stopy).toBe(conf.height + conf.boxMargin + 2 * conf.noteMargin + 10);
expect(bounds.stopy).toBe(models.lastNote().stopy);
});
it('it should handle two actors', function() {
const str = `
sequenceDiagram
Alice->Bob: Hello Bob, how are you?`;
parser.parse(str);
mermaidAPI.parse(str);
renderer.draw(str, 'tst');
const bounds = renderer.bounds.getBounds();
const { bounds, models } = renderer.bounds.getBounds();
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(models.lastMessage().stopy);
});
it('it should handle two actors with init directive', function() {
const str = `
@@ -1029,16 +1036,16 @@ Alice->Bob: Hello Bob, how are you?`;
sequenceDiagram
Alice->Bob: Hello Bob, how are you?`;
parser.parse(str);
mermaidAPI.parse(str);
renderer.draw(str, 'tst');
const bounds = renderer.bounds.getBounds();
const { bounds, models } = 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.height + conf.messageMargin + (conf.mirrorActors ? 2 * conf.boxMargin + conf.height : 0));
expect(bounds.stopy).toBe(models.lastMessage().stopy);
});
it('it should handle two actors with init directive with multiline directive', function() {
const str = `
@@ -1049,17 +1056,17 @@ wrap
}%%
Alice->Bob: Hello Bob, how are you?`;
parser.parse(str);
mermaidAPI.parse(str);
renderer.draw(str, 'tst');
const msgs = parser.yy.getMessages();
const bounds = renderer.bounds.getBounds();
const { bounds, models } = 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(bounds.stopy).toBe(models.lastMessage().stopy);
expect(msgs.every(v => v.wrap)).toBe(true);
});
@@ -1070,17 +1077,15 @@ Alice->Bob: Hello Bob, how are you?
Note over Alice,Bob: Looks
Note over Bob,Alice: Looks back
`;
parser.parse(str);
mermaidAPI.initialize({logLevel:0})
mermaidAPI.parse(str);
renderer.draw(str, 'tst');
const bounds = renderer.bounds.getBounds();
const { bounds, models } = renderer.bounds.getBounds();
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 + 2 * (conf.boxMargin + 2 * conf.noteMargin + 10)
);
expect(bounds.stopy).toBe(models.lastNote().stopy);
});
it('it should draw two actors and two messages', function() {
const str = `
@@ -1088,14 +1093,14 @@ sequenceDiagram
Alice->Bob: Hello Bob, how are you?
Bob->Alice: Fine!`;
parser.parse(str);
mermaidAPI.parse(str);
renderer.draw(str, 'tst');
const bounds = renderer.bounds.getBounds();
const { bounds, models } = renderer.bounds.getBounds();
expect(bounds.startx).toBe(0);
expect(bounds.starty).toBe(0);
expect(bounds.stopx).toBe(0 + conf.width * 2 + conf.actorMargin);
expect(bounds.stopy).toBe(0 + 2 * conf.messageMargin + conf.height);
expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin);
expect(bounds.stopy).toBe(models.lastMessage().stopy);
});
it('it should draw two actors notes to the right', function() {
const str = `
@@ -1104,19 +1109,17 @@ Alice->Bob: Hello Bob, how are you?
Note right of Bob: Bob thinks
Bob->Alice: Fine!`;
parser.parse(str);
mermaidAPI.parse(str);
renderer.draw(str, 'tst');
const bounds = renderer.bounds.getBounds();
const { bounds, models } = renderer.bounds.getBounds();
expect(bounds.startx).toBe(0);
expect(bounds.starty).toBe(0);
const expStopX = conf.actorMargin + conf.width + conf.width / 2 + conf.noteMargin + conf.width;
expect(bounds.stopx).toBe(expStopX);
expect(bounds.stopy).toBe(
2 * conf.messageMargin + conf.height + conf.boxMargin + 10 + 2 * conf.noteMargin
);
expect(bounds.stopy).toBe(models.lastMessage().stopy);
});
it('it should draw two actors notes to the left', function() {
const str = `
@@ -1125,17 +1128,15 @@ Alice->Bob: Hello Bob, how are you?
Note left of Alice: Bob thinks
Bob->Alice: Fine!`;
parser.parse(str);
mermaidAPI.parse(str);
renderer.draw(str, 'tst');
const bounds = renderer.bounds.getBounds();
const { bounds, models } = renderer.bounds.getBounds();
expect(bounds.startx).toBe(-(conf.width / 2) - conf.actorMargin / 2);
expect(bounds.starty).toBe(0);
expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin);
expect(bounds.stopy).toBe(
2 * conf.messageMargin + conf.height + conf.boxMargin + 10 + 2 * conf.noteMargin
);
expect(bounds.stopy).toBe(models.lastMessage().stopy);
});
it('it should draw two actors notes to the left with text wrapped (inline)', function() {
const str = `
@@ -1144,19 +1145,17 @@ Alice->>Bob:wrap: Hello Bob, how are you? If you are not available right now, I
Note left of Alice: Bob thinks
Bob->>Alice: Fine!`;
parser.parse(str);
mermaidAPI.parse(str);
renderer.draw(str, 'tst');
const bounds = renderer.bounds.getBounds();
const { bounds, models } = renderer.bounds.getBounds();
const msgs = parser.yy.getMessages();
expect(bounds.startx).toBe(-(conf.width / 2) - conf.actorMargin / 2);
expect(bounds.starty).toBe(0);
expect(msgs[0].wrap).toBe(true);
expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin);
expect(bounds.stopy).toBe(
2 * conf.messageMargin + conf.height + conf.boxMargin + 10 + 2 * conf.noteMargin
);
expect(bounds.stopy).toBe(models.lastMessage().stopy);
});
it('it should draw two actors notes to the left with text wrapped (directive)', function() {
const str = `
@@ -1167,10 +1166,10 @@ Alice->>Bob: Hello Bob, how are you? If you are not available right now, I can l
Note left of Alice: Bob thinks
Bob->>Alice: Fine!`;
parser.parse(str);
mermaidAPI.parse(str);
renderer.draw(str, 'tst');
const bounds = renderer.bounds.getBounds();
const { bounds, models } = renderer.bounds.getBounds();
const msgs = parser.yy.getMessages();
const mermaid = mermaidAPI.getConfig();
expect(bounds.startx).toBe(-(conf.width / 2) - conf.actorMargin / 2);
@@ -1179,9 +1178,7 @@ Bob->>Alice: Fine!`;
expect(msgs.every(v => v.wrap)).toBe(true);
expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin);
expect(bounds.stopy).toBe(
2 * conf.messageMargin + conf.height + conf.boxMargin + 10 + 2 * conf.noteMargin
);
expect(bounds.stopy).toBe(models.lastMessage().stopy);
});
it('it should draw two actors notes to the left with text wrapped and the init directive sets the theme to dark', function() {
const str = `
@@ -1191,10 +1188,11 @@ 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);
mermaidAPI.parse(str);
renderer.draw(str, 'tst');
const bounds = renderer.bounds.getBounds();
const { bounds, models } = renderer.bounds.getBounds();
const msgs = parser.yy.getMessages();
const mermaid = mermaidAPI.getConfig();
expect(bounds.startx).toBe(-(conf.width / 2) - conf.actorMargin / 2);
@@ -1203,22 +1201,19 @@ Bob->>Alice: Fine!`;
expect(msgs.every(v => v.wrap)).toBe(true);
expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin);
expect(bounds.stopy).toBe(
2 * conf.messageMargin + conf.height + conf.boxMargin + 10 + 2 * conf.noteMargin
);
expect(bounds.stopy).toBe(models.lastMessage().stopy);
});
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() {
const str = `
%%{init: { "theme": "dark", 'config': { "fontFamily": "Menlo", "fontSize": 18, "fontWeight": 400, "wrapEnabled": true }}}%%
%%{init: { "theme": "dark", 'config': { "fontFamily": "Menlo", "fontSize": 18, "fontWeight": 400, "wrap": true }}}%%
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.setConf(mermaidAPI.getConfig().sequence);
mermaidAPI.parse(str);
renderer.draw(str, 'tst');
const bounds = renderer.bounds.getBounds();
const { bounds, models } = renderer.bounds.getBounds();
const msgs = parser.yy.getMessages();
const mermaid = mermaidAPI.getConfig();
expect(bounds.startx).toBe(-(conf.width / 2) - conf.actorMargin / 2);
@@ -1230,9 +1225,7 @@ Bob->>Alice: Fine!`;
expect(msgs.every(v => v.wrap)).toBe(true);
expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin);
expect(bounds.stopy).toBe(
2 * conf.messageMargin + conf.height + conf.boxMargin + 10 + 2 * conf.noteMargin
);
expect(bounds.stopy).toBe(models.lastMessage().stopy);
});
it('it should draw two loops', function() {
const str = `
@@ -1241,17 +1234,15 @@ Alice->Bob: Hello Bob, how are you?
loop Cheers
Bob->Alice: Fine!
end`;
parser.parse(str);
mermaidAPI.parse(str);
renderer.draw(str, 'tst');
const bounds = renderer.bounds.getBounds();
const { bounds, models } = renderer.bounds.getBounds();
expect(bounds.startx).toBe(0);
expect(bounds.starty).toBe(0);
expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin);
expect(bounds.stopy).toBe(
2 * conf.messageMargin + conf.height + 3 * conf.boxMargin + conf.boxTextMargin
);
expect(bounds.stopy).toBe(models.lastLoop().stopy);
});
it('it should draw background rect', function() {
const str = `
@@ -1261,26 +1252,21 @@ end`;
Bob->Alice: I feel surrounded by darkness
end
`;
parser.parse(str);
mermaidAPI.parse(str);
renderer.draw(str, 'tst');
const bounds = renderer.bounds.getBounds();
const { bounds, models } = renderer.bounds.getBounds();
expect(bounds.startx).toBe(0);
expect(bounds.starty).toBe(0);
expect(bounds.stopx).toBe(0 + conf.width * 2 + conf.actorMargin);
expect(bounds.stopy).toBe(0 + 2 * conf.messageMargin + conf.height + 3 * conf.boxMargin);
expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin);
expect(bounds.stopy).toBe(models.lastLoop().stopy);
});
});
describe('when rendering a sequenceDiagram with actor mirror activated', function() {
let conf;
beforeEach(function() {
mermaidAPI.reset();
parser.yy = sequenceDb;
parser.yy.clear();
conf = {
beforeAll(() => {
let conf = {
diagramMarginX: 50,
diagramMarginY: 10,
actorMargin: 50,
@@ -1296,7 +1282,16 @@ describe('when rendering a sequenceDiagram with actor mirror activated', functio
// Prolongs the edge of the diagram downwards
bottomMarginAdj: 1
};
mermaidAPI.initialize({ sequence: conf });
});
let conf;
beforeEach(function() {
mermaidAPI.reset();
parser.yy = sequenceDb;
parser.yy.clear();
conf = parser.yy.getConfig();
renderer.bounds.init();
});
['tspan', 'fo', 'old', undefined].forEach(function(textPlacement) {
@@ -1306,31 +1301,26 @@ describe('when rendering a sequenceDiagram with actor mirror activated', functio
const str = `
sequenceDiagram
participant Alice`;
parser.parse(str);
renderer.bounds.init();
mermaidAPI.parse(str);
renderer.draw(str, 'tst');
const bounds = renderer.bounds.getBounds();
const { bounds, models } = renderer.bounds.getBounds();
expect(bounds.startx).toBe(0);
expect(bounds.starty).toBe(0);
expect(bounds.stopx).toBe(conf.width);
expect(bounds.stopy).toBe(2 * conf.height + 2 * conf.boxMargin);
expect(bounds.stopy).toBe(models.lastActor().y + models.lastActor().height);
});
});
});
describe('when rendering a sequenceDiagram with directives', function() {
let conf;
beforeEach(function() {
mermaidAPI.reset();
parser.yy = sequenceDb;
parser.yy.clear();
conf = {
beforeAll(function() {
let conf = {
diagramMarginX: 50,
diagramMarginY: 10,
actorMargin: 50,
width: 150,
// Height of actor boxes
height: 65,
boxMargin: 10,
messageMargin: 40,
@@ -1338,6 +1328,14 @@ describe('when rendering a sequenceDiagram with directives', function() {
noteMargin: 25
};
mermaidAPI.initialize({ sequence: conf });
});
let conf;
beforeEach(function() {
mermaidAPI.reset();
parser.yy = sequenceDb;
parser.yy.clear();
conf = parser.yy.getConfig();
renderer.bounds.init();
});
@@ -1349,17 +1347,18 @@ sequenceDiagram
participant Alice
`;
parser.parse(str);
renderer.bounds.init();
mermaidAPI.parse(str);
renderer.draw(str, 'tst');
const bounds = renderer.bounds.getBounds();
const { bounds, models } = renderer.bounds.getBounds();
const mermaid = mermaidAPI.getConfig();
expect(mermaid.theme).toBe('dark');
expect(mermaid.logLevel).toBe(1);
expect(bounds.startx).toBe(0);
expect(bounds.startx).toBe(0);
expect(bounds.starty).toBe(0);
expect(bounds.stopy).toBe(2 * conf.height + 2 * conf.boxMargin);
expect(bounds.stopy).toBe(models.lastActor().y + models.lastActor().height);
});
it('it should handle one actor, when logLevel is 3', function() {
const str = `
@@ -1368,15 +1367,15 @@ sequenceDiagram
participant Alice
`;
parser.parse(str);
mermaidAPI.parse(str);
renderer.draw(str, 'tst');
const bounds = renderer.bounds.getBounds();
const { bounds, models } = renderer.bounds.getBounds();
const mermaid = mermaidAPI.getConfig();
expect(mermaid.logLevel).toBe(3);
expect(bounds.startx).toBe(0);
expect(bounds.startx).toBe(0);
expect(bounds.starty).toBe(0);
expect(bounds.stopy).toBe(2 * conf.height + 2 * conf.boxMargin);
expect(bounds.stopy).toBe(models.lastActor().y + models.lastActor().height);
});
});

View File

@@ -8,79 +8,7 @@ import utils, { assignWithDepth } from '../../utils';
parser.yy = sequenceDb;
const conf = {
diagramMarginX: 50,
diagramMarginY: 30,
// Margin between actors
actorMargin: 50,
// Width of actor boxes
width: 150,
// Height of actor boxes
height: 65,
actorFontSize: 14,
actorFontFamily: '"Open-Sans", "sans-serif"',
// 400 = normal
actorFontWeight: 400,
// Note font settings
noteFontSize: 14,
noteFontFamily: '"trebuchet ms", verdana, arial',
noteFontWeight: 400,
noteAlign: 'center',
// Message font settings
messageFontSize: 16,
messageFontFamily: '"trebuchet ms", verdana, arial',
messageFontWeight: 400,
// Margin around loop boxes
boxMargin: 10,
boxTextMargin: 5,
noteMargin: 10,
// Space between messages
messageMargin: 35,
// Multiline message alignment
messageAlign: 'center',
// mirror actors under diagram
mirrorActors: false,
// Depending on css styling this might need adjustment
// Prolongs the edge of the diagram downwards
bottomMarginAdj: 1,
// width of activation box
activationWidth: 10,
labelBoxWidth: 50,
labelBoxHeight: 20,
// text placement as: tspan | fo | old only text as before
textPlacement: 'tspan',
showSequenceNumbers: false,
// wrap text
wrapEnabled: false,
// padding for wrapped text
wrapPadding: 15,
messageFont: () => {
return {
fontFamily: conf.messageFontFamily,
fontSize: conf.messageFontSize,
fontWeight: conf.messageFontWeight
};
},
noteFont: () => {
return {
fontFamily: conf.noteFontFamily,
fontSize: conf.noteFontSize,
fontWeight: conf.noteFontWeight
};
},
actorFont: () => {
return {
fontFamily: conf.actorFontFamily,
fontSize: conf.actorFontSize,
fontWeight: conf.actorFontWeight
};
}
};
const conf = {};
export const bounds = {
data: {
@@ -90,10 +18,57 @@ export const bounds = {
stopy: undefined
},
verticalPos: 0,
sequenceItems: [],
activations: [],
models: {
getHeight: function() {
return (
Math.max.apply(
null,
this.actors.length === 0 ? [0] : this.actors.map(actor => actor.height || 0)
) +
(this.loops.length === 0
? 0
: this.loops.map(it => it.height || 0).reduce((acc, h) => acc + h)) +
(this.messages.length === 0
? 0
: this.messages.map(it => it.height || 0).reduce((acc, h) => acc + h)) +
(this.notes.length === 0
? 0
: this.notes.map(it => it.height || 0).reduce((acc, h) => acc + h))
);
},
clear: function() {
this.actors = [];
this.loops = [];
this.messages = [];
this.notes = [];
},
addActor: function(actorModel) {
this.actors.push(actorModel);
},
addLoop: function(loopModel) {
this.loops.push(loopModel);
},
addMessage: function(msgModel) {
this.messages.push(msgModel);
},
addNote: function(noteModel) {
this.notes.push(noteModel);
},
lastActor: function() {
return this.actors[this.actors.length - 1];
},
lastLoop: function() {
return this.loops[this.loops.length - 1];
},
lastMessage: function() {
return this.messages[this.messages.length - 1];
},
lastNote: function() {
return this.notes[this.notes.length - 1];
},
actors: [],
loops: [],
messages: [],
notes: []
@@ -101,11 +76,7 @@ export const bounds = {
init: function() {
this.sequenceItems = [];
this.activations = [];
this.models = {
loops: [],
messages: [],
notes: []
};
this.models.clear();
this.data = {
startx: undefined,
stopx: undefined,
@@ -113,6 +84,7 @@ export const bounds = {
stopy: undefined
};
this.verticalPos = 0;
setConf(parser.yy.getConfig());
},
updateVal: function(obj, key, val, fun) {
if (typeof obj[key] === 'undefined') {
@@ -219,7 +191,7 @@ export const bounds = {
return this.verticalPos;
},
getBounds: function() {
return this.data;
return { bounds: this.data, models: this.models };
}
};
@@ -229,17 +201,20 @@ export const bounds = {
* @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.
*/
const drawNote = function(elem, noteModel) {
bounds.bumpVerticalPos(conf.boxMargin);
noteModel.height = conf.boxMargin;
noteModel.starty = bounds.getVerticalPos();
const rect = svgDraw.getNoteRect();
rect.x = noteModel.x;
rect.y = noteModel.y;
rect.x = noteModel.startx;
rect.y = noteModel.starty;
rect.width = noteModel.width || conf.width;
rect.class = 'note';
let g = elem.append('g');
const rectElem = svgDraw.drawRect(g, rect);
const textObj = svgDraw.getTextObj();
textObj.x = noteModel.x;
textObj.y = noteModel.y;
textObj.x = noteModel.startx;
textObj.y = noteModel.starty;
textObj.width = rect.width;
textObj.dy = '1em';
textObj.text = noteModel.message;
@@ -258,12 +233,13 @@ const drawNote = function(elem, noteModel) {
textElem.map(te => (te._groups || te)[0][0].getBBox().height).reduce((acc, curr) => acc + curr)
);
noteModel.height = textHeight + 2 * conf.noteMargin;
bounds.insert(noteModel.x, noteModel.y, noteModel.x + rect.width, noteModel.y + noteModel.height);
rectElem.attr('height', noteModel.height);
bounds.bumpVerticalPos(noteModel.height);
rectElem.attr('height', textHeight + 2 * conf.noteMargin);
noteModel.height += textHeight + 2 * conf.noteMargin;
bounds.bumpVerticalPos(textHeight + 2 * conf.noteMargin);
noteModel.stopy = noteModel.starty + textHeight + 2 * conf.noteMargin;
noteModel.stopx = noteModel.startx + rect.width;
bounds.insert(noteModel.startx, noteModel.starty, noteModel.stopx, noteModel.stopy);
bounds.models.addNote(noteModel);
};
/**
@@ -272,10 +248,13 @@ const drawNote = function(elem, noteModel) {
* @param msgModel - the model containing fields describing a message
*/
const drawMessage = function(g, msgModel) {
bounds.bumpVerticalPos(conf.messageMargin);
msgModel.height += conf.messageMargin;
msgModel.starty = bounds.getVerticalPos();
const { startx, stopx, starty: verticalPos, message, type, sequenceIndex, wrap } = msgModel;
const textObj = svgDraw.getTextObj();
textObj.x = startx;
textObj.y = verticalPos - (conf.messageFontSize + 7);
textObj.y = verticalPos;
textObj.width = stopx - startx;
textObj.class = 'messageText';
textObj.dy = '1em';
@@ -290,20 +269,18 @@ const drawMessage = function(g, msgModel) {
textObj.wrap = wrap;
let textElem = drawText(g, textObj);
const lineHeight = (textElem[0]._groups || textElem[0])[0][0].getBBox().height;
textElem.forEach(te => te.attr('y', verticalPos - 7 - lineHeight / 2));
const lines = message.split(common.lineBreakRegex).length - 1 > 0 ? 1 : 0;
const lines = message.split(common.lineBreakRegex).length - 1;
let totalOffset = Math.round(
textElem.map(te => (te._groups || te)[0][0].getBBox().height).reduce((acc, curr) => acc + curr)
);
let totalOffset = Math.round(lineHeight + lines * lineHeight);
let textWidth = Math.max.apply(
null,
textElem.map(te => (te._groups || te)[0][0].getBBox().width)
);
bounds.bumpVerticalPos(totalOffset - lines * conf.messageFontSize);
let line;
if (startx === stopx) {
if (conf.rightAngles) {
@@ -342,25 +319,32 @@ const drawMessage = function(g, msgModel) {
}
bounds.bumpVerticalPos(30);
msgModel.height += 30;
const dx = Math.max(textWidth / 2, 100);
bounds.insert(
startx - dx,
bounds.getVerticalPos() - 10 + totalOffset,
stopx + dx,
bounds.getVerticalPos() + totalOffset
bounds.getVerticalPos() + 30 + totalOffset
);
bounds.bumpVerticalPos(10);
msgModel.height += 10;
} else {
line = g.append('line');
line.attr('x1', startx);
line.attr('y1', verticalPos + totalOffset);
line.attr('x2', stopx);
line.attr('y2', verticalPos + totalOffset);
bounds.bumpVerticalPos(10);
msgModel.height += 10;
bounds.insert(
startx,
bounds.getVerticalPos() - 10 + totalOffset,
stopx,
bounds.getVerticalPos() + totalOffset
);
msgModel.height += 10;
bounds.bumpVerticalPos(10);
}
// Make an SVG Container
// Draw the line
@@ -411,6 +395,9 @@ const drawMessage = function(g, msgModel) {
.attr('class', 'sequenceNumber')
.text(sequenceIndex);
}
msgModel.stopy = msgModel.starty + msgModel.height;
bounds.insert(msgModel.fromBounds, msgModel.starty, msgModel.toBounds, msgModel.stopy);
logger.debug(`mm.h:${msgModel.height} vs c.h:${msgModel.stopy - msgModel.starty}`);
};
export const drawActors = function(diagram, actors, actorKeys, verticalPos) {
@@ -435,6 +422,7 @@ export const drawActors = function(diagram, actors, actorKeys, verticalPos) {
prevWidth += actor.width;
prevMargin += actor.margin;
bounds.models.addActor(actor);
}
// Add a margin between the actor boxes and the first arrow
@@ -461,7 +449,7 @@ const actorActivations = function(actor) {
});
};
const actorFlowVerticaBounds = function(actor, actors) {
const activationBounds = function(actor, actors) {
// handle multiple stacked activations for same actor
const actorObj = actors[actor];
const activations = actorActivations(actor);
@@ -498,7 +486,7 @@ function adjustLoopHeightForWrap(loopWidths, msg, preMargin, postMargin, addLoop
*/
export const draw = function(text, id) {
parser.yy.clear();
parser.yy.setWrap(conf.wrapEnabled);
parser.yy.setWrap(conf.wrap);
parser.parse(text + '\n');
bounds.init();
@@ -545,11 +533,8 @@ export const draw = function(text, id) {
switch (msg.type) {
case parser.yy.LINETYPE.NOTE:
bounds.bumpVerticalPos(conf.boxMargin);
noteModel = msg.noteModel;
noteModel.y = bounds.getVerticalPos();
drawNote(diagram, noteModel);
bounds.models.notes.push(noteModel);
break;
case parser.yy.LINETYPE.ACTIVE_START:
bounds.newActivation(msg, diagram, actors);
@@ -568,9 +553,9 @@ export const draw = function(text, id) {
break;
case parser.yy.LINETYPE.LOOP_END:
loopModel = bounds.endLoop();
svgDraw.drawLoop(diagram, loopModel, 'loop', conf);
bounds.models.loops.push(loopModel);
svgDraw.drawLoop(diagram, loopModel, 'loop', conf, bounds);
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
bounds.models.addLoop(loopModel);
break;
case parser.yy.LINETYPE.RECT_START:
adjustLoopHeightForWrap(loopWidths, msg, conf.boxMargin, conf.boxMargin, message =>
@@ -580,7 +565,7 @@ export const draw = function(text, id) {
case parser.yy.LINETYPE.RECT_END:
loopModel = bounds.endLoop();
svgDraw.drawBackgroundRect(diagram, loopModel);
bounds.models.loops.push(loopModel);
bounds.models.addLoop(loopModel);
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
break;
case parser.yy.LINETYPE.OPT_START:
@@ -595,8 +580,8 @@ export const draw = function(text, id) {
case parser.yy.LINETYPE.OPT_END:
loopModel = bounds.endLoop();
svgDraw.drawLoop(diagram, loopModel, 'opt', conf);
bounds.models.loops.push(loopModel);
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
bounds.models.addLoop(loopModel);
break;
case parser.yy.LINETYPE.ALT_START:
adjustLoopHeightForWrap(
@@ -619,8 +604,8 @@ export const draw = function(text, id) {
case parser.yy.LINETYPE.ALT_END:
loopModel = bounds.endLoop();
svgDraw.drawLoop(diagram, loopModel, 'alt', conf);
bounds.models.loops.push(loopModel);
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
bounds.models.addLoop(loopModel);
break;
case parser.yy.LINETYPE.PAR_START:
adjustLoopHeightForWrap(
@@ -643,19 +628,16 @@ export const draw = function(text, id) {
case parser.yy.LINETYPE.PAR_END:
loopModel = bounds.endLoop();
svgDraw.drawLoop(diagram, loopModel, 'par', conf);
bounds.models.loops.push(loopModel);
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
bounds.models.addLoop(loopModel);
break;
default:
try {
// lastMsg = msg
bounds.bumpVerticalPos(conf.messageMargin);
msgModel = msg.msgModel;
msgModel.starty = bounds.getVerticalPos();
msgModel.sequenceIndex = sequenceIndex;
drawMessage(diagram, msgModel);
bounds.models.messages.push(msgModel);
bounds.insert(msgModel.fromBounds, msgModel.starty, msgModel.toBounds, msgModel.starty);
bounds.models.addMessage(msgModel);
} catch (e) {
logger.error('error while drawing message', e);
}
@@ -681,7 +663,7 @@ export const draw = function(text, id) {
drawActors(diagram, actors, actorKeys, bounds.getVerticalPos());
}
const box = bounds.getBounds();
const { bounds: box } = bounds.getBounds();
// Adjust line height of actor lines now that the height of the diagram is known
logger.debug('For line height fix Querying: #' + id + ' .actor-line');
@@ -724,7 +706,7 @@ export const draw = function(text, id) {
' ' +
(height + extraVertForTitle)
);
logger.debug('bounds', bounds);
logger.debug(`models: ${JSON.stringify(bounds.models, null, 2)}`);
};
/**
@@ -879,13 +861,16 @@ const buildNoteModel = function(msg, actors) {
shouldWrap ? utils.wrapLabel(msg.message, conf.width, conf.noteFont()) : msg.message,
conf.noteFont()
);
logger.debug(`TD:[${textDimensions.width},${textDimensions.height}]`);
let noteModel = {
width: shouldWrap
? conf.width
: Math.max(conf.width, textDimensions.width + 2 * conf.noteMargin),
height: 0,
x: actors[msg.from].x,
y: 0,
startx: actors[msg.from].x,
stopx: 0,
starty: 0,
stopy: 0,
message: msg.message
};
if (msg.placement === parser.yy.PLACEMENT.RIGHTOF) {
@@ -895,7 +880,7 @@ const buildNoteModel = function(msg, actors) {
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;
noteModel.startx = startx + (actors[msg.from].width + conf.actorMargin) / 2;
} else if (msg.placement === parser.yy.PLACEMENT.LEFTOF) {
noteModel.width = shouldWrap
? Math.max(conf.width, textDimensions.width + 2 * conf.noteMargin)
@@ -903,7 +888,7 @@ const buildNoteModel = function(msg, actors) {
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;
noteModel.startx = startx - noteModel.width + (actors[msg.from].width - conf.actorMargin) / 2;
} else if (msg.to === msg.from) {
textDimensions = utils.calculateTextDimensions(
shouldWrap
@@ -914,12 +899,12 @@ const buildNoteModel = function(msg, actors) {
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;
noteModel.startx = 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 =
noteModel.startx =
startx < stopx
? startx + actors[msg.from].width / 2 - conf.actorMargin / 2
: stopx + actors[msg.to].width / 2 - conf.actorMargin / 2;
@@ -951,8 +936,8 @@ const buildMessageModel = function(msg, actors) {
if (!process) {
return {};
}
const fromBounds = actorFlowVerticaBounds(msg.from, actors);
const toBounds = actorFlowVerticaBounds(msg.to, actors);
const fromBounds = activationBounds(msg.from, actors);
const toBounds = activationBounds(msg.to, actors);
const fromIdx = fromBounds[0] <= toBounds[0] ? 1 : 0;
const toIdx = fromBounds[0] < toBounds[0] ? 0 : 1;
const allBounds = fromBounds.concat(toBounds);
@@ -985,7 +970,7 @@ const calculateLoopBounds = function(messages, actors) {
let current, noteModel, msgModel;
messages.forEach(function(msg) {
msg.id = utils.generateId();
msg.id = utils.random({ length: 10 });
switch (msg.type) {
case parser.yy.LINETYPE.LOOP_START:
case parser.yy.LINETYPE.ALT_START:
@@ -1046,8 +1031,8 @@ const calculateLoopBounds = function(messages, actors) {
let depth = 0;
stack.forEach(stk => {
current = stk;
current.from = Math.min(current.from, noteModel.x);
current.to = Math.max(current.to, noteModel.x + noteModel.width);
current.from = Math.min(current.from, noteModel.startx);
current.to = Math.max(current.to, noteModel.startx + noteModel.width);
current.width =
Math.max(current.width, Math.abs(current.from - current.to)) -
50 -

View File

@@ -251,11 +251,11 @@ export const drawActivation = function(elem, bounds, verticalPos, conf, actorAct
/**
* Draws a loop in the diagram
* @param elem - elemenet to append the loop to.
* @param bounds - bounds of the given loop.
* @param loopModel - loopModel of the given loop.
* @param labelText - Text within the loop.
* @param conf
* @param conf - diagrom configuration
*/
export const drawLoop = function(elem, bounds, labelText, conf) {
export const drawLoop = function(elem, loopModel, labelText, conf) {
const g = elem.append('g');
const drawLoopLine = function(startx, starty, stopx, stopy) {
return g
@@ -266,20 +266,23 @@ export const drawLoop = function(elem, bounds, labelText, conf) {
.attr('y2', stopy)
.attr('class', 'loopLine');
};
drawLoopLine(bounds.startx, bounds.starty, bounds.stopx, bounds.starty);
drawLoopLine(bounds.stopx, bounds.starty, bounds.stopx, bounds.stopy);
drawLoopLine(bounds.startx, bounds.stopy, bounds.stopx, bounds.stopy);
drawLoopLine(bounds.startx, bounds.starty, bounds.startx, bounds.stopy);
if (typeof bounds.sections !== 'undefined') {
bounds.sections.forEach(function(item) {
drawLoopLine(bounds.startx, item.y, bounds.stopx, item.y).style('stroke-dasharray', '3, 3');
drawLoopLine(loopModel.startx, loopModel.starty, loopModel.stopx, loopModel.starty);
drawLoopLine(loopModel.stopx, loopModel.starty, loopModel.stopx, loopModel.stopy);
drawLoopLine(loopModel.startx, loopModel.stopy, loopModel.stopx, loopModel.stopy);
drawLoopLine(loopModel.startx, loopModel.starty, loopModel.startx, loopModel.stopy);
if (typeof loopModel.sections !== 'undefined') {
loopModel.sections.forEach(function(item) {
drawLoopLine(loopModel.startx, item.y, loopModel.stopx, item.y).style(
'stroke-dasharray',
'3, 3'
);
});
}
let txt = getTextObj();
txt.text = labelText;
txt.x = bounds.startx;
txt.y = bounds.starty;
txt.x = loopModel.startx;
txt.y = loopModel.starty;
const msgFont = conf.messageFont();
txt.fontFamily = msgFont.fontFamily;
txt.fontSize = msgFont.fontSize;
@@ -294,9 +297,9 @@ export const drawLoop = function(elem, bounds, labelText, conf) {
drawLabel(g, txt);
txt = getTextObj();
txt.text = bounds.title;
txt.x = bounds.startx + conf.labelBoxWidth / 2 + (bounds.stopx - bounds.startx) / 2;
txt.y = bounds.starty + conf.boxMargin + conf.boxTextMargin;
txt.text = loopModel.title;
txt.x = loopModel.startx + conf.labelBoxWidth / 2 + (loopModel.stopx - loopModel.startx) / 2;
txt.y = loopModel.starty + conf.boxMargin + conf.boxTextMargin;
txt.anchor = 'middle';
txt.class = 'loopText';
txt.fontFamily = msgFont.fontFamily;
@@ -306,12 +309,12 @@ export const drawLoop = function(elem, bounds, labelText, conf) {
let textElem = drawText(g, txt);
if (typeof bounds.sectionTitles !== 'undefined') {
bounds.sectionTitles.forEach(function(item, idx) {
if (typeof loopModel.sectionTitles !== 'undefined') {
loopModel.sectionTitles.forEach(function(item, idx) {
if (item.message) {
txt.text = item.message;
txt.x = bounds.startx + (bounds.stopx - bounds.startx) / 2;
txt.y = bounds.sections[idx].y + conf.boxMargin + conf.boxTextMargin;
txt.x = loopModel.startx + (loopModel.stopx - loopModel.startx) / 2;
txt.y = loopModel.sections[idx].y + conf.boxMargin + conf.boxTextMargin;
txt.class = 'loopText';
txt.anchor = 'middle';
txt.valign = 'middle';
@@ -319,20 +322,19 @@ export const drawLoop = function(elem, bounds, labelText, conf) {
txt.fontFamily = msgFont.fontFamily;
txt.fontSize = msgFont.fontSize;
txt.fontWeight = msgFont.fontWeight;
txt.wrap = bounds.wrap;
txt.wrap = loopModel.wrap;
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);
loopModel.sections[idx].height += sectionHeight - (conf.boxMargin + conf.boxTextMargin);
}
});
}
bounds.height = Math.round(bounds.stopy - bounds.starty);
loopModel.height = Math.round(loopModel.stopy - loopModel.starty);
return g;
};