Add support for rendering notes and state [#2]
This commit is contained in:
parent
5a2eb4813b
commit
b240990f3e
|
@ -51,19 +51,17 @@ define(() => {
|
||||||
const NOTE_TYPES = {
|
const NOTE_TYPES = {
|
||||||
'note': {
|
'note': {
|
||||||
mode: 'note',
|
mode: 'note',
|
||||||
multiAgent: true,
|
|
||||||
types: {
|
types: {
|
||||||
'over': {type: 'note over', skip: []},
|
'over': {type: 'note over', skip: [], min: 1, max: null},
|
||||||
'left': {type: 'note left', skip: ['of']},
|
'left': {type: 'note left', skip: ['of'], min: 1, max: null},
|
||||||
'right': {type: 'note right', skip: ['of']},
|
'right': {type: 'note right', skip: ['of'], min: 1, max: null},
|
||||||
'between': {type: 'note between', skip: []},
|
'between': {type: 'note between', skip: [], min: 2, max: null},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'state': {
|
'state': {
|
||||||
mode: 'state',
|
mode: 'state',
|
||||||
multiAgent: false,
|
|
||||||
types: {
|
types: {
|
||||||
'over': {type: 'note over', skip: []},
|
'over': {type: 'note over', skip: [], min: 1, max: 1},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -209,7 +207,10 @@ define(() => {
|
||||||
let skip = 2;
|
let skip = 2;
|
||||||
skip = skipOver(line, skip, type.skip);
|
skip = skipOver(line, skip, type.skip);
|
||||||
const agents = parseCommaList(line.slice(skip, labelSplit));
|
const agents = parseCommaList(line.slice(skip, labelSplit));
|
||||||
if(agents.length < 1 || (agents.length > 1 && !mode.multiAgent)) {
|
if(
|
||||||
|
agents.length < type.min ||
|
||||||
|
(type.max !== null && agents.length > type.max)
|
||||||
|
) {
|
||||||
throw new Error('Invalid ' + line[0] + ': ' + line.join(' '));
|
throw new Error('Invalid ' + line[0] + ': ' + line.join(' '));
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -326,6 +326,10 @@ defineDescribe('Sequence Parser', ['./Parser'], (Parser) => {
|
||||||
}]);
|
}]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('rejects note between for a single agent', () => {
|
||||||
|
expect(() => parser.parse('state between A: hi')).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
it('converts state', () => {
|
it('converts state', () => {
|
||||||
const parsed = parser.parse('state over A: doing stuff');
|
const parsed = parser.parse('state over A: doing stuff');
|
||||||
expect(parsed.stages).toEqual([{
|
expect(parsed.stages).toEqual([{
|
||||||
|
|
|
@ -3,6 +3,22 @@ define(() => {
|
||||||
|
|
||||||
/* jshint -W071 */ // TODO: break up rendering logic
|
/* jshint -W071 */ // TODO: break up rendering logic
|
||||||
|
|
||||||
|
const NS = 'http://www.w3.org/2000/svg';
|
||||||
|
|
||||||
|
function makeText(text = '') {
|
||||||
|
return document.createTextNode(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeSVGNode(type, attrs = {}) {
|
||||||
|
const o = document.createElementNS(NS, type);
|
||||||
|
for(let k in attrs) {
|
||||||
|
if(attrs.hasOwnProperty(k)) {
|
||||||
|
o.setAttribute(k, attrs[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
function empty(node) {
|
function empty(node) {
|
||||||
while(node.childNodes.length > 0) {
|
while(node.childNodes.length > 0) {
|
||||||
node.removeChild(node.lastChild);
|
node.removeChild(node.lastChild);
|
||||||
|
@ -32,9 +48,41 @@ define(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const SEP_ZERO = {left: 0, right: 0};
|
function boxRenderer(attrs, position) {
|
||||||
|
return makeSVGNode('rect', Object.assign({}, position, attrs));
|
||||||
|
}
|
||||||
|
|
||||||
const NS = 'http://www.w3.org/2000/svg';
|
function noteRenderer(attrs, flickAttrs, position) {
|
||||||
|
const g = makeSVGNode('g');
|
||||||
|
const x0 = position.x;
|
||||||
|
const x1 = position.x + position.width;
|
||||||
|
const y0 = position.y;
|
||||||
|
const y1 = position.y + position.height;
|
||||||
|
const flick = 7;
|
||||||
|
|
||||||
|
g.appendChild(makeSVGNode('path', Object.assign({
|
||||||
|
'd': (
|
||||||
|
'M ' + x0 + ' ' + y0 +
|
||||||
|
' L ' + (x1 - flick) + ' ' + y0 +
|
||||||
|
' L ' + x1 + ' ' + (y0 + flick) +
|
||||||
|
' L ' + x1 + ' ' + y1 +
|
||||||
|
' L ' + x0 + ' ' + y1 +
|
||||||
|
' Z'
|
||||||
|
),
|
||||||
|
}, attrs)));
|
||||||
|
|
||||||
|
g.appendChild(makeSVGNode('path', Object.assign({
|
||||||
|
'd': (
|
||||||
|
'M ' + (x1 - flick) + ' ' + y0 +
|
||||||
|
' L ' + (x1 - flick) + ' ' + (y0 + flick) +
|
||||||
|
' L ' + x1 + ' ' + (y0 + flick)
|
||||||
|
),
|
||||||
|
}, flickAttrs)));
|
||||||
|
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SEP_ZERO = {left: 0, right: 0};
|
||||||
|
|
||||||
const LINE_HEIGHT = 1.3;
|
const LINE_HEIGHT = 1.3;
|
||||||
const TITLE_MARGIN = 10;
|
const TITLE_MARGIN = 10;
|
||||||
|
@ -53,12 +101,12 @@ define(() => {
|
||||||
bottom: 1,
|
bottom: 1,
|
||||||
};
|
};
|
||||||
const BLOCK_MARGIN = {
|
const BLOCK_MARGIN = {
|
||||||
top: 5,
|
top: 0,
|
||||||
bottom: 5,
|
bottom: 0,
|
||||||
};
|
};
|
||||||
const BLOCK_SECTION_PADDING = {
|
const BLOCK_SECTION_PADDING = {
|
||||||
top: 3,
|
top: 3,
|
||||||
bottom: 5,
|
bottom: 2,
|
||||||
};
|
};
|
||||||
const BLOCK_MODE_PADDING = {
|
const BLOCK_MODE_PADDING = {
|
||||||
top: 1,
|
top: 1,
|
||||||
|
@ -75,6 +123,43 @@ define(() => {
|
||||||
right: 3,
|
right: 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const NOTE = {
|
||||||
|
'note': {
|
||||||
|
margin: {top: 0, left: 5, right: 5, bottom: 0},
|
||||||
|
padding: {top: 5, left: 5, right: 10, bottom: 5},
|
||||||
|
overlap: {left: 10, right: 10},
|
||||||
|
boxRenderer: noteRenderer.bind(null, {
|
||||||
|
'fill': '#FFFFFF',
|
||||||
|
'stroke': '#000000',
|
||||||
|
'stroke-width': 1,
|
||||||
|
}, {
|
||||||
|
'fill': 'none',
|
||||||
|
'stroke': '#000000',
|
||||||
|
'stroke-width': 1,
|
||||||
|
}),
|
||||||
|
labelAttrs: {
|
||||||
|
'font-family': 'sans-serif',
|
||||||
|
'font-size': 8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'state': {
|
||||||
|
margin: {top: 0, left: 5, right: 5, bottom: 0},
|
||||||
|
padding: {top: 7, left: 7, right: 7, bottom: 7},
|
||||||
|
overlap: {left: 10, right: 10},
|
||||||
|
boxRenderer: boxRenderer.bind(null, {
|
||||||
|
'fill': '#FFFFFF',
|
||||||
|
'stroke': '#000000',
|
||||||
|
'stroke-width': 1,
|
||||||
|
'rx': 10,
|
||||||
|
'ry': 10,
|
||||||
|
}),
|
||||||
|
labelAttrs: {
|
||||||
|
'font-family': 'sans-serif',
|
||||||
|
'font-size': 8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const ATTRS = {
|
const ATTRS = {
|
||||||
TITLE: {
|
TITLE: {
|
||||||
'font-family': 'sans-serif',
|
'font-family': 'sans-serif',
|
||||||
|
@ -170,20 +255,6 @@ define(() => {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function makeText(text = '') {
|
|
||||||
return document.createTextNode(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeSVGNode(type, attrs = {}) {
|
|
||||||
const o = document.createElementNS(NS, type);
|
|
||||||
for(let k in attrs) {
|
|
||||||
if(attrs.hasOwnProperty(k)) {
|
|
||||||
o.setAttribute(k, attrs[k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
function traverse(stages, callbacks) {
|
function traverse(stages, callbacks) {
|
||||||
stages.forEach((stage) => {
|
stages.forEach((stage) => {
|
||||||
if(stage.type === 'block') {
|
if(stage.type === 'block') {
|
||||||
|
@ -238,6 +309,9 @@ define(() => {
|
||||||
this.diagram.appendChild(this.actions);
|
this.diagram.appendChild(this.actions);
|
||||||
this.base.appendChild(this.diagram);
|
this.base.appendChild(this.diagram);
|
||||||
|
|
||||||
|
this.testers = makeSVGNode('g');
|
||||||
|
this.testersCache = new Map();
|
||||||
|
|
||||||
this.separationAgentCap = {
|
this.separationAgentCap = {
|
||||||
'box': this.separationAgentCapBox.bind(this),
|
'box': this.separationAgentCapBox.bind(this),
|
||||||
'cross': this.separationAgentCapCross.bind(this),
|
'cross': this.separationAgentCapCross.bind(this),
|
||||||
|
@ -291,6 +365,24 @@ define(() => {
|
||||||
this.height = 0;
|
this.height = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
findExtremes(agents) {
|
||||||
|
let min = null;
|
||||||
|
let max = null;
|
||||||
|
agents.forEach((agent) => {
|
||||||
|
const info = this.agentInfos.get(agent);
|
||||||
|
if(min === null || info.index < min.index) {
|
||||||
|
min = info;
|
||||||
|
}
|
||||||
|
if(max === null || info.index > max.index) {
|
||||||
|
max = info;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
left: min.label,
|
||||||
|
right: max.label,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
addSeparation(agent1, agent2, dist) {
|
addSeparation(agent1, agent2, dist) {
|
||||||
const info1 = this.agentInfos.get(agent1);
|
const info1 = this.agentInfos.get(agent1);
|
||||||
const info2 = this.agentInfos.get(agent2);
|
const info2 = this.agentInfos.get(agent2);
|
||||||
|
@ -303,19 +395,19 @@ define(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
addSeparations(agents, agentSpaces) {
|
addSeparations(agents, agentSpaces) {
|
||||||
agents.forEach((agent1) => {
|
agents.forEach((agentR) => {
|
||||||
const info1 = this.agentInfos.get(agent1);
|
const infoR = this.agentInfos.get(agentR);
|
||||||
const sep1 = agentSpaces.get(agent1) || SEP_ZERO;
|
const sepR = agentSpaces.get(agentR) || SEP_ZERO;
|
||||||
agents.forEach((agent2) => {
|
agents.forEach((agentL) => {
|
||||||
const info2 = this.agentInfos.get(agent2);
|
const infoL = this.agentInfos.get(agentL);
|
||||||
if(info2.index >= info1.index) {
|
if(infoL.index >= infoR.index) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const sep2 = agentSpaces.get(agent2) || SEP_ZERO;
|
const sepL = agentSpaces.get(agentL) || SEP_ZERO;
|
||||||
this.addSeparation(
|
this.addSeparation(
|
||||||
agent1,
|
agentR,
|
||||||
agent2,
|
agentL,
|
||||||
sep1.right + sep2.left + AGENT_MARGIN
|
sepR.left + sepL.right + AGENT_MARGIN
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -369,27 +461,95 @@ define(() => {
|
||||||
agents[0],
|
agents[0],
|
||||||
agents[1],
|
agents[1],
|
||||||
|
|
||||||
this.testTextWidth(this.testConnect, label) +
|
this.testTextWidth(ATTRS.CONNECT_LABEL, 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']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
separationNoteOver(/*stage*/) {
|
separationNoteOver({agents, mode, label}) {
|
||||||
// TODO
|
const config = NOTE[mode];
|
||||||
|
const width = (
|
||||||
|
this.testTextWidth(config.labelAttrs, label) +
|
||||||
|
config.padding.left +
|
||||||
|
config.padding.right
|
||||||
|
);
|
||||||
|
|
||||||
|
const agentSpaces = new Map();
|
||||||
|
if(agents.length > 1) {
|
||||||
|
const {left, right} = this.findExtremes(agents);
|
||||||
|
|
||||||
|
this.addSeparation(
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
|
||||||
|
width -
|
||||||
|
config.overlap.left -
|
||||||
|
config.overlap.right
|
||||||
|
);
|
||||||
|
|
||||||
|
agentSpaces.set(left, {left: config.overlap.left, right: 0});
|
||||||
|
agentSpaces.set(right, {left: 0, right: config.overlap.right});
|
||||||
|
} else {
|
||||||
|
agentSpaces.set(agents[0], {
|
||||||
|
left: width / 2,
|
||||||
|
right: width / 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.addSeparations(this.visibleAgents, agentSpaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
separationNoteLeft(/*stage*/) {
|
separationNoteLeft({agents, mode, label}) {
|
||||||
// TODO
|
const config = NOTE[mode];
|
||||||
|
const {left} = this.findExtremes(agents);
|
||||||
|
|
||||||
|
const agentSpaces = new Map();
|
||||||
|
agentSpaces.set(left, {
|
||||||
|
left: (
|
||||||
|
this.testTextWidth(config.labelAttrs, label) +
|
||||||
|
config.padding.left +
|
||||||
|
config.padding.right +
|
||||||
|
config.margin.left +
|
||||||
|
config.margin.right
|
||||||
|
),
|
||||||
|
right: 0,
|
||||||
|
});
|
||||||
|
this.addSeparations(this.visibleAgents, agentSpaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
separationNoteRight(/*stage*/) {
|
separationNoteRight({agents, mode, label}) {
|
||||||
// TODO
|
const config = NOTE[mode];
|
||||||
|
const {right} = this.findExtremes(agents);
|
||||||
|
|
||||||
|
const agentSpaces = new Map();
|
||||||
|
agentSpaces.set(right, {
|
||||||
|
left: 0,
|
||||||
|
right: (
|
||||||
|
this.testTextWidth(config.labelAttrs, label) +
|
||||||
|
config.padding.left +
|
||||||
|
config.padding.right +
|
||||||
|
config.margin.left +
|
||||||
|
config.margin.right
|
||||||
|
),
|
||||||
|
});
|
||||||
|
this.addSeparations(this.visibleAgents, agentSpaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
separationNoteBetween(/*stage*/) {
|
separationNoteBetween({agents, mode, label}) {
|
||||||
// TODO
|
const config = NOTE[mode];
|
||||||
|
const {left, right} = this.findExtremes(agents);
|
||||||
|
|
||||||
|
this.addSeparation(
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
|
||||||
|
this.testTextWidth(config.labelAttrs, label) +
|
||||||
|
config.padding.left +
|
||||||
|
config.padding.right +
|
||||||
|
config.margin.left +
|
||||||
|
config.margin.right
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
separationBlockBegin(scope, {left, right}) {
|
separationBlockBegin(scope, {left, right}) {
|
||||||
|
@ -399,9 +559,9 @@ define(() => {
|
||||||
|
|
||||||
separationSectionBegin(scope, {left, right}, {mode, label}) {
|
separationSectionBegin(scope, {left, right}, {mode, label}) {
|
||||||
const width = (
|
const width = (
|
||||||
this.testTextWidth(this.testBlockMode, mode) +
|
this.testTextWidth(ATTRS.BLOCK_MODE_LABEL, mode) +
|
||||||
BLOCK_MODE_PADDING.left + BLOCK_MODE_PADDING.right +
|
BLOCK_MODE_PADDING.left + BLOCK_MODE_PADDING.right +
|
||||||
this.testTextWidth(this.testBlockLabel, label) +
|
this.testTextWidth(ATTRS.BLOCK_LABEL, label) +
|
||||||
BLOCK_LABEL_PADDING.left + BLOCK_LABEL_PADDING.right
|
BLOCK_LABEL_PADDING.left + BLOCK_LABEL_PADDING.right
|
||||||
);
|
);
|
||||||
this.addSeparation(left, right, width);
|
this.addSeparation(left, right, width);
|
||||||
|
@ -587,20 +747,103 @@ define(() => {
|
||||||
this.currentY = y + dy + ACTION_MARGIN;
|
this.currentY = y + dy + ACTION_MARGIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderNoteOver(/*stage*/) {
|
renderNote({xMid = null, x0 = null, x1 = null}, anchor, mode, label) {
|
||||||
// TODO
|
const config = NOTE[mode];
|
||||||
|
|
||||||
|
const sz = config.labelAttrs['font-size'];
|
||||||
|
|
||||||
|
this.currentY += config.margin.top;
|
||||||
|
|
||||||
|
const labelNode = makeSVGNode('text', Object.assign({
|
||||||
|
'y': this.currentY + config.padding.top + sz,
|
||||||
|
'text-anchor': anchor,
|
||||||
|
}, config.labelAttrs));
|
||||||
|
labelNode.appendChild(makeText(label));
|
||||||
|
this.actions.appendChild(labelNode);
|
||||||
|
|
||||||
|
const w = labelNode.getComputedTextLength();
|
||||||
|
const fullW = w + config.padding.left + config.padding.right;
|
||||||
|
if(x0 === null && xMid !== null) {
|
||||||
|
x0 = xMid - fullW / 2;
|
||||||
|
}
|
||||||
|
if(x1 === null && x0 !== null) {
|
||||||
|
x1 = x0 + fullW;
|
||||||
|
} else if(x0 === null) {
|
||||||
|
x0 = x1 - fullW;
|
||||||
|
}
|
||||||
|
switch(anchor) {
|
||||||
|
case 'start':
|
||||||
|
labelNode.setAttribute('x', x0 + config.padding.left);
|
||||||
|
break;
|
||||||
|
case 'end':
|
||||||
|
labelNode.setAttribute('x', x1 - config.padding.right);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
labelNode.setAttribute('x', (
|
||||||
|
x0 + config.padding.left +
|
||||||
|
x1 - config.padding.right
|
||||||
|
) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.actions.insertBefore(config.boxRenderer({
|
||||||
|
x: x0,
|
||||||
|
y: this.currentY,
|
||||||
|
width: x1 - x0,
|
||||||
|
height: (
|
||||||
|
config.padding.top +
|
||||||
|
sz * LINE_HEIGHT +
|
||||||
|
config.padding.bottom
|
||||||
|
),
|
||||||
|
}), labelNode);
|
||||||
|
|
||||||
|
this.currentY += (
|
||||||
|
config.padding.top +
|
||||||
|
sz * LINE_HEIGHT +
|
||||||
|
config.padding.bottom +
|
||||||
|
config.margin.bottom +
|
||||||
|
ACTION_MARGIN
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderNoteLeft(/*stage*/) {
|
renderNoteOver({agents, mode, label}) {
|
||||||
// TODO
|
const config = NOTE[mode];
|
||||||
|
|
||||||
|
if(agents.length > 1) {
|
||||||
|
const {left, right} = this.findExtremes(agents);
|
||||||
|
this.renderNote({
|
||||||
|
x0: this.agentInfos.get(left).x - config.overlap.left,
|
||||||
|
x1: this.agentInfos.get(right).x + config.overlap.right,
|
||||||
|
}, 'middle', mode, label);
|
||||||
|
} else {
|
||||||
|
const xMid = this.agentInfos.get(agents[0]).x;
|
||||||
|
this.renderNote({xMid}, 'middle', mode, label);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderNoteRight(/*stage*/) {
|
renderNoteLeft({agents, mode, label}) {
|
||||||
// TODO
|
const config = NOTE[mode];
|
||||||
|
|
||||||
|
const {left} = this.findExtremes(agents);
|
||||||
|
const x1 = this.agentInfos.get(left).x - config.margin.right;
|
||||||
|
this.renderNote({x1}, 'end', mode, label);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderNoteBetween(/*stage*/) {
|
renderNoteRight({agents, mode, label}) {
|
||||||
// TODO
|
const config = NOTE[mode];
|
||||||
|
|
||||||
|
const {right} = this.findExtremes(agents);
|
||||||
|
const x0 = this.agentInfos.get(right).x + config.margin.left;
|
||||||
|
this.renderNote({x0}, 'start', mode, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderNoteBetween({agents, mode, label}) {
|
||||||
|
const {left, right} = this.findExtremes(agents);
|
||||||
|
const xMid = (
|
||||||
|
this.agentInfos.get(left).x +
|
||||||
|
this.agentInfos.get(right).x
|
||||||
|
) / 2;
|
||||||
|
|
||||||
|
this.renderNote({xMid}, 'middle', mode, label);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderBlockBegin(scope) {
|
renderBlockBegin(scope) {
|
||||||
|
@ -700,39 +943,39 @@ define(() => {
|
||||||
'height': this.currentY - scope.y,
|
'height': this.currentY - scope.y,
|
||||||
}, ATTRS.BLOCK_BOX)));
|
}, ATTRS.BLOCK_BOX)));
|
||||||
|
|
||||||
this.currentY += BLOCK_MARGIN.bottom;
|
this.currentY += BLOCK_MARGIN.bottom + ACTION_MARGIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
addAction(stage) {
|
addAction(stage) {
|
||||||
this.renderAction[stage.type](stage);
|
this.renderAction[stage.type](stage);
|
||||||
}
|
}
|
||||||
|
|
||||||
makeTextTester(attrs) {
|
testTextWidth(attrs, content) {
|
||||||
const text = makeText();
|
let tester = this.testersCache.get(attrs);
|
||||||
const node = makeSVGNode('text', attrs);
|
if(!tester) {
|
||||||
node.appendChild(text);
|
const text = makeText();
|
||||||
this.agentDecor.appendChild(node);
|
const node = makeSVGNode('text', attrs);
|
||||||
return {text, node};
|
node.appendChild(text);
|
||||||
}
|
this.testers.appendChild(node);
|
||||||
|
tester = {text, node};
|
||||||
|
this.testersCache.set(attrs, tester);
|
||||||
|
}
|
||||||
|
|
||||||
testTextWidth(tester, text) {
|
tester.text.nodeValue = content;
|
||||||
tester.text.nodeValue = text;
|
|
||||||
return tester.node.getComputedTextLength();
|
return tester.node.getComputedTextLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
removeTextTester(tester) {
|
|
||||||
this.agentDecor.removeChild(tester.node);
|
|
||||||
}
|
|
||||||
|
|
||||||
buildAgentInfos(agents, stages) {
|
buildAgentInfos(agents, stages) {
|
||||||
const testName = this.makeTextTester(ATTRS.AGENT_BOX_LABEL);
|
empty(this.testers);
|
||||||
|
this.testersCache.clear();
|
||||||
|
this.diagram.appendChild(this.testers);
|
||||||
|
|
||||||
this.agentInfos = new Map();
|
this.agentInfos = new Map();
|
||||||
agents.forEach((agent, index) => {
|
agents.forEach((agent, index) => {
|
||||||
this.agentInfos.set(agent, {
|
this.agentInfos.set(agent, {
|
||||||
label: agent,
|
label: agent,
|
||||||
labelWidth: (
|
labelWidth: (
|
||||||
this.testTextWidth(testName, agent) +
|
this.testTextWidth(ATTRS.AGENT_BOX_LABEL, agent) +
|
||||||
BOX_PADDING * 2
|
BOX_PADDING * 2
|
||||||
),
|
),
|
||||||
index,
|
index,
|
||||||
|
@ -744,16 +987,9 @@ define(() => {
|
||||||
this.agentInfos.get('[').labelWidth = 0;
|
this.agentInfos.get('[').labelWidth = 0;
|
||||||
this.agentInfos.get(']').labelWidth = 0;
|
this.agentInfos.get(']').labelWidth = 0;
|
||||||
|
|
||||||
this.removeTextTester(testName);
|
|
||||||
|
|
||||||
this.testConnect = this.makeTextTester(ATTRS.CONNECT_LABEL);
|
|
||||||
this.testBlockMode = this.makeTextTester(ATTRS.BLOCK_MODE_LABEL);
|
|
||||||
this.testBlockLabel = this.makeTextTester(ATTRS.BLOCK_LABEL);
|
|
||||||
this.visibleAgents = ['[', ']'];
|
this.visibleAgents = ['[', ']'];
|
||||||
traverse(stages, this.separationTraversalFns);
|
traverse(stages, this.separationTraversalFns);
|
||||||
this.removeTextTester(this.testConnect);
|
this.diagram.removeChild(this.testers);
|
||||||
this.removeTextTester(this.testBlockMode);
|
|
||||||
this.removeTextTester(this.testBlockLabel);
|
|
||||||
|
|
||||||
agents.forEach((agent) => {
|
agents.forEach((agent) => {
|
||||||
const agentInfo = this.agentInfos.get(agent);
|
const agentInfo = this.agentInfos.get(agent);
|
||||||
|
|
Loading…
Reference in New Issue