Support self-connections [#7]

This commit is contained in:
David Evans 2017-10-28 14:47:46 +01:00
parent fafaff7bce
commit 4772b16783
4 changed files with 112 additions and 8 deletions

View File

@ -50,6 +50,8 @@ Foo <--> Bar: Double dashed arrow
# An arrow with no label: # An arrow with no label:
Foo -> Bar Foo -> Bar
Foo -> Foo: Foo talks to itself
# Arrows leaving on the left and right of the diagram # Arrows leaving on the left and right of the diagram
[ -> Foo: From the left [ -> Foo: From the left
[ <- Foo: To the left [ <- Foo: To the left

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

@ -241,16 +241,32 @@ define([
separationConnection({agents, label}) { separationConnection({agents, label}) {
const config = this.theme.connect; const config = this.theme.connect;
const labelWidth = (
this.sizer.measure(config.label.attrs, label).width +
config.label.padding * 2
);
const strokeWidth = this.theme.agentLineAttrs['stroke-width'];
if(agents[0] === agents[1]) {
const agentSpaces = new Map();
agentSpaces.set(agents[0], {
left: 0,
right: (
labelWidth +
config.arrow.width +
strokeWidth +
config.loopbackRadius
),
});
this.addSeparations(this.visibleAgents, agentSpaces);
} else {
this.addSeparation( this.addSeparation(
agents[0], agents[0],
agents[1], agents[1],
labelWidth + config.arrow.width * 2 + strokeWidth
this.sizer.measure(config.label.attrs, label).width +
config.arrow.width * 2 +
config.label.padding * 2 +
this.theme.agentLineAttrs['stroke-width']
); );
} }
}
separationNoteOver({agents, mode, label}) { separationNoteOver({agents, mode, label}) {
const config = this.theme.note[mode]; const config = this.theme.note[mode];
@ -463,7 +479,79 @@ define([
this.currentY += maxHeight + this.theme.actionMargin; this.currentY += maxHeight + this.theme.actionMargin;
} }
renderConnection({label, agents, line, left, right}) { renderSelfConnection({label, agents, line, left, right}) {
const config = this.theme.connect;
const from = this.agentInfos.get(agents[0]);
const dy = config.arrow.height / 2;
const short = this.theme.agentLineAttrs['stroke-width'];
const height = (
this.sizer.measureHeight(config.label.attrs, label) +
config.label.margin.top +
config.label.margin.bottom
);
const y0 = this.currentY + Math.max(dy, height);
const x0 = (
from.x +
short +
config.arrow.width +
config.label.padding
);
const renderedText = SVGShapes.renderBoxedText(label, {
x: x0 - config.mask.padding.left,
y: y0 - height + config.label.margin.top,
padding: config.mask.padding,
boxAttrs: config.mask.maskAttrs,
labelAttrs: config.label.loopbackAttrs,
boxLayer: this.mask,
labelLayer: this.actionLabels,
});
const r = config.loopbackRadius;
const x1 = (
x0 +
renderedText.width +
config.label.padding -
config.mask.padding.left -
config.mask.padding.right
);
const y1 = y0 + r * 2;
this.actionShapes.appendChild(svg.make('path', Object.assign({
'd': (
'M ' + (from.x + (left ? short : 0)) + ' ' + y0 +
' L ' + x1 + ' ' + y0 +
' A ' + r + ' ' + r + ' 0 0 1 ' + x1 + ' ' + y1 +
' L ' + (from.x + (right ? short : 0)) + ' ' + y1
),
}, config.lineAttrs[line])));
if(left) {
drawHorizontalArrowHead(this.actionShapes, {
x: from.x + short,
y: y0,
dx: config.arrow.width,
dy,
attrs: config.arrow.attrs,
});
}
if(right) {
drawHorizontalArrowHead(this.actionShapes, {
x: from.x + short,
y: y1,
dx: config.arrow.width,
dy,
attrs: config.arrow.attrs,
});
}
this.currentY = y1 + dy + this.theme.actionMargin;
}
renderSimpleConnection({label, agents, line, left, right}) {
const config = this.theme.connect; const config = this.theme.connect;
const from = this.agentInfos.get(agents[0]); const from = this.agentInfos.get(agents[0]);
const to = this.agentInfos.get(agents[1]); const to = this.agentInfos.get(agents[1]);
@ -520,6 +608,14 @@ define([
this.currentY = y + dy + this.theme.actionMargin; this.currentY = y + dy + this.theme.actionMargin;
} }
renderConnection(stage) {
if(stage.agents[0] === stage.agents[1]) {
this.renderSelfConnection(stage);
} else {
this.renderSimpleConnection(stage);
}
}
renderNote({xMid = null, x0 = null, x1 = null}, anchor, mode, label) { renderNote({xMid = null, x0 = null, x1 = null}, anchor, mode, label) {
const config = this.theme.note[mode]; const config = this.theme.note[mode];

View File

@ -59,6 +59,7 @@ define([
}, },
connect: { connect: {
loopbackRadius: 6,
lineAttrs: { lineAttrs: {
'solid': { 'solid': {
'fill': 'none', 'fill': 'none',
@ -91,6 +92,11 @@ define([
'line-height': LINE_HEIGHT, 'line-height': LINE_HEIGHT,
'text-anchor': 'middle', 'text-anchor': 'middle',
}, },
loopbackAttrs: {
'font-family': 'sans-serif',
'font-size': 8,
'line-height': LINE_HEIGHT,
},
}, },
mask: { mask: {
padding: { padding: {