403 lines
10 KiB
JavaScript
Raw Normal View History

2019-09-12 12:54:59 -07:00
export const drawRect = function(elem, rectData) {
const rectElem = elem.append('rect');
rectElem.attr('x', rectData.x);
rectElem.attr('y', rectData.y);
rectElem.attr('fill', rectData.fill);
rectElem.attr('stroke', rectData.stroke);
rectElem.attr('width', rectData.width);
rectElem.attr('height', rectData.height);
rectElem.attr('rx', rectData.rx);
rectElem.attr('ry', rectData.ry);
2017-04-11 22:14:25 +08:00
if (typeof rectData.class !== 'undefined') {
2019-09-12 12:54:59 -07:00
rectElem.attr('class', rectData.class);
2017-04-11 22:14:25 +08:00
}
2019-09-12 12:54:59 -07:00
return rectElem;
};
2017-04-11 22:14:25 +08:00
2019-09-12 12:54:59 -07:00
export const drawText = function(elem, textData, width) {
2017-04-16 23:48:36 +08:00
// Remove and ignore br:s
2019-09-12 12:54:59 -07:00
const nText = textData.text.replace(/<br\/?>/gi, ' ');
2017-04-11 22:14:25 +08:00
2019-09-12 12:54:59 -07:00
const textElem = elem.append('text');
textElem.attr('x', textData.x);
textElem.attr('y', textData.y);
textElem.style('text-anchor', textData.anchor);
textElem.attr('fill', textData.fill);
2017-04-11 22:14:25 +08:00
if (typeof textData.class !== 'undefined') {
2019-09-12 12:54:59 -07:00
textElem.attr('class', textData.class);
2017-04-11 22:14:25 +08:00
}
2019-09-12 12:54:59 -07:00
const span = textElem.append('tspan');
span.attr('x', textData.x + textData.textMargin * 2);
span.attr('fill', textData.fill);
span.text(nText);
return textElem;
};
export const drawLabel = function(elem, txtObject) {
function genPoints(x, y, width, height, cut) {
return (
x +
',' +
y +
' ' +
(x + width) +
',' +
y +
' ' +
(x + width) +
',' +
(y + height - cut) +
' ' +
(x + width - cut * 1.2) +
',' +
(y + height) +
' ' +
x +
',' +
(y + height)
);
2017-04-11 22:14:25 +08:00
}
2019-09-12 12:54:59 -07:00
const polygon = elem.append('polygon');
polygon.attr('points', genPoints(txtObject.x, txtObject.y, 50, 20, 7));
polygon.attr('class', 'labelBox');
2017-04-11 22:14:25 +08:00
2019-09-12 12:54:59 -07:00
txtObject.y = txtObject.y + txtObject.labelMargin;
txtObject.x = txtObject.x + 0.5 * txtObject.labelMargin;
drawText(elem, txtObject);
};
2018-03-08 21:33:23 +08:00
2019-09-12 12:54:59 -07:00
let actorCnt = -1;
2015-01-05 13:41:32 +01:00
/**
* Draws an actor in the diagram with the attaced line
* @param center - The center of the the actor
* @param pos The position if the actor in the liost of actors
* @param description The text in the box
*/
2019-09-12 12:54:59 -07:00
export const drawActor = function(elem, left, verticalPos, description, conf) {
const center = left + conf.width / 2;
const g = elem.append('g');
2017-04-11 22:14:25 +08:00
if (verticalPos === 0) {
2019-09-12 12:54:59 -07:00
actorCnt++;
2017-04-11 22:14:25 +08:00
g.append('line')
2017-04-16 23:48:36 +08:00
.attr('id', 'actor' + actorCnt)
.attr('x1', center)
.attr('y1', 5)
.attr('x2', center)
.attr('y2', 2000)
.attr('class', 'actor-line')
.attr('stroke-width', '0.5px')
2019-09-12 12:54:59 -07:00
.attr('stroke', '#999');
2017-04-11 22:14:25 +08:00
}
2019-09-12 12:54:59 -07:00
const rect = getNoteRect();
rect.x = left;
rect.y = verticalPos;
rect.fill = '#eaeaea';
rect.width = conf.width;
rect.height = conf.height;
rect.class = 'actor';
rect.rx = 3;
rect.ry = 3;
drawRect(g, rect);
_drawTextCandidateFunc(conf)(
description,
g,
rect.x,
rect.y,
rect.width,
rect.height,
{ class: 'actor' },
conf
);
};
export const anchorElement = function(elem) {
return elem.append('g');
};
2016-03-08 10:40:52 +01:00
/**
* Draws an actor in the diagram with the attaced line
2016-03-11 16:44:45 +01:00
* @param elem - element to append activation rect
* @param bounds - activation box bounds
* @param verticalPos - precise y cooridnate of bottom activation box edge
2016-03-08 10:40:52 +01:00
*/
2019-09-12 12:54:59 -07:00
export const drawActivation = function(elem, bounds, verticalPos, conf, actorActivations) {
const rect = getNoteRect();
const g = bounds.anchored;
rect.x = bounds.startx;
rect.y = bounds.starty;
rect.class = 'activation' + (actorActivations % 3); // Will evaluate to 0, 1 or 2
rect.width = bounds.stopx - bounds.startx;
rect.height = verticalPos - bounds.starty;
drawRect(g, rect);
};
2016-03-08 10:40:52 +01:00
2015-01-05 14:41:00 +01:00
/**
* Draws an actor in the diagram with the attaced line
* @param center - The center of the the actor
* @param pos The position if the actor in the list of actors
* @param description The text in the box
*/
2019-09-12 12:54:59 -07:00
export const drawLoop = function(elem, bounds, labelText, conf) {
const g = elem.append('g');
const drawLoopLine = function(startx, starty, stopx, stopy) {
return g
.append('line')
2017-04-16 23:48:36 +08:00
.attr('x1', startx)
.attr('y1', starty)
.attr('x2', stopx)
.attr('y2', stopy)
2019-09-12 12:54:59 -07:00
.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);
2017-04-11 22:14:25 +08:00
if (typeof bounds.sections !== 'undefined') {
2019-09-12 12:54:59 -07:00
bounds.sections.forEach(function(item) {
drawLoopLine(bounds.startx, item, bounds.stopx, item).style('stroke-dasharray', '3, 3');
});
2017-04-11 22:14:25 +08:00
}
2019-09-12 12:54:59 -07:00
let txt = getTextObj();
txt.text = labelText;
txt.x = bounds.startx;
txt.y = bounds.starty;
txt.labelMargin = 1.5 * 10; // This is the small box that says "loop"
txt.class = 'labelText'; // Its size & position are fixed.
2017-04-11 22:14:25 +08:00
2019-09-12 12:54:59 -07:00
drawLabel(g, txt);
2017-04-11 22:14:25 +08:00
2019-09-12 12:54:59 -07:00
txt = getTextObj();
txt.text = '[ ' + bounds.title + ' ]';
txt.x = bounds.startx + (bounds.stopx - bounds.startx) / 2;
txt.y = bounds.starty + 1.5 * conf.boxMargin;
txt.anchor = 'middle';
txt.class = 'loopText';
2017-04-11 22:14:25 +08:00
2019-09-12 12:54:59 -07:00
drawText(g, txt);
2017-04-11 22:14:25 +08:00
if (typeof bounds.sectionTitles !== 'undefined') {
2019-09-12 12:54:59 -07:00
bounds.sectionTitles.forEach(function(item, idx) {
2017-04-11 22:14:25 +08:00
if (item !== '') {
2019-09-12 12:54:59 -07:00
txt.text = '[ ' + item + ' ]';
txt.y = bounds.sections[idx] + 1.5 * conf.boxMargin;
drawText(g, txt);
2017-04-11 22:14:25 +08:00
}
2019-09-12 12:54:59 -07:00
});
2017-04-11 22:14:25 +08:00
}
2019-09-12 12:54:59 -07:00
};
2015-01-05 14:41:00 +01:00
/**
* Draws a background rectangle
* @param color - The fill color for the background
*/
2019-09-12 12:54:59 -07:00
export const drawBackgroundRect = function(elem, bounds) {
const rectElem = drawRect(elem, {
x: bounds.startx,
y: bounds.starty,
width: bounds.stopx - bounds.startx,
height: bounds.stopy - bounds.starty,
fill: bounds.fill,
class: 'rect'
2019-09-12 12:54:59 -07:00
});
rectElem.lower();
};
2015-01-05 13:41:32 +01:00
/**
* Setup arrow head and define the marker. The result is appended to the svg.
*/
2019-09-12 12:54:59 -07:00
export const insertArrowHead = function(elem) {
elem
.append('defs')
.append('marker')
2017-04-16 23:48:36 +08:00
.attr('id', 'arrowhead')
.attr('refX', 5)
.attr('refY', 2)
.attr('markerWidth', 6)
.attr('markerHeight', 4)
.attr('orient', 'auto')
.append('path')
2019-09-12 12:54:59 -07:00
.attr('d', 'M 0,0 V 4 L6,2 Z'); // this is actual shape for arrowhead
};
2018-08-16 13:44:59 -04:00
/**
* Setup node number. The result is appended to the svg.
*/
2019-09-12 12:54:59 -07:00
export const insertSequenceNumber = function(elem) {
elem
.append('defs')
.append('marker')
.attr('id', 'sequencenumber')
2018-08-16 13:44:59 -04:00
.attr('refX', 15)
.attr('refY', 15)
.attr('markerWidth', 60)
.attr('markerHeight', 40)
.attr('orient', 'auto')
.append('circle')
.attr('cx', 15)
.attr('cy', 15)
2019-09-12 12:54:59 -07:00
.attr('r', 6);
// .style("fill", '#f00');
};
2015-01-05 13:41:32 +01:00
/**
* Setup arrow head and define the marker. The result is appended to the svg.
*/
2019-09-12 12:54:59 -07:00
export const insertArrowCrossHead = function(elem) {
const defs = elem.append('defs');
const marker = defs
.append('marker')
2017-04-16 23:48:36 +08:00
.attr('id', 'crosshead')
.attr('markerWidth', 15)
.attr('markerHeight', 8)
.attr('orient', 'auto')
.attr('refX', 16)
2019-09-12 12:54:59 -07:00
.attr('refY', 4);
2017-04-16 23:48:36 +08:00
// The arrow
2019-09-12 12:54:59 -07:00
marker
.append('path')
2017-04-16 23:48:36 +08:00
.attr('fill', 'black')
.attr('stroke', '#000000')
2019-09-12 12:54:59 -07:00
.style('stroke-dasharray', '0, 0')
2017-04-16 23:48:36 +08:00
.attr('stroke-width', '1px')
2019-09-12 12:54:59 -07:00
.attr('d', 'M 9,2 V 6 L16,4 Z');
2017-04-16 23:48:36 +08:00
// The cross
2019-09-12 12:54:59 -07:00
marker
.append('path')
2017-04-16 23:48:36 +08:00
.attr('fill', 'none')
.attr('stroke', '#000000')
2019-09-12 12:54:59 -07:00
.style('stroke-dasharray', '0, 0')
2017-04-16 23:48:36 +08:00
.attr('stroke-width', '1px')
2019-09-12 12:54:59 -07:00
.attr('d', 'M 0,1 L 6,7 M 6,1 L 0,7');
2017-04-16 23:48:36 +08:00
// this is actual shape for arrowhead
2019-09-12 12:54:59 -07:00
};
2017-04-11 22:14:25 +08:00
2019-09-12 12:54:59 -07:00
export const getTextObj = function() {
2017-09-14 20:35:00 +08:00
const txt = {
2017-04-11 22:14:25 +08:00
x: 0,
y: 0,
2019-09-12 12:54:59 -07:00
fill: undefined,
2017-04-11 22:14:25 +08:00
'text-anchor': 'start',
style: '#666',
width: 100,
height: 100,
textMargin: 0,
rx: 0,
ry: 0
2019-09-12 12:54:59 -07:00
};
return txt;
};
2017-04-11 22:14:25 +08:00
2019-09-12 12:54:59 -07:00
export const getNoteRect = function() {
2017-09-14 20:35:00 +08:00
const rect = {
2017-04-11 22:14:25 +08:00
x: 0,
y: 0,
fill: '#EDF2AE',
stroke: '#666',
width: 100,
anchor: 'start',
height: 100,
rx: 0,
ry: 0
2019-09-12 12:54:59 -07:00
};
return rect;
};
const _drawTextCandidateFunc = (function() {
function byText(content, g, x, y, width, height, textAttrs) {
const text = g
.append('text')
.attr('x', x + width / 2)
.attr('y', y + height / 2 + 5)
2017-04-16 23:48:36 +08:00
.style('text-anchor', 'middle')
2019-09-12 12:54:59 -07:00
.text(content);
_setTextAttrs(text, textAttrs);
2017-04-11 22:14:25 +08:00
}
2019-09-12 12:54:59 -07:00
function byTspan(content, g, x, y, width, height, textAttrs, conf) {
const { actorFontSize, actorFontFamily } = conf;
2019-09-12 12:54:59 -07:00
const lines = content.split(/<br\/?>/gi);
for (let i = 0; i < lines.length; i++) {
2019-09-12 12:54:59 -07:00
const dy = i * actorFontSize - (actorFontSize * (lines.length - 1)) / 2;
const text = g
.append('text')
.attr('x', x + width / 2)
.attr('y', y)
.style('text-anchor', 'middle')
.style('font-size', actorFontSize)
2019-09-12 12:54:59 -07:00
.style('font-family', actorFontFamily);
text
.append('tspan')
.attr('x', x + width / 2)
.attr('dy', dy)
.text(lines[i]);
text
.attr('y', y + height / 2.0)
.attr('dominant-baseline', 'central')
2019-09-12 12:54:59 -07:00
.attr('alignment-baseline', 'central');
2019-09-12 12:54:59 -07:00
_setTextAttrs(text, textAttrs);
}
2017-04-11 22:14:25 +08:00
}
2019-09-12 12:54:59 -07:00
function byFo(content, g, x, y, width, height, textAttrs, conf) {
const s = g.append('switch');
const f = s
.append('foreignObject')
.attr('x', x)
.attr('y', y)
.attr('width', width)
.attr('height', height);
const text = f
.append('div')
.style('display', 'table')
.style('height', '100%')
.style('width', '100%');
text
.append('div')
.style('display', 'table-cell')
.style('text-align', 'center')
.style('vertical-align', 'middle')
.text(content);
byTspan(content, s, x, y, width, height, textAttrs, conf);
_setTextAttrs(text, textAttrs);
2017-04-11 22:14:25 +08:00
}
2019-09-12 12:54:59 -07:00
function _setTextAttrs(toText, fromTextAttrsDict) {
2017-09-14 20:35:00 +08:00
for (const key in fromTextAttrsDict) {
2017-04-11 22:14:25 +08:00
if (fromTextAttrsDict.hasOwnProperty(key)) {
2019-09-12 12:54:59 -07:00
toText.attr(key, fromTextAttrsDict[key]);
2016-12-17 18:03:11 -05:00
}
}
2017-04-11 22:14:25 +08:00
}
2019-09-12 12:54:59 -07:00
return function(conf) {
return conf.textPlacement === 'fo' ? byFo : conf.textPlacement === 'old' ? byText : byTspan;
};
})();
2017-09-10 22:03:10 +08:00
export default {
drawRect,
drawText,
drawLabel,
drawActor,
anchorElement,
drawActivation,
drawLoop,
drawBackgroundRect,
2017-09-10 22:03:10 +08:00
insertArrowHead,
2018-08-16 16:55:28 -04:00
insertSequenceNumber,
2017-09-10 22:03:10 +08:00
insertArrowCrossHead,
getTextObj,
getNoteRect
2019-09-12 12:54:59 -07:00
};