#931 Aligning code standard

This commit is contained in:
knsv
2019-09-12 12:55:10 -07:00
parent f2a6ba80b5
commit ad5669b523
3 changed files with 1212 additions and 1084 deletions

View File

@@ -1,51 +1,53 @@
import { logger } from '../../logger' import { logger } from '../../logger';
let actors = {} let actors = {};
let messages = [] let messages = [];
const notes = [] const notes = [];
let title = '' let title = '';
export const addActor = function (id, name, description) { export const addActor = function(id, name, description) {
// Don't allow description nulling // Don't allow description nulling
const old = actors[id] const old = actors[id];
if (old && name === old.name && description == null) return if (old && name === old.name && description == null) return;
// Don't allow null descriptions, either // Don't allow null descriptions, either
if (description == null) description = name if (description == null) description = name;
actors[id] = { name: name, description: description } actors[id] = { name: name, description: description };
} };
export const addMessage = function (idFrom, idTo, message, answer) { export const addMessage = function(idFrom, idTo, message, answer) {
messages.push({ from: idFrom, to: idTo, message: message, answer: answer }) messages.push({ from: idFrom, to: idTo, message: message, answer: answer });
} };
export const addSignal = function (idFrom, idTo, message, messageType) { export const addSignal = function(idFrom, idTo, message, messageType) {
logger.debug('Adding message from=' + idFrom + ' to=' + idTo + ' message=' + message + ' type=' + messageType) logger.debug(
messages.push({ from: idFrom, to: idTo, message: message, type: messageType }) 'Adding message from=' + idFrom + ' to=' + idTo + ' message=' + message + ' type=' + messageType
} );
messages.push({ from: idFrom, to: idTo, message: message, type: messageType });
};
export const getMessages = function () { export const getMessages = function() {
return messages return messages;
} };
export const getActors = function () { export const getActors = function() {
return actors return actors;
} };
export const getActor = function (id) { export const getActor = function(id) {
return actors[id] return actors[id];
} };
export const getActorKeys = function () { export const getActorKeys = function() {
return Object.keys(actors) return Object.keys(actors);
} };
export const getTitle = function () { export const getTitle = function() {
return title return title;
} };
export const clear = function () { export const clear = function() {
actors = {} actors = {};
messages = [] messages = [];
} };
export const LINETYPE = { export const LINETYPE = {
SOLID: 0, SOLID: 0,
@@ -69,97 +71,103 @@ export const LINETYPE = {
PAR_END: 21, PAR_END: 21,
RECT_START: 22, RECT_START: 22,
RECT_END: 23 RECT_END: 23
} };
export const ARROWTYPE = { export const ARROWTYPE = {
FILLED: 0, FILLED: 0,
OPEN: 1 OPEN: 1
} };
export const PLACEMENT = { export const PLACEMENT = {
LEFTOF: 0, LEFTOF: 0,
RIGHTOF: 1, RIGHTOF: 1,
OVER: 2 OVER: 2
} };
export const addNote = function (actor, placement, message) { export const addNote = function(actor, placement, message) {
const note = { actor: actor, placement: placement, message: message } const note = { actor: actor, placement: placement, message: message };
// Coerce actor into a [to, from, ...] array // Coerce actor into a [to, from, ...] array
const actors = [].concat(actor, actor) const actors = [].concat(actor, actor);
notes.push(note) notes.push(note);
messages.push({ from: actors[0], to: actors[1], message: message, type: LINETYPE.NOTE, placement: placement }) messages.push({
} from: actors[0],
to: actors[1],
message: message,
type: LINETYPE.NOTE,
placement: placement
});
};
export const setTitle = function (titleText) { export const setTitle = function(titleText) {
title = titleText title = titleText;
} };
export const apply = function (param) { export const apply = function(param) {
if (param instanceof Array) { if (param instanceof Array) {
param.forEach(function (item) { param.forEach(function(item) {
apply(item) apply(item);
}) });
} else { } else {
switch (param.type) { switch (param.type) {
case 'addActor': case 'addActor':
addActor(param.actor, param.actor, param.description) addActor(param.actor, param.actor, param.description);
break break;
case 'activeStart': case 'activeStart':
addSignal(param.actor, undefined, undefined, param.signalType) addSignal(param.actor, undefined, undefined, param.signalType);
break break;
case 'activeEnd': case 'activeEnd':
addSignal(param.actor, undefined, undefined, param.signalType) addSignal(param.actor, undefined, undefined, param.signalType);
break break;
case 'addNote': case 'addNote':
addNote(param.actor, param.placement, param.text) addNote(param.actor, param.placement, param.text);
break break;
case 'addMessage': case 'addMessage':
addSignal(param.from, param.to, param.msg, param.signalType) addSignal(param.from, param.to, param.msg, param.signalType);
break break;
case 'loopStart': case 'loopStart':
addSignal(undefined, undefined, param.loopText, param.signalType) addSignal(undefined, undefined, param.loopText, param.signalType);
break break;
case 'loopEnd': case 'loopEnd':
addSignal(undefined, undefined, undefined, param.signalType) addSignal(undefined, undefined, undefined, param.signalType);
break break;
case 'rectStart': case 'rectStart':
addSignal(undefined, undefined, param.color, param.signalType) addSignal(undefined, undefined, param.color, param.signalType);
break break;
case 'rectEnd': case 'rectEnd':
addSignal(undefined, undefined, undefined, param.signalType) addSignal(undefined, undefined, undefined, param.signalType);
break break;
case 'optStart': case 'optStart':
addSignal(undefined, undefined, param.optText, param.signalType) addSignal(undefined, undefined, param.optText, param.signalType);
break break;
case 'optEnd': case 'optEnd':
addSignal(undefined, undefined, undefined, param.signalType) addSignal(undefined, undefined, undefined, param.signalType);
break break;
case 'altStart': case 'altStart':
addSignal(undefined, undefined, param.altText, param.signalType) addSignal(undefined, undefined, param.altText, param.signalType);
break break;
case 'else': case 'else':
addSignal(undefined, undefined, param.altText, param.signalType) addSignal(undefined, undefined, param.altText, param.signalType);
break break;
case 'altEnd': case 'altEnd':
addSignal(undefined, undefined, undefined, param.signalType) addSignal(undefined, undefined, undefined, param.signalType);
break break;
case 'setTitle': case 'setTitle':
setTitle(param.text) setTitle(param.text);
break break;
case 'parStart': case 'parStart':
addSignal(undefined, undefined, param.parText, param.signalType) addSignal(undefined, undefined, param.parText, param.signalType);
break break;
case 'and': case 'and':
addSignal(undefined, undefined, param.parText, param.signalType) addSignal(undefined, undefined, param.parText, param.signalType);
break break;
case 'parEnd': case 'parEnd':
addSignal(undefined, undefined, undefined, param.signalType) addSignal(undefined, undefined, undefined, param.signalType);
break break;
} }
} }
} };
export default { export default {
addActor, addActor,
@@ -177,4 +185,4 @@ export default {
addNote, addNote,
setTitle, setTitle,
apply apply
} };

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,13 @@
import * as d3 from 'd3' import * as d3 from 'd3';
import svgDraw from './svgDraw' import svgDraw from './svgDraw';
import { logger } from '../../logger' import { logger } from '../../logger';
import { parser } from './parser/sequenceDiagram' import { parser } from './parser/sequenceDiagram';
import sequenceDb from './sequenceDb' import sequenceDb from './sequenceDb';
parser.yy = sequenceDb parser.yy = sequenceDb;
const conf = { const conf = {
diagramMarginX: 50, diagramMarginX: 50,
diagramMarginY: 30, diagramMarginY: 30,
// Margin between actors // Margin between actors
@@ -38,7 +37,7 @@ const conf = {
textPlacement: 'tspan', textPlacement: 'tspan',
showSequenceNumbers: false showSequenceNumbers: false
} };
export const bounds = { export const bounds = {
data: { data: {
@@ -51,69 +50,69 @@ export const bounds = {
sequenceItems: [], sequenceItems: [],
activations: [], activations: [],
init: function () { init: function() {
this.sequenceItems = [] this.sequenceItems = [];
this.activations = [] this.activations = [];
this.data = { this.data = {
startx: undefined, startx: undefined,
stopx: undefined, stopx: undefined,
starty: undefined, starty: undefined,
stopy: undefined stopy: undefined
} };
this.verticalPos = 0 this.verticalPos = 0;
}, },
updateVal: function (obj, key, val, fun) { updateVal: function(obj, key, val, fun) {
if (typeof obj[key] === 'undefined') { if (typeof obj[key] === 'undefined') {
obj[key] = val obj[key] = val;
} else { } else {
obj[key] = fun(val, obj[key]) obj[key] = fun(val, obj[key]);
} }
}, },
updateBounds: function (startx, starty, stopx, stopy) { updateBounds: function(startx, starty, stopx, stopy) {
const _self = this const _self = this;
let cnt = 0 let cnt = 0;
function updateFn (type) { function updateFn(type) {
return function updateItemBounds (item) { return function updateItemBounds(item) {
cnt++ cnt++;
// The loop sequenceItems is a stack so the biggest margins in the beginning of the sequenceItems // The loop sequenceItems is a stack so the biggest margins in the beginning of the sequenceItems
const n = _self.sequenceItems.length - cnt + 1 const n = _self.sequenceItems.length - cnt + 1;
_self.updateVal(item, 'starty', starty - n * conf.boxMargin, Math.min) _self.updateVal(item, 'starty', starty - n * conf.boxMargin, Math.min);
_self.updateVal(item, 'stopy', stopy + n * conf.boxMargin, Math.max) _self.updateVal(item, 'stopy', stopy + n * conf.boxMargin, Math.max);
_self.updateVal(bounds.data, 'startx', startx - n * conf.boxMargin, Math.min) _self.updateVal(bounds.data, 'startx', startx - n * conf.boxMargin, Math.min);
_self.updateVal(bounds.data, 'stopx', stopx + n * conf.boxMargin, Math.max) _self.updateVal(bounds.data, 'stopx', stopx + n * conf.boxMargin, Math.max);
if (!(type === 'activation')) { if (!(type === 'activation')) {
_self.updateVal(item, 'startx', startx - n * conf.boxMargin, Math.min) _self.updateVal(item, 'startx', startx - n * conf.boxMargin, Math.min);
_self.updateVal(item, 'stopx', stopx + n * conf.boxMargin, Math.max) _self.updateVal(item, 'stopx', stopx + n * conf.boxMargin, Math.max);
_self.updateVal(bounds.data, 'starty', starty - n * conf.boxMargin, Math.min) _self.updateVal(bounds.data, 'starty', starty - n * conf.boxMargin, Math.min);
_self.updateVal(bounds.data, 'stopy', stopy + n * conf.boxMargin, Math.max) _self.updateVal(bounds.data, 'stopy', stopy + n * conf.boxMargin, Math.max);
} }
} };
} }
this.sequenceItems.forEach(updateFn()) this.sequenceItems.forEach(updateFn());
this.activations.forEach(updateFn('activation')) this.activations.forEach(updateFn('activation'));
}, },
insert: function (startx, starty, stopx, stopy) { insert: function(startx, starty, stopx, stopy) {
const _startx = Math.min(startx, stopx) const _startx = Math.min(startx, stopx);
const _stopx = Math.max(startx, stopx) const _stopx = Math.max(startx, stopx);
const _starty = Math.min(starty, stopy) const _starty = Math.min(starty, stopy);
const _stopy = Math.max(starty, stopy) const _stopy = Math.max(starty, stopy);
this.updateVal(bounds.data, 'startx', _startx, Math.min) this.updateVal(bounds.data, 'startx', _startx, Math.min);
this.updateVal(bounds.data, 'starty', _starty, Math.min) this.updateVal(bounds.data, 'starty', _starty, Math.min);
this.updateVal(bounds.data, 'stopx', _stopx, Math.max) this.updateVal(bounds.data, 'stopx', _stopx, Math.max);
this.updateVal(bounds.data, 'stopy', _stopy, Math.max) this.updateVal(bounds.data, 'stopy', _stopy, Math.max);
this.updateBounds(_startx, _starty, _stopx, _stopy) this.updateBounds(_startx, _starty, _stopx, _stopy);
}, },
newActivation: function (message, diagram) { newActivation: function(message, diagram) {
const actorRect = parser.yy.getActors()[message.from.actor] const actorRect = parser.yy.getActors()[message.from.actor];
const stackedSize = actorActivations(message.from.actor).length const stackedSize = actorActivations(message.from.actor).length;
const x = actorRect.x + conf.width / 2 + (stackedSize - 1) * conf.activationWidth / 2 const x = actorRect.x + conf.width / 2 + ((stackedSize - 1) * conf.activationWidth) / 2;
this.activations.push({ this.activations.push({
startx: x, startx: x,
starty: this.verticalPos + 2, starty: this.verticalPos + 2,
@@ -121,59 +120,68 @@ export const bounds = {
stopy: undefined, stopy: undefined,
actor: message.from.actor, actor: message.from.actor,
anchored: svgDraw.anchorElement(diagram) anchored: svgDraw.anchorElement(diagram)
}) });
}, },
endActivation: function (message) { endActivation: function(message) {
// find most recent activation for given actor // find most recent activation for given actor
const lastActorActivationIdx = this.activations const lastActorActivationIdx = this.activations
.map(function (activation) { return activation.actor }) .map(function(activation) {
.lastIndexOf(message.from.actor) return activation.actor;
const activation = this.activations.splice(lastActorActivationIdx, 1)[0] })
return activation .lastIndexOf(message.from.actor);
const activation = this.activations.splice(lastActorActivationIdx, 1)[0];
return activation;
}, },
newLoop: function (title, fill) { newLoop: function(title, fill) {
this.sequenceItems.push({ startx: undefined, starty: this.verticalPos, stopx: undefined, stopy: undefined, title: title, fill: fill }) this.sequenceItems.push({
startx: undefined,
starty: this.verticalPos,
stopx: undefined,
stopy: undefined,
title: title,
fill: fill
});
}, },
endLoop: function () { endLoop: function() {
const loop = this.sequenceItems.pop() const loop = this.sequenceItems.pop();
return loop return loop;
}, },
addSectionToLoop: function (message) { addSectionToLoop: function(message) {
const loop = this.sequenceItems.pop() const loop = this.sequenceItems.pop();
loop.sections = loop.sections || [] loop.sections = loop.sections || [];
loop.sectionTitles = loop.sectionTitles || [] loop.sectionTitles = loop.sectionTitles || [];
loop.sections.push(bounds.getVerticalPos()) loop.sections.push(bounds.getVerticalPos());
loop.sectionTitles.push(message) loop.sectionTitles.push(message);
this.sequenceItems.push(loop) this.sequenceItems.push(loop);
}, },
bumpVerticalPos: function (bump) { bumpVerticalPos: function(bump) {
this.verticalPos = this.verticalPos + bump this.verticalPos = this.verticalPos + bump;
this.data.stopy = this.verticalPos this.data.stopy = this.verticalPos;
}, },
getVerticalPos: function () { getVerticalPos: function() {
return this.verticalPos return this.verticalPos;
}, },
getBounds: function () { getBounds: function() {
return this.data return this.data;
} }
} };
const _drawLongText = (text, x, y, g, width) => { const _drawLongText = (text, x, y, g, width) => {
let textHeight = 0 let textHeight = 0;
const lines = text.split(/<br\/?>/ig) const lines = text.split(/<br\/?>/gi);
for (const line of lines) { for (const line of lines) {
const textObj = svgDraw.getTextObj() const textObj = svgDraw.getTextObj();
textObj.x = x textObj.x = x;
textObj.y = y + textHeight textObj.y = y + textHeight;
textObj.textMargin = conf.noteMargin textObj.textMargin = conf.noteMargin;
textObj.dy = '1em' textObj.dy = '1em';
textObj.text = line textObj.text = line;
textObj.class = 'noteText' textObj.class = 'noteText';
const textElem = svgDraw.drawText(g, textObj, width) const textElem = svgDraw.drawText(g, textObj, width);
textHeight += (textElem._groups || textElem)[0][0].getBBox().height textHeight += (textElem._groups || textElem)[0][0].getBBox().height;
} }
return textHeight return textHeight;
} };
/** /**
* Draws an actor in the diagram with the attaced line * Draws an actor in the diagram with the attaced line
@@ -181,22 +189,33 @@ const _drawLongText = (text, x, y, g, width) => {
* @param pos The position if the actor in the liost of actors * @param pos The position if the actor in the liost of actors
* @param description The text in the box * @param description The text in the box
*/ */
const drawNote = function (elem, startx, verticalPos, msg, forceWidth) { const drawNote = function(elem, startx, verticalPos, msg, forceWidth) {
const rect = svgDraw.getNoteRect() const rect = svgDraw.getNoteRect();
rect.x = startx rect.x = startx;
rect.y = verticalPos rect.y = verticalPos;
rect.width = forceWidth || conf.width rect.width = forceWidth || conf.width;
rect.class = 'note' rect.class = 'note';
let g = elem.append('g') let g = elem.append('g');
const rectElem = svgDraw.drawRect(g, rect) const rectElem = svgDraw.drawRect(g, rect);
const textHeight = _drawLongText(msg.message, startx - 4, verticalPos + 24, g, rect.width - conf.noteMargin) const textHeight = _drawLongText(
msg.message,
startx - 4,
verticalPos + 24,
g,
rect.width - conf.noteMargin
);
bounds.insert(startx, verticalPos, startx + rect.width, verticalPos + 2 * conf.noteMargin + textHeight) bounds.insert(
rectElem.attr('height', textHeight + 2 * conf.noteMargin) startx,
bounds.bumpVerticalPos(textHeight + 2 * conf.noteMargin) verticalPos,
} startx + rect.width,
verticalPos + 2 * conf.noteMargin + textHeight
);
rectElem.attr('height', textHeight + 2 * conf.noteMargin);
bounds.bumpVerticalPos(textHeight + 2 * conf.noteMargin);
};
/** /**
* Draws a message * Draws a message
@@ -207,70 +226,104 @@ const drawNote = function (elem, startx, verticalPos, msg, forceWidth) {
* @param txtCenter * @param txtCenter
* @param msg * @param msg
*/ */
const drawMessage = function (elem, startx, stopx, verticalPos, msg, sequenceIndex) { const drawMessage = function(elem, startx, stopx, verticalPos, msg, sequenceIndex) {
const g = elem.append('g') const g = elem.append('g');
const txtCenter = startx + (stopx - startx) / 2 const txtCenter = startx + (stopx - startx) / 2;
const textElem = g.append('text') // text label for the x axis const textElem = g
.append('text') // text label for the x axis
.attr('x', txtCenter) .attr('x', txtCenter)
.attr('y', verticalPos - 7) .attr('y', verticalPos - 7)
.style('text-anchor', 'middle') .style('text-anchor', 'middle')
.attr('class', 'messageText') .attr('class', 'messageText')
.text(msg.message) .text(msg.message);
let textWidth = (textElem._groups || textElem)[0][0].getBBox().width let textWidth = (textElem._groups || textElem)[0][0].getBBox().width;
let line let line;
if (startx === stopx) { if (startx === stopx) {
if (conf.rightAngles) { if (conf.rightAngles) {
line = g.append('path').attr('d', `M ${startx},${verticalPos} H ${startx + (conf.width / 2)} V ${verticalPos + 25} H ${startx}`) line = g
.append('path')
.attr(
'd',
`M ${startx},${verticalPos} H ${startx + conf.width / 2} V ${verticalPos +
25} H ${startx}`
);
} else { } else {
line = g.append('path') line = g
.attr('d', 'M ' + startx + ',' + verticalPos + ' C ' + (startx + 60) + ',' + (verticalPos - 10) + ' ' + (startx + 60) + ',' + .append('path')
(verticalPos + 30) + ' ' + startx + ',' + (verticalPos + 20)) .attr(
'd',
'M ' +
startx +
',' +
verticalPos +
' C ' +
(startx + 60) +
',' +
(verticalPos - 10) +
' ' +
(startx + 60) +
',' +
(verticalPos + 30) +
' ' +
startx +
',' +
(verticalPos + 20)
);
} }
bounds.bumpVerticalPos(30) bounds.bumpVerticalPos(30);
const dx = Math.max(textWidth / 2, 100) const dx = Math.max(textWidth / 2, 100);
bounds.insert(startx - dx, bounds.getVerticalPos() - 10, stopx + dx, bounds.getVerticalPos()) bounds.insert(startx - dx, bounds.getVerticalPos() - 10, stopx + dx, bounds.getVerticalPos());
} else { } else {
line = g.append('line') line = g.append('line');
line.attr('x1', startx) line.attr('x1', startx);
line.attr('y1', verticalPos) line.attr('y1', verticalPos);
line.attr('x2', stopx) line.attr('x2', stopx);
line.attr('y2', verticalPos) line.attr('y2', verticalPos);
bounds.insert(startx, bounds.getVerticalPos() - 10, stopx, bounds.getVerticalPos()) bounds.insert(startx, bounds.getVerticalPos() - 10, stopx, bounds.getVerticalPos());
} }
// Make an SVG Container // Make an SVG Container
// Draw the line // Draw the line
if (msg.type === parser.yy.LINETYPE.DOTTED || msg.type === parser.yy.LINETYPE.DOTTED_CROSS || msg.type === parser.yy.LINETYPE.DOTTED_OPEN) { if (
line.style('stroke-dasharray', ('3, 3')) msg.type === parser.yy.LINETYPE.DOTTED ||
line.attr('class', 'messageLine1') msg.type === parser.yy.LINETYPE.DOTTED_CROSS ||
msg.type === parser.yy.LINETYPE.DOTTED_OPEN
) {
line.style('stroke-dasharray', '3, 3');
line.attr('class', 'messageLine1');
} else { } else {
line.attr('class', 'messageLine0') line.attr('class', 'messageLine0');
} }
let url = '' let url = '';
if (conf.arrowMarkerAbsolute) { if (conf.arrowMarkerAbsolute) {
url = window.location.protocol + '//' + window.location.host + window.location.pathname + window.location.search url =
url = url.replace(/\(/g, '\\(') window.location.protocol +
url = url.replace(/\)/g, '\\)') '//' +
window.location.host +
window.location.pathname +
window.location.search;
url = url.replace(/\(/g, '\\(');
url = url.replace(/\)/g, '\\)');
} }
line.attr('stroke-width', 2) line.attr('stroke-width', 2);
line.attr('stroke', 'black') line.attr('stroke', 'black');
line.style('fill', 'none') // remove any fill colour line.style('fill', 'none'); // remove any fill colour
if (msg.type === parser.yy.LINETYPE.SOLID || msg.type === parser.yy.LINETYPE.DOTTED) { if (msg.type === parser.yy.LINETYPE.SOLID || msg.type === parser.yy.LINETYPE.DOTTED) {
line.attr('marker-end', 'url(' + url + '#arrowhead)') line.attr('marker-end', 'url(' + url + '#arrowhead)');
} }
if (msg.type === parser.yy.LINETYPE.SOLID_CROSS || msg.type === parser.yy.LINETYPE.DOTTED_CROSS) { if (msg.type === parser.yy.LINETYPE.SOLID_CROSS || msg.type === parser.yy.LINETYPE.DOTTED_CROSS) {
line.attr('marker-end', 'url(' + url + '#crosshead)') line.attr('marker-end', 'url(' + url + '#crosshead)');
} }
// add node number // add node number
if (conf.showSequenceNumbers) { if (conf.showSequenceNumbers) {
line.attr('marker-start', 'url(' + url + '#sequencenumber)') line.attr('marker-start', 'url(' + url + '#sequencenumber)');
g.append('text') g.append('text')
.attr('x', startx) .attr('x', startx)
.attr('y', verticalPos + 4) .attr('y', verticalPos + 4)
@@ -279,263 +332,306 @@ const drawMessage = function (elem, startx, stopx, verticalPos, msg, sequenceInd
.attr('text-anchor', 'middle') .attr('text-anchor', 'middle')
.attr('textLength', '16px') .attr('textLength', '16px')
.attr('class', 'sequenceNumber') .attr('class', 'sequenceNumber')
.text(sequenceIndex) .text(sequenceIndex);
} }
} };
export const drawActors = function (diagram, actors, actorKeys, verticalPos) { export const drawActors = function(diagram, actors, actorKeys, verticalPos) {
// Draw the actors // Draw the actors
for (let i = 0; i < actorKeys.length; i++) { for (let i = 0; i < actorKeys.length; i++) {
const key = actorKeys[i] const key = actorKeys[i];
// Add some rendering data to the object // Add some rendering data to the object
actors[key].x = i * conf.actorMargin + i * conf.width actors[key].x = i * conf.actorMargin + i * conf.width;
actors[key].y = verticalPos actors[key].y = verticalPos;
actors[key].width = conf.diagramMarginX actors[key].width = conf.diagramMarginX;
actors[key].height = conf.diagramMarginY actors[key].height = conf.diagramMarginY;
// Draw the box with the attached line // Draw the box with the attached line
svgDraw.drawActor(diagram, actors[key].x, verticalPos, actors[key].description, conf) svgDraw.drawActor(diagram, actors[key].x, verticalPos, actors[key].description, conf);
bounds.insert(actors[key].x, verticalPos, actors[key].x + conf.width, conf.height) bounds.insert(actors[key].x, verticalPos, actors[key].x + conf.width, conf.height);
} }
// Add a margin between the actor boxes and the first arrow // Add a margin between the actor boxes and the first arrow
bounds.bumpVerticalPos(conf.height) bounds.bumpVerticalPos(conf.height);
} };
export const setConf = function (cnf) { export const setConf = function(cnf) {
const keys = Object.keys(cnf) const keys = Object.keys(cnf);
keys.forEach(function (key) { keys.forEach(function(key) {
conf[key] = cnf[key] conf[key] = cnf[key];
}) });
} };
const actorActivations = function (actor) { const actorActivations = function(actor) {
return bounds.activations.filter(function (activation) { return bounds.activations.filter(function(activation) {
return activation.actor === actor return activation.actor === actor;
}) });
} };
const actorFlowVerticaBounds = function (actor) { const actorFlowVerticaBounds = function(actor) {
// handle multiple stacked activations for same actor // handle multiple stacked activations for same actor
const actors = parser.yy.getActors() const actors = parser.yy.getActors();
const activations = actorActivations(actor) const activations = actorActivations(actor);
const left = activations.reduce(function (acc, activation) { return Math.min(acc, activation.startx) }, actors[actor].x + conf.width / 2) const left = activations.reduce(function(acc, activation) {
const right = activations.reduce(function (acc, activation) { return Math.max(acc, activation.stopx) }, actors[actor].x + conf.width / 2) return Math.min(acc, activation.startx);
return [left, right] }, actors[actor].x + conf.width / 2);
} const right = activations.reduce(function(acc, activation) {
return Math.max(acc, activation.stopx);
}, actors[actor].x + conf.width / 2);
return [left, right];
};
/** /**
* Draws a flowchart in the tag with id: id based on the graph definition in text. * Draws a flowchart in the tag with id: id based on the graph definition in text.
* @param text * @param text
* @param id * @param id
*/ */
export const draw = function (text, id) { export const draw = function(text, id) {
parser.yy.clear() parser.yy.clear();
parser.parse(text + '\n') parser.parse(text + '\n');
bounds.init() bounds.init();
const diagram = d3.select(`[id="${id}"]`) const diagram = d3.select(`[id="${id}"]`);
let startx let startx;
let stopx let stopx;
let forceWidth let forceWidth;
// Fetch data from the parsing // Fetch data from the parsing
const actors = parser.yy.getActors() const actors = parser.yy.getActors();
const actorKeys = parser.yy.getActorKeys() const actorKeys = parser.yy.getActorKeys();
const messages = parser.yy.getMessages() const messages = parser.yy.getMessages();
const title = parser.yy.getTitle() const title = parser.yy.getTitle();
drawActors(diagram, actors, actorKeys, 0) drawActors(diagram, actors, actorKeys, 0);
// The arrow head definition is attached to the svg once // The arrow head definition is attached to the svg once
svgDraw.insertArrowHead(diagram) svgDraw.insertArrowHead(diagram);
svgDraw.insertArrowCrossHead(diagram) svgDraw.insertArrowCrossHead(diagram);
svgDraw.insertSequenceNumber(diagram) svgDraw.insertSequenceNumber(diagram);
function activeEnd (msg, verticalPos) { function activeEnd(msg, verticalPos) {
const activationData = bounds.endActivation(msg) const activationData = bounds.endActivation(msg);
if (activationData.starty + 18 > verticalPos) { if (activationData.starty + 18 > verticalPos) {
activationData.starty = verticalPos - 6 activationData.starty = verticalPos - 6;
verticalPos += 12 verticalPos += 12;
} }
svgDraw.drawActivation(diagram, activationData, verticalPos, conf, actorActivations(msg.from.actor).length) svgDraw.drawActivation(
diagram,
activationData,
verticalPos,
conf,
actorActivations(msg.from.actor).length
);
bounds.insert(activationData.startx, verticalPos - 10, activationData.stopx, verticalPos) bounds.insert(activationData.startx, verticalPos - 10, activationData.stopx, verticalPos);
} }
// const lastMsg // const lastMsg
// Draw the messages/signals // Draw the messages/signals
let sequenceIndex = 1 let sequenceIndex = 1;
messages.forEach(function (msg) { messages.forEach(function(msg) {
let loopData let loopData;
switch (msg.type) { switch (msg.type) {
case parser.yy.LINETYPE.NOTE: case parser.yy.LINETYPE.NOTE:
bounds.bumpVerticalPos(conf.boxMargin) bounds.bumpVerticalPos(conf.boxMargin);
startx = actors[msg.from].x startx = actors[msg.from].x;
stopx = actors[msg.to].x stopx = actors[msg.to].x;
if (msg.placement === parser.yy.PLACEMENT.RIGHTOF) { if (msg.placement === parser.yy.PLACEMENT.RIGHTOF) {
drawNote(diagram, startx + (conf.width + conf.actorMargin) / 2, bounds.getVerticalPos(), msg) drawNote(
diagram,
startx + (conf.width + conf.actorMargin) / 2,
bounds.getVerticalPos(),
msg
);
} else if (msg.placement === parser.yy.PLACEMENT.LEFTOF) { } else if (msg.placement === parser.yy.PLACEMENT.LEFTOF) {
drawNote(diagram, startx - (conf.width + conf.actorMargin) / 2, bounds.getVerticalPos(), msg) drawNote(
diagram,
startx - (conf.width + conf.actorMargin) / 2,
bounds.getVerticalPos(),
msg
);
} else if (msg.to === msg.from) { } else if (msg.to === msg.from) {
// Single-actor over // Single-actor over
drawNote(diagram, startx, bounds.getVerticalPos(), msg) drawNote(diagram, startx, bounds.getVerticalPos(), msg);
} else { } else {
// Multi-actor over // Multi-actor over
forceWidth = Math.abs(startx - stopx) + conf.actorMargin forceWidth = Math.abs(startx - stopx) + conf.actorMargin;
drawNote(diagram, (startx + stopx + conf.width - forceWidth) / 2, bounds.getVerticalPos(), msg, drawNote(
forceWidth) diagram,
(startx + stopx + conf.width - forceWidth) / 2,
bounds.getVerticalPos(),
msg,
forceWidth
);
} }
break break;
case parser.yy.LINETYPE.ACTIVE_START: case parser.yy.LINETYPE.ACTIVE_START:
bounds.newActivation(msg, diagram) bounds.newActivation(msg, diagram);
break break;
case parser.yy.LINETYPE.ACTIVE_END: case parser.yy.LINETYPE.ACTIVE_END:
activeEnd(msg, bounds.getVerticalPos()) activeEnd(msg, bounds.getVerticalPos());
break break;
case parser.yy.LINETYPE.LOOP_START: case parser.yy.LINETYPE.LOOP_START:
bounds.bumpVerticalPos(conf.boxMargin) bounds.bumpVerticalPos(conf.boxMargin);
bounds.newLoop(msg.message) bounds.newLoop(msg.message);
bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin) bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin);
break break;
case parser.yy.LINETYPE.LOOP_END: case parser.yy.LINETYPE.LOOP_END:
loopData = bounds.endLoop() loopData = bounds.endLoop();
svgDraw.drawLoop(diagram, loopData, 'loop', conf) svgDraw.drawLoop(diagram, loopData, 'loop', conf);
bounds.bumpVerticalPos(conf.boxMargin) bounds.bumpVerticalPos(conf.boxMargin);
break break;
case parser.yy.LINETYPE.RECT_START: case parser.yy.LINETYPE.RECT_START:
bounds.bumpVerticalPos(conf.boxMargin) bounds.bumpVerticalPos(conf.boxMargin);
bounds.newLoop(undefined, msg.message) bounds.newLoop(undefined, msg.message);
bounds.bumpVerticalPos(conf.boxMargin) bounds.bumpVerticalPos(conf.boxMargin);
break break;
case parser.yy.LINETYPE.RECT_END: case parser.yy.LINETYPE.RECT_END:
const rectData = bounds.endLoop() const rectData = bounds.endLoop();
svgDraw.drawBackgroundRect(diagram, rectData) svgDraw.drawBackgroundRect(diagram, rectData);
bounds.bumpVerticalPos(conf.boxMargin) bounds.bumpVerticalPos(conf.boxMargin);
break break;
case parser.yy.LINETYPE.OPT_START: case parser.yy.LINETYPE.OPT_START:
bounds.bumpVerticalPos(conf.boxMargin) bounds.bumpVerticalPos(conf.boxMargin);
bounds.newLoop(msg.message) bounds.newLoop(msg.message);
bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin) bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin);
break break;
case parser.yy.LINETYPE.OPT_END: case parser.yy.LINETYPE.OPT_END:
loopData = bounds.endLoop() loopData = bounds.endLoop();
svgDraw.drawLoop(diagram, loopData, 'opt', conf) svgDraw.drawLoop(diagram, loopData, 'opt', conf);
bounds.bumpVerticalPos(conf.boxMargin) bounds.bumpVerticalPos(conf.boxMargin);
break break;
case parser.yy.LINETYPE.ALT_START: case parser.yy.LINETYPE.ALT_START:
bounds.bumpVerticalPos(conf.boxMargin) bounds.bumpVerticalPos(conf.boxMargin);
bounds.newLoop(msg.message) bounds.newLoop(msg.message);
bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin) bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin);
break break;
case parser.yy.LINETYPE.ALT_ELSE: case parser.yy.LINETYPE.ALT_ELSE:
bounds.bumpVerticalPos(conf.boxMargin) bounds.bumpVerticalPos(conf.boxMargin);
loopData = bounds.addSectionToLoop(msg.message) loopData = bounds.addSectionToLoop(msg.message);
bounds.bumpVerticalPos(conf.boxMargin) bounds.bumpVerticalPos(conf.boxMargin);
break break;
case parser.yy.LINETYPE.ALT_END: case parser.yy.LINETYPE.ALT_END:
loopData = bounds.endLoop() loopData = bounds.endLoop();
svgDraw.drawLoop(diagram, loopData, 'alt', conf) svgDraw.drawLoop(diagram, loopData, 'alt', conf);
bounds.bumpVerticalPos(conf.boxMargin) bounds.bumpVerticalPos(conf.boxMargin);
break break;
case parser.yy.LINETYPE.PAR_START: case parser.yy.LINETYPE.PAR_START:
bounds.bumpVerticalPos(conf.boxMargin) bounds.bumpVerticalPos(conf.boxMargin);
bounds.newLoop(msg.message) bounds.newLoop(msg.message);
bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin) bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin);
break break;
case parser.yy.LINETYPE.PAR_AND: case parser.yy.LINETYPE.PAR_AND:
bounds.bumpVerticalPos(conf.boxMargin) bounds.bumpVerticalPos(conf.boxMargin);
loopData = bounds.addSectionToLoop(msg.message) loopData = bounds.addSectionToLoop(msg.message);
bounds.bumpVerticalPos(conf.boxMargin) bounds.bumpVerticalPos(conf.boxMargin);
break break;
case parser.yy.LINETYPE.PAR_END: case parser.yy.LINETYPE.PAR_END:
loopData = bounds.endLoop() loopData = bounds.endLoop();
svgDraw.drawLoop(diagram, loopData, 'par', conf) svgDraw.drawLoop(diagram, loopData, 'par', conf);
bounds.bumpVerticalPos(conf.boxMargin) bounds.bumpVerticalPos(conf.boxMargin);
break break;
default: default:
try { try {
// lastMsg = msg // lastMsg = msg
bounds.bumpVerticalPos(conf.messageMargin) bounds.bumpVerticalPos(conf.messageMargin);
const fromBounds = actorFlowVerticaBounds(msg.from) const fromBounds = actorFlowVerticaBounds(msg.from);
const toBounds = actorFlowVerticaBounds(msg.to) const toBounds = actorFlowVerticaBounds(msg.to);
const fromIdx = fromBounds[0] <= toBounds[0] ? 1 : 0 const fromIdx = fromBounds[0] <= toBounds[0] ? 1 : 0;
const toIdx = fromBounds[0] < toBounds[0] ? 0 : 1 const toIdx = fromBounds[0] < toBounds[0] ? 0 : 1;
startx = fromBounds[fromIdx] startx = fromBounds[fromIdx];
stopx = toBounds[toIdx] stopx = toBounds[toIdx];
const verticalPos = bounds.getVerticalPos() const verticalPos = bounds.getVerticalPos();
drawMessage(diagram, startx, stopx, verticalPos, msg, sequenceIndex) drawMessage(diagram, startx, stopx, verticalPos, msg, sequenceIndex);
const allBounds = fromBounds.concat(toBounds) const allBounds = fromBounds.concat(toBounds);
bounds.insert(Math.min.apply(null, allBounds), verticalPos, Math.max.apply(null, allBounds), verticalPos) bounds.insert(
Math.min.apply(null, allBounds),
verticalPos,
Math.max.apply(null, allBounds),
verticalPos
);
} catch (e) { } catch (e) {
logger.error('error while drawing message', e) logger.error('error while drawing message', e);
} }
} }
// Increment sequence counter if msg.type is a line (and not another event like activation or note, etc) // Increment sequence counter if msg.type is a line (and not another event like activation or note, etc)
if ([ if (
parser.yy.LINETYPE.SOLID_OPEN, [
parser.yy.LINETYPE.DOTTED_OPEN, parser.yy.LINETYPE.SOLID_OPEN,
parser.yy.LINETYPE.SOLID, parser.yy.LINETYPE.DOTTED_OPEN,
parser.yy.LINETYPE.DOTTED, parser.yy.LINETYPE.SOLID,
parser.yy.LINETYPE.SOLID_CROSS, parser.yy.LINETYPE.DOTTED,
parser.yy.LINETYPE.DOTTED_CROSS parser.yy.LINETYPE.SOLID_CROSS,
].includes(msg.type)) { parser.yy.LINETYPE.DOTTED_CROSS
sequenceIndex++ ].includes(msg.type)
) {
sequenceIndex++;
} }
}) });
if (conf.mirrorActors) { if (conf.mirrorActors) {
// Draw actors below diagram // Draw actors below diagram
bounds.bumpVerticalPos(conf.boxMargin * 2) bounds.bumpVerticalPos(conf.boxMargin * 2);
drawActors(diagram, actors, actorKeys, bounds.getVerticalPos()) drawActors(diagram, actors, actorKeys, bounds.getVerticalPos());
} }
const box = bounds.getBounds() const box = bounds.getBounds();
// Adjust line height of actor lines now that the height of the diagram is known // 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') logger.debug('For line height fix Querying: #' + id + ' .actor-line');
const actorLines = d3.selectAll('#' + id + ' .actor-line') const actorLines = d3.selectAll('#' + id + ' .actor-line');
actorLines.attr('y2', box.stopy) actorLines.attr('y2', box.stopy);
let height = box.stopy - box.starty + 2 * conf.diagramMarginY let height = box.stopy - box.starty + 2 * conf.diagramMarginY;
if (conf.mirrorActors) { if (conf.mirrorActors) {
height = height - conf.boxMargin + conf.bottomMarginAdj height = height - conf.boxMargin + conf.bottomMarginAdj;
} }
const width = (box.stopx - box.startx) + (2 * conf.diagramMarginX) const width = box.stopx - box.startx + 2 * conf.diagramMarginX;
if (title) { if (title) {
diagram.append('text') diagram
.append('text')
.text(title) .text(title)
.attr('x', ((box.stopx - box.startx) / 2) - (2 * conf.diagramMarginX)) .attr('x', (box.stopx - box.startx) / 2 - 2 * conf.diagramMarginX)
.attr('y', -25) .attr('y', -25);
} }
if (conf.useMaxWidth) { if (conf.useMaxWidth) {
diagram.attr('height', '100%') diagram.attr('height', '100%');
diagram.attr('width', '100%') diagram.attr('width', '100%');
diagram.attr('style', 'max-width:' + (width) + 'px;') diagram.attr('style', 'max-width:' + width + 'px;');
} else { } else {
diagram.attr('height', height) diagram.attr('height', height);
diagram.attr('width', width) diagram.attr('width', width);
} }
const extraVertForTitle = title ? 40 : 0 const extraVertForTitle = title ? 40 : 0;
diagram.attr('viewBox', (box.startx - conf.diagramMarginX) + ' -' + (conf.diagramMarginY + extraVertForTitle) + ' ' + width + ' ' + (height + extraVertForTitle)) diagram.attr(
} 'viewBox',
box.startx -
conf.diagramMarginX +
' -' +
(conf.diagramMarginY + extraVertForTitle) +
' ' +
width +
' ' +
(height + extraVertForTitle)
);
};
export default { export default {
bounds, bounds,
drawActors, drawActors,
setConf, setConf,
draw draw
} };