diff --git a/lib/features/modeling/behavior/CreateOnFlowBehavior.js b/lib/features/modeling/behavior/CreateOnFlowBehavior.js deleted file mode 100644 index 993d8957..00000000 --- a/lib/features/modeling/behavior/CreateOnFlowBehavior.js +++ /dev/null @@ -1,95 +0,0 @@ -'use strict'; - -var inherits = require('inherits'); - -var assign = require('lodash/object/assign'); - -var CommandInterceptor = require('diagram-js/lib/command/CommandInterceptor'); - -var getApproxIntersection = require('diagram-js/lib/util/LineIntersection').getApproxIntersection; - - -function copy(obj) { - return assign({}, obj); -} - -function CreateOnFlowBehavior(eventBus, bpmnRules, modeling) { - - CommandInterceptor.call(this, eventBus); - - /** - * Reconnect start / end of a connection after - * dropping an element on a flow. - */ - - this.preExecute('shape.create', function(context) { - - var parent = context.parent, - shape = context.shape; - - if (bpmnRules.canInsert(shape, parent)) { - context.targetFlow = parent; - context.parent = parent.parent; - } - }, true); - - - this.postExecute('shape.create', function(context) { - - var shape = context.shape, - targetFlow = context.targetFlow, - position = context.position, - source, - target, - reconnected, - intersection, - waypoints, - waypointsBefore, - waypointsAfter, - dockingPoint; - - if (targetFlow) { - - waypoints = targetFlow.waypoints; - - - intersection = getApproxIntersection(waypoints, position); - - if (intersection) { - waypointsBefore = waypoints.slice(0, intersection.index); - waypointsAfter = waypoints.slice(intersection.index + (intersection.bendpoint ? 1 : 0)); - - dockingPoint = intersection.bendpoint ? waypoints[intersection.index] : position; - - waypointsBefore.push(copy(dockingPoint)); - waypointsAfter.unshift(copy(dockingPoint)); - } - - source = targetFlow.source; - target = targetFlow.target; - - if (bpmnRules.canConnect(source, shape, targetFlow)) { - // reconnect source -> inserted shape - modeling.reconnectEnd(targetFlow, shape, waypointsBefore || copy(position)); - - reconnected = true; - } - - if (bpmnRules.canConnect(shape, target, targetFlow)) { - - if (!reconnected) { - // reconnect inserted shape -> end - modeling.reconnectStart(targetFlow, shape, waypointsAfter || copy(position)); - } else { - modeling.connect(shape, target, { type: targetFlow.type, waypoints: waypointsAfter }); - } - } - } - }, true); -} - -inherits(CreateOnFlowBehavior, CommandInterceptor); - -CreateOnFlowBehavior.$inject = [ 'eventBus', 'bpmnRules', 'modeling' ]; - -module.exports = CreateOnFlowBehavior; diff --git a/lib/features/modeling/behavior/DropOnFlowBehavior.js b/lib/features/modeling/behavior/DropOnFlowBehavior.js new file mode 100644 index 00000000..39037d5b --- /dev/null +++ b/lib/features/modeling/behavior/DropOnFlowBehavior.js @@ -0,0 +1,121 @@ +'use strict'; + +var inherits = require('inherits'); + +var assign = require('lodash/object/assign'); + +var CommandInterceptor = require('diagram-js/lib/command/CommandInterceptor'); + +var getApproxIntersection = require('diagram-js/lib/util/LineIntersection').getApproxIntersection; + + +function copy(obj) { + return assign({}, obj); +} + +function DropOnFlow(eventBus, bpmnRules, modeling) { + + CommandInterceptor.call(this, eventBus); + + /** + * Reconnect start / end of a connection after + * dropping an element on a flow. + */ + + function insertShape(shape, targetFlow, position) { + var waypoints = targetFlow.waypoints, + waypointsBefore, waypointsAfter, dockingPoint, source, target, reconnected; + + var intersection = getApproxIntersection(waypoints, position); + + if (intersection) { + waypointsBefore = waypoints.slice(0, intersection.index); + waypointsAfter = waypoints.slice(intersection.index + (intersection.bendpoint ? 1 : 0)); + + dockingPoint = intersection.bendpoint ? waypoints[intersection.index] : position; + + waypointsBefore.push(copy(dockingPoint)); + waypointsAfter.unshift(copy(dockingPoint)); + } + + source = targetFlow.source; + target = targetFlow.target; + + if (bpmnRules.canConnect(source, shape, targetFlow)) { + // reconnect source -> inserted shape + modeling.reconnectEnd(targetFlow, shape, waypointsBefore || position); + + reconnected = true; + } + + if (bpmnRules.canConnect(shape, target, targetFlow)) { + + if (!reconnected) { + // reconnect inserted shape -> end + modeling.reconnectStart(targetFlow, shape, waypointsAfter || position); + } else { + modeling.connect(shape, target, { type: targetFlow.type, waypoints: waypointsAfter }); + } + } + } + + eventBus.on('shape.move.move', 250, function(event) { + + var context = event.context, + target = context.target, + targetFlow = context.targetFlow, + shape = context.shape, + shapes = context.shapes; + + if (shapes.length === 1 && bpmnRules.canInsert(shape, target)) { + context.targetFlow = target; + context.target = target.parent; + } else if (targetFlow) { + context.targetFlow = context.flowParent = null; + } + }); + + eventBus.on('shape.move.end', 250, function(event) { + + var context = event.context, + shape = context.shape, + targetFlow = context.targetFlow, + position = { + x: shape.x + (shape.width / 2), + y: shape.y + (shape.height / 2) + }; + + if (targetFlow) { + insertShape(shape, targetFlow, position); + } + }, true); + + this.preExecute('shape.create', function(context) { + + var parent = context.parent, + shape = context.shape; + + if (bpmnRules.canInsert(shape, parent)) { + context.targetFlow = parent; + context.parent = parent.parent; + } + }, true); + + + this.postExecute('shape.create', function(context) { + + var shape = context.shape, + targetFlow = context.targetFlow, + position = context.position; + + if (targetFlow) { + insertShape(shape, targetFlow, position); + } + }, true); +} + +inherits(DropOnFlow, CommandInterceptor); + +DropOnFlow.$inject = [ 'eventBus', 'bpmnRules', 'modeling' ]; + +module.exports = DropOnFlow; diff --git a/lib/features/modeling/behavior/index.js b/lib/features/modeling/behavior/index.js index 59c11df4..d1f3c914 100644 --- a/lib/features/modeling/behavior/index.js +++ b/lib/features/modeling/behavior/index.js @@ -4,7 +4,7 @@ module.exports = { 'copyPasteBehavior', 'createBoundaryEventBehavior', 'createDataObjectBehavior', - 'createOnFlowBehavior', + 'dropOnFlowBehavior', 'createParticipantBehavior', 'dataInputAssociationBehavior', 'deleteLaneBehavior', @@ -25,7 +25,7 @@ module.exports = { copyPasteBehavior: [ 'type', require('./CopyPasteBehavior') ], createBoundaryEventBehavior: [ 'type', require('./CreateBoundaryEventBehavior') ], createDataObjectBehavior: [ 'type', require('./CreateDataObjectBehavior') ], - createOnFlowBehavior: [ 'type', require('./CreateOnFlowBehavior') ], + dropOnFlowBehavior: [ 'type', require('./DropOnFlowBehavior') ], createParticipantBehavior: [ 'type', require('./CreateParticipantBehavior') ], dataInputAssociationBehavior: [ 'type', require('./DataInputAssociationBehavior') ], deleteLaneBehavior: [ 'type', require('./DeleteLaneBehavior') ], diff --git a/lib/features/rules/BpmnRules.js b/lib/features/rules/BpmnRules.js index 65db3575..a9e0c98b 100644 --- a/lib/features/rules/BpmnRules.js +++ b/lib/features/rules/BpmnRules.js @@ -83,7 +83,8 @@ BpmnRules.prototype.init = function() { return canAttach(shapes, target, null, position) || canReplace(shapes, target, position) || - canMove(shapes, target, position); + canMove(shapes, target, position) || + canInsert(shapes, target, position); }); this.addRule([ 'shape.create', 'shape.append' ], function(context) { @@ -749,6 +750,14 @@ function canConnectDataAssociation(source, target) { function canInsert(shape, flow, position) { + if (Array.isArray(shape)) { + if (shape.length !== 1) { + return false; + } + + shape = shape[0]; + } + // return true if we can drop on the // underlying flow parent // diff --git a/test/spec/features/modeling/behavior/CreateOnFlowBehaviorSpec.js b/test/spec/features/modeling/behavior/CreateOnFlowBehaviorSpec.js deleted file mode 100644 index faef4a27..00000000 --- a/test/spec/features/modeling/behavior/CreateOnFlowBehaviorSpec.js +++ /dev/null @@ -1,171 +0,0 @@ -'use strict'; - -require('../../../../TestHelper'); - -/* global inject, bootstrapModeler */ - -var flatten = require('lodash/array/flatten'); - -var modelingModule = require('../../../../../lib/features/modeling'); - - -describe('modeling/behavior - drop on connection', function() { - - var diagramXML = require('./CreateOnFlowBehavior.bpmn'); - - beforeEach(bootstrapModeler(diagramXML, { modules: modelingModule })); - - - describe('rules', function() { - - it('should be allowed for an IntermediateThrowEvent', inject(function(elementRegistry, bpmnRules, elementFactory) { - - // when - var sequenceFlow = elementRegistry.get('SequenceFlow'); - var intermediateThrowEvent = elementFactory.createShape({ type: 'bpmn:IntermediateThrowEvent' }); - - // then - expect(bpmnRules.canCreate(intermediateThrowEvent, sequenceFlow)).to.be.true; - })); - - }); - - - describe('execution', function() { - - it('should connect start -> target -> end', inject(function(modeling, elementRegistry, elementFactory) { - - // given - var intermediateThrowEvent = elementFactory.createShape({ type: 'bpmn:IntermediateThrowEvent' }); - - var startEvent = elementRegistry.get('StartEvent'), - sequenceFlow = elementRegistry.get('SequenceFlow'), - task = elementRegistry.get('Task'); - - var originalWaypoints = sequenceFlow.waypoints; - - var dropPosition = { x: 340, y: 120 }; // first bendpoint - - // when - var newShape = modeling.createShape(intermediateThrowEvent, dropPosition, 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.be.ok; - expect(targetConnection.type).to.equal('bpmn:SequenceFlow'); - - expect(startEvent.outgoing[0]).to.equal(newShape.incoming[0]); - expect(task.incoming[0]).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(dropPosition); - - expect(targetConnection).to.have.waypoints(flatten([ - { x: 340, y: 138 }, - originalWaypoints.slice(2) - ])); - - expect(targetConnection).to.have.startDocking(dropPosition); - })); - - - it('should connect start -> target', inject(function(modeling, elementRegistry, elementFactory) { - - // given - var endEventShape = elementFactory.createShape({ type: 'bpmn:EndEvent' }); - - var sequenceFlow = elementRegistry.get('SequenceFlow'); - var originalWaypoints = sequenceFlow.waypoints; - - var dropPosition = { x: 340, y: 120 }; // first bendpoint - - // when - var newShape = modeling.createShape(endEventShape, dropPosition, sequenceFlow); - - // then - - // new incoming connection - expect(newShape.incoming.length).to.equal(1); - expect(newShape.incoming[0]).to.eql(sequenceFlow); - - // no outgoing edges - expect(newShape.outgoing.length).to.equal(0); - - // split target at insertion point - expect(sequenceFlow).to.have.waypoints(flatten([ - originalWaypoints.slice(0, 1), - { x: 322, y: 120 } - ])); - })); - - - it('should connect target -> end', inject(function(modeling, elementRegistry, elementFactory) { - - // given - var startEventShape = elementFactory.createShape({ type: 'bpmn:StartEvent' }); - - var sequenceFlow = elementRegistry.get('SequenceFlow'); - var originalWaypoints = sequenceFlow.waypoints; - - var dropPosition = { x: 340, y: 120 }; // first bendpoint - - // when - var newShape = modeling.createShape(startEventShape, dropPosition, sequenceFlow); - - // then - - // no incoming connection - expect(newShape.incoming.length).to.equal(0); - - // no outgoing edges - expect(newShape.outgoing.length).to.equal(1); - expect(newShape.outgoing[0]).to.eql(sequenceFlow); - - // split target at insertion point - expect(sequenceFlow).to.have.waypoints(flatten([ - { x: 340, y: 138 }, - originalWaypoints.slice(2) - ])); - })); - - }); - - - describe('rules', function() { - - it('should not insert participant', inject(function(rules, elementRegistry, elementFactory) { - - // given - var participantShape = elementFactory.createShape({ type: 'bpmn:Participant' }); - - var sequenceFlow = elementRegistry.get('SequenceFlow'); - - var dropPosition = { x: 340, y: 120 }; // first bendpoint - - // when - var canDrop = rules.allowed('shape.create', { - shape: participantShape, - parent: sequenceFlow, - dropPosition: dropPosition - }); - - // then - expect(canDrop).to.be.false; - })); - - }); - -}); \ No newline at end of file diff --git a/test/spec/features/modeling/behavior/CreateOnFlowBehavior.bpmn b/test/spec/features/modeling/behavior/DropOnFlowBehavior.bpmn similarity index 60% rename from test/spec/features/modeling/behavior/CreateOnFlowBehavior.bpmn rename to test/spec/features/modeling/behavior/DropOnFlowBehavior.bpmn index 3bc7b4d7..5a835bc5 100644 --- a/test/spec/features/modeling/behavior/CreateOnFlowBehavior.bpmn +++ b/test/spec/features/modeling/behavior/DropOnFlowBehavior.bpmn @@ -1,5 +1,5 @@ - + SequenceFlow @@ -8,6 +8,9 @@ SequenceFlow + + + @@ -26,6 +29,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/test/spec/features/modeling/behavior/DropOnFlowBehaviorSpec.js b/test/spec/features/modeling/behavior/DropOnFlowBehaviorSpec.js new file mode 100644 index 00000000..6ab82cf0 --- /dev/null +++ b/test/spec/features/modeling/behavior/DropOnFlowBehaviorSpec.js @@ -0,0 +1,364 @@ +'use strict'; + +require('../../../../TestHelper'); + +/* global inject, bootstrapModeler */ + +var flatten = require('lodash/array/flatten'); + +var coreModule = require('../../../../../lib/core'), + moveModule = require('diagram-js/lib/features/move'), + modelingModule = require('../../../../../lib/features/modeling'), + noTouchInteractionModule = { touchInteractionEvents: ['value', null ] }; + +var canvasEvent = require('../../../../util/MockEvents').createCanvasEvent; + + +describe('modeling/behavior - drop on connection', function() { + + var diagramXML = require('./DropOnFlowBehavior.bpmn'); + + var testModules = [ noTouchInteractionModule, moveModule, modelingModule, coreModule ]; + + beforeEach(bootstrapModeler(diagramXML, { modules: testModules })); + + + describe('rules', function() { + + it('should be allowed for an IntermediateThrowEvent', inject(function(elementRegistry, bpmnRules, elementFactory) { + + // when + var sequenceFlow = elementRegistry.get('SequenceFlow'); + var intermediateThrowEvent = elementFactory.createShape({ type: 'bpmn:IntermediateThrowEvent' }); + + // then + expect(bpmnRules.canCreate(intermediateThrowEvent, sequenceFlow)).to.be.true; + })); + + }); + + + describe('execution', function() { + + describe('create', function() { + + it('should connect start -> target -> end', inject(function(modeling, elementRegistry, elementFactory) { + + // given + var intermediateThrowEvent = elementFactory.createShape({ type: 'bpmn:IntermediateThrowEvent' }); + + var startEvent = elementRegistry.get('StartEvent'), + sequenceFlow = elementRegistry.get('SequenceFlow'), + task = elementRegistry.get('Task'); + + var originalWaypoints = sequenceFlow.waypoints; + + var dropPosition = { x: 340, y: 120 }; // first bendpoint + + // when + var newShape = modeling.createShape(intermediateThrowEvent, dropPosition, 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.be.ok; + expect(targetConnection.type).to.equal('bpmn:SequenceFlow'); + + expect(startEvent.outgoing[0]).to.equal(newShape.incoming[0]); + expect(task.incoming[0]).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(dropPosition); + + expect(targetConnection).to.have.waypoints(flatten([ + { x: 340, y: 138 }, + originalWaypoints.slice(2) + ])); + + expect(targetConnection).to.have.startDocking(dropPosition); + })); + + + it('should connect start -> target', inject(function(modeling, elementRegistry, elementFactory) { + + // given + var endEventShape = elementFactory.createShape({ type: 'bpmn:EndEvent' }); + + var sequenceFlow = elementRegistry.get('SequenceFlow'); + var originalWaypoints = sequenceFlow.waypoints; + + var dropPosition = { x: 340, y: 120 }; // first bendpoint + + // when + var newShape = modeling.createShape(endEventShape, dropPosition, sequenceFlow); + + // then + + // new incoming connection + expect(newShape.incoming.length).to.equal(1); + expect(newShape.incoming[0]).to.eql(sequenceFlow); + + // no outgoing edges + expect(newShape.outgoing.length).to.equal(0); + + // split target at insertion point + expect(sequenceFlow).to.have.waypoints(flatten([ + originalWaypoints.slice(0, 1), + { x: 322, y: 120 } + ])); + })); + + + it('should connect target -> end', inject(function(modeling, elementRegistry, elementFactory) { + + // given + var startEventShape = elementFactory.createShape({ type: 'bpmn:StartEvent' }); + + var sequenceFlow = elementRegistry.get('SequenceFlow'); + var originalWaypoints = sequenceFlow.waypoints; + + var dropPosition = { x: 340, y: 120 }; // first bendpoint + + // when + var newShape = modeling.createShape(startEventShape, dropPosition, sequenceFlow); + + // then + + // no incoming connection + expect(newShape.incoming.length).to.equal(0); + + // no outgoing edges + expect(newShape.outgoing.length).to.equal(1); + expect(newShape.outgoing[0]).to.eql(sequenceFlow); + + // split target at insertion point + expect(sequenceFlow).to.have.waypoints(flatten([ + { x: 340, y: 138 }, + originalWaypoints.slice(2) + ])); + })); + + }); + + describe('move', function() { + + beforeEach(inject(function(dragging) { + dragging.setOptions({ manual: true }); + })); + + it('should connect start -> target -> end', inject(function(dragging, move, elementRegistry, selection) { + + // given + var intermediateThrowEvent = elementRegistry.get('IntermediateThrowEvent_foo'); + + var startEvent = elementRegistry.get('StartEvent'), + sequenceFlow = elementRegistry.get('SequenceFlow'), + sequenceFlowGfx = elementRegistry.getGraphics(sequenceFlow), + task = elementRegistry.get('Task'); + + var originalWaypoints = sequenceFlow.waypoints; + + // when + selection.select(intermediateThrowEvent); + + move.start(canvasEvent({ x: 0, y: 0 }), intermediateThrowEvent); + + dragging.hover({ + element: sequenceFlow, + gfx: sequenceFlowGfx + }); + + dragging.move(canvasEvent({ x: 150, y: 0 })); + + dragging.end(); + + // then + var targetConnection = intermediateThrowEvent.outgoing[0]; + + // new incoming connection + expect(intermediateThrowEvent.incoming.length).to.equal(1); + expect(intermediateThrowEvent.incoming[0]).to.eql(sequenceFlow); + + // new outgoing connection + expect(intermediateThrowEvent.outgoing.length).to.equal(1); + expect(targetConnection).to.be.ok; + expect(targetConnection.type).to.equal('bpmn:SequenceFlow'); + + expect(startEvent.outgoing[0]).to.equal(intermediateThrowEvent.incoming[0]); + expect(task.incoming[0]).to.equal(intermediateThrowEvent.outgoing[0]); + + // split target at insertion point + expect(sequenceFlow).to.have.waypoints(flatten([ + originalWaypoints.slice(0, 2), + { x: 341, y: 192 } + ])); + + expect(sequenceFlow).to.have.endDocking({ x: 341, y: 210 }); + + expect(targetConnection).to.have.waypoints(flatten([ + { x: 341, y: 228 }, + originalWaypoints.slice(2) + ])); + + expect(targetConnection).to.have.startDocking({ x: 341, y: 210 }); + })); + + + it('should connect start -> target', inject(function(modeling, elementRegistry, selection, move, dragging) { + + // given + var endEventShape = elementRegistry.get('EndEvent_foo'); + + var sequenceFlow = elementRegistry.get('SequenceFlow'), + sequenceFlowGfx = elementRegistry.getGraphics(sequenceFlow), + originalWaypoints = sequenceFlow.waypoints; + + // when + selection.select(endEventShape); + + move.start(canvasEvent({ x: 0, y: 0 }), endEventShape); + + dragging.hover({ + element: sequenceFlow, + gfx: sequenceFlowGfx + }); + + dragging.move(canvasEvent({ x: 150, y: 0 })); + + dragging.end(); + + // then + + // new incoming connection + expect(endEventShape.incoming.length).to.equal(1); + expect(endEventShape.incoming[0]).to.eql(sequenceFlow); + + // no outgoing edges + expect(endEventShape.outgoing.length).to.equal(0); + + // split target at insertion point + expect(sequenceFlow).to.have.waypoints(flatten([ + originalWaypoints.slice(0, 2), + { x: 340, y: 281 } + ])); + })); + + + it('should connect target -> end', inject(function(modeling, elementRegistry, dragging, selection, move) { + + var startEventShape = elementRegistry.get('StartEvent_foo'); + + var sequenceFlow = elementRegistry.get('SequenceFlow'), + sequenceFlowGfx = elementRegistry.getGraphics(sequenceFlow), + originalWaypoints = sequenceFlow.waypoints; + + // when + selection.select(startEventShape); + + move.start(canvasEvent({ x: 0, y: 0 }), startEventShape); + + dragging.hover({ + element: sequenceFlow, + gfx: sequenceFlowGfx + }); + + dragging.move(canvasEvent({ x: -215, y: 0 })); + + dragging.end(); + + // then + + // no incoming connection + expect(startEventShape.incoming.length).to.equal(0); + + // no outgoing edges + expect(startEventShape.outgoing.length).to.equal(1); + expect(startEventShape.outgoing[0]).to.eql(sequenceFlow); + + // split target at insertion point + expect(sequenceFlow).to.have.waypoints(flatten([ + { x: 338, y: 228 }, + originalWaypoints.slice(2) + ])); + })); + + }); + + }); + + + describe('rules', function() { + + it('should not insert participant', inject(function(rules, elementRegistry, elementFactory) { + + // given + var participantShape = elementFactory.createShape({ type: 'bpmn:Participant' }); + + var sequenceFlow = elementRegistry.get('SequenceFlow'); + + var dropPosition = { x: 340, y: 120 }; // first bendpoint + + // when + var canDrop = rules.allowed('shape.create', { + shape: participantShape, + parent: sequenceFlow, + dropPosition: dropPosition + }); + + // then + expect(canDrop).to.be.false; + })); + + + it('should not insert multiple with "move"', inject(function(elementRegistry, selection, move, dragging) { + + // given + var intermediateThrowEvent = elementRegistry.get('IntermediateThrowEvent_foo'), + endEventShape = elementRegistry.get('EndEvent_foo'); + + var sequenceFlow = elementRegistry.get('SequenceFlow'), + sequenceFlowGfx = elementRegistry.getGraphics(sequenceFlow); + + var intInitPosition = { + x: intermediateThrowEvent.x, + y: intermediateThrowEvent.y + }, + endInitPosition = { + x: endEventShape.x, + y: endEventShape.y + }; + + selection.select([ intermediateThrowEvent, endEventShape ]); + + // when + move.start(canvasEvent({ x: 0, y: 0 }), intermediateThrowEvent); + + dragging.hover({ + element: sequenceFlow, + gfx: sequenceFlowGfx + }); + + dragging.move(canvasEvent({ x: -215, y: 0 })); + + dragging.end(); + + // then + expect(intermediateThrowEvent).to.have.position(intInitPosition); + expect(endEventShape).to.have.position(endInitPosition); + })); + + }); + +});