bpmn-js/lib/features/modeling/behavior/CreateParticipantBehavior.js

255 lines
6.7 KiB
JavaScript

import inherits from 'inherits';
import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
import { is } from '../../../util/ModelUtil';
import { isLabel } from '../../../util/LabelUtil';
import { getBBox } from 'diagram-js/lib/util/Elements';
import {
assign,
find
} from 'min-dash';
import { asTRBL } from 'diagram-js/lib/layout/LayoutUtil';
var HORIZONTAL_PARTICIPANT_PADDING = 20,
VERTICAL_PARTICIPANT_PADDING = 20;
export var PARTICIPANT_BORDER_WIDTH = 30;
var HIGH_PRIORITY = 2000;
/**
* BPMN-specific behavior for creating participants.
*/
export default function CreateParticipantBehavior(canvas, eventBus, modeling) {
CommandInterceptor.call(this, eventBus);
// fit participant
eventBus.on([
'create.start',
'shape.move.start'
], HIGH_PRIORITY, function(event) {
var context = event.context,
shape = context.shape,
rootElement = canvas.getRootElement();
if (!is(shape, 'bpmn:Participant') ||
!is(rootElement, 'bpmn:Process') ||
!rootElement.children.length) {
return;
}
// ignore connections, groups and labels
var children = rootElement.children.filter(function(element) {
return !is(element, 'bpmn:Group') &&
!isLabel(element) &&
!isConnection(element);
});
// ensure for available children to calculate bounds
if (!children.length) {
return;
}
var childrenBBox = getBBox(children);
var participantBounds = getParticipantBounds(shape, childrenBBox);
// assign width and height
assign(shape, participantBounds);
// assign create constraints
context.createConstraints = getParticipantCreateConstraints(shape, childrenBBox);
});
// force hovering process when creating first participant
eventBus.on('create.start', HIGH_PRIORITY, function(event) {
var context = event.context,
shape = context.shape,
rootElement = canvas.getRootElement(),
rootElementGfx = canvas.getGraphics(rootElement);
function ensureHoveringProcess(event) {
event.element = rootElement;
event.gfx = rootElementGfx;
}
if (is(shape, 'bpmn:Participant') && is(rootElement, 'bpmn:Process')) {
eventBus.on('element.hover', HIGH_PRIORITY, ensureHoveringProcess);
eventBus.once('create.cleanup', function() {
eventBus.off('element.hover', ensureHoveringProcess);
});
}
});
function ensureCollaboration(context) {
var parent = context.parent,
collaboration;
var rootElement = canvas.getRootElement();
if (is(rootElement, 'bpmn:Collaboration')) {
collaboration = rootElement;
} else {
// update root element by making collaboration
collaboration = modeling.makeCollaboration();
// re-use process when creating first participant
context.process = parent;
}
context.parent = collaboration;
}
// turn process into collaboration before adding participant
this.preExecute('shape.create', function(context) {
var parent = context.parent,
shape = context.shape;
if (is(shape, 'bpmn:Participant') && is(parent, 'bpmn:Process')) {
ensureCollaboration(context);
}
}, true);
this.execute('shape.create', function(context) {
var process = context.process,
shape = context.shape;
if (process) {
context.oldProcessRef = shape.businessObject.processRef;
// re-use process when creating first participant
shape.businessObject.processRef = process.businessObject;
}
}, true);
this.revert('shape.create', function(context) {
var process = context.process,
shape = context.shape;
if (process) {
// re-use process when creating first participant
shape.businessObject.processRef = context.oldProcessRef;
}
}, true);
this.postExecute('shape.create', function(context) {
var process = context.process,
shape = context.shape;
if (process) {
// move children from process to participant
var processChildren = process.children.slice();
modeling.moveElements(processChildren, { x: 0, y: 0 }, shape);
}
}, true);
// turn process into collaboration when creating participants
this.preExecute('elements.create', HIGH_PRIORITY, function(context) {
var elements = context.elements,
parent = context.parent,
participant;
var hasParticipants = findParticipant(elements);
if (hasParticipants && is(parent, 'bpmn:Process')) {
ensureCollaboration(context);
participant = findParticipant(elements);
context.oldProcessRef = participant.businessObject.processRef;
// re-use process when creating first participant
participant.businessObject.processRef = parent.businessObject;
}
}, true);
this.revert('elements.create', function(context) {
var elements = context.elements,
process = context.process,
participant;
if (process) {
participant = findParticipant(elements);
// re-use process when creating first participant
participant.businessObject.processRef = context.oldProcessRef;
}
}, true);
this.postExecute('elements.create', function(context) {
var elements = context.elements,
process = context.process,
participant;
if (process) {
participant = findParticipant(elements);
// move children from process to first participant
var processChildren = process.children.slice();
modeling.moveElements(processChildren, { x: 0, y: 0 }, participant);
}
}, true);
}
CreateParticipantBehavior.$inject = [
'canvas',
'eventBus',
'modeling'
];
inherits(CreateParticipantBehavior, CommandInterceptor);
// helpers //////////
function getParticipantBounds(shape, childrenBBox) {
childrenBBox = {
width: childrenBBox.width + HORIZONTAL_PARTICIPANT_PADDING * 2 + PARTICIPANT_BORDER_WIDTH,
height: childrenBBox.height + VERTICAL_PARTICIPANT_PADDING * 2
};
var width = Math.max(shape.width, childrenBBox.width),
height = Math.max(shape.height, childrenBBox.height);
return {
x: -width / 2,
y: -height / 2,
width: width,
height: height
};
}
function getParticipantCreateConstraints(shape, childrenBBox) {
childrenBBox = asTRBL(childrenBBox);
return {
bottom: childrenBBox.top + shape.height / 2 - VERTICAL_PARTICIPANT_PADDING,
left: childrenBBox.right - shape.width / 2 + HORIZONTAL_PARTICIPANT_PADDING,
top: childrenBBox.bottom - shape.height / 2 + VERTICAL_PARTICIPANT_PADDING,
right: childrenBBox.left + shape.width / 2 - HORIZONTAL_PARTICIPANT_PADDING - PARTICIPANT_BORDER_WIDTH
};
}
function isConnection(element) {
return !!element.waypoints;
}
function findParticipant(elements) {
return find(elements, function(element) {
return is(element, 'bpmn:Participant');
});
}