fix(drop-on-flow-behavior): handle shape created with bounds
* take into account that shapes can be created with position OR bounds Fixes #1178
This commit is contained in:
parent
c9e9f002c9
commit
e1d8a67527
|
@ -2,10 +2,13 @@ import inherits from 'inherits';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
assign,
|
assign,
|
||||||
|
filter,
|
||||||
find,
|
find,
|
||||||
filter
|
isNumber
|
||||||
} from 'min-dash';
|
} from 'min-dash';
|
||||||
|
|
||||||
|
import { getMid } from 'diagram-js/lib/layout/LayoutUtil';
|
||||||
|
|
||||||
import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
|
import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -22,7 +25,7 @@ export default function DropOnFlowBehavior(eventBus, bpmnRules, modeling) {
|
||||||
* dropping an element on a flow.
|
* dropping an element on a flow.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function insertShape(shape, targetFlow, position) {
|
function insertShape(shape, targetFlow, positionOrBounds) {
|
||||||
var waypoints = targetFlow.waypoints,
|
var waypoints = targetFlow.waypoints,
|
||||||
waypointsBefore,
|
waypointsBefore,
|
||||||
waypointsAfter,
|
waypointsAfter,
|
||||||
|
@ -34,7 +37,15 @@ export default function DropOnFlowBehavior(eventBus, bpmnRules, modeling) {
|
||||||
oldOutgoing = shape.outgoing.slice(),
|
oldOutgoing = shape.outgoing.slice(),
|
||||||
oldIncoming = shape.incoming.slice();
|
oldIncoming = shape.incoming.slice();
|
||||||
|
|
||||||
var intersection = getApproxIntersection(waypoints, position);
|
var mid;
|
||||||
|
|
||||||
|
if (isNumber(positionOrBounds.width)) {
|
||||||
|
mid = getMid(positionOrBounds);
|
||||||
|
} else {
|
||||||
|
mid = positionOrBounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
var intersection = getApproxIntersection(waypoints, mid);
|
||||||
|
|
||||||
if (intersection) {
|
if (intersection) {
|
||||||
waypointsBefore = waypoints.slice(0, intersection.index);
|
waypointsBefore = waypoints.slice(0, intersection.index);
|
||||||
|
@ -45,7 +56,7 @@ export default function DropOnFlowBehavior(eventBus, bpmnRules, modeling) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dockingPoint = intersection.bendpoint ? waypoints[intersection.index] : position;
|
dockingPoint = intersection.bendpoint ? waypoints[intersection.index] : mid;
|
||||||
|
|
||||||
// if last waypointBefore is inside shape's bounds, ignore docking point
|
// if last waypointBefore is inside shape's bounds, ignore docking point
|
||||||
if (!isPointInsideBBox(shape, waypointsBefore[waypointsBefore.length-1])) {
|
if (!isPointInsideBBox(shape, waypointsBefore[waypointsBefore.length-1])) {
|
||||||
|
@ -64,7 +75,7 @@ export default function DropOnFlowBehavior(eventBus, bpmnRules, modeling) {
|
||||||
if (bpmnRules.canConnect(source, shape, targetFlow)) {
|
if (bpmnRules.canConnect(source, shape, targetFlow)) {
|
||||||
|
|
||||||
// reconnect source -> inserted shape
|
// reconnect source -> inserted shape
|
||||||
modeling.reconnectEnd(targetFlow, shape, waypointsBefore || position);
|
modeling.reconnectEnd(targetFlow, shape, waypointsBefore || mid);
|
||||||
|
|
||||||
incomingConnection = targetFlow;
|
incomingConnection = targetFlow;
|
||||||
}
|
}
|
||||||
|
@ -74,7 +85,7 @@ export default function DropOnFlowBehavior(eventBus, bpmnRules, modeling) {
|
||||||
if (!incomingConnection) {
|
if (!incomingConnection) {
|
||||||
|
|
||||||
// reconnect inserted shape -> end
|
// reconnect inserted shape -> end
|
||||||
modeling.reconnectStart(targetFlow, shape, waypointsAfter || position);
|
modeling.reconnectStart(targetFlow, shape, waypointsAfter || mid);
|
||||||
|
|
||||||
outgoingConnection = targetFlow;
|
outgoingConnection = targetFlow;
|
||||||
} else {
|
} else {
|
||||||
|
@ -165,10 +176,10 @@ export default function DropOnFlowBehavior(eventBus, bpmnRules, modeling) {
|
||||||
|
|
||||||
var shape = context.shape,
|
var shape = context.shape,
|
||||||
targetFlow = context.targetFlow,
|
targetFlow = context.targetFlow,
|
||||||
position = context.position;
|
positionOrBounds = context.position;
|
||||||
|
|
||||||
if (targetFlow) {
|
if (targetFlow) {
|
||||||
insertShape(shape, targetFlow, position);
|
insertShape(shape, targetFlow, positionOrBounds);
|
||||||
}
|
}
|
||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
@ -198,11 +209,3 @@ function copy(obj) {
|
||||||
return assign({}, obj);
|
return assign({}, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMid(bounds) {
|
|
||||||
|
|
||||||
return {
|
|
||||||
x: Math.round(bounds.x + bounds.width / 2),
|
|
||||||
y: Math.round(bounds.y + bounds.height / 2)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@ import {
|
||||||
createCanvasEvent as canvasEvent
|
createCanvasEvent as canvasEvent
|
||||||
} from '../../../../util/MockEvents';
|
} from '../../../../util/MockEvents';
|
||||||
|
|
||||||
|
import { getMid } from 'diagram-js/lib/layout/LayoutUtil';
|
||||||
|
|
||||||
|
|
||||||
describe('modeling/behavior - drop on connection', function() {
|
describe('modeling/behavior - drop on connection', function() {
|
||||||
|
|
||||||
|
@ -60,7 +62,6 @@ describe('modeling/behavior - drop on connection', function() {
|
||||||
);
|
);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
|
|
||||||
var targetConnection = newShape.outgoing[0];
|
var targetConnection = newShape.outgoing[0];
|
||||||
|
|
||||||
// new incoming connection
|
// new incoming connection
|
||||||
|
@ -215,6 +216,62 @@ describe('modeling/behavior - drop on connection', function() {
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
||||||
|
it('should handle shape created with bounds', inject(
|
||||||
|
function(elementFactory, elementRegistry, modeling) {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var intermediateThrowEvent = elementFactory.createShape({
|
||||||
|
type: 'bpmn:IntermediateThrowEvent'
|
||||||
|
});
|
||||||
|
|
||||||
|
var startEvent = elementRegistry.get('StartEvent'),
|
||||||
|
sequenceFlow = elementRegistry.get('SequenceFlow_1'),
|
||||||
|
task = elementRegistry.get('Task_1');
|
||||||
|
|
||||||
|
var originalWaypoints = sequenceFlow.waypoints;
|
||||||
|
|
||||||
|
var dropBounds = { x: 322, y: 102, width: 36, height: 36 }; // first bendpoint
|
||||||
|
|
||||||
|
// when
|
||||||
|
var newShape = modeling.createShape(
|
||||||
|
intermediateThrowEvent,
|
||||||
|
dropBounds,
|
||||||
|
sequenceFlow
|
||||||
|
);
|
||||||
|
|
||||||
|
// then
|
||||||
|
var targetConnection = newShape.outgoing[0];
|
||||||
|
|
||||||
|
// new incoming connection
|
||||||
|
expect(newShape.incoming.length).to.equal(1);
|
||||||
|
expect(newShape.incoming[0]).to.eql(sequenceFlow);
|
||||||
|
|
||||||
|
// new outgoing connection
|
||||||
|
expect(newShape.outgoing.length).to.equal(1);
|
||||||
|
expect(targetConnection).to.exist;
|
||||||
|
expect(targetConnection.type).to.equal('bpmn:SequenceFlow');
|
||||||
|
|
||||||
|
expect(startEvent.outgoing[0]).to.equal(newShape.incoming[0]);
|
||||||
|
expect(task.incoming[1]).to.equal(newShape.outgoing[0]);
|
||||||
|
|
||||||
|
// split target at insertion point
|
||||||
|
expect(sequenceFlow).to.have.waypoints(flatten([
|
||||||
|
originalWaypoints.slice(0, 1),
|
||||||
|
{ x: 322, y: 120 }
|
||||||
|
]));
|
||||||
|
|
||||||
|
expect(sequenceFlow).to.have.endDocking(getMid(dropBounds));
|
||||||
|
|
||||||
|
expect(targetConnection).to.have.waypoints(flatten([
|
||||||
|
{ x: 340, y: 138 },
|
||||||
|
originalWaypoints.slice(2)
|
||||||
|
]));
|
||||||
|
|
||||||
|
expect(targetConnection).to.have.startDocking(getMid(dropBounds));
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue