From bdc3b70b2a516a0a2c4ed1acfd20f8b013d95c88 Mon Sep 17 00:00:00 2001 From: Philipp Fromme Date: Tue, 5 Nov 2019 12:47:11 +0100 Subject: [PATCH] chore(connect-snapping): snap correctly --- lib/features/snapping/BpmnConnectSnapping.js | 131 ++++++++++--------- 1 file changed, 70 insertions(+), 61 deletions(-) diff --git a/lib/features/snapping/BpmnConnectSnapping.js b/lib/features/snapping/BpmnConnectSnapping.js index 40c45e98..5c8c8cd7 100644 --- a/lib/features/snapping/BpmnConnectSnapping.js +++ b/lib/features/snapping/BpmnConnectSnapping.js @@ -11,22 +11,19 @@ import { import { is } from '../../util/ModelUtil'; -import { - some -} from 'min-dash'; - import { isAny } from '../modeling/util/ModelingUtil'; +import { some } from 'min-dash'; + var HIGHER_PRIORITY = 1250; var BOUNDARY_TO_HOST_THRESHOLD = 40; -var TARGET_BOUNDS_PADDING = 20; +var TARGET_BOUNDS_PADDING = 20, + TASK_BOUNDS_PADDING = 10; var TARGET_CENTER_PADDING = 20; -var TASK_BOUNDS_PADDING = 10; - var AXES = [ 'x', 'y' ]; var abs = Math.abs; @@ -44,66 +41,67 @@ export default function BpmnConnectSnapping(eventBus, rules) { 'connect.end', ], HIGHER_PRIORITY, function(event) { var context = event.context, + canExecute = context.canExecute, + start = context.start, + hover = context.hover, source = context.source, target = context.target; + // do NOT snap on CMD if (event.originalEvent && isCmd(event.originalEvent)) { return; } - if (!context.initialSourcePosition) { - context.initialSourcePosition = context.sourcePosition; + if (!context.initialConnectionStart) { + context.initialConnectionStart = context.connectionStart; } - var connectionAttrs = rules.allowed('connection.create', { - source: source, - target: target - }); - - if (target && connectionAttrs) { - snapInsideTarget(event, target, getTargetBoundsPadding(target)); + // snap hover + if (canExecute && hover) { + snapToShape(event, hover, getTargetBoundsPadding(hover)); } - if (target && isAnyType(connectionAttrs, [ + if (hover && isAnyType(canExecute, [ 'bpmn:Association', 'bpmn:DataInputAssociation', 'bpmn:DataOutputAssociation', 'bpmn:SequenceFlow' ])) { + context.connectionStart = mid(start); - // snap source - context.sourcePosition = mid(source); - - if (isAny(target, [ 'bpmn:Event', 'bpmn:Gateway' ])) { - snapToPosition(event, mid(target)); + // snap hover + if (isAny(hover, [ 'bpmn:Event', 'bpmn:Gateway' ])) { + snapToPosition(event, mid(hover)); } - if (isAny(target, [ 'bpmn:Task', 'bpmn:SubProcess' ])) { - snapToTaskMid(event, target); + // snap hover + if (isAny(hover, [ 'bpmn:Task', 'bpmn:SubProcess' ])) { + snapToTargetMid(event, hover); } + // snap source and target if (is(source, 'bpmn:BoundaryEvent') && target === source.host) { - snapBoundaryEventLoop(event, source, target); + snapBoundaryEventLoop(event); } - } else if (isType(connectionAttrs, 'bpmn:MessageFlow')) { + } else if (isType(canExecute, 'bpmn:MessageFlow')) { - if (is(source, 'bpmn:Event')) { + if (is(start, 'bpmn:Event')) { - // snap source - context.sourcePosition = mid(source); + // snap start + context.connectionStart = mid(start); } - if (is(target, 'bpmn:Event')) { + if (is(hover, 'bpmn:Event')) { - // snap target - snapToPosition(event, mid(target)); + // snap hover + snapToPosition(event, mid(hover)); } } else { // un-snap source - context.sourcePosition = context.initialSourcePosition; + context.connectionStart = context.initialConnectionStart; } }); } @@ -113,58 +111,64 @@ BpmnConnectSnapping.$inject = [ 'rules' ]; -function snapInsideTarget(event, target, padding) { +// helpers ////////// + +// snap to target if event in target +function snapToShape(event, target, padding) { AXES.forEach(function(axis) { - var matchingTargetDimension = getDimensionForAxis(axis, target), - newCoordinate; + var dimensionForAxis = getDimensionForAxis(axis, target); - if (event[axis] < target[axis] + padding) { - newCoordinate = target[axis] + padding; - } else if (event[axis] > target[axis] + matchingTargetDimension - padding) { - newCoordinate = target[axis] + matchingTargetDimension - padding; - } - - if (newCoordinate) { - setSnapped(event, axis, newCoordinate); + if (event[ axis ] < target[ axis ] + padding) { + setSnapped(event, axis, target[ axis ] + padding); + } else if (event[ axis ] > target[ axis ] + dimensionForAxis - padding) { + setSnapped(event, axis, target[ axis ] + dimensionForAxis - padding); } }); } -// snap to target mid if event in center -function snapToTaskMid(event, target) { +// snap to target mid if event in target mid +function snapToTargetMid(event, target) { var targetMid = mid(target); AXES.forEach(function(axis) { - if (isCenter(event, target, axis)) { + if (isMid(event, target, axis)) { setSnapped(event, axis, targetMid[ axis ]); } }); } -// snap outside of Boundary Event surroundings -function snapBoundaryEventLoop(event, source, target) { +// snap to prevent loop overlapping boundary event +function snapBoundaryEventLoop(event) { + var context = event.context, + source = context.source, + target = context.target; + + if (isReverse(context)) { + return; + } + var sourceMid = mid(source), orientation = getOrientation(sourceMid, target, -10), - snappingAxes = []; + axes = []; if (/top|bottom/.test(orientation)) { - snappingAxes.push('x'); + axes.push('x'); } if (/left|right/.test(orientation)) { - snappingAxes.push('y'); + axes.push('y'); } - snappingAxes.forEach(function(axis) { - var coordinate = event[axis], newCoordinate; + axes.forEach(function(axis) { + var coordinate = event[ axis ], newCoordinate; - if (abs(coordinate - sourceMid[axis]) < BOUNDARY_TO_HOST_THRESHOLD) { - if (coordinate > sourceMid[axis]) { - newCoordinate = sourceMid[axis] + BOUNDARY_TO_HOST_THRESHOLD; + if (abs(coordinate - sourceMid[ axis ]) < BOUNDARY_TO_HOST_THRESHOLD) { + if (coordinate > sourceMid[ axis ]) { + newCoordinate = sourceMid[ axis ] + BOUNDARY_TO_HOST_THRESHOLD; } else { - newCoordinate = sourceMid[axis] - BOUNDARY_TO_HOST_THRESHOLD; + newCoordinate = sourceMid[ axis ] - BOUNDARY_TO_HOST_THRESHOLD; } setSnapped(event, axis, newCoordinate); @@ -172,8 +176,6 @@ function snapBoundaryEventLoop(event, source, target) { }); } -// helpers ////////// - function snapToPosition(event, position) { setSnapped(event, 'x', position.x); setSnapped(event, 'y', position.y); @@ -201,7 +203,14 @@ function getTargetBoundsPadding(target) { } } -function isCenter(event, target, axis) { +function isMid(event, target, axis) { return event[ axis ] > target[ axis ] + TARGET_CENTER_PADDING && event[ axis ] < target[ axis ] + getDimensionForAxis(axis, target) - TARGET_CENTER_PADDING; } + +function isReverse(context) { + var hover = context.hover, + source = context.source; + + return hover && source && hover === source; +} \ No newline at end of file