Skip to content

Commit

Permalink
feat(bpmn-snapping): snap boundary event loop when close to source
Browse files Browse the repository at this point in the history
Closes #903
  • Loading branch information
barmac committed Jun 12, 2019
1 parent 067e36f commit 1f49652
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 0 deletions.
42 changes: 42 additions & 0 deletions lib/features/snapping/BpmnConnectSnapping.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,23 @@ import {

import { isCmd } from 'diagram-js/lib/features/keyboard/KeyboardUtil';

import {
getOrientation
} from 'diagram-js/lib/layout/LayoutUtil';

import { is } from '../../util/ModelUtil';

import { some } from 'min-dash';

var HIGHER_PRIORITY = 1250;

var BOUNDARY_TO_HOST_THRESHOLD = 40;

var TARGET_BOUNDS_PADDING = 20;

var AXES = [ 'x', 'y' ];

var abs = Math.abs;

/**
* Snap during connect.
Expand Down Expand Up @@ -59,6 +66,10 @@ export default function BpmnConnectSnapping(eventBus, rules) {
// snap source
context.sourcePosition = mid(source);

if (is(source, 'bpmn:BoundaryEvent') && target === source.host) {
snapBoundaryEventLoop(event, source, target);
}

// snap target
// snapToPosition(event, mid(target));
} else if (isType(connectionAttrs, 'bpmn:MessageFlow')) {
Expand Down Expand Up @@ -105,6 +116,37 @@ function snapInsideTarget(event, target) {
}
});
}

// snap outside of Boundary Event surroundings
function snapBoundaryEventLoop(event, source, target) {
var sourceMid = mid(source),
orientation = getOrientation(sourceMid, target, -10),
snappingAxes = [];

if (/top|bottom/.test(orientation)) {
snappingAxes.push('x');
}

if (/left|right/.test(orientation)) {
snappingAxes.push('y');
}

snappingAxes.forEach(function(axis) {
var coordinate = event[axis], newCoordinate;

if (abs(coordinate - sourceMid[axis]) < BOUNDARY_TO_HOST_THRESHOLD) {
if (coordinate > sourceMid[axis]) {
newCoordinate = sourceMid[axis] + BOUNDARY_TO_HOST_THRESHOLD;
}
else {
newCoordinate = sourceMid[axis] - BOUNDARY_TO_HOST_THRESHOLD;
}

setSnapped(event, axis, newCoordinate);
}
});
}

// helpers //////////

function snapToPosition(event, position) {
Expand Down
4 changes: 4 additions & 0 deletions test/spec/features/snapping/BpmnConnectSnapping.bpmn
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<bpmn:dataObject id="DataObject_16xfc7e" />
<bpmn:subProcess id="SubProcess" />
<bpmn:boundaryEvent id="BoundaryEvent" attachedToRef="SubProcess" />
<bpmn:boundaryEvent id="BoundaryEventRight" attachedToRef="SubProcess" />
</bpmn:process>
<bpmn:process id="Process_2" isExecutable="false">
<bpmn:task id="Task_2" />
Expand Down Expand Up @@ -57,6 +58,9 @@
<bpmndi:BPMNShape id="BoundaryEvent_di" bpmnElement="BoundaryEvent">
<dc:Bounds x="582" y="282" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BoundaryEventRight_di" bpmnElement="BoundaryEventRight">
<dc:Bounds x="743" y="200" width="36" height="36" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
104 changes: 104 additions & 0 deletions test/spec/features/snapping/BpmnConnectSnappingSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,110 @@ describe('features/snapping - BpmnConnectSnapping', function() {

describe('connect', function() {

describe('Boundary Event loop', function() {

it('should snap to the left',
inject(function(connect, dragging, elementRegistry) {

// given
var boundaryEvent = elementRegistry.get('BoundaryEvent'),
subProcess = elementRegistry.get('SubProcess'),
subProcessGfx = elementRegistry.getGraphics(subProcess);

// when
connect.start(canvasEvent({ x: 600, y: 300 }), boundaryEvent);

dragging.hover({ element: subProcess, gfx: subProcessGfx });

dragging.move(canvasEvent({ x: 582, y: 300 }));

dragging.end();

// then
var waypoints = boundaryEvent.outgoing[0].waypoints;

expect(waypoints[3].x).to.eql(560);
})
);


it('should snap to the right',
inject(function(connect, dragging, elementRegistry) {

// given
var boundaryEvent = elementRegistry.get('BoundaryEvent'),
subProcess = elementRegistry.get('SubProcess'),
subProcessGfx = elementRegistry.getGraphics(subProcess);

// when
connect.start(canvasEvent({ x: 600, y: 300 }), boundaryEvent);

dragging.hover({ element: subProcess, gfx: subProcessGfx });

dragging.move(canvasEvent({ x: 618, y: 300 }));

dragging.end();

// then
var waypoints = boundaryEvent.outgoing[0].waypoints;

expect(waypoints[3].x).to.eql(640);
})
);


it('should snap above',
inject(function(connect, dragging, elementRegistry) {

// given
var boundaryEvent = elementRegistry.get('BoundaryEventRight'),
subProcess = elementRegistry.get('SubProcess'),
subProcessGfx = elementRegistry.getGraphics(subProcess);

// when
connect.start(canvasEvent({ x: 761, y: 218 }), boundaryEvent);

dragging.hover({ element: subProcess, gfx: subProcessGfx });

dragging.move(canvasEvent({ x: 761, y: 200 }));

dragging.end();

// then
var waypoints = boundaryEvent.outgoing[0].waypoints;

expect(waypoints[3].y).to.eql(178);
})
);


it('should snap below',
inject(function(connect, dragging, elementRegistry) {

// given
var boundaryEvent = elementRegistry.get('BoundaryEventRight'),
subProcess = elementRegistry.get('SubProcess'),
subProcessGfx = elementRegistry.getGraphics(subProcess);

// when
connect.start(canvasEvent({ x: 761, y: 218 }), boundaryEvent);

dragging.hover({ element: subProcess, gfx: subProcessGfx });

dragging.move(canvasEvent({ x: 761, y: 230 }));

dragging.end();

// then
var waypoints = boundaryEvent.outgoing[0].waypoints;

expect(waypoints[3].y).to.eql(258);
})
);

});


it('should snap event if close to target bounds',
inject(function(connect, dragging, elementRegistry) {

Expand Down

0 comments on commit 1f49652

Please sign in to comment.