chore(bpmn-snapping): move participant fitting to participant behavior

Related to #1290
This commit is contained in:
Philipp Fromme 2019-06-03 10:46:52 +02:00 committed by Nico Rehwaldt
parent 8862865e2a
commit ca12ac91a4
5 changed files with 470 additions and 350 deletions

View File

@ -4,23 +4,81 @@ 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 } from 'min-dash';
var HORIZONTAL_PARTICIPANT_PADDING = 20,
VERTICAL_PARTICIPANT_PADDING = 20,
PARTICIPANT_BORDER_WIDTH = 30;
var HIGH_PRIORITY = 2000;
/**
* BPMN specific create participant behavior
* BPMN-specific behavior for creating participants.
*/
export default function CreateParticipantBehavior(
eventBus, modeling, elementFactory,
bpmnFactory, canvas) {
export default function CreateParticipantBehavior(canvas, eventBus, modeling) {
CommandInterceptor.call(this, eventBus);
/**
* morph process into collaboration before adding
* participant onto collaboration
*/
// 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);
});
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);
});
}
});
// turn process into collaboration before adding participant
this.preExecute('shape.create', function(context) {
var parent = context.parent,
shape = context.shape,
position = context.position;
@ -48,9 +106,7 @@ export default function CreateParticipantBehavior(
}
}, true);
this.execute('shape.create', function(context) {
var processRoot = context.processRoot,
shape = context.shape;
@ -62,39 +118,63 @@ export default function CreateParticipantBehavior(
}
}, true);
this.revert('shape.create', function(context) {
var processRoot = context.processRoot,
shape = context.shape;
if (processRoot) {
// assign the participant processRef
shape.businessObject.processRef = context.oldProcessRef;
}
}, true);
this.postExecute('shape.create', function(context) {
var processRoot = context.processRoot,
shape = context.shape;
if (processRoot) {
// process root is already detached at this point
var processChildren = processRoot.children.slice();
modeling.moveElements(processChildren, { x: 0, y: 0 }, shape);
}
}, true);
}
CreateParticipantBehavior.$inject = [
'canvas',
'eventBus',
'modeling',
'elementFactory',
'bpmnFactory',
'canvas'
'modeling'
];
inherits(CreateParticipantBehavior, CommandInterceptor);
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
};
return {
width: Math.max(shape.width, childrenBBox.width),
height: Math.max(shape.height, childrenBBox.height)
};
}
function getParticipantCreateConstraints(shape, childrenBBox) {
return {
bottom: childrenBBox.y + shape.height / 2 - VERTICAL_PARTICIPANT_PADDING,
left: childrenBBox.x + childrenBBox.width - shape.width / 2 + HORIZONTAL_PARTICIPANT_PADDING,
top: childrenBBox.y + childrenBBox.height - shape.height / 2 + VERTICAL_PARTICIPANT_PADDING,
right: childrenBBox.x + shape.width / 2 - HORIZONTAL_PARTICIPANT_PADDING - PARTICIPANT_BORDER_WIDTH
};
}
function isConnection(element) {
return !!element.waypoints;
}

View File

