From e1d8a675277e31582da8871a0d1c2a1e606ab0c5 Mon Sep 17 00:00:00 2001 From: Philipp Fromme Date: Thu, 29 Aug 2019 11:55:34 +0200 Subject: [PATCH] fix(drop-on-flow-behavior): handle shape created with bounds * take into account that shapes can be created with position OR bounds Fixes #1178 --- .../modeling/behavior/DropOnFlowBehavior.js | 35 ++++++----- .../behavior/DropOnFlowBehaviorSpec.js | 59 ++++++++++++++++++- 2 files changed, 77 insertions(+), 17 deletions(-) diff --git a/lib/features/modeling/behavior/DropOnFlowBehavior.js b/lib/features/modeling/behavior/DropOnFlowBehavior.js index 4d1c35ba..a08947d2 100644 --- a/lib/features/modeling/behavior/DropOnFlowBehavior.js +++ b/lib/features/modeling/behavior/DropOnFlowBehavior.js @@ -2,10 +2,13 @@ import inherits from 'inherits'; import { assign, + filter, find, - filter + isNumber } from 'min-dash'; +import { getMid } from 'diagram-js/lib/layout/LayoutUtil'; + import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor'; import { @@ -22,7 +25,7 @@ export default function DropOnFlowBehavior(eventBus, bpmnRules, modeling) { * dropping an element on a flow. */ - function insertShape(shape, targetFlow, position) { + function insertShape(shape, targetFlow, positionOrBounds) { var waypoints = targetFlow.waypoints, waypointsBefore, waypointsAfter, @@ -34,7 +37,15 @@ export default function DropOnFlowBehavior(eventBus, bpmnRules, modeling) { oldOutgoing = shape.outgoing.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) { waypointsBefore = waypoints.slice(0, intersection.index); @@ -45,7 +56,7 @@ export default function DropOnFlowBehavior(eventBus, bpmnRules, modeling) { 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 (!isPointInsideBBox(shape, waypointsBefore[waypointsBefore.length-1])) { @@ -64,7 +75,7 @@ export default function DropOnFlowBehavior(eventBus, bpmnRules, modeling) { if (bpmnRules.canConnect(source, shape, targetFlow)) { // reconnect source -> inserted shape - modeling.reconnectEnd(targetFlow, shape, waypointsBefore || position); + modeling.reconnectEnd(targetFlow, shape, waypointsBefore || mid); incomingConnection = targetFlow; } @@ -74,7 +85,7 @@ export default function DropOnFlowBehavior(eventBus, bpmnRules, modeling) { if (!incomingConnection) { // reconnect inserted shape -> end - modeling.reconnectStart(targetFlow, shape, waypointsAfter || position); + modeling.reconnectStart(targetFlow, shape, waypointsAfter || mid); outgoingConnection = targetFlow; } else { @@ -165,10 +176,10 @@ export default function DropOnFlowBehavior(eventBus, bpmnRules, modeling) { var shape = context.shape, targetFlow = context.targetFlow, - position = context.position; + positionOrBounds = context.position; if (targetFlow) { - insertShape(shape, targetFlow, position); + insertShape(shape, targetFlow, positionOrBounds); } }, true); } @@ -198,11 +209,3 @@ function copy(obj) { return assign({}, obj); } -function getMid(bounds) { - - return { - x: Math.round(bounds.x + bounds.width / 2), - y: Math.round(bounds.y + bounds.height / 2) - }; -} - diff --git a/test/spec/features/modeling/behavior/DropOnFlowBehaviorSpec.js b/test/spec/features/modeling/behavior/DropOnFlowBehaviorSpec.js index 4392f998..e98675d5 100644 --- a/test/spec/features/modeling/behavior/DropOnFlowBehaviorSpec.js +++ b/test/spec/features/modeling/behavior/DropOnFlowBehaviorSpec.js @@ -17,6 +17,8 @@ import { createCanvasEvent as canvasEvent } from '../../../../util/MockEvents'; +import { getMid } from 'diagram-js/lib/layout/LayoutUtil'; + describe('modeling/behavior - drop on connection', function() { @@ -60,7 +62,6 @@ describe('modeling/behavior - drop on connection', function() { ); // then - var targetConnection = newShape.outgoing[0]; // 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)); + } + )); + });