feat(snapping): snap participant to child lane border

This commit is contained in:
Nico Rehwaldt 2015-08-24 16:59:13 +02:00
parent b0ce4d834d
commit 834f1844ec
6 changed files with 219 additions and 40 deletions

View File

@ -116,11 +116,11 @@ function BpmnSnapping(eventBus, canvas, bpmnRules) {
} }
if (is(shape, 'bpmn:Participant')) { if (is(shape, 'bpmn:Participant')) {
context.minDimensions = { width: 300, height: 150 }; context.minDimensions = { width: 300, height: 150 };
context.childrenBoxPadding = { }
left: 50,
right: 35 if (is(shape, 'bpmn:Participant') || is(shape, 'bpmn:Lane')) {
}; context.minBounds = computeParticipantMinBounds(shape);
} }
if (is(shape, 'bpmn:TextAnnotation')) { if (is(shape, 'bpmn:TextAnnotation')) {
@ -342,4 +342,47 @@ function snapBoundaryEvent(event, shape, target) {
if (/right/.test(direction)) { if (/right/.test(direction)) {
setSnapped(event, 'x', targetTRBL.right); setSnapped(event, 'x', targetTRBL.right);
} }
}
//////// participant / lane min bounds
var getBBox = require('diagram-js/lib/util/Elements').getBBox,
addPadding = require('diagram-js/lib/features/resize/ResizeUtil').addPadding;
function computeParticipantMinBounds(element) {
var lanePadding = {
left: 30,
top: 0,
right: 0,
bottom: 0
};
var flowElementPadding = {
left: 50,
right: 35
};
function getChildBox(child) {
if (is(child, 'bpmn:Lane')) {
return addPadding(child, lanePadding);
}
if (child.labelTarget || child.waypoints) {
return null;
}
return addPadding(child, flowElementPadding);
}
function nonNull(e) {
return !!e;
}
var childrenBoxes = element.children.map(getChildBox).filter(nonNull);
if (childrenBoxes.length) {
return getBBox(childrenBoxes);
}
} }

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn:collaboration id="Collaboration">
<bpmn:participant id="Participant" name="Participant" processRef="Process" />
</bpmn:collaboration>
<bpmn:process id="Process" isExecutable="false">
<bpmn:laneSet>
<bpmn:lane id="Lane_A" name="Lane_A" />
<bpmn:lane id="Lane_B_0" name="Lane_B_0">
<bpmn:childLaneSet xsi:type="bpmn:tLaneSet">
<bpmn:lane id="Lane_B_1" name="Lane_B_1" />
</bpmn:childLaneSet>
</bpmn:lane>
</bpmn:laneSet>
<bpmn:startEvent id="StartEvent" />
<bpmn:task id="Task" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration">
<bpmndi:BPMNShape id="Participant_di" bpmnElement="Participant">
<dc:Bounds x="123" y="49" width="600" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="StartEvent_di" bpmnElement="StartEvent">
<dc:Bounds x="210" y="96" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="183" y="132" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_A_di" bpmnElement="Lane_A">
<dc:Bounds x="153" y="49" width="570" height="132" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_B_0_di" bpmnElement="Lane_B_0">
<dc:Bounds x="153" y="181" width="570" height="118" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_di" bpmnElement="Task">
<dc:Bounds x="345.84507042253523" y="203.42637644046096" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_B_1_di" bpmnElement="Lane_B_1">
<dc:Bounds x="183" y="181" width="540" height="118" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn:process id="Process" isExecutable="false">
<bpmn:subProcess id="SubProcess">
<bpmn:startEvent id="StartEvent" />
</bpmn:subProcess>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent">
<dc:Bounds x="199" y="99" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="172" y="135" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="SubProcess_di" bpmnElement="SubProcess" isExpanded="true">
<dc:Bounds x="133" y="58" width="350" height="200" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn:process id="Process">
<bpmn:task id="Task" />
<bpmn:textAnnotation id="TextAnnotation" />
<bpmn:association id="Association" sourceRef="Task" targetRef="TextAnnotation" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process">
<bpmndi:BPMNShape id="Task_di" bpmnElement="Task">
<dc:Bounds x="101" y="191" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="TextAnnotation_di" bpmnElement="TextAnnotation">
<dc:Bounds x="322" y="126" width="121" height="112" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Association_di" bpmnElement="Association">
<di:waypoint xsi:type="dc:Point" x="201" y="220" />
<di:waypoint xsi:type="dc:Point" x="322" y="195" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -34,7 +34,7 @@ describe('features/snapping - BpmnSnapping', function() {
var task, intermediateThrowEvent; var task, intermediateThrowEvent;
beforeEach(inject(function(elementFactory, elementRegistry, canvas, dragging) { beforeEach(inject(function(elementFactory, elementRegistry, dragging) {
task = elementRegistry.get('Task_1'); task = elementRegistry.get('Task_1');
intermediateThrowEvent = elementFactory.createShape({ intermediateThrowEvent = elementFactory.createShape({
@ -229,16 +229,16 @@ describe('features/snapping - BpmnSnapping', function() {
describe('on Participant resize', function () { describe('on Participant resize', function () {
var diagramXML = require('./BpmnSnapping.collaboration-resize.bpmn');
var testResizeModules = [ coreModule, resizeModule, rulesModule, snappingModule ];
beforeEach(bootstrapModeler(diagramXML, { modules: testResizeModules }));
describe('snap min bounds', function() { describe('snap min bounds', function() {
it('should snap to children from <se>', inject(function(canvas, elementRegistry, resize, dragging) { var diagramXML = require('./BpmnSnapping.participant-resize.bpmn');
var testResizeModules = [ coreModule, resizeModule, rulesModule, snappingModule ];
beforeEach(bootstrapModeler(diagramXML, { modules: testResizeModules }));
it('should snap to children from <se>', inject(function(elementRegistry, resize, dragging) {
var participant = elementRegistry.get('Participant_2'); var participant = elementRegistry.get('Participant_2');
@ -251,7 +251,7 @@ describe('features/snapping - BpmnSnapping', function() {
})); }));
it('should snap to children from <nw>', inject(function(canvas, elementRegistry, resize, dragging) { it('should snap to children from <nw>', inject(function(elementRegistry, resize, dragging) {
var participant = elementRegistry.get('Participant_2'); var participant = elementRegistry.get('Participant_2');
@ -264,7 +264,7 @@ describe('features/snapping - BpmnSnapping', function() {
})); }));
it('should snap to min dimensions from <se>', inject(function(canvas, elementRegistry, resize, dragging) { it('should snap to min dimensions from <se>', inject(function(elementRegistry, resize, dragging) {
var participant = elementRegistry.get('Participant_1'); var participant = elementRegistry.get('Participant_1');
@ -277,7 +277,7 @@ describe('features/snapping - BpmnSnapping', function() {
})); }));
it('should snap to min dimensions from <nw>', inject(function(canvas, elementRegistry, resize, dragging) { it('should snap to min dimensions from <nw>', inject(function(elementRegistry, resize, dragging) {
var participant = elementRegistry.get('Participant_1'); var participant = elementRegistry.get('Participant_1');
@ -290,7 +290,7 @@ describe('features/snapping - BpmnSnapping', function() {
})); }));
it('should snap to min dimensions + children from <se>', inject(function(canvas, elementRegistry, resize, dragging) { it('should snap to min dimensions + children from <se>', inject(function(elementRegistry, resize, dragging) {
var participant = elementRegistry.get('Participant_3'); var participant = elementRegistry.get('Participant_3');
@ -299,11 +299,13 @@ describe('features/snapping - BpmnSnapping', function() {
dragging.end(); dragging.end();
expect(participant.width).to.equal(320); expect(participant.width).to.equal(320);
expect(participant.height).to.equal(150);
// snap to children rather than min dimensions
expect(participant.height).to.equal(143);
})); }));
it('should snap to min dimensions + children from <nw>', inject(function(canvas, elementRegistry, resize, dragging) { it('should snap to min dimensions + children from <nw>', inject(function(elementRegistry, resize, dragging) {
var participant = elementRegistry.get('Participant_3'); var participant = elementRegistry.get('Participant_3');
@ -318,38 +320,86 @@ describe('features/snapping - BpmnSnapping', function() {
}); });
it('should snap a SubProcess to minimum bounds', inject(function(canvas, elementRegistry, resize, dragging) { describe('snap child lanes', function() {
var subProcess = elementRegistry.get('SubProcess_1'); var diagramXML = require('./BpmnSnapping.lanes-resize.bpmn');
resize.activate(canvasEvent({ x: 453, y: 624 }), subProcess, 'se'); var testResizeModules = [ coreModule, resizeModule, rulesModule, snappingModule ];
dragging.move(canvasEvent({ x: -453, y: -624 }));
beforeEach(bootstrapModeler(diagramXML, { modules: testResizeModules }));
it('should snap to child lanes from <nw>', inject(function(elementRegistry, resize, dragging) {
var participant = elementRegistry.get('Participant');
resize.activate(canvasEvent({ x: 0, y: 0 }), participant, 'nw');
dragging.move(canvasEvent({ x: 500, y: 500 }));
dragging.end();
expect(participant.width).to.equal(600);
expect(participant.height).to.equal(250);
}));
it('should snap to nested child lanes from <se>', inject(function(elementRegistry, resize, dragging) {
var lane = elementRegistry.get('Lane_B_0');
resize.activate(canvasEvent({ x: 0, y: 0 }), lane, 'se');
dragging.move(canvasEvent({ x: -500, y: -500 }));
dragging.end();
expect(lane.width).to.equal(570);
expect(lane.height).to.equal(118);
}));
});
});
describe('on SubProcess resize', function() {
var diagramXML = require('./BpmnSnapping.subProcess-resize.bpmn');
var testResizeModules = [ coreModule, resizeModule, rulesModule, snappingModule ];
beforeEach(bootstrapModeler(diagramXML, { modules: testResizeModules }));
it('should snap to minimum bounds', inject(function(elementRegistry, resize, dragging) {
var subProcess = elementRegistry.get('SubProcess');
resize.activate(canvasEvent({ x: 0, y: 0 }), subProcess, 'se');
dragging.move(canvasEvent({ x: -400, y: -400 }));
dragging.end(); dragging.end();
expect(subProcess.width).to.equal(140); expect(subProcess.width).to.equal(140);
expect(subProcess.height).to.equal(120); expect(subProcess.height).to.equal(120);
})); }));
});
it('should snap a Participant to minimum bounds', inject(function(canvas, elementRegistry, resize, dragging) {
var participant = elementRegistry.get('Participant_1');
resize.activate(canvasEvent({ x: 614, y: 310 }), participant, 'se');
dragging.move(canvasEvent({ x: -614, y: -310 }));
dragging.end();
expect(participant.width).to.equal(300);
expect(participant.height).to.equal(150);
}));
it('should snap a TextAnnotation to minimum bounds', inject(function(canvas, elementRegistry, resize, dragging) { describe('on TextAnnotation resize', function() {
var textAnnotation = elementRegistry.get('TextAnnotation_1');
resize.activate(canvasEvent({ x: 592, y: 452 }), textAnnotation, 'se'); var diagramXML = require('./BpmnSnapping.textAnnotation-resize.bpmn');
dragging.move(canvasEvent({ x: -592, y: -452 }));
var testResizeModules = [ coreModule, resizeModule, rulesModule, snappingModule ];
beforeEach(bootstrapModeler(diagramXML, { modules: testResizeModules }));
it('should snap a TextAnnotation to minimum bounds', inject(function(elementRegistry, resize, dragging) {
var textAnnotation = elementRegistry.get('TextAnnotation');
resize.activate(canvasEvent({ x: 0, y: 0 }), textAnnotation, 'se');
dragging.move(canvasEvent({ x: -400, y: -400 }));
dragging.end(); dragging.end();
expect(textAnnotation.width).to.equal(50); expect(textAnnotation.width).to.equal(50);