mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-28 07:03:17 +08:00
feat(sequence): actor creation and destruction #1838
This commit is contained in:
parent
9a080bb975
commit
d06bb05c5f
@ -156,6 +156,81 @@ context('Sequence diagram', () => {
|
||||
`
|
||||
);
|
||||
});
|
||||
it('should render a sequence diagram with basic actor creation and destruction', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice ->> Bob: Hello Bob, how are you ?
|
||||
Bob ->> Alice: Fine, thank you. And you?
|
||||
create participant Polo
|
||||
Alice ->> Polo: Hi Polo!
|
||||
create actor Ola1 as Ola
|
||||
Polo ->> Ola1: Hiii
|
||||
Ola1 ->> Alice: Hi too
|
||||
destroy Ola1
|
||||
Alice --x Ola1: Bye!
|
||||
Alice ->> Bob: And now?
|
||||
create participant Ola2 as Ola
|
||||
Alice ->> Ola2: Hello again
|
||||
destroy Alice
|
||||
Alice --x Ola2: Bye for me!
|
||||
destroy Bob
|
||||
Ola2 --> Bob: The end
|
||||
`
|
||||
);
|
||||
});
|
||||
it('should render a sequence diagram with actor creation and destruction coupled with backgrounds, loops and notes', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
accTitle: test the accTitle
|
||||
accDescr: Test a description
|
||||
|
||||
participant Alice
|
||||
participant Bob
|
||||
autonumber 10 10
|
||||
rect rgb(200, 220, 100)
|
||||
rect rgb(200, 255, 200)
|
||||
|
||||
Alice ->> Bob: Hello Bob, how are you?
|
||||
create participant John as John<br />Second Line
|
||||
Bob-->>John: How about you John?
|
||||
end
|
||||
|
||||
Bob--x Alice: I am good thanks!
|
||||
Bob-x John: I am good thanks!
|
||||
Note right of John: John thinks a long<br />long time, so long<br />that the text does<br />not fit on a row.
|
||||
|
||||
Bob-->Alice: Checking with John...
|
||||
Note over John:wrap: John looks like he's still thinking, so Bob prods him a bit.
|
||||
Bob-x John: Hey John - we're still waiting to know<br />how you're doing
|
||||
Note over John:nowrap: John's trying hard not to break his train of thought.
|
||||
destroy John
|
||||
Bob-x John: John! Cmon!
|
||||
Note over John: After a few more moments, John<br />finally snaps out of it.
|
||||
end
|
||||
|
||||
autonumber off
|
||||
alt either this
|
||||
create actor Lola
|
||||
Alice->>+Lola: Yes
|
||||
Lola-->>-Alice: OK
|
||||
else or this
|
||||
autonumber
|
||||
Alice->>Lola: No
|
||||
else or this will happen
|
||||
Alice->Lola: Maybe
|
||||
end
|
||||
autonumber 200
|
||||
par this happens in parallel
|
||||
destroy Bob
|
||||
Alice -->> Bob: Parallel message 1
|
||||
and
|
||||
Alice -->> Lola: Parallel message 2
|
||||
end
|
||||
`
|
||||
);
|
||||
});
|
||||
context('font settings', () => {
|
||||
it('should render different note fonts when configured', () => {
|
||||
imgSnapshotTest(
|
||||
|
@ -38,6 +38,8 @@
|
||||
"box" { this.begin('LINE'); return 'box'; }
|
||||
"participant" { this.begin('ID'); return 'participant'; }
|
||||
"actor" { this.begin('ID'); return 'participant_actor'; }
|
||||
"create" return 'create';
|
||||
"destroy" { this.begin('ID'); return 'destroy'; }
|
||||
<ID>[^\->:\n,;]+?([\-]*[^\->:\n,;]+?)*?(?=((?!\n)\s)+"as"(?!\n)\s|[#\n;]|$) { yytext = yytext.trim(); this.begin('ALIAS'); return 'ACTOR'; }
|
||||
<ALIAS>"as" { this.popState(); this.popState(); this.begin('LINE'); return 'AS'; }
|
||||
<ALIAS>(?:) { this.popState(); this.popState(); return 'NEWLINE'; }
|
||||
@ -138,6 +140,7 @@ directive
|
||||
|
||||
statement
|
||||
: participant_statement
|
||||
| 'create' participant_statement {$2.type='createParticipant'; $$=$2;}
|
||||
| 'box' restOfLine box_section end
|
||||
{
|
||||
$3.unshift({type: 'boxStart', boxData:yy.parseBoxData($2) });
|
||||
@ -234,10 +237,11 @@ else_sections
|
||||
;
|
||||
|
||||
participant_statement
|
||||
: 'participant' actor 'AS' restOfLine 'NEWLINE' {$2.type='addParticipant';$2.description=yy.parseMessage($4); $$=$2;}
|
||||
| 'participant' actor 'NEWLINE' {$2.type='addParticipant';$$=$2;}
|
||||
| 'participant_actor' actor 'AS' restOfLine 'NEWLINE' {$2.type='addActor';$2.description=yy.parseMessage($4); $$=$2;}
|
||||
| 'participant_actor' actor 'NEWLINE' {$2.type='addActor'; $$=$2;}
|
||||
: 'participant' actor 'AS' restOfLine 'NEWLINE' {$2.draw='participant'; $2.type='addParticipant';$2.description=yy.parseMessage($4); $$=$2;}
|
||||
| 'participant' actor 'NEWLINE' {$2.draw='participant'; $2.type='addParticipant';$$=$2;}
|
||||
| 'participant_actor' actor 'AS' restOfLine 'NEWLINE' {$2.draw='actor'; $2.type='addParticipant';$2.description=yy.parseMessage($4); $$=$2;}
|
||||
| 'participant_actor' actor 'NEWLINE' {$2.draw='actor'; $2.type='addParticipant'; $$=$2;}
|
||||
| 'destroy' actor 'NEWLINE' {$2.type='destroyParticipant'; $$=$2;}
|
||||
;
|
||||
|
||||
note_statement
|
||||
|
@ -14,12 +14,16 @@ import {
|
||||
|
||||
let prevActor = undefined;
|
||||
let actors = {};
|
||||
let createdActors = {};
|
||||
let destroyedActors = {};
|
||||
let boxes = [];
|
||||
let messages = [];
|
||||
const notes = [];
|
||||
let sequenceNumbersEnabled = false;
|
||||
let wrapEnabled;
|
||||
let currentBox = undefined;
|
||||
let lastCreated = undefined;
|
||||
let lastDestroyed = undefined;
|
||||
|
||||
export const parseDirective = function (statement, context, type) {
|
||||
mermaidAPI.parseDirective(this, statement, context, type);
|
||||
@ -165,6 +169,12 @@ export const getBoxes = function () {
|
||||
export const getActors = function () {
|
||||
return actors;
|
||||
};
|
||||
export const getCreatedActors = function () {
|
||||
return createdActors;
|
||||
};
|
||||
export const getDestroyedActors = function () {
|
||||
return destroyedActors;
|
||||
};
|
||||
export const getActor = function (id) {
|
||||
return actors[id];
|
||||
};
|
||||
@ -194,6 +204,8 @@ export const autoWrap = () => {
|
||||
|
||||
export const clear = function () {
|
||||
actors = {};
|
||||
createdActors = {};
|
||||
destroyedActors = {};
|
||||
boxes = [];
|
||||
messages = [];
|
||||
sequenceNumbersEnabled = false;
|
||||
@ -459,10 +471,21 @@ export const apply = function (param) {
|
||||
});
|
||||
break;
|
||||
case 'addParticipant':
|
||||
addActor(param.actor, param.actor, param.description, 'participant');
|
||||
addActor(param.actor, param.actor, param.description, param.draw);
|
||||
break;
|
||||
case 'addActor':
|
||||
addActor(param.actor, param.actor, param.description, 'actor');
|
||||
case 'createParticipant':
|
||||
if (actors[param.actor]) {
|
||||
throw new Error(
|
||||
"It is not possible to have actors with the same id, even if one is destroyed before the next is created. Use 'AS' aliases to simulate the behavior"
|
||||
);
|
||||
}
|
||||
lastCreated = param.actor;
|
||||
addActor(param.actor, param.actor, param.description, param.draw);
|
||||
createdActors[param.actor] = messages.length;
|
||||
break;
|
||||
case 'destroyParticipant':
|
||||
lastDestroyed = param.actor;
|
||||
destroyedActors[param.actor] = messages.length;
|
||||
break;
|
||||
case 'activeStart':
|
||||
addSignal(param.actor, undefined, undefined, param.signalType);
|
||||
@ -486,6 +509,27 @@ export const apply = function (param) {
|
||||
addDetails(param.actor, param.text);
|
||||
break;
|
||||
case 'addMessage':
|
||||
if (lastCreated) {
|
||||
if (param.to !== lastCreated) {
|
||||
throw new Error(
|
||||
'The created participant ' +
|
||||
lastCreated +
|
||||
' does not have an associated creating message after its declaration. Please check the sequence diagram.'
|
||||
);
|
||||
} else {
|
||||
lastCreated = undefined;
|
||||
}
|
||||
} else if (lastDestroyed) {
|
||||
if (param.to !== lastDestroyed && param.from !== lastDestroyed) {
|
||||
throw new Error(
|
||||
'The destroyed participant ' +
|
||||
lastDestroyed +
|
||||
' does not have an associated destroying message after its declaration. Please check the sequence diagram.'
|
||||
);
|
||||
} else {
|
||||
lastDestroyed = undefined;
|
||||
}
|
||||
}
|
||||
addSignal(param.from, param.to, param.msg, param.signalType);
|
||||
break;
|
||||
case 'boxStart':
|
||||
@ -566,6 +610,8 @@ export default {
|
||||
showSequenceNumbers,
|
||||
getMessages,
|
||||
getActors,
|
||||
getCreatedActors,
|
||||
getDestroyedActors,
|
||||
getActor,
|
||||
getActorKeys,
|
||||
getActorProperty,
|
||||
|
@ -1404,6 +1404,62 @@ link a: Tests @ https://tests.contoso.com/?svc=alice@contoso.com
|
||||
expect(boxes[0].actorKeys).toEqual(['a', 'b']);
|
||||
expect(boxes[0].fill).toEqual('Aqua');
|
||||
});
|
||||
|
||||
it('should handle simple actor creation', async () => {
|
||||
const str = `
|
||||
sequenceDiagram
|
||||
participant a as Alice
|
||||
a ->>b: Hello Bob?
|
||||
create participant c
|
||||
b-->>c: Hello c!
|
||||
c ->> b: Hello b?
|
||||
create actor d as Donald
|
||||
a ->> d: Hello Donald?
|
||||
`;
|
||||
await mermaidAPI.parse(str);
|
||||
const actors = diagram.db.getActors();
|
||||
const createdActors = diagram.db.getCreatedActors();
|
||||
expect(actors['c'].name).toEqual('c');
|
||||
expect(actors['c'].description).toEqual('c');
|
||||
expect(actors['c'].type).toEqual('participant');
|
||||
expect(createdActors['c']).toEqual(1);
|
||||
expect(actors['d'].name).toEqual('d');
|
||||
expect(actors['d'].description).toEqual('Donald');
|
||||
expect(actors['d'].type).toEqual('actor');
|
||||
expect(createdActors['d']).toEqual(3);
|
||||
});
|
||||
it('should handle simple actor destruction', async () => {
|
||||
const str = `
|
||||
sequenceDiagram
|
||||
participant a as Alice
|
||||
a ->>b: Hello Bob?
|
||||
destroy a
|
||||
b-->>a: Hello Alice!
|
||||
b ->> c: Where is Alice?
|
||||
destroy c
|
||||
b ->> c: Where are you?
|
||||
`;
|
||||
await mermaidAPI.parse(str);
|
||||
const destroyedActors = diagram.db.getDestroyedActors();
|
||||
expect(destroyedActors['a']).toEqual(1);
|
||||
expect(destroyedActors['c']).toEqual(3);
|
||||
});
|
||||
it('should handle the creation and destruction of the same actor', async () => {
|
||||
const str = `
|
||||
sequenceDiagram
|
||||
a ->>b: Hello Bob?
|
||||
create participant c
|
||||
b ->>c: Hello c!
|
||||
c ->> b: Hello b?
|
||||
destroy c
|
||||
b ->> c : Bye c !
|
||||
`;
|
||||
await mermaidAPI.parse(str);
|
||||
const createdActors = diagram.db.getCreatedActors();
|
||||
const destroyedActors = diagram.db.getDestroyedActors();
|
||||
expect(createdActors['c']).toEqual(1);
|
||||
expect(destroyedActors['c']).toEqual(3);
|
||||
});
|
||||
});
|
||||
describe('when checking the bounds in a sequenceDiagram', function () {
|
||||
beforeAll(() => {
|
||||
@ -1973,7 +2029,9 @@ participant Alice`;
|
||||
expect(bounds.startx).toBe(0);
|
||||
expect(bounds.starty).toBe(0);
|
||||
expect(bounds.stopx).toBe(conf.width);
|
||||
expect(bounds.stopy).toBe(models.lastActor().y + models.lastActor().height + conf.boxMargin);
|
||||
expect(bounds.stopy).toBe(
|
||||
models.lastActor().stopy + models.lastActor().height + conf.boxMargin
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -2025,7 +2083,7 @@ participant Alice
|
||||
expect(bounds.startx).toBe(0);
|
||||
expect(bounds.starty).toBe(0);
|
||||
expect(bounds.stopy).toBe(
|
||||
models.lastActor().y + models.lastActor().height + mermaid.sequence.boxMargin
|
||||
models.lastActor().stopy + models.lastActor().height + mermaid.sequence.boxMargin
|
||||
);
|
||||
});
|
||||
it('should handle one actor, when logLevel is 3 (dfg0)', async () => {
|
||||
@ -2045,7 +2103,7 @@ participant Alice
|
||||
expect(bounds.startx).toBe(0);
|
||||
expect(bounds.starty).toBe(0);
|
||||
expect(bounds.stopy).toBe(
|
||||
models.lastActor().y + models.lastActor().height + mermaid.sequence.boxMargin
|
||||
models.lastActor().stopy + models.lastActor().height + mermaid.sequence.boxMargin
|
||||
);
|
||||
});
|
||||
it('should hide sequence numbers when autonumber is removed when autonumber is enabled', async () => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
// @ts-nocheck TODO: fix file
|
||||
import { select, selectAll } from 'd3';
|
||||
import svgDraw, { drawText, fixLifeLineHeights } from './svgDraw.js';
|
||||
import svgDraw, { ACTOR_TYPE_WIDTH, drawText, fixLifeLineHeights } from './svgDraw.js';
|
||||
import { log } from '../../logger.js';
|
||||
import common from '../common/common.js';
|
||||
import * as svgDrawCommon from '../common/svgDrawCommon';
|
||||
@ -478,29 +478,19 @@ const drawMessage = function (diagram, msgModel, lineStartY: number, diagObj: Di
|
||||
}
|
||||
};
|
||||
|
||||
export const drawActors = function (
|
||||
const addActorRenderingData = function (
|
||||
diagram,
|
||||
actors,
|
||||
createdActors,
|
||||
actorKeys,
|
||||
verticalPos,
|
||||
configuration,
|
||||
messages,
|
||||
isFooter
|
||||
) {
|
||||
if (configuration.hideUnusedParticipants === true) {
|
||||
const newActors = new Set();
|
||||
messages.forEach((message) => {
|
||||
newActors.add(message.from);
|
||||
newActors.add(message.to);
|
||||
});
|
||||
actorKeys = actorKeys.filter((actorKey) => newActors.has(actorKey));
|
||||
}
|
||||
|
||||
// Draw the actors
|
||||
let prevWidth = 0;
|
||||
let prevMargin = 0;
|
||||
let maxHeight = 0;
|
||||
let prevBox = undefined;
|
||||
let maxHeight = 0;
|
||||
|
||||
for (const actorKey of actorKeys) {
|
||||
const actor = actors[actorKey];
|
||||
@ -528,12 +518,16 @@ export const drawActors = function (
|
||||
actor.height = common.getMax(actor.height || conf.height, conf.height);
|
||||
actor.margin = actor.margin || conf.actorMargin;
|
||||
|
||||
actor.x = prevWidth + prevMargin;
|
||||
actor.y = bounds.getVerticalPos();
|
||||
maxHeight = common.getMax(maxHeight, actor.height);
|
||||
|
||||
// if the actor is created by a message, widen margin
|
||||
if (createdActors[actor.name]) {
|
||||
prevMargin += actor.width / 2;
|
||||
}
|
||||
|
||||
actor.x = prevWidth + prevMargin;
|
||||
actor.starty = bounds.getVerticalPos();
|
||||
|
||||
// Draw the box with the attached line
|
||||
const height = svgDraw.drawActor(diagram, actor, conf, isFooter);
|
||||
maxHeight = common.getMax(maxHeight, height);
|
||||
bounds.insert(actor.x, verticalPos, actor.x + actor.width, actor.height);
|
||||
|
||||
prevWidth += actor.width + prevMargin;
|
||||
@ -554,6 +548,28 @@ export const drawActors = function (
|
||||
bounds.bumpVerticalPos(maxHeight);
|
||||
};
|
||||
|
||||
export const drawActors = function (diagram, actors, actorKeys, isFooter) {
|
||||
if (!isFooter) {
|
||||
for (const actorKey of actorKeys) {
|
||||
const actor = actors[actorKey];
|
||||
// Draw the box with the attached line
|
||||
svgDraw.drawActor(diagram, actor, conf, false);
|
||||
}
|
||||
} else {
|
||||
let maxHeight = 0;
|
||||
bounds.bumpVerticalPos(conf.boxMargin * 2);
|
||||
for (const actorKey of actorKeys) {
|
||||
const actor = actors[actorKey];
|
||||
if (!actor.stopy) {
|
||||
actor.stopy = bounds.getVerticalPos();
|
||||
}
|
||||
const height = svgDraw.drawActor(diagram, actor, conf, true);
|
||||
maxHeight = common.getMax(maxHeight, height);
|
||||
}
|
||||
bounds.bumpVerticalPos(maxHeight + conf.boxMargin);
|
||||
}
|
||||
};
|
||||
|
||||
export const drawActorsPopup = function (diagram, actors, actorKeys, doc) {
|
||||
let maxHeight = 0;
|
||||
let maxWidth = 0;
|
||||
@ -633,6 +649,95 @@ function adjustLoopHeightForWrap(loopWidths, msg, preMargin, postMargin, addLoop
|
||||
bounds.bumpVerticalPos(heightAdjust);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the msgModel and the actor for the rendering in case the latter is created or destroyed by the msg
|
||||
* @param msg - the potentially creating or destroying message
|
||||
* @param msgModel - the model associated with the message
|
||||
* @param lineStartY - the y position of the message line
|
||||
* @param index - the index of the current actor under consideration
|
||||
* @param actors - the array of all actors
|
||||
* @param createdActors - the array of actors created in the diagram
|
||||
* @param destroyedActors - the array of actors destroyed in the diagram
|
||||
*/
|
||||
function adjustCreatedDestroyedData(
|
||||
msg,
|
||||
msgModel,
|
||||
lineStartY,
|
||||
index,
|
||||
actors,
|
||||
createdActors,
|
||||
destroyedActors
|
||||
) {
|
||||
function receiverAdjustment(actor, adjustment) {
|
||||
if (actor.x < actors[msg.from].x) {
|
||||
bounds.insert(
|
||||
msgModel.stopx - adjustment,
|
||||
msgModel.starty,
|
||||
msgModel.startx,
|
||||
msgModel.stopy + actor.height / 2 + conf.noteMargin
|
||||
);
|
||||
msgModel.stopx = msgModel.stopx + adjustment;
|
||||
} else {
|
||||
bounds.insert(
|
||||
msgModel.startx,
|
||||
msgModel.starty,
|
||||
msgModel.stopx + adjustment,
|
||||
msgModel.stopy + actor.height / 2 + conf.noteMargin
|
||||
);
|
||||
msgModel.stopx = msgModel.stopx - adjustment;
|
||||
}
|
||||
}
|
||||
|
||||
function senderAdjustment(actor, adjustment) {
|
||||
if (actor.x < actors[msg.to].x) {
|
||||
bounds.insert(
|
||||
msgModel.startx - adjustment,
|
||||
msgModel.starty,
|
||||
msgModel.stopx,
|
||||
msgModel.stopy + actor.height / 2 + conf.noteMargin
|
||||
);
|
||||
msgModel.startx = msgModel.startx + adjustment;
|
||||
} else {
|
||||
bounds.insert(
|
||||
msgModel.stopx,
|
||||
msgModel.starty,
|
||||
msgModel.startx + adjustment,
|
||||
msgModel.stopy + actor.height / 2 + conf.noteMargin
|
||||
);
|
||||
msgModel.startx = msgModel.startx - adjustment;
|
||||
}
|
||||
}
|
||||
|
||||
// if it is a create message
|
||||
if (createdActors[msg.to] == index) {
|
||||
const actor = actors[msg.to];
|
||||
const adjustment = actor.type == 'actor' ? ACTOR_TYPE_WIDTH / 2 + 3 : actor.width / 2 + 3;
|
||||
receiverAdjustment(actor, adjustment);
|
||||
actor.starty = lineStartY - actor.height / 2;
|
||||
bounds.bumpVerticalPos(actor.height / 2);
|
||||
}
|
||||
// if it is a destroy sender message
|
||||
else if (destroyedActors[msg.from] == index) {
|
||||
const actor = actors[msg.from];
|
||||
if (conf.mirrorActors) {
|
||||
const adjustment = actor.type == 'actor' ? ACTOR_TYPE_WIDTH / 2 : actor.width / 2;
|
||||
senderAdjustment(actor, adjustment);
|
||||
}
|
||||
actor.stopy = lineStartY - actor.height / 2;
|
||||
bounds.bumpVerticalPos(actor.height / 2);
|
||||
}
|
||||
// if it is a destroy receiver message
|
||||
else if (destroyedActors[msg.to] == index) {
|
||||
const actor = actors[msg.to];
|
||||
if (conf.mirrorActors) {
|
||||
const adjustment = actor.type == 'actor' ? ACTOR_TYPE_WIDTH / 2 + 3 : actor.width / 2 + 3;
|
||||
receiverAdjustment(actor, adjustment);
|
||||
}
|
||||
actor.stopy = lineStartY - actor.height / 2;
|
||||
bounds.bumpVerticalPos(actor.height / 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a sequenceDiagram in the tag with id: id based on the graph definition in text.
|
||||
*
|
||||
@ -666,8 +771,10 @@ export const draw = function (_text: string, id: string, _version: string, diagO
|
||||
|
||||
// Fetch data from the parsing
|
||||
const actors = diagObj.db.getActors();
|
||||
const createdActors = diagObj.db.getCreatedActors();
|
||||
const destroyedActors = diagObj.db.getDestroyedActors();
|
||||
const boxes = diagObj.db.getBoxes();
|
||||
const actorKeys = diagObj.db.getActorKeys();
|
||||
let actorKeys = diagObj.db.getActorKeys();
|
||||
const messages = diagObj.db.getMessages();
|
||||
const title = diagObj.db.getDiagramTitle();
|
||||
const hasBoxes = diagObj.db.hasAtLeastOneBox();
|
||||
@ -686,7 +793,16 @@ export const draw = function (_text: string, id: string, _version: string, diagO
|
||||
}
|
||||
}
|
||||
|
||||
drawActors(diagram, actors, actorKeys, 0, conf, messages, false);
|
||||
if (conf.hideUnusedParticipants === true) {
|
||||
const newActors = new Set();
|
||||
messages.forEach((message) => {
|
||||
newActors.add(message.from);
|
||||
newActors.add(message.to);
|
||||
});
|
||||
actorKeys = actorKeys.filter((actorKey) => newActors.has(actorKey));
|
||||
}
|
||||
|
||||
addActorRenderingData(diagram, actors, createdActors, actorKeys, 0, messages, false);
|
||||
const loopWidths = calculateLoopBounds(messages, actors, maxMessageWidthPerActor, diagObj);
|
||||
|
||||
// The arrow head definition is attached to the svg once
|
||||
@ -720,7 +836,8 @@ export const draw = function (_text: string, id: string, _version: string, diagO
|
||||
let sequenceIndex = 1;
|
||||
let sequenceIndexStep = 1;
|
||||
const messagesToDraw = [];
|
||||
messages.forEach(function (msg) {
|
||||
const backgrounds = [];
|
||||
messages.forEach(function (msg, index) {
|
||||
let loopModel, noteModel, msgModel;
|
||||
|
||||
switch (msg.type) {
|
||||
@ -757,7 +874,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
|
||||
break;
|
||||
case diagObj.db.LINETYPE.RECT_END:
|
||||
loopModel = bounds.endLoop();
|
||||
svgDraw.drawBackgroundRect(diagram, loopModel);
|
||||
backgrounds.push(loopModel);
|
||||
bounds.models.addLoop(loopModel);
|
||||
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
|
||||
break;
|
||||
@ -876,13 +993,20 @@ export const draw = function (_text: string, id: string, _version: string, diagO
|
||||
break;
|
||||
default:
|
||||
try {
|
||||
// lastMsg = msg
|
||||
bounds.resetVerticalPos();
|
||||
msgModel = msg.msgModel;
|
||||
msgModel.starty = bounds.getVerticalPos();
|
||||
msgModel.sequenceIndex = sequenceIndex;
|
||||
msgModel.sequenceVisible = diagObj.db.showSequenceNumbers();
|
||||
const lineStartY = boundMessage(diagram, msgModel);
|
||||
adjustCreatedDestroyedData(
|
||||
msg,
|
||||
msgModel,
|
||||
lineStartY,
|
||||
index,
|
||||
actors,
|
||||
createdActors,
|
||||
destroyedActors
|
||||
);
|
||||
messagesToDraw.push({ messageModel: msgModel, lineStartY: lineStartY });
|
||||
bounds.models.addMessage(msgModel);
|
||||
} catch (e) {
|
||||
@ -907,15 +1031,16 @@ export const draw = function (_text: string, id: string, _version: string, diagO
|
||||
}
|
||||
});
|
||||
|
||||
messagesToDraw.forEach((e) => drawMessage(diagram, e.messageModel, e.lineStartY, diagObj));
|
||||
log.debug('createdActors', createdActors);
|
||||
log.debug('destroyedActors', destroyedActors);
|
||||
|
||||
drawActors(diagram, actors, actorKeys, false);
|
||||
messagesToDraw.forEach((e) => drawMessage(diagram, e.messageModel, e.lineStartY, diagObj));
|
||||
if (conf.mirrorActors) {
|
||||
// Draw actors below diagram
|
||||
bounds.bumpVerticalPos(conf.boxMargin * 2);
|
||||
drawActors(diagram, actors, actorKeys, bounds.getVerticalPos(), conf, messages, true);
|
||||
bounds.bumpVerticalPos(conf.boxMargin);
|
||||
fixLifeLineHeights(diagram, bounds.getVerticalPos());
|
||||
drawActors(diagram, actors, actorKeys, true);
|
||||
}
|
||||
backgrounds.forEach((e) => svgDraw.drawBackgroundRect(diagram, e));
|
||||
fixLifeLineHeights(diagram, actors, actorKeys, conf);
|
||||
|
||||
bounds.models.boxes.forEach(function (box) {
|
||||
box.height = bounds.getVerticalPos() - box.y;
|
||||
@ -937,11 +1062,6 @@ export const draw = function (_text: string, id: string, _version: string, diagO
|
||||
|
||||
const { bounds: box } = bounds.getBounds();
|
||||
|
||||
// Adjust line height of actor lines now that the height of the diagram is known
|
||||
log.debug('For line height fix Querying: #' + id + ' .actor-line');
|
||||
const actorLines = selectAll('#' + id + ' .actor-line');
|
||||
actorLines.attr('y2', box.stopy);
|
||||
|
||||
// Make sure the height of the diagram supports long menus.
|
||||
let boxHeight = box.stopy - box.starty;
|
||||
if (boxHeight < requiredBoxSize.maxHeight) {
|
||||
|
@ -4,6 +4,8 @@ import { addFunction } from '../../interactionDb.js';
|
||||
import { ZERO_WIDTH_SPACE, parseFontSize } from '../../utils.js';
|
||||
import { sanitizeUrl } from '@braintree/sanitize-url';
|
||||
|
||||
export const ACTOR_TYPE_WIDTH = 18 * 2;
|
||||
|
||||
export const drawRect = function (elem, rectData) {
|
||||
return svgDrawCommon.drawRect(elem, rectData);
|
||||
};
|
||||
@ -294,14 +296,19 @@ export const drawLabel = function (elem, txtObject) {
|
||||
|
||||
let actorCnt = -1;
|
||||
|
||||
export const fixLifeLineHeights = (diagram, bounds) => {
|
||||
if (!diagram.selectAll) {
|
||||
export const fixLifeLineHeights = (diagram, actors, actorKeys, conf) => {
|
||||
if (!diagram.select) {
|
||||
return;
|
||||
}
|
||||
diagram
|
||||
.selectAll('.actor-line')
|
||||
.attr('class', '200')
|
||||
.attr('y2', bounds - 55);
|
||||
actorKeys.forEach((actorKey) => {
|
||||
const actor = actors[actorKey];
|
||||
const actorDOM = diagram.select('#actor' + actor.actorCnt);
|
||||
if (!conf.mirrorActors && actor.stopy) {
|
||||
actorDOM.attr('y2', actor.stopy + actor.height / 2);
|
||||
} else if (conf.mirrorActors) {
|
||||
actorDOM.attr('y2', actor.stopy);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -313,10 +320,11 @@ export const fixLifeLineHeights = (diagram, bounds) => {
|
||||
* @param {boolean} isFooter - If the actor is the footer one
|
||||
*/
|
||||
const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
|
||||
const actorY = isFooter ? actor.stopy : actor.starty;
|
||||
const center = actor.x + actor.width / 2;
|
||||
const centerY = actor.y + 5;
|
||||
const centerY = actorY + 5;
|
||||
|
||||
const boxpluslineGroup = elem.append('g');
|
||||
const boxpluslineGroup = elem.append('g').lower();
|
||||
var g = boxpluslineGroup;
|
||||
|
||||
if (!isFooter) {
|
||||
@ -328,6 +336,7 @@ const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
|
||||
.attr('x2', center)
|
||||
.attr('y2', 2000)
|
||||
.attr('class', 'actor-line')
|
||||
.attr('class', '200')
|
||||
.attr('stroke-width', '0.5px')
|
||||
.attr('stroke', '#999');
|
||||
|
||||
@ -348,7 +357,7 @@ const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
|
||||
rect.fill = '#eaeaea';
|
||||
}
|
||||
rect.x = actor.x;
|
||||
rect.y = actor.y;
|
||||
rect.y = actorY;
|
||||
rect.width = actor.width;
|
||||
rect.height = actor.height;
|
||||
rect.class = cssclass;
|
||||
@ -388,8 +397,11 @@ const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
|
||||
};
|
||||
|
||||
const drawActorTypeActor = function (elem, actor, conf, isFooter) {
|
||||
const actorY = isFooter ? actor.stopy : actor.starty;
|
||||
const center = actor.x + actor.width / 2;
|
||||
const centerY = actor.y + 80;
|
||||
const centerY = actorY + 80;
|
||||
|
||||
elem.lower();
|
||||
|
||||
if (!isFooter) {
|
||||
actorCnt++;
|
||||
@ -401,15 +413,18 @@ const drawActorTypeActor = function (elem, actor, conf, isFooter) {
|
||||
.attr('x2', center)
|
||||
.attr('y2', 2000)
|
||||
.attr('class', 'actor-line')
|
||||
.attr('class', '200')
|
||||
.attr('stroke-width', '0.5px')
|
||||
.attr('stroke', '#999');
|
||||
|
||||
actor.actorCnt = actorCnt;
|
||||
}
|
||||
const actElem = elem.append('g');
|
||||
actElem.attr('class', 'actor-man');
|
||||
|
||||
const rect = svgDrawCommon.getNoteRect();
|
||||
rect.x = actor.x;
|
||||
rect.y = actor.y;
|
||||
rect.y = actorY;
|
||||
rect.fill = '#eaeaea';
|
||||
rect.width = actor.width;
|
||||
rect.height = actor.height;
|
||||
@ -421,33 +436,33 @@ const drawActorTypeActor = function (elem, actor, conf, isFooter) {
|
||||
.append('line')
|
||||
.attr('id', 'actor-man-torso' + actorCnt)
|
||||
.attr('x1', center)
|
||||
.attr('y1', actor.y + 25)
|
||||
.attr('y1', actorY + 25)
|
||||
.attr('x2', center)
|
||||
.attr('y2', actor.y + 45);
|
||||
.attr('y2', actorY + 45);
|
||||
|
||||
actElem
|
||||
.append('line')
|
||||
.attr('id', 'actor-man-arms' + actorCnt)
|
||||
.attr('x1', center - 18)
|
||||
.attr('y1', actor.y + 33)
|
||||
.attr('x2', center + 18)
|
||||
.attr('y2', actor.y + 33);
|
||||
.attr('x1', center - ACTOR_TYPE_WIDTH / 2)
|
||||
.attr('y1', actorY + 33)
|
||||
.attr('x2', center + ACTOR_TYPE_WIDTH / 2)
|
||||
.attr('y2', actorY + 33);
|
||||
actElem
|
||||
.append('line')
|
||||
.attr('x1', center - 18)
|
||||
.attr('y1', actor.y + 60)
|
||||
.attr('x1', center - ACTOR_TYPE_WIDTH / 2)
|
||||
.attr('y1', actorY + 60)
|
||||
.attr('x2', center)
|
||||
.attr('y2', actor.y + 45);
|
||||
.attr('y2', actorY + 45);
|
||||
actElem
|
||||
.append('line')
|
||||
.attr('x1', center)
|
||||
.attr('y1', actor.y + 45)
|
||||
.attr('x2', center + 16)
|
||||
.attr('y2', actor.y + 60);
|
||||
.attr('y1', actorY + 45)
|
||||
.attr('x2', center + ACTOR_TYPE_WIDTH / 2 - 2)
|
||||
.attr('y2', actorY + 60);
|
||||
|
||||
const circle = actElem.append('circle');
|
||||
circle.attr('cx', actor.x + actor.width / 2);
|
||||
circle.attr('cy', actor.y + 10);
|
||||
circle.attr('cy', actorY + 10);
|
||||
circle.attr('r', 15);
|
||||
circle.attr('width', actor.width);
|
||||
circle.attr('height', actor.height);
|
||||
|
Loading…
x
Reference in New Issue
Block a user