@ -5,41 +5,30 @@ import {
isNumber
} from 'min-dash';
import {
getBBox as getBoundingBox
} from 'diagram-js/lib/util/Elements';
import Snapping from 'diagram-js/lib/features/snapping/Snapping';
import { is } from '../../util/ModelUtil';
import { isAny } from '../modeling/util/ModelingUtil';
import {
isExpanded
} from '../../util/DiUtil';
import Snapping from 'diagram-js/lib/features/snapping/Snapping';
import { isExpanded } from '../../util/DiUtil';
import {
mid,
topLeft,
bottomRight,
isSnapped,
setSnapped
mid,
setSnapped,
topLeft
} from 'diagram-js/lib/features/snapping/SnapUtil';
import {
asTRBL
} from 'diagram-js/lib/layout/LayoutUtil';
import { asTRBL } from 'diagram-js/lib/layout/LayoutUtil';
import {
getBoundaryAttachment,
getParticipantSizeConstraints
} from './BpmnSnappingUtil';
import {
getLanesRoot
} from '../modeling/util/LaneUtil';
import { getLanesRoot } from '../modeling/util/LaneUtil';
var round = Math.round;
@ -47,59 +36,14 @@ var HIGH_PRIORITY = 1500;
/**
* BPMN specific snapping functionality
*
* * snap on process elements if a pool is created inside a
* process diagram
* BPMN-specific snapping.
*
* @param {EventBus} eventBus
* @param {Canvas} canvas
*/
export default function BpmnSnapping(eventBus, canvas, bpmnRules, elementRegistry) {
// instantiate super
export default function BpmnSnapping(bpmnRules, canvas, elementRegistry, eventBus) {
Snapping.call(this, eventBus, canvas);
/**
* Drop participant on process <> process elements snapping
*/
eventBus.on('create.start', function(event) {
var context = event.context,
shape = context.shape,
rootElement = canvas.getRootElement();
// snap participant around existing elements (if any)
if (is(shape, 'bpmn:Participant') && is(rootElement, 'bpmn:Process')) {
initParticipantSnapping(context, shape, rootElement.children);
}
});
eventBus.on([ 'create.move', 'create.end' ], HIGH_PRIORITY, function(event) {
var context = event.context,
shape = context.shape,
participantSnapBox = context.participantSnapBox;
if (!isSnapped(event) && participantSnapBox) {
snapParticipant(participantSnapBox, shape, event);
}
});
eventBus.on('shape.move.start', function(event) {
var context = event.context,
shape = context.shape,
rootElement = canvas.getRootElement();
// snap participant around existing elements (if any)
if (is(shape, 'bpmn:Participant') && is(rootElement, 'bpmn:Process')) {
initParticipantSnapping(context, shape, rootElement.children);
}
});
function canAttach(shape, target, position) {
return bpmnRules.canAttach([ shape ], target, null, position) === 'attach';
}
@ -108,6 +52,9 @@ export default function BpmnSnapping(eventBus, canvas, bpmnRules, elementRegistr
return bpmnRules.canConnect(source, target);
}
// creating first participant
eventBus.on([ 'create.move', 'create.end' ], HIGH_PRIORITY, setSnappedIfConstrained);
/**
* Snap boundary events to elements border
*/
@ -233,15 +180,13 @@ export default function BpmnSnapping(eventBus, canvas, bpmnRules, elementRegistr
inherits(BpmnSnapping, Snapping);
BpmnSnapping.$inject = [
'eventBus',
'canvas',
'bpmnRules',
'elementRegistry'
'canvas',
'elementRegistry',
'eventBus'
];
BpmnSnapping.prototype.initSnap = function(event) {
var context = event.context,
shape = event.shape,
shapeMid,
@ -250,11 +195,11 @@ BpmnSnapping.prototype.initSnap = function(event) {
shapeBottomRight,
snapContext;
snapContext = Snapping.prototype.initSnap.call(this, event);
if (is(shape, 'bpmn:Participant')) {
// assign higher priority for outer snaps on participants
// snap to borders with higher priority
snapContext.setSnapLocations([ 'top-left', 'bottom-right', 'mid' ]);
}
@ -393,67 +338,7 @@ BpmnSnapping.prototype.addTargetSnaps = function(snapPoints, shape, target) {
});
};
// participant snapping //////////////////////
function initParticipantSnapping(context, shape, elements) {
if (!elements.length) {
return;
}
var snapBox = getBoundingBox(elements.filter(function(e) {
return !e.labelTarget && !e.waypoints && !is(e, 'bpmn:Group');
}));
snapBox.x -= 50;
snapBox.y -= 20;
snapBox.width += 70;
snapBox.height += 40;
// adjust shape height to include bounding box
shape.width = Math.max(shape.width, snapBox.width);
shape.height = Math.max(shape.height, snapBox.height);
context.participantSnapBox = snapBox;
}
function snapParticipant(snapBox, shape, event, offset) {
offset = offset || 0;
var shapeHalfWidth = shape.width / 2 - offset,
shapeHalfHeight = shape.height / 2;
var currentTopLeft = {
x: event.x - shapeHalfWidth - offset,
y: event.y - shapeHalfHeight
};
var currentBottomRight = {
x: event.x + shapeHalfWidth + offset,
y: event.y + shapeHalfHeight
};
var snapTopLeft = snapBox,
snapBottomRight = bottomRight(snapBox);
if (currentTopLeft.x >= snapTopLeft.x) {
setSnapped(event, 'x', snapTopLeft.x + offset + shapeHalfWidth);
} else
if (currentBottomRight.x <= snapBottomRight.x) {
setSnapped(event, 'x', snapBottomRight.x - offset - shapeHalfWidth);
}
if (currentTopLeft.y >= snapTopLeft.y) {
setSnapped(event, 'y', snapTopLeft.y + shapeHalfHeight);
} else
if (currentBottomRight.y <= snapBottomRight.y) {
setSnapped(event, 'y', snapBottomRight.y - shapeHalfHeight);
}
}
// boundary event snapping //////////////////////
// helpers //////////
function snapBoundaryEvent(event, shape, target) {
var targetTRBL = asTRBL(target);
@ -479,4 +364,26 @@ function snapBoundaryEvent(event, shape, target) {
function snapToPosition(event, position) {
setSnapped(event, 'x', position.x);
setSnapped(event, 'y', position.y);
}
function setSnappedIfConstrained(event) {
var context = event.context,
createConstraints = context.createConstraints;
if (!createConstraints) {
return;
}
var top = createConstraints.top,
right = createConstraints.right,
bottom = createConstraints.bottom,
left = createConstraints.left;
if ((left && left >= event.x) || (right && right <= event.x)) {
setSnapped(event, 'x', event.x);
}
if ((top && top >= event.y) || (bottom && bottom <= event.y)) {
setSnapped(event, 'y', event.y);
}
}

View File

@ -153,5 +153,5 @@ export function getExternalLabelBounds(semantic, element) {
}
export function isLabel(element) {
return element && element.labelTarget;
return element && !!element.labelTarget;
}

View File

@ -3,220 +3,394 @@ import {
inject
} from 'test/TestHelper';
import modelingModule from 'lib/features/modeling';
import coreModule from 'lib/core';
import createModule from 'diagram-js/lib/features/create';
import modelingModule from 'lib/features/modeling';
import {
getBBox
} from 'diagram-js/lib/util/Elements';
import { asTRBL } from 'diagram-js/lib/layout/LayoutUtil';
import {
createCanvasEvent as canvasEvent
} from '../../../../util/MockEvents';
describe('features/modeling - create participant', function() {
var testModules = [ coreModule, modelingModule ];
var testModules = [
coreModule,
createModule,
modelingModule
];
describe('process', function() {
describe('on process diagram', function() {
describe('should transform diagram into collaboration', function() {
describe('should turn diagram into collaboration', function() {
var processDiagramXML = require('../../../../fixtures/bpmn/collaboration/process-empty.bpmn');
beforeEach(bootstrapModeler(processDiagramXML, { modules: testModules }));
var collaboration,
collaborationBo,
collaborationDi,
diRoot,
participant,
participantBo,
participantDi,
process,
processBo,
processDi;
it('execute', inject(function(modeling, elementFactory, canvas) {
beforeEach(inject(function(canvas, elementFactory, modeling) {
// given
var processShape = canvas.getRootElement(),
process = processShape.businessObject,
participantShape = elementFactory.createParticipantShape(true),
participant = participantShape.businessObject,
diRoot = process.di.$parent;
process = canvas.getRootElement();
processBo = process.businessObject;
processDi = processBo.di;
diRoot = processBo.di.$parent;
participant = elementFactory.createParticipantShape();
participantBo = participant.businessObject;
participantDi = participantBo.di;
// when
modeling.createShape(participantShape, { x: 350, y: 200 }, processShape);
modeling.createShape(participant, { x: 350, y: 200 }, process);
// then
expect(participant.processRef).to.eql(process);
var collaborationRoot = canvas.getRootElement(),
collaboration = collaborationRoot.businessObject,
collaborationDi = collaboration.di;
expect(collaboration.$instanceOf('bpmn:Collaboration')).to.be.true;
// participant / collaboration are wired
expect(participant.$parent).to.eql(collaboration);
expect(collaboration.participants).to.include(participant);
// collaboration is added to root elements
expect(collaboration.$parent).to.eql(process.$parent);
// di is wired
var participantDi = participant.di;
expect(participantDi.$parent).to.eql(collaborationDi);
expect(collaborationDi.$parent).to.eql(diRoot);
collaboration = canvas.getRootElement();
collaborationBo = collaboration.businessObject;
collaborationDi = collaborationBo.di;
}));
it('undo', inject(function(modeling, elementFactory, canvas, commandStack) {
it('execute', function() {
// given
var processShape = canvas.getRootElement(),
process = processShape.businessObject,
processDi = process.di,
participantShape = elementFactory.createParticipantShape(true),
participant = participantShape.businessObject,
oldParticipantProcessRef = participant.processRef,
diRoot = process.di.$parent;
// then
expect(participantBo.$parent).to.equal(collaborationBo);
expect(participantBo.processRef).to.equal(processBo);
modeling.createShape(participantShape, { x: 350, y: 200 }, processShape);
expect(collaborationBo.$instanceOf('bpmn:Collaboration')).to.be.true;
expect(collaborationBo.$parent).to.equal(processBo.$parent);
expect(collaborationBo.participants).to.include(participantBo);
var collaborationRoot = canvas.getRootElement(),
collaboration = collaborationRoot.businessObject;
expect(participantDi.$parent).to.equal(collaborationDi);
expect(collaborationDi.$parent).to.equal(diRoot);
});
it('undo', inject(function(commandStack) {
// when
commandStack.undo();
// then
expect(participant.processRef).to.eql(oldParticipantProcessRef);
expect(participantBo.$parent).not.to.exist;
expect(participantBo.processRef).not.to.equal(processBo);
expect(participant.$parent).to.be.null;
expect(collaboration.participants).not.to.include(participant);
expect(collaborationBo.$parent).not.to.exist;
expect(collaborationBo.participants).not.to.include(participantBo);
// collaboration is detached
expect(collaboration.$parent).to.be.null;
// di is wired
expect(processDi.$parent).to.eql(diRoot);
expect(processDi.$parent).to.equal(diRoot);
}));
});
describe('should wrap existing elements', function() {
describe('should move existing elements', function() {
var processDiagramXML = require('../../../../fixtures/bpmn/collaboration/process.bpmn');
beforeEach(bootstrapModeler(processDiagramXML, { modules: testModules }));
var collaboration,
collaborationBo,
collaborationDi,
participant,
process,
processBo,
processDi;
it('execute', inject(function(modeling, elementFactory, canvas) {
beforeEach(inject(function(canvas, elementFactory, modeling) {
// given
var processShape = canvas.getRootElement(),
process = processShape.businessObject,
participantShape = elementFactory.createParticipantShape(true),
participant = participantShape.businessObject;
process = canvas.getRootElement();
processBo = process.businessObject;
processDi = processBo.di;
participant = elementFactory.createParticipantShape();
// when
modeling.createShape(participantShape, { x: 350, y: 200 }, processShape);
modeling.createShape(participant, { x: 350, y: 200 }, process);
// then
expect(participant.processRef).to.eql(process);
var newRootShape = canvas.getRootElement(),
collaboration = newRootShape.businessObject;
expect(collaboration.$instanceOf('bpmn:Collaboration')).to.be.true;
expect(participant.$parent).to.eql(collaboration);
expect(collaboration.participants).to.include(participant);
collaboration = canvas.getRootElement();
collaborationBo = collaboration.businessObject;
collaborationDi = collaborationBo.di;
}));
it('undo', inject(function(modeling, elementFactory, elementRegistry, canvas, commandStack) {
it('execute', function() {
// given
var processShape = canvas.getRootElement(),
participantShape = elementFactory.createParticipantShape(true);
// then
expect(collaboration.children).to.have.length(4);
modeling.createShape(participantShape, { x: 350, y: 200 }, processShape);
collaboration.children.forEach(function(child) {
var childBo = child.businessObject,
childDi = childBo.di;
expect(childDi.$parent).to.eql(collaborationDi);
expect(collaborationDi.planeElement).to.include(childDi);
});
expect(participant.children).to.have.length(5);
participant.children.forEach(function(child) {
var childBo = child.businessObject,
childDi = childBo.di;
expect(childDi.$parent).to.eql(collaborationDi);
expect(collaborationDi.planeElement).to.include(childDi);
});
});
it('undo', inject(function(commandStack) {
// when
commandStack.undo();
var startEventElement = elementRegistry.get('StartEvent_1'),
startEventDi = startEventElement.businessObject.di,
rootElement = canvas.getRootElement(),
rootShapeDi = rootElement.businessObject.di;
expect(process.children).to.have.length(8);
// then
expect(participantShape.children.length).to.equal(0);
expect(processShape.children.length).to.equal(8);
process.children.forEach(function(child) {
var childBo = child.businessObject,
childDi = childBo.di;
// children di is wired
expect(startEventDi.$parent).to.eql(rootShapeDi);
expect(rootShapeDi.planeElement).to.include(startEventDi);
expect(childDi.$parent).to.eql(processDi);
expect(processDi.planeElement).to.include(childDi);
});
expect(participant.children.length).to.equal(0);
}));
it('should detach DI on update canvas root', inject(
function(canvas, elementFactory, commandStack, modeling, elementRegistry) {
it('should detach DI when turning process into collaboration', inject(function(modeling) {
// when
modeling.makeCollaboration();
// when
modeling.makeCollaboration();
var startEventElement = elementRegistry.get('StartEvent_1'),
startEventDi = startEventElement.businessObject.di,
rootElement = canvas.getRootElement(),
rootShapeDi = rootElement.businessObject.di;
// then
process.children.forEach(function(child) {
var childBo = child.businessObject,
childDi = childBo.di;
// then
expect(startEventDi.$parent).not.to.be.ok;
expect(rootShapeDi.planeElement).not.to.include(startEventDi);
expect(childDi.$parent).not.to.exist;
expect(processDi.planeElement).not.to.include(childDi);
});
}));
});
describe('hovering process when creating first participant', function() {
var processDiagramXML = require('../../../../fixtures/bpmn/collaboration/process.bpmn');
beforeEach(bootstrapModeler(processDiagramXML, { modules: testModules }));
var participant,
process,
processGfx,
subProcess,
subProcessGfx;
beforeEach(inject(function(canvas, elementFactory, elementRegistry) {
// given
process = canvas.getRootElement();
processGfx = canvas.getGraphics(process);
participant = elementFactory.createParticipantShape();
subProcess = elementRegistry.get('SubProcess_1');
subProcessGfx = canvas.getGraphics(subProcess);
}));
it('should ensure hovering process', inject(function(create, dragging, eventBus) {
// given
create.start(canvasEvent({ x: 100, y: 100 }), participant);
var event = eventBus.createEvent({
element: subProcess,
gfx: subProcessGfx
});
// when
eventBus.fire('element.hover', event);
// then
expect(event.element).to.equal(process);
expect(event.gfx).to.equal(processGfx);
}));
it('should clean up', inject(function(create, dragging, eventBus) {
// given
create.start(canvasEvent({ x: 100, y: 100 }), participant);
// when
dragging.end();
// then
var event = eventBus.createEvent({
element: subProcess,
gfx: subProcessGfx
});
eventBus.fire('element.hover', event);
expect(event.element).to.equal(subProcess);
expect(event.gfx).to.equal(subProcessGfx);
}));
});
describe('fitting participant (default size)', function() {
var processDiagramXML = require('../../../../fixtures/bpmn/collaboration/process.bpmn');
beforeEach(bootstrapModeler(processDiagramXML, { modules: testModules }));
var participant,
participantBo,
process,
processGfx;
beforeEach(inject(function(canvas, create, dragging, elementFactory) {
// given
process = canvas.getRootElement();
processGfx = canvas.getGraphics(process);
participant = elementFactory.createParticipantShape();
participantBo = participant.businessObject;
create.start(canvasEvent({ x: 100, y: 100 }), participant);
dragging.hover({ element: process, gfx: processGfx });
}));
it('should fit participant', inject(function(elementFactory) {
// then
var defaultSize = elementFactory._getDefaultSize(participantBo);
expect(participant.width).to.equal(defaultSize.width);
expect(participant.height).to.equal(defaultSize.height);
}));
describe('create constraints', function() {
function expectBoundsWithin(inner, outer, padding) {
expect(inner.top >= outer.top + padding.top).to.be.true;
expect(inner.right <= outer.right - padding.right).to.be.true;
expect(inner.bottom <= outer.bottom - padding.bottom).to.be.true;
expect(inner.left >= outer.left + padding.left).to.be.true;
}
));
var padding = {
top: 20,
right: 20,
bottom: 20,
left: 50
};
[
{ x: 0, y: 0 },
{ x: 1000, y: 0 },
{ x: 0, y: 1000 },
{ x: 1000, y: 1000 }
].forEach(function(position) {
it('should constrain ' + JSON.stringify(position), inject(function(dragging) {
// when
dragging.move(canvasEvent(position));
dragging.end();
// then
expectBoundsWithin(
asTRBL(getBBox(participant.children)),
asTRBL(getBBox(participant)),
padding
);
}));
});
});
});
});
describe('should add to collaboration', function() {
describe('collaboration', function() {
var collaborationDiagramXML = require('../../../../fixtures/bpmn/collaboration/collaboration-participant.bpmn');
var collaborationDiagramXML =
require('../../../../fixtures/bpmn/collaboration/collaboration-participant.bpmn');
beforeEach(bootstrapModeler(collaborationDiagramXML, { modules: testModules }));
var collaborationBo,
participant,
participantBo,
rootElement;
it('execute', inject(function(modeling, elementFactory, canvas) {
beforeEach(inject(function(canvas, elementFactory, modeling) {
// given
var collaborationRoot = canvas.getRootElement(),
collaboration = collaborationRoot.businessObject,
participantShape = elementFactory.createParticipantShape(true),
participant = participantShape.businessObject;
rootElement = canvas.getRootElement();
collaborationBo = rootElement.businessObject;
participant = elementFactory.createParticipantShape();
participantBo = participant.businessObject;
// when
modeling.createShape(participantShape, { x: 350, y: 500 }, collaborationRoot);
// then
expect(collaborationRoot.children).to.include(participantShape);
expect(participant.$parent).to.eql(collaboration);
expect(collaboration.participants).to.include(participant);
modeling.createShape(participant, { x: 350, y: 500 }, rootElement);
}));
it('undo', inject(function(modeling, elementFactory, canvas, commandStack) {
it('execute', function() {
// given
var collaborationRoot = canvas.getRootElement(),
collaboration = collaborationRoot.businessObject,
participantShape = elementFactory.createParticipantShape(true),
participant = participantShape.businessObject;
// then
expect(rootElement.children).to.include(participant);
modeling.createShape(participantShape, { x: 350, y: 500 }, collaborationRoot);
expect(participantBo.$parent).to.equal(collaborationBo);
expect(collaborationBo.participants).to.include(participantBo);
});
it('undo', inject(function(commandStack) {
// when
commandStack.undo();
// then
expect(collaborationRoot.children).not.to.include(participantShape);
expect(rootElement.children).not.to.include(participant);
expect(participant.$parent).not.to.be.ok;
expect(collaboration.participants).not.to.include(participant);
expect(participantBo.$parent).not.to.exist;
expect(collaborationBo.participants).not.to.include(participantBo);
}));
});

View File

@ -3,6 +3,8 @@ import {
inject
} from 'test/TestHelper';
import TestContainer from 'mocha-test-container-support';
import {
createCanvasEvent as canvasEvent
} from '../../../util/MockEvents';
@ -16,6 +18,8 @@ import moveModule from 'diagram-js/lib/features/move';
import rulesModule from 'lib/features/rules';
import connectModule from 'diagram-js/lib/features/connect';
import { isSnapped } from 'diagram-js/lib/features/snapping/SnapUtil';
describe('features/snapping - BpmnSnapping', function() {
@ -29,7 +33,7 @@ describe('features/snapping - BpmnSnapping', function() {
connectModule
];
describe('general', function() {
describe('on itself', function() {
var diagramXML = require('./BpmnSnapping.general.bpmn');
@ -75,6 +79,7 @@ describe('features/snapping - BpmnSnapping', function() {
});
describe('on Boundary Events', function() {
var diagramXML = require('../../../fixtures/bpmn/collaboration/process.bpmn');
@ -304,89 +309,43 @@ describe('features/snapping - BpmnSnapping', function() {
var diagramXML = require('../../../fixtures/bpmn/collaboration/process.bpmn');
beforeEach(bootstrapModeler(diagramXML, {
modules: testModules
}));
it('should set snapped if outside of constraints', function(done) {
beforeEach(inject(function(dragging) {
dragging.setOptions({ manual: true });
}));
it('should snap to process children bounds / top left',
inject(function(canvas, create, dragging, elementFactory) {
// given
var participantShape = elementFactory.createParticipantShape(false),
rootElement = canvas.getRootElement(),
rootGfx = canvas.getGraphics(rootElement);
bootstrapModeler(diagramXML, {
container: TestContainer.get(this),
modules: testModules
})(function() {
// when
create.start(canvasEvent({ x: 50, y: 50 }), participantShape);
inject(function(canvas, create, dragging, elementFactory, eventBus) {
dragging.hover({ element: rootElement, gfx: rootGfx });
// given
dragging.setOptions({ manual: true });
dragging.move(canvasEvent({ x: 65, y: 65 }));
dragging.end(canvasEvent({ x: 65, y: 65 }));
var participantShape = elementFactory.createParticipantShape(false),
rootElement = canvas.getRootElement(),
rootGfx = canvas.getGraphics(rootElement);
// then
expect(participantShape).to.have.bounds({
width: 600, height: 250, x: 18, y: -8
});
})
);
create.start(canvasEvent({ x: 50, y: 50 }), participantShape);
dragging.hover({ element: rootElement, gfx: rootGfx });
it('should not snap to group bounds',
inject(function(canvas, create, dragging, elementFactory, elementRegistry) {
eventBus.once('create.move', function(event) {
// given
var participantShape = elementFactory.createParticipantShape(false),
rootElement = canvas.getRootElement(),
rootGfx = canvas.getGraphics(rootElement),
groupElement = elementRegistry.get('Group_1');
// then
// expect snapped to avoid snapping outside of constraints
expect(isSnapped(event)).to.be.true;
// when
create.start(canvasEvent({ x: 50, y: 50 }), participantShape);
done();
});
dragging.hover({ element: rootElement, gfx: rootGfx });
// when
dragging.move(canvasEvent({ x: 0, y: 0 }));
})();
dragging.move(canvasEvent({ x: 400, y: 400 }));
dragging.end(canvasEvent({ x: 400, y: 400 }));
});
// then
var totalWidth = groupElement.x + groupElement.width + 70,
totalHeight = groupElement.y + groupElement.height + 40;
expect(participantShape).not.to.have.bounds({
width: totalWidth, height: totalHeight, x: 100, y: 52
});
})
);
it('should snap to process children bounds / bottom right',
inject(function(canvas, create, dragging, elementFactory) {
// given
var participantShape = elementFactory.createParticipantShape(false),
rootElement = canvas.getRootElement(),
rootGfx = canvas.getGraphics(rootElement);
// when
create.start(canvasEvent({ x: 50, y: 50 }), participantShape);
dragging.hover({ element: rootElement, gfx: rootGfx });
dragging.move(canvasEvent({ x: 400, y: 400 }));
dragging.end(canvasEvent({ x: 400, y: 400 }));
// then
expect(participantShape).to.have.bounds({
width: 600, height: 250, x: 100, y: 52
});
})
);
});
});
@ -1188,4 +1147,4 @@ describe('features/snapping - BpmnSnapping', function() {
});
});
});