fix(snapping): snap sequence flows mid -> mid
With the latest version of bpmn-js it is possible to draw point top point connections between elements. This restores the mid -> mid connection snapping for sequence flows. Closes #588
This commit is contained in:
parent
28f7145b32
commit
7fdd9bc611
|
@ -2,7 +2,11 @@
|
||||||
|
|
||||||
var inherits = require('inherits');
|
var inherits = require('inherits');
|
||||||
|
|
||||||
var forEach = require('lodash/collection/forEach');
|
var abs = Math.abs;
|
||||||
|
|
||||||
|
var forEach = require('lodash/collection/forEach'),
|
||||||
|
filter = require('lodash/collection/filter'),
|
||||||
|
assign = require('lodash/object/assign');
|
||||||
|
|
||||||
var getBoundingBox = require('diagram-js/lib/util/Elements').getBBox;
|
var getBoundingBox = require('diagram-js/lib/util/Elements').getBBox;
|
||||||
|
|
||||||
|
@ -88,6 +92,10 @@ function BpmnSnapping(eventBus, canvas, bpmnRules, elementRegistry) {
|
||||||
return bpmnRules.canAttach([ shape ], target, null, position) === 'attach';
|
return bpmnRules.canAttach([ shape ], target, null, position) === 'attach';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function canConnect(source, target) {
|
||||||
|
return bpmnRules.canConnect(source, target);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Snap boundary events to elements border
|
* Snap boundary events to elements border
|
||||||
*/
|
*/
|
||||||
|
@ -129,11 +137,38 @@ function BpmnSnapping(eventBus, canvas, bpmnRules, elementRegistry) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Snap sequence flows.
|
||||||
|
*/
|
||||||
|
eventBus.on([
|
||||||
|
'connect.move',
|
||||||
|
'connect.hover',
|
||||||
|
'connect.end'
|
||||||
|
], HIGH_PRIORITY, function(event) {
|
||||||
|
var context = event.context,
|
||||||
|
source = context.source,
|
||||||
|
target = context.target;
|
||||||
|
|
||||||
var abs = Math.abs;
|
var connection = canConnect(source, target) || {};
|
||||||
|
|
||||||
var filter = require('lodash/collection/filter'),
|
if (!context.initialSourcePosition) {
|
||||||
assign = require('lodash/object/assign');
|
context.initialSourcePosition = context.sourcePosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target && connection.type === 'bpmn:SequenceFlow') {
|
||||||
|
|
||||||
|
// snap source
|
||||||
|
context.sourcePosition = mid(source);
|
||||||
|
|
||||||
|
// snap target
|
||||||
|
assign(event, mid(target));
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// otherwise reset source snap
|
||||||
|
context.sourcePosition = context.initialSourcePosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
eventBus.on([
|
eventBus.on([
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?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" exporter="Camunda Modeler" exporterVersion="1.1.1">
|
||||||
|
<bpmn:collaboration id="Collaboration_1">
|
||||||
|
<bpmn:participant id="Participant_1" processRef="Process_1" />
|
||||||
|
<bpmn:participant id="Participant_2" processRef="Process_1e043dv" />
|
||||||
|
</bpmn:collaboration>
|
||||||
|
<bpmn:process id="Process_1" isExecutable="false">
|
||||||
|
<bpmn:startEvent id="StartEvent_1" />
|
||||||
|
<bpmn:task id="Task_1" />
|
||||||
|
</bpmn:process>
|
||||||
|
<bpmn:process id="Process_1e043dv" isExecutable="false">
|
||||||
|
<bpmn:task id="Task_2" />
|
||||||
|
</bpmn:process>
|
||||||
|
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||||
|
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_1">
|
||||||
|
<bpmndi:BPMNShape id="Participant_1sh90bv_di" bpmnElement="Participant_1">
|
||||||
|
<dc:Bounds x="50" y="58" width="370" height="120" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||||
|
<dc:Bounds x="100" y="100" width="36" height="36" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="73" y="136" width="90" height="20" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Task_005jq1a_di" bpmnElement="Task_1">
|
||||||
|
<dc:Bounds x="300" y="78" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Participant_1lvgmm2_di" bpmnElement="Participant_2">
|
||||||
|
<dc:Bounds x="50" y="185" width="370" height="113" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Task_0ythg78_di" bpmnElement="Task_2">
|
||||||
|
<dc:Bounds x="240" y="200" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
</bpmndi:BPMNPlane>
|
||||||
|
</bpmndi:BPMNDiagram>
|
||||||
|
</bpmn:definitions>
|
|
@ -12,7 +12,8 @@ var coreModule = require('../../../../lib/core'),
|
||||||
createModule = require('diagram-js/lib/features/create'),
|
createModule = require('diagram-js/lib/features/create'),
|
||||||
resizeModule = require('diagram-js/lib/features/resize'),
|
resizeModule = require('diagram-js/lib/features/resize'),
|
||||||
moveModule = require('diagram-js/lib/features/move'),
|
moveModule = require('diagram-js/lib/features/move'),
|
||||||
rulesModule = require('../../../../lib/features/rules');
|
rulesModule = require('../../../../lib/features/rules'),
|
||||||
|
connectModule = require('diagram-js/lib/features/connect');
|
||||||
|
|
||||||
|
|
||||||
describe('features/snapping - BpmnSnapping', function() {
|
describe('features/snapping - BpmnSnapping', function() {
|
||||||
|
@ -23,7 +24,8 @@ describe('features/snapping - BpmnSnapping', function() {
|
||||||
modelingModule,
|
modelingModule,
|
||||||
createModule,
|
createModule,
|
||||||
rulesModule,
|
rulesModule,
|
||||||
moveModule
|
moveModule,
|
||||||
|
connectModule
|
||||||
];
|
];
|
||||||
|
|
||||||
describe('on Boundary Events', function() {
|
describe('on Boundary Events', function() {
|
||||||
|
@ -541,4 +543,214 @@ describe('features/snapping - BpmnSnapping', function() {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('on connect', function() {
|
||||||
|
|
||||||
|
var diagramXML = require('./BpmnSnapping.connect.bpmn');
|
||||||
|
|
||||||
|
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
|
||||||
|
|
||||||
|
|
||||||
|
it('should snap sequence flow on global connect', inject(function(connect, dragging, elementRegistry) {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var startEvent = elementRegistry.get('StartEvent_1'),
|
||||||
|
task = elementRegistry.get('Task_1');
|
||||||
|
|
||||||
|
var mid = {
|
||||||
|
x: startEvent.x + startEvent.width / 2,
|
||||||
|
y: startEvent.y + startEvent.height / 2
|
||||||
|
};
|
||||||
|
|
||||||
|
// when
|
||||||
|
connect.start(canvasEvent({ x: mid.x + 10, y: mid.y + 10 }), startEvent);
|
||||||
|
|
||||||
|
dragging.hover({
|
||||||
|
element: task,
|
||||||
|
gfx: elementRegistry.getGraphics(task)
|
||||||
|
});
|
||||||
|
|
||||||
|
dragging.move(canvasEvent({
|
||||||
|
x: task.x + task.width / 2,
|
||||||
|
y: task.y + task.height / 2
|
||||||
|
}));
|
||||||
|
|
||||||
|
dragging.end();
|
||||||
|
|
||||||
|
// then
|
||||||
|
var expected = [
|
||||||
|
{
|
||||||
|
original:
|
||||||
|
{
|
||||||
|
x: startEvent.x + startEvent.width / 2,
|
||||||
|
y: startEvent.y + startEvent.height / 2
|
||||||
|
},
|
||||||
|
x: startEvent.x + startEvent.width,
|
||||||
|
y: startEvent.y + startEvent.height / 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
original:
|
||||||
|
{
|
||||||
|
x: task.x + task.width / 2,
|
||||||
|
y: task.y + task.height / 2
|
||||||
|
},
|
||||||
|
x: task.x,
|
||||||
|
y: task.y + task.height / 2
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
expect(startEvent.outgoing[0].waypoints).to.eql(expected);
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should snap sequence flow on connect', inject(function(connect, dragging, elementRegistry) {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var startEvent = elementRegistry.get('StartEvent_1'),
|
||||||
|
task = elementRegistry.get('Task_1');
|
||||||
|
|
||||||
|
var mid = { x: task.x + task.width / 2, y: task.y + task.height / 2 };
|
||||||
|
|
||||||
|
// when
|
||||||
|
connect.start(canvasEvent({ x: 0, y: 0 }), startEvent);
|
||||||
|
|
||||||
|
dragging.hover({
|
||||||
|
element: task,
|
||||||
|
gfx: elementRegistry.getGraphics(task)
|
||||||
|
});
|
||||||
|
|
||||||
|
dragging.move(canvasEvent({ x: mid.x + 10, y: mid.y + 10 }));
|
||||||
|
|
||||||
|
dragging.end();
|
||||||
|
|
||||||
|
// then
|
||||||
|
var expected = [
|
||||||
|
{
|
||||||
|
original:
|
||||||
|
{
|
||||||
|
x: startEvent.x + startEvent.width / 2,
|
||||||
|
y: startEvent.y + startEvent.height / 2
|
||||||
|
},
|
||||||
|
x: startEvent.x + startEvent.width,
|
||||||
|
y: startEvent.y + startEvent.height / 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
original:
|
||||||
|
{
|
||||||
|
x: task.x + task.width / 2,
|
||||||
|
y: task.y + task.height / 2
|
||||||
|
},
|
||||||
|
x: task.x,
|
||||||
|
y: task.y + task.height / 2
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
expect(startEvent.outgoing[0].waypoints).to.eql(expected);
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should NOT snap message flow on global connect', inject(function(connect, dragging, elementRegistry) {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var task1 = elementRegistry.get('Task_1'),
|
||||||
|
task2 = elementRegistry.get('Task_2');
|
||||||
|
|
||||||
|
var task1Mid = { x: task1.x + task1.width / 2, y: task1.y + task1.height / 2 },
|
||||||
|
task2Mid = { x: task2.x + task2.width / 2, y: task2.y + task2.height / 2 };
|
||||||
|
|
||||||
|
// when
|
||||||
|
connect.start(null, task1, { x: 320, y: task1Mid.y + 20 });
|
||||||
|
|
||||||
|
dragging.hover({
|
||||||
|
element: task2,
|
||||||
|
gfx: elementRegistry.getGraphics(task2)
|
||||||
|
});
|
||||||
|
|
||||||
|
dragging.move(canvasEvent({
|
||||||
|
x: 320,
|
||||||
|
y: task2Mid.y - 20
|
||||||
|
}));
|
||||||
|
|
||||||
|
dragging.end();
|
||||||
|
|
||||||
|
// then
|
||||||
|
var expected = [
|
||||||
|
{
|
||||||
|
original:
|
||||||
|
{
|
||||||
|
x: 320,
|
||||||
|
y: task1Mid.y + 20
|
||||||
|
},
|
||||||
|
x: 320,
|
||||||
|
y: task1.y + task1.height
|
||||||
|
},
|
||||||
|
{
|
||||||
|
original:
|
||||||
|
{
|
||||||
|
x: 320,
|
||||||
|
y: task2Mid.y - 20
|
||||||
|
},
|
||||||
|
x: 320,
|
||||||
|
y: task2.y
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
expect(task1.outgoing[0].waypoints).to.eql(expected);
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should NOT snap message flow on connect', inject(function(connect, dragging, elementRegistry) {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var task1 = elementRegistry.get('Task_1'),
|
||||||
|
task2 = elementRegistry.get('Task_2');
|
||||||
|
|
||||||
|
var task1Mid = { x: task1.x + task1.width / 2, y: task1.y + task1.height / 2 },
|
||||||
|
task2Mid = { x: task2.x + task2.width / 2, y: task2.y + task2.height / 2 };
|
||||||
|
|
||||||
|
// when
|
||||||
|
connect.start(canvasEvent({ x: 0, y: 0 }), task1);
|
||||||
|
|
||||||
|
dragging.hover({
|
||||||
|
element: task2,
|
||||||
|
gfx: elementRegistry.getGraphics(task2)
|
||||||
|
});
|
||||||
|
|
||||||
|
dragging.move(canvasEvent({
|
||||||
|
x: task2Mid.x + 20,
|
||||||
|
y: task2Mid.y - 20
|
||||||
|
}));
|
||||||
|
|
||||||
|
dragging.end();
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(task1.outgoing[0].waypoints.length).to.equal(4);
|
||||||
|
|
||||||
|
expect(task1.outgoing[0].waypoints[0]).to.eql({
|
||||||
|
original:
|
||||||
|
{
|
||||||
|
x: task1Mid.x,
|
||||||
|
y: task1Mid.y
|
||||||
|
},
|
||||||
|
x: task1Mid.x,
|
||||||
|
y: task1.y + task1.height
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(task1.outgoing[0].waypoints[3]).to.eql({
|
||||||
|
original:
|
||||||
|
{
|
||||||
|
x: task2Mid.x + 20,
|
||||||
|
y: task2Mid.y - 20
|
||||||
|
},
|
||||||
|
x: task2Mid.x + 20,
|
||||||
|
y: task2.y
|
||||||
|
});
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue