diff --git a/packages/mermaid/src/diagrams/sequence/parser/sequenceDiagram.jison b/packages/mermaid/src/diagrams/sequence/parser/sequenceDiagram.jison index 2685a5d50..696b39563 100644 --- a/packages/mermaid/src/diagrams/sequence/parser/sequenceDiagram.jison +++ b/packages/mermaid/src/diagrams/sequence/parser/sequenceDiagram.jison @@ -73,7 +73,7 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili "off" return 'off'; "," return ','; ";" return 'NEWLINE'; -[^\/\\\+\<->\->:\n,;]+((?!(\-x|\-\-x|\-\)|\-\-\)|\-\|\\|\-\\|\-\/|\-\/\/|\-\|\/|\/\|\-|\\\|\-|\/\/\-|\\\\\-|\/\|\-|\-\-\|\\|\-\-))[\-]*[^\+\<->\->:\n,;]+)* { yytext = yytext.trim(); return 'ACTOR'; } //final_4.11 +[^\/\\\+\()\<->\->:\n,;]+((?!(\-x|\-\-x|\-\)|\-\-\)|\-\|\\|\-\\|\-\/|\-\/\/|\-\|\/|\/\|\-|\\\|\-|\/\/\-|\\\\\-|\/\|\-|\-\-\|\\|\-\-|\(\)))[\-]*[^\+\<->\->:\n,;]+)* { yytext = yytext.trim(); return 'ACTOR'; } //final_4.11 "->>" return 'SOLID_ARROW'; "<<->>" return 'BIDIRECTIONAL_SOLID_ARROW'; "-->>" return 'DOTTED_ARROW'; @@ -113,6 +113,7 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili ":" return 'TXT'; "+" return '+'; "-" return '-'; +"()" return '()'; <> return 'NEWLINE'; . return 'INVALID'; @@ -322,6 +323,20 @@ signal { $$ = [$1,$4,{type: 'addMessage', from:$1.actor, to:$4.actor, signalType:$2, msg:$5}, {type: 'activeEnd', signalType: yy.LINETYPE.ACTIVE_END, actor: $1.actor} ]} + | actor signaltype '()' actor text2 + { $$ = [$1,$4,{type: 'addMessage', from:$1.actor, to:$4.actor, signalType:$2, msg:$5, activate: true, centralConnection: yy.LINETYPE.CENTRAL_CONNECTION}, + {type: 'centralConnection', signalType: yy.LINETYPE.CENTRAL_CONNECTION, actor: $4.actor, } + ]} + + | actor '()' signaltype actor text2 + { $$ = [$1,$4,{type: 'addMessage', from:$1.actor, to:$4.actor, signalType:$3, msg:$5, activate: false, centralConnection: yy.LINETYPE.CENTRAL_CONNECTION_REVERSE}, + {type: 'centralConnectionReverse', signalType: yy.LINETYPE.CENTRAL_CONNECTION_REVERSE, actor: $1.actor} + ]} + | actor '()' signaltype '()' actor text2 + { $$ = [$1,$5,{type: 'addMessage', from:$1.actor, to:$5.actor, signalType:$3, msg:$6, activate: true, centralConnection: yy.LINETYPE.CENTRAL_CONNECTION_DUAL}, + {type: 'centralConnection', signalType: yy.LINETYPE.CENTRAL_CONNECTION, actor: $5.actor, }, + {type: 'centralConnectionReverse', signalType: yy.LINETYPE.CENTRAL_CONNECTION_REVERSE, actor: $1.actor} + ]} | actor signaltype actor text2 { $$ = [$1,$3,{type: 'addMessage', from:$1.actor, to:$3.actor, signalType:$2, msg:$4}]} ; diff --git a/packages/mermaid/src/diagrams/sequence/sequenceDb.ts b/packages/mermaid/src/diagrams/sequence/sequenceDb.ts index ff1dea393..671f3038e 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceDb.ts +++ b/packages/mermaid/src/diagrams/sequence/sequenceDb.ts @@ -82,6 +82,10 @@ const LINETYPE = { SOLID_ARROW_BOTTOM_REVERSE_DOTTED: 56, STICK_ARROW_TOP_REVERSE_DOTTED: 57, STICK_ARROW_BOTTOM_REVERSE_DOTTED: 58, + + CENTRAL_CONNECTION: 59, + CENTRAL_CONNECTION_REVERSE: 60, + CENTRAL_CONNECTION_DUAL: 61, } as const; const ARROWTYPE = { @@ -238,7 +242,8 @@ export class SequenceDB implements DiagramDB { idTo?: Message['to'], message?: { text: string; wrap: boolean }, messageType?: number, - activate = false + activate = false, + centralConnection?: number ) { if (messageType === this.LINETYPE.ACTIVE_END) { const cnt = this.activationCount(idFrom ?? ''); @@ -265,6 +270,7 @@ export class SequenceDB implements DiagramDB { wrap: message?.wrap ?? this.autoWrap(), type: messageType, activate, + centralConnection, }); return true; } @@ -557,6 +563,12 @@ export class SequenceDB implements DiagramDB { case 'activeStart': this.addSignal(param.actor, undefined, undefined, param.signalType); break; + case 'centralConnection': + this.addSignal(param.actor, undefined, undefined, param.signalType); + break; + case 'centralConnectionReverse': + this.addSignal(param.actor, undefined, undefined, param.signalType); + break; case 'activeEnd': this.addSignal(param.actor, undefined, undefined, param.signalType); break; @@ -600,7 +612,14 @@ export class SequenceDB implements DiagramDB { this.state.records.lastDestroyed = undefined; } } - this.addSignal(param.from, param.to, param.msg, param.signalType, param.activate); + this.addSignal( + param.from, + param.to, + param.msg, + param.signalType, + param.activate, + param.centralConnection + ); break; case 'boxStart': this.addBox(param.boxData); diff --git a/packages/mermaid/src/diagrams/sequence/sequenceRenderer.ts b/packages/mermaid/src/diagrams/sequence/sequenceRenderer.ts index d902cac97..9c73b9f2a 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceRenderer.ts +++ b/packages/mermaid/src/diagrams/sequence/sequenceRenderer.ts @@ -281,6 +281,36 @@ const drawNote = async function (elem: any, noteModel: NoteModel) { bounds.models.addNote(noteModel); }; +const drawCentralConnection = function ( + elem: any, + msg: any, + msgModel: any, + diagObj: Diagram, + startx, + stopx, + lineStartY +) { + const g = elem.append('g'); + const circle = g.append('circle'); + circle.attr( + 'cx', + msg.centralConnection === diagObj.db.LINETYPE.CENTRAL_CONNECTION ? stopx + 7.5 : startx - 5 + ); + // circle.attr('cx',x); + circle.attr('cy', lineStartY); + circle.attr('r', 5); + circle.attr('width', 10); + circle.attr('height', 10); + if (msg.centralConnection === diagObj.db.LINETYPE.CENTRAL_CONNECTION_DUAL) { + const circle = g.append('circle'); + circle.attr('cx', stopx + 7.5); + circle.attr('cy', lineStartY); + circle.attr('r', 5); + circle.attr('width', 10); + circle.attr('height', 10); + } +}; + const messageFont = (cnf) => { return { fontFamily: cnf.messageFontFamily, @@ -366,7 +396,7 @@ async function boundMessage(_diagram, msgModel): Promise { * @param lineStartY - The Y coordinate at which the message line starts * @param diagObj - The diagram object. */ -const drawMessage = async function (diagram, msgModel, lineStartY: number, diagObj: Diagram) { +const drawMessage = async function (diagram, msgModel, lineStartY: number, diagObj: Diagram, msg) { const { startx, stopx, starty, message, type, sequenceIndex, sequenceVisible } = msgModel; const textDims = utils.calculateTextDimensions(message, messageFont(conf)); const textObj = svgDrawCommon.getTextObj(); @@ -432,6 +462,9 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO line.attr('y1', lineStartY); line.attr('x2', stopx); line.attr('y2', lineStartY); + if (msg.centralConnection) { + drawCentralConnection(diagram, msg, msgModel, diagObj, startx, stopx, lineStartY); + } } // Make an SVG Container // Draw the line @@ -921,6 +954,12 @@ export const draw = async function (_text: string, id: string, _version: string, case diagObj.db.LINETYPE.ACTIVE_START: bounds.newActivation(msg, diagram, actors); break; + case diagObj.db.LINETYPE.CENTRAL_CONNECTION: + bounds.newActivation(msg, diagram, actors); + break; + case diagObj.db.LINETYPE.CENTRAL_CONNECTION_REVERSE: + bounds.newActivation(msg, diagram, actors); + break; case diagObj.db.LINETYPE.ACTIVE_END: activeEnd(msg, bounds.getVerticalPos()); break; @@ -1079,7 +1118,7 @@ export const draw = async function (_text: string, id: string, _version: string, createdActors, destroyedActors ); - messagesToDraw.push({ messageModel: msgModel, lineStartY: lineStartY }); + messagesToDraw.push({ messageModel: msgModel, lineStartY: lineStartY, msg }); bounds.models.addMessage(msgModel); } catch (e) { log.error('error while drawing message', e); @@ -1132,7 +1171,7 @@ export const draw = async function (_text: string, id: string, _version: string, await drawActors(diagram, actors, actorKeys, false); for (const e of messagesToDraw) { - await drawMessage(diagram, e.messageModel, e.lineStartY, diagObj); + await drawMessage(diagram, e.messageModel, e.lineStartY, diagObj, e.msg); } if (conf.mirrorActors) { await drawActors(diagram, actors, actorKeys, true); @@ -1546,6 +1585,12 @@ const buildMessageModel = function (msg, actors, diagObj) { let startx = isArrowToRight ? fromRight : fromLeft; let stopx = isArrowToRight ? toLeft : toRight; + if ( + msg.centralConnection === diagObj.db.LINETYPE.CENTRAL_CONNECTION_REVERSE || + msg.centralConnection === diagObj.db.LINETYPE.CENTRAL_CONNECTION_DUAL + ) { + startx += 4; + } // As the line width is considered, the left and right values will be off by 2. const isArrowToActivation = Math.abs(toLeft - toRight) > 2; diff --git a/packages/mermaid/src/diagrams/sequence/types.ts b/packages/mermaid/src/diagrams/sequence/types.ts index 7cf2ead9c..c25463ac6 100644 --- a/packages/mermaid/src/diagrams/sequence/types.ts +++ b/packages/mermaid/src/diagrams/sequence/types.ts @@ -35,6 +35,7 @@ export interface Message { type?: number; activate?: boolean; placement?: string; + centralConnection?: number; } export interface AddMessageParams { @@ -50,6 +51,8 @@ export interface AddMessageParams { | 'destroyParticipant' | 'activeStart' | 'activeEnd' + | 'centralConnection' + | 'centralConnectionReverse' | 'addNote' | 'addLinks' | 'addALink'