Simplify column positioning, automatic reordering where guaranteed safe
This commit is contained in:
parent
45295a3843
commit
1449d73194
|
@ -184,7 +184,9 @@ define(() => {
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
meta,
|
meta: {
|
||||||
|
title: meta.title,
|
||||||
|
},
|
||||||
agents,
|
agents,
|
||||||
stages: rootStages,
|
stages: rootStages,
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,13 +14,13 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
||||||
const BLOCK_END = 'block end';
|
const BLOCK_END = 'block end';
|
||||||
|
|
||||||
describe('.generate', () => {
|
describe('.generate', () => {
|
||||||
it('propagates metadata', () => {
|
it('propagates title metadata', () => {
|
||||||
const input = {
|
const input = {
|
||||||
meta: {foo: 'bar'},
|
meta: {title: 'bar'},
|
||||||
stages: [],
|
stages: [],
|
||||||
};
|
};
|
||||||
const sequence = generator.generate(input);
|
const sequence = generator.generate(input);
|
||||||
expect(sequence.meta).toEqual({foo: 'bar'});
|
expect(sequence.meta).toEqual({title: 'bar'});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns an empty sequence for blank input', () => {
|
it('returns an empty sequence for blank input', () => {
|
||||||
|
|
|
@ -32,6 +32,8 @@ define(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SEP_ZERO = {left: 0, right: 0};
|
||||||
|
|
||||||
const NS = 'http://www.w3.org/2000/svg';
|
const NS = 'http://www.w3.org/2000/svg';
|
||||||
|
|
||||||
const LINE_HEIGHT = 1.3;
|
const LINE_HEIGHT = 1.3;
|
||||||
|
@ -160,6 +162,24 @@ define(() => {
|
||||||
this.diagram.appendChild(this.actions);
|
this.diagram.appendChild(this.actions);
|
||||||
this.base.appendChild(this.diagram);
|
this.base.appendChild(this.diagram);
|
||||||
|
|
||||||
|
this.separationAgentCap = {
|
||||||
|
'box': this.separationAgentCapBox.bind(this),
|
||||||
|
'cross': this.separationAgentCapCross.bind(this),
|
||||||
|
'bar': this.separationAgentCapBar.bind(this),
|
||||||
|
'none': this.separationAgentCapNone.bind(this),
|
||||||
|
};
|
||||||
|
|
||||||
|
this.separationAction = {
|
||||||
|
'agent begin': this.separationAgent.bind(this),
|
||||||
|
'agent end': this.separationAgent.bind(this),
|
||||||
|
'connection': this.separationConnection.bind(this),
|
||||||
|
'block': this.separationBlock.bind(this),
|
||||||
|
'note over': this.separationNoteOver.bind(this),
|
||||||
|
'note left': this.separationNoteLeft.bind(this),
|
||||||
|
'note right': this.separationNoteRight.bind(this),
|
||||||
|
'note between': this.separationNoteBetween.bind(this),
|
||||||
|
};
|
||||||
|
|
||||||
this.renderAgentCap = {
|
this.renderAgentCap = {
|
||||||
'box': this.renderAgentCapBox.bind(this),
|
'box': this.renderAgentCapBox.bind(this),
|
||||||
'cross': this.renderAgentCapCross.bind(this),
|
'cross': this.renderAgentCapCross.bind(this),
|
||||||
|
@ -178,121 +198,117 @@ define(() => {
|
||||||
'note between': this.renderNoteBetween.bind(this),
|
'note between': this.renderNoteBetween.bind(this),
|
||||||
};
|
};
|
||||||
|
|
||||||
this.separationAction = {
|
|
||||||
'agent begin': this.separationAgentCap.bind(this),
|
|
||||||
'agent end': this.separationAgentCap.bind(this),
|
|
||||||
'connection': this.separationConnection.bind(this),
|
|
||||||
'block': this.separationBlock.bind(this),
|
|
||||||
'note over': this.separationNoteOver.bind(this),
|
|
||||||
'note left': this.separationNoteLeft.bind(this),
|
|
||||||
'note right': this.separationNoteRight.bind(this),
|
|
||||||
'note between': this.separationNoteBetween.bind(this),
|
|
||||||
};
|
|
||||||
|
|
||||||
this.width = 0;
|
this.width = 0;
|
||||||
this.height = 0;
|
this.height = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
addSeparation(agentInfo, agent, dist) {
|
addSeparation(agent1, agent2, dist) {
|
||||||
let d = agentInfo.separations.get(agent) || 0;
|
const info1 = this.agentInfos.get(agent1);
|
||||||
agentInfo.separations.set(agent, Math.max(d, dist));
|
const info2 = this.agentInfos.get(agent2);
|
||||||
|
|
||||||
|
const d1 = info1.separations.get(agent2) || 0;
|
||||||
|
info1.separations.set(agent2, Math.max(d1, dist));
|
||||||
|
|
||||||
|
const d2 = info2.separations.get(agent1) || 0;
|
||||||
|
info2.separations.set(agent1, Math.max(d2, dist));
|
||||||
}
|
}
|
||||||
|
|
||||||
separationAgentCap(agentInfos, stage) {
|
addSeparations(agents, agentSpaces) {
|
||||||
switch(stage.mode) {
|
agents.forEach((agent1) => {
|
||||||
case 'box':
|
const info1 = this.agentInfos.get(agent1);
|
||||||
case 'bar':
|
const sep1 = agentSpaces.get(agent1) || SEP_ZERO;
|
||||||
stage.agents.forEach((agent1) => {
|
agents.forEach((agent2) => {
|
||||||
const info1 = agentInfos.get(agent1);
|
const info2 = this.agentInfos.get(agent2);
|
||||||
const sep1 = (
|
if(info2.index >= info1.index) {
|
||||||
info1.labelWidth / 2 +
|
|
||||||
AGENT_MARGIN
|
|
||||||
);
|
|
||||||
stage.agents.forEach((agent2) => {
|
|
||||||
if(agent1 === agent2) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const info2 = agentInfos.get(agent2);
|
const sep2 = agentSpaces.get(agent2) || SEP_ZERO;
|
||||||
this.addSeparation(info1, agent2,
|
this.addSeparation(
|
||||||
sep1 + info2.labelWidth / 2
|
agent1,
|
||||||
|
agent2,
|
||||||
|
sep1.right + sep2.left + AGENT_MARGIN
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
this.visibleAgents.forEach((agent2) => {
|
});
|
||||||
if(stage.agents.indexOf(agent2) === -1) {
|
|
||||||
const info2 = agentInfos.get(agent2);
|
|
||||||
this.addSeparation(info1, agent2, sep1);
|
|
||||||
this.addSeparation(info2, agent1, sep1);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
separationAgentCapBox(agentInfo) {
|
||||||
break;
|
return {
|
||||||
case 'cross':
|
left: agentInfo.labelWidth / 2,
|
||||||
stage.agents.forEach((agent1) => {
|
right: agentInfo.labelWidth / 2,
|
||||||
const info1 = agentInfos.get(agent1);
|
};
|
||||||
const sep1 = (
|
|
||||||
AGENT_CROSS_SIZE / 2 +
|
|
||||||
AGENT_MARGIN
|
|
||||||
);
|
|
||||||
stage.agents.forEach((agent2) => {
|
|
||||||
if(agent1 === agent2) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
this.addSeparation(info1, agent2,
|
|
||||||
sep1 + AGENT_CROSS_SIZE / 2
|
separationAgentCapCross() {
|
||||||
);
|
return {
|
||||||
});
|
left: AGENT_CROSS_SIZE / 2,
|
||||||
this.visibleAgents.forEach((agent2) => {
|
right: AGENT_CROSS_SIZE / 2,
|
||||||
if(stage.agents.indexOf(agent2) === -1) {
|
};
|
||||||
const info2 = agentInfos.get(agent2);
|
|
||||||
this.addSeparation(info1, agent2, sep1);
|
|
||||||
this.addSeparation(info2, agent1, sep1);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
separationAgentCapBar(agentInfo) {
|
||||||
break;
|
return {
|
||||||
|
left: agentInfo.labelWidth / 2,
|
||||||
|
right: agentInfo.labelWidth / 2,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if(stage.type === 'agent begin') {
|
|
||||||
mergeSets(this.visibleAgents, stage.agents);
|
separationAgentCapNone() {
|
||||||
} else if(stage.type === 'agent end') {
|
return {left: 0, right: 0};
|
||||||
removeAll(this.visibleAgents, stage.agents);
|
}
|
||||||
|
|
||||||
|
separationAgent({type, mode, agents}) {
|
||||||
|
if(type === 'agent begin') {
|
||||||
|
mergeSets(this.visibleAgents, agents);
|
||||||
|
}
|
||||||
|
|
||||||
|
const agentSpaces = new Map();
|
||||||
|
agents.forEach((agent) => {
|
||||||
|
const info = this.agentInfos.get(agent);
|
||||||
|
const separationFn = this.separationAgentCap[mode];
|
||||||
|
agentSpaces.set(agent, separationFn(info));
|
||||||
|
});
|
||||||
|
this.addSeparations(this.visibleAgents, agentSpaces);
|
||||||
|
|
||||||
|
if(type === 'agent end') {
|
||||||
|
removeAll(this.visibleAgents, agents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
separationConnection(agentInfos, stage) {
|
separationConnection({agents, label}) {
|
||||||
const w = (
|
this.addSeparation(
|
||||||
this.testTextWidth(this.testConnectWidth, stage.label) +
|
agents[0],
|
||||||
|
agents[1],
|
||||||
|
|
||||||
|
this.testTextWidth(this.testConnectWidth, label) +
|
||||||
CONNECT_POINT * 2 +
|
CONNECT_POINT * 2 +
|
||||||
CONNECT_LABEL_PADDING * 2 +
|
CONNECT_LABEL_PADDING * 2 +
|
||||||
ATTRS.AGENT_LINE['stroke-width']
|
ATTRS.AGENT_LINE['stroke-width']
|
||||||
);
|
);
|
||||||
const agent1 = stage.agents[0];
|
|
||||||
const agent2 = stage.agents[1];
|
|
||||||
this.addSeparation(agentInfos.get(agent1), agent2, w);
|
|
||||||
this.addSeparation(agentInfos.get(agent2), agent1, w);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
separationBlock(/*agentInfos, stage*/) {
|
separationBlock(/*stage*/) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
separationNoteOver(/*agentInfos, stage*/) {
|
separationNoteOver(/*stage*/) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
separationNoteLeft(/*agentInfos, stage*/) {
|
separationNoteLeft(/*stage*/) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
separationNoteRight(/*agentInfos, stage*/) {
|
separationNoteRight(/*stage*/) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
separationNoteBetween(/*agentInfos, stage*/) {
|
separationNoteBetween(/*stage*/) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
checkSeparation(agentInfos, stage) {
|
checkSeparation(stage) {
|
||||||
this.separationAction[stage.type](agentInfos, stage);
|
this.separationAction[stage.type](stage);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderAgentCapBox({x, labelWidth, label}) {
|
renderAgentCapBox({x, labelWidth, label}) {
|
||||||
|
@ -361,37 +377,38 @@ define(() => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
renderAgentBegin(agentInfos, stage) {
|
renderAgentBegin({mode, agents}) {
|
||||||
let shifts = {height: 0};
|
let shifts = {height: 0};
|
||||||
stage.agents.forEach((agent) => {
|
agents.forEach((agent) => {
|
||||||
const agentInfo = agentInfos.get(agent);
|
const agentInfo = this.agentInfos.get(agent);
|
||||||
shifts = this.renderAgentCap[stage.mode](agentInfo);
|
shifts = this.renderAgentCap[mode](agentInfo);
|
||||||
agentInfo.latestYStart = this.currentY + shifts.lineBottom;
|
agentInfo.latestYStart = this.currentY + shifts.lineBottom;
|
||||||
});
|
});
|
||||||
this.currentY += shifts.height + ACTION_MARGIN;
|
this.currentY += shifts.height + ACTION_MARGIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderAgentEnd(agentInfos, stage) {
|
renderAgentEnd({mode, agents}) {
|
||||||
let shifts = {height: 0};
|
let shifts = {height: 0};
|
||||||
stage.agents.forEach((agent) => {
|
agents.forEach((agent) => {
|
||||||
const agentInfo = agentInfos.get(agent);
|
const agentInfo = this.agentInfos.get(agent);
|
||||||
const x = agentInfo.x;
|
const x = agentInfo.x;
|
||||||
shifts = this.renderAgentCap[stage.mode](agentInfo);
|
shifts = this.renderAgentCap[mode](agentInfo);
|
||||||
this.agentLines.appendChild(makeSVGNode('path', Object.assign({
|
this.agentLines.appendChild(makeSVGNode('path', Object.assign({
|
||||||
'd': (
|
'd': (
|
||||||
'M ' + x + ' ' + agentInfo.latestYStart +
|
'M ' + x + ' ' + agentInfo.latestYStart +
|
||||||
' L ' + x + ' ' + (this.currentY + shifts.lineTop)
|
' L ' + x + ' ' + (this.currentY + shifts.lineTop)
|
||||||
),
|
),
|
||||||
|
'class': 'agent-' + agentInfo.index + '-line',
|
||||||
}, ATTRS.AGENT_LINE)));
|
}, ATTRS.AGENT_LINE)));
|
||||||
agentInfo.latestYStart = null;
|
agentInfo.latestYStart = null;
|
||||||
});
|
});
|
||||||
this.currentY += shifts.height + ACTION_MARGIN;
|
this.currentY += shifts.height + ACTION_MARGIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderConnection(agentInfos, {label, agents, line, left, right}) {
|
renderConnection({label, agents, line, left, right}) {
|
||||||
/* jshint -W074, -W071 */ // TODO: tidy this up
|
/* jshint -W074, -W071 */ // TODO: tidy this up
|
||||||
const from = agentInfos.get(agents[0]);
|
const from = this.agentInfos.get(agents[0]);
|
||||||
const to = agentInfos.get(agents[1]);
|
const to = this.agentInfos.get(agents[1]);
|
||||||
|
|
||||||
const dy = CONNECT_HEIGHT / 2;
|
const dy = CONNECT_HEIGHT / 2;
|
||||||
const dx = CONNECT_POINT;
|
const dx = CONNECT_POINT;
|
||||||
|
@ -466,28 +483,28 @@ define(() => {
|
||||||
this.currentY = y + dy + ACTION_MARGIN;
|
this.currentY = y + dy + ACTION_MARGIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderBlock(/*agentInfos, stage*/) {
|
renderBlock(/*stage*/) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
renderNoteOver(/*agentInfos, stage*/) {
|
renderNoteOver(/*stage*/) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
renderNoteLeft(/*agentInfos, stage*/) {
|
renderNoteLeft(/*stage*/) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
renderNoteRight(/*agentInfos, stage*/) {
|
renderNoteRight(/*stage*/) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
renderNoteBetween(/*agentInfos, stage*/) {
|
renderNoteBetween(/*stage*/) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
addAction(agentInfos, stage) {
|
addAction(stage) {
|
||||||
this.renderAction[stage.type](agentInfos, stage);
|
this.renderAction[stage.type](stage);
|
||||||
}
|
}
|
||||||
|
|
||||||
makeTextTester(attrs) {
|
makeTextTester(attrs) {
|
||||||
|
@ -510,42 +527,43 @@ define(() => {
|
||||||
buildAgentInfos(agents, stages) {
|
buildAgentInfos(agents, stages) {
|
||||||
const testNameWidth = this.makeTextTester(ATTRS.AGENT_BOX_LABEL);
|
const testNameWidth = this.makeTextTester(ATTRS.AGENT_BOX_LABEL);
|
||||||
|
|
||||||
const agentInfos = new Map();
|
this.agentInfos = new Map();
|
||||||
agents.forEach((agent) => {
|
agents.forEach((agent, index) => {
|
||||||
agentInfos.set(agent, {
|
this.agentInfos.set(agent, {
|
||||||
label: agent,
|
label: agent,
|
||||||
labelWidth: (
|
labelWidth: (
|
||||||
this.testTextWidth(testNameWidth, agent) +
|
this.testTextWidth(testNameWidth, agent) +
|
||||||
BOX_PADDING * 2
|
BOX_PADDING * 2
|
||||||
),
|
),
|
||||||
|
index,
|
||||||
x: null,
|
x: null,
|
||||||
latestYStart: null,
|
latestYStart: null,
|
||||||
separations: new Map(),
|
separations: new Map(),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
agentInfos.get('[').labelWidth = 0;
|
this.agentInfos.get('[').labelWidth = 0;
|
||||||
agentInfos.get(']').labelWidth = 0;
|
this.agentInfos.get(']').labelWidth = 0;
|
||||||
|
|
||||||
this.removeTextTester(testNameWidth);
|
this.removeTextTester(testNameWidth);
|
||||||
|
|
||||||
this.testConnectWidth = this.makeTextTester(ATTRS.CONNECT_LABEL);
|
this.testConnectWidth = this.makeTextTester(ATTRS.CONNECT_LABEL);
|
||||||
this.visibleAgents = ['[', ']'];
|
this.visibleAgents = ['[', ']'];
|
||||||
traverse(stages, this.checkSeparation.bind(this, agentInfos));
|
traverse(stages, this.checkSeparation.bind(this));
|
||||||
this.removeTextTester(this.testConnectWidth);
|
this.removeTextTester(this.testConnectWidth);
|
||||||
|
|
||||||
let currentX = 0;
|
|
||||||
agents.forEach((agent) => {
|
agents.forEach((agent) => {
|
||||||
const agentInfo = agentInfos.get(agent);
|
const agentInfo = this.agentInfos.get(agent);
|
||||||
|
let currentX = 0;
|
||||||
agentInfo.separations.forEach((dist, otherAgent) => {
|
agentInfo.separations.forEach((dist, otherAgent) => {
|
||||||
const otherAgentInfo = agentInfos.get(otherAgent);
|
const otherAgentInfo = this.agentInfos.get(otherAgent);
|
||||||
if(otherAgentInfo.x !== null) {
|
if(otherAgentInfo.x !== null) {
|
||||||
currentX = Math.max(currentX, otherAgentInfo.x + dist);
|
currentX = Math.max(currentX, otherAgentInfo.x + dist);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
agentInfo.x = currentX;
|
agentInfo.x = currentX;
|
||||||
|
this.minX = Math.min(this.minX, currentX);
|
||||||
|
this.maxX = Math.max(this.maxX, currentX);
|
||||||
});
|
});
|
||||||
|
|
||||||
return {agentInfos, minX: 0, maxX: currentX};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateBounds(stagesHeight) {
|
updateBounds(stagesHeight) {
|
||||||
|
@ -584,17 +602,20 @@ define(() => {
|
||||||
|
|
||||||
this.titleText.nodeValue = meta.title || '';
|
this.titleText.nodeValue = meta.title || '';
|
||||||
|
|
||||||
const info = this.buildAgentInfos(agents, stages);
|
this.minX = 0;
|
||||||
|
this.maxX = 0;
|
||||||
|
this.buildAgentInfos(agents, stages);
|
||||||
|
|
||||||
this.minX = info.minX;
|
|
||||||
this.maxX = info.maxX;
|
|
||||||
this.currentY = 0;
|
this.currentY = 0;
|
||||||
|
traverse(stages, this.addAction.bind(this));
|
||||||
traverse(stages, this.addAction.bind(this, info.agentInfos));
|
|
||||||
|
|
||||||
this.updateBounds(Math.max(this.currentY - ACTION_MARGIN, 0));
|
this.updateBounds(Math.max(this.currentY - ACTION_MARGIN, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getColumnX(name) {
|
||||||
|
return this.agentInfos.get(name).x;
|
||||||
|
}
|
||||||
|
|
||||||
svg() {
|
svg() {
|
||||||
return this.base;
|
return this.base;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,11 @@ defineDescribe('Sequence Renderer', ['./Renderer'], (Renderer) => {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
renderer = new Renderer();
|
renderer = new Renderer();
|
||||||
|
document.body.appendChild(renderer.svg());
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
document.body.removeChild(renderer.svg());
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('.svg', () => {
|
describe('.svg', () => {
|
||||||
|
@ -14,6 +19,17 @@ defineDescribe('Sequence Renderer', ['./Renderer'], (Renderer) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function connectionStage(agents, label = '') {
|
||||||
|
return {
|
||||||
|
type: 'connection',
|
||||||
|
line: 'solid',
|
||||||
|
left: false,
|
||||||
|
right: true,
|
||||||
|
agents,
|
||||||
|
label,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
describe('.render', () => {
|
describe('.render', () => {
|
||||||
it('populates the SVG with content', () => {
|
it('populates the SVG with content', () => {
|
||||||
renderer.render({
|
renderer.render({
|
||||||
|
@ -25,5 +41,101 @@ defineDescribe('Sequence Renderer', ['./Renderer'], (Renderer) => {
|
||||||
const title = element.getElementsByClassName('title')[0];
|
const title = element.getElementsByClassName('title')[0];
|
||||||
expect(title.innerHTML).toEqual('Title');
|
expect(title.innerHTML).toEqual('Title');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('positions column lines', () => {
|
||||||
|
/*
|
||||||
|
A -> B
|
||||||
|
*/
|
||||||
|
|
||||||
|
renderer.render({
|
||||||
|
meta: {title: ''},
|
||||||
|
agents: ['[', 'A', 'B', ']'],
|
||||||
|
stages: [
|
||||||
|
{type: 'agent begin', agents: ['A', 'B'], mode: 'box'},
|
||||||
|
connectionStage(['A', 'B']),
|
||||||
|
{type: 'agent end', agents: ['A', 'B'], mode: 'none'},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const element = renderer.svg();
|
||||||
|
const line = element.getElementsByClassName('agent-1-line')[0];
|
||||||
|
const drawnX = Number(line.getAttribute('d').split(' ')[1]);
|
||||||
|
|
||||||
|
expect(drawnX).toEqual(renderer.getColumnX('A'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('arranges columns left-to-right', () => {
|
||||||
|
/*
|
||||||
|
[ -> A
|
||||||
|
A -> B
|
||||||
|
B -> C
|
||||||
|
C -> ]
|
||||||
|
*/
|
||||||
|
|
||||||
|
renderer.render({
|
||||||
|
meta: {title: ''},
|
||||||
|
agents: ['[', 'A', 'B', 'C', ']'],
|
||||||
|
stages: [
|
||||||
|
{type: 'agent begin', agents: ['A', 'B', 'C'], mode: 'box'},
|
||||||
|
connectionStage(['[', 'A']),
|
||||||
|
connectionStage(['A', 'B']),
|
||||||
|
connectionStage(['B', 'C']),
|
||||||
|
connectionStage(['C', ']']),
|
||||||
|
{type: 'agent end', agents: ['A', 'B', 'C'], mode: 'none'},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const xL = renderer.getColumnX('[');
|
||||||
|
const xA = renderer.getColumnX('A');
|
||||||
|
const xB = renderer.getColumnX('B');
|
||||||
|
const xC = renderer.getColumnX('C');
|
||||||
|
const xR = renderer.getColumnX(']');
|
||||||
|
|
||||||
|
expect(xA).toBeGreaterThan(xL);
|
||||||
|
expect(xB).toBeGreaterThan(xA);
|
||||||
|
expect(xC).toBeGreaterThan(xB);
|
||||||
|
expect(xR).toBeGreaterThan(xC);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allows column reordering for mutually-exclusive columns', () => {
|
||||||
|
/*
|
||||||
|
A -> B: short
|
||||||
|
end B
|
||||||
|
A -> C: long description here
|
||||||
|
end C
|
||||||
|
A -> D: short again
|
||||||
|
end A, D
|
||||||
|
*/
|
||||||
|
|
||||||
|
renderer.render({
|
||||||
|
meta: {title: ''},
|
||||||
|
agents: ['[', 'A', 'B', 'C', 'D', ']'],
|
||||||
|
stages: [
|
||||||
|
{type: 'agent begin', agents: ['A', 'B'], mode: 'box'},
|
||||||
|
connectionStage(['A', 'B'], 'short'),
|
||||||
|
{type: 'agent end', agents: ['B'], mode: 'cross'},
|
||||||
|
{type: 'agent begin', agents: ['C'], mode: 'box'},
|
||||||
|
connectionStage(['A', 'C'], 'long description here'),
|
||||||
|
{type: 'agent end', agents: ['C'], mode: 'cross'},
|
||||||
|
{type: 'agent begin', agents: ['D'], mode: 'box'},
|
||||||
|
connectionStage(['A', 'D'], 'short again'),
|
||||||
|
{type: 'agent end', agents: ['A', 'D'], mode: 'cross'},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const xA = renderer.getColumnX('A');
|
||||||
|
const xB = renderer.getColumnX('B');
|
||||||
|
const xC = renderer.getColumnX('C');
|
||||||
|
const xD = renderer.getColumnX('D');
|
||||||
|
|
||||||
|
expect(xB).toBeGreaterThan(xA);
|
||||||
|
expect(xC).toBeGreaterThan(xA);
|
||||||
|
expect(xD).toBeGreaterThan(xA);
|
||||||
|
|
||||||
|
expect(xC).toBeGreaterThan(xB);
|
||||||
|
expect(xD).toBeGreaterThan(xB);
|
||||||
|
|
||||||
|
expect(xD).toBeLessThan(xC);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue