fix(snapping): snap to docking points

Closes #1081
This commit is contained in:
Philipp Fromme 2019-06-17 07:39:39 +02:00 committed by merge-me[bot]
parent aed11d88af
commit bef75b2435
3 changed files with 188 additions and 1 deletions

View File

@ -9,10 +9,15 @@ import {
import { is } from '../../util/ModelUtil'; import { is } from '../../util/ModelUtil';
import { asTRBL } from 'diagram-js/lib/layout/LayoutUtil'; import {
asTRBL,
getMid
} from 'diagram-js/lib/layout/LayoutUtil';
import { getBoundaryAttachment } from './BpmnSnappingUtil'; import { getBoundaryAttachment } from './BpmnSnappingUtil';
import { forEach } from 'min-dash';
var HIGH_PRIORITY = 1500; var HIGH_PRIORITY = 1500;
@ -63,6 +68,29 @@ BpmnCreateMoveSnapping.prototype.initSnap = function(event) {
var shape = event.shape; var shape = event.shape;
// snap to docking points
forEach(shape.outgoing, function(connection) {
var docking = connection.waypoints[0];
docking = docking.original || docking;
snapContext.setSnapOrigin(connection.id + '-docking', {
x: docking.x - event.x,
y: docking.y - event.y
});
});
forEach(shape.incoming, function(connection) {
var docking = connection.waypoints[connection.waypoints.length - 1];
docking = docking.original || docking;
snapContext.setSnapOrigin(connection.id + '-docking', {
x: docking.x - event.x,
y: docking.y - event.y
});
});
if (is(shape, 'bpmn:Participant')) { if (is(shape, 'bpmn:Participant')) {
// snap to borders with higher priority // snap to borders with higher priority
@ -75,6 +103,32 @@ BpmnCreateMoveSnapping.prototype.initSnap = function(event) {
BpmnCreateMoveSnapping.prototype.addSnapTargetPoints = function(snapPoints, shape, target) { BpmnCreateMoveSnapping.prototype.addSnapTargetPoints = function(snapPoints, shape, target) {
CreateMoveSnapping.prototype.addSnapTargetPoints.call(this, snapPoints, shape, target); CreateMoveSnapping.prototype.addSnapTargetPoints.call(this, snapPoints, shape, target);
var snapTargets = this.getSnapTargets(shape, target);
// snap to docking points
forEach(shape.incoming, function(connection) {
if (!includes(snapTargets, connection.source)) {
snapPoints.add('mid', getMid(connection.source));
}
var docking = connection.waypoints[0];
snapPoints.add(connection.id + '-docking', docking.original || docking);
});
forEach(shape.outgoing, function(connection) {
if (!includes(snapTargets, connection.target)) {
snapPoints.add('mid', getMid(connection.target));
}
var docking = connection.waypoints[ connection.waypoints.length - 1 ];
snapPoints.add(connection.id + '-docking', docking.original || docking);
});
// add sequence flow parents as snap targets // add sequence flow parents as snap targets
if (is(target, 'bpmn:SequenceFlow')) { if (is(target, 'bpmn:SequenceFlow')) {
snapPoints = this.addSnapTargetPoints(snapPoints, shape, target.parent); snapPoints = this.addSnapTargetPoints(snapPoints, shape, target.parent);
@ -134,4 +188,8 @@ function setSnappedIfConstrained(event) {
if ((top && top >= event.y) || (bottom && bottom <= event.y)) { if ((top && top >= event.y) || (bottom && bottom <= event.y)) {
setSnapped(event, 'y', event.y); setSnapped(event, 'y', event.y);
} }
}
function includes(array, value) {
return array.indexOf(value) !== -1;
} }

View File

@ -0,0 +1,56 @@
<?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:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_1u6quyt" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.1.2">
<bpmn:collaboration id="Collaboration_1i29mxs">
<bpmn:participant id="Participant_1" processRef="Process_1" />
<bpmn:participant id="Participant_2" processRef="Process_2" />
<bpmn:messageFlow id="MessageFlow_1" sourceRef="Task_1" targetRef="Task_2" />
<bpmn:messageFlow id="MessageFlow_2" sourceRef="Task_4" targetRef="Task_3" />
</bpmn:collaboration>
<bpmn:process id="Process_1" isExecutable="true" camunda:modelerTemplate="test">
<bpmn:extensionElements>
<camunda:properties>
<camunda:property name="Test Property" value="" />
</camunda:properties>
</bpmn:extensionElements>
<bpmn:task id="Task_1" />
<bpmn:task id="Task_3" />
</bpmn:process>
<bpmn:process id="Process_2" isExecutable="false">
<bpmn:task id="Task_2" />
<bpmn:task id="Task_4" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_1i29mxs">
<bpmndi:BPMNShape id="Participant_0ijucrg_di" bpmnElement="Participant_1" isHorizontal="true">
<dc:Bounds x="100" y="100" width="600" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Participant_1xqykjr_di" bpmnElement="Participant_2" isHorizontal="true">
<dc:Bounds x="100" y="400" width="600" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_0hpqryw_di" bpmnElement="Task_1">
<dc:Bounds x="200" y="200" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_0n6qirq_di" bpmnElement="Task_2">
<dc:Bounds x="350" y="500" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="MessageFlow_1rs289f_di" bpmnElement="MessageFlow_1">
<di:waypoint x="275" y="280" />
<di:waypoint x="275" y="380" />
<di:waypoint x="400" y="380" />
<di:waypoint x="400" y="500" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Task_09n61pi_di" bpmnElement="Task_3">
<dc:Bounds x="400" y="200" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_0zuw5ek_di" bpmnElement="Task_4">
<dc:Bounds x="550" y="500" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="MessageFlow_0zxikve_di" bpmnElement="MessageFlow_2">
<di:waypoint x="600" y="500" />
<di:waypoint x="600" y="390" />
<di:waypoint x="480" y="390" />
<di:waypoint x="480" y="280" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -365,6 +365,79 @@ describe('features/snapping - BpmnCreateMoveSnapping', function() {
}); });
describe('docking points', function() {
var diagramXML = require('./BpmnCreateMoveSnapping.docking-points.bpmn');
beforeEach(bootstrapModeler(diagramXML, {
modules: testModules
}));
var participant,
participantGfx;
beforeEach(inject(function(dragging, elementRegistry, move) {
participant = elementRegistry.get('Participant_2');
participantGfx = elementRegistry.getGraphics(participant);
dragging.setOptions({ manual: true });
}));
it('should snap to docking point (incoming connections)', inject(
function(dragging, elementRegistry, move) {
// given
var task = elementRegistry.get('Task_2');
move.start(canvasEvent({ x: 400, y: 540 }), task);
dragging.hover({ element: participant, gfx: participantGfx });
dragging.move(canvasEvent({ x: 0, y: 0 }));
// when
dragging.move(canvasEvent({ x: 270, y: 540 }));
dragging.end();
// then
expect(mid(task)).to.eql({
x: 275,
y: 540
});
}
));
it('should snap to docking point (outgoing connections)', inject(
function(dragging, elementRegistry, move) {
// given
var task = elementRegistry.get('Task_4');
move.start(canvasEvent({ x: 600, y: 540 }), task);
dragging.hover({ element: participant, gfx: participantGfx });
dragging.move(canvasEvent({ x: 0, y: 0 }));
// when
dragging.move(canvasEvent({ x: 475, y: 540 }));
dragging.end();
// then
expect(mid(task)).to.eql({
x: 480,
y: 540
});
}
));
});
}); });
// helpers ////////// // helpers //////////