2019-05-23 20:37:06 +00:00
|
|
|
import inherits from 'inherits';
|
|
|
|
|
|
|
|
import CreateMoveSnapping from 'diagram-js/lib/features/snapping/CreateMoveSnapping';
|
|
|
|
|
|
|
|
import {
|
|
|
|
isSnapped,
|
|
|
|
setSnapped,
|
2019-06-26 13:35:18 +00:00
|
|
|
topLeft,
|
|
|
|
bottomRight
|
2019-05-23 20:37:06 +00:00
|
|
|
} from 'diagram-js/lib/features/snapping/SnapUtil';
|
|
|
|
|
2019-10-11 14:39:29 +00:00
|
|
|
import { isExpanded } from '../../util/DiUtil';
|
2019-06-26 13:35:18 +00:00
|
|
|
|
2019-05-23 20:37:06 +00:00
|
|
|
import { is } from '../../util/ModelUtil';
|
|
|
|
|
2019-06-17 05:39:39 +00:00
|
|
|
import {
|
|
|
|
asTRBL,
|
|
|
|
getMid
|
|
|
|
} from 'diagram-js/lib/layout/LayoutUtil';
|
2019-05-23 20:37:06 +00:00
|
|
|
|
|
|
|
import { getBoundaryAttachment } from './BpmnSnappingUtil';
|
|
|
|
|
2019-06-17 05:39:39 +00:00
|
|
|
import { forEach } from 'min-dash';
|
|
|
|
|
2019-05-23 20:37:06 +00:00
|
|
|
var HIGH_PRIORITY = 1500;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Snap during create and move.
|
|
|
|
*
|
|
|
|
* @param {EventBus} eventBus
|
|
|
|
* @param {Injector} injector
|
|
|
|
*/
|
2019-10-11 14:39:29 +00:00
|
|
|
export default function BpmnCreateMoveSnapping(eventBus, injector) {
|
2019-05-23 20:37:06 +00:00
|
|
|
injector.invoke(CreateMoveSnapping, this);
|
|
|
|
|
|
|
|
// creating first participant
|
|
|
|
eventBus.on([ 'create.move', 'create.end' ], HIGH_PRIORITY, setSnappedIfConstrained);
|
|
|
|
|
|
|
|
// snap boundary events
|
|
|
|
eventBus.on([
|
|
|
|
'create.move',
|
|
|
|
'create.end',
|
|
|
|
'shape.move.move',
|
|
|
|
'shape.move.end'
|
|
|
|
], HIGH_PRIORITY, function(event) {
|
|
|
|
var context = event.context,
|
2019-10-11 14:39:29 +00:00
|
|
|
canExecute = context.canExecute,
|
|
|
|
target = context.target;
|
2019-05-23 20:37:06 +00:00
|
|
|
|
2019-10-11 14:39:29 +00:00
|
|
|
var canAttach = canExecute && (canExecute === 'attach' || canExecute.attach);
|
|
|
|
|
|
|
|
if (canAttach && !isSnapped(event)) {
|
2019-05-23 20:37:06 +00:00
|
|
|
snapBoundaryEvent(event, target);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
inherits(BpmnCreateMoveSnapping, CreateMoveSnapping);
|
|
|
|
|
|
|
|
BpmnCreateMoveSnapping.$inject = [
|
|
|
|
'eventBus',
|
|
|
|
'injector'
|
|
|
|
];
|
|
|
|
|
|
|
|
BpmnCreateMoveSnapping.prototype.initSnap = function(event) {
|
|
|
|
var snapContext = CreateMoveSnapping.prototype.initSnap.call(this, event);
|
|
|
|
|
|
|
|
var shape = event.shape;
|
|
|
|
|
2019-06-17 05:39:39 +00:00
|
|
|
// snap to docking points
|
|
|
|
forEach(shape.outgoing, function(connection) {
|
|
|
|
var docking = connection.waypoints[0];
|
|
|
|
|
|
|
|
docking = docking.original || docking;
|
|
|
|
|
|
|
|
snapContext.setSnapOrigin(connection.id + '-docking', {
|
|
|
|
x: docking.x - event.x,
|
|
|
|
y: docking.y - event.y
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
forEach(shape.incoming, function(connection) {
|
|
|
|
var docking = connection.waypoints[connection.waypoints.length - 1];
|
|
|
|
|
|
|
|
docking = docking.original || docking;
|
|
|
|
|
|
|
|
snapContext.setSnapOrigin(connection.id + '-docking', {
|
|
|
|
x: docking.x - event.x,
|
|
|
|
y: docking.y - event.y
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2019-05-23 20:37:06 +00:00
|
|
|
if (is(shape, 'bpmn:Participant')) {
|
|
|
|
|
|
|
|
// snap to borders with higher priority
|
|
|
|
snapContext.setSnapLocations([ 'top-left', 'bottom-right', 'mid' ]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return snapContext;
|
|
|
|
};
|
|
|
|
|
|
|
|
BpmnCreateMoveSnapping.prototype.addSnapTargetPoints = function(snapPoints, shape, target) {
|
|
|
|
CreateMoveSnapping.prototype.addSnapTargetPoints.call(this, snapPoints, shape, target);
|
|
|
|
|
2019-06-17 05:39:39 +00:00
|
|
|
var snapTargets = this.getSnapTargets(shape, target);
|
|
|
|
|
2019-06-26 13:35:18 +00:00
|
|
|
forEach(snapTargets, function(snapTarget) {
|
|
|
|
|
|
|
|
// handle TRBL alignment
|
|
|
|
//
|
|
|
|
// * with container elements
|
|
|
|
// * with text annotations
|
|
|
|
if (isContainer(snapTarget) || areAll([ shape, snapTarget ], 'bpmn:TextAnnotation')) {
|
|
|
|
snapPoints.add('top-left', topLeft(snapTarget));
|
|
|
|
snapPoints.add('bottom-right', bottomRight(snapTarget));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2019-06-17 05:39:39 +00:00
|
|
|
// snap to docking points
|
|
|
|
forEach(shape.incoming, function(connection) {
|
|
|
|
|
|
|
|
if (!includes(snapTargets, connection.source)) {
|
|
|
|
snapPoints.add('mid', getMid(connection.source));
|
|
|
|
}
|
|
|
|
|
|
|
|
var docking = connection.waypoints[0];
|
|
|
|
|
|
|
|
snapPoints.add(connection.id + '-docking', docking.original || docking);
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
forEach(shape.outgoing, function(connection) {
|
|
|
|
|
|
|
|
if (!includes(snapTargets, connection.target)) {
|
|
|
|
snapPoints.add('mid', getMid(connection.target));
|
|
|
|
}
|
|
|
|
|
|
|
|
var docking = connection.waypoints[ connection.waypoints.length - 1 ];
|
|
|
|
|
|
|
|
snapPoints.add(connection.id + '-docking', docking.original || docking);
|
|
|
|
});
|
|
|
|
|
2019-05-23 20:37:06 +00:00
|
|
|
// add sequence flow parents as snap targets
|
|
|
|
if (is(target, 'bpmn:SequenceFlow')) {
|
|
|
|
snapPoints = this.addSnapTargetPoints(snapPoints, shape, target.parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
return snapPoints;
|
|
|
|
};
|
|
|
|
|
|
|
|
BpmnCreateMoveSnapping.prototype.getSnapTargets = function(shape, target) {
|
|
|
|
return CreateMoveSnapping.prototype.getSnapTargets.call(this, shape, target)
|
|
|
|
.filter(function(snapTarget) {
|
|
|
|
|
|
|
|
// do not snap to lanes
|
|
|
|
return !is(snapTarget, 'bpmn:Lane');
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
// helpers //////////
|
|
|
|
|
|
|
|
function snapBoundaryEvent(event, target) {
|
|
|
|
var targetTRBL = asTRBL(target);
|
|
|
|
|
|
|
|
var direction = getBoundaryAttachment(event, target);
|
|
|
|
|
2019-10-11 14:39:29 +00:00
|
|
|
var context = event.context,
|
|
|
|
shape = context.shape;
|
|
|
|
|
|
|
|
var offset;
|
|
|
|
|
|
|
|
if (shape.parent) {
|
|
|
|
offset = { x: 0, y: 0 };
|
|
|
|
} else {
|
|
|
|
offset = getMid(shape);
|
|
|
|
}
|
|
|
|
|
2019-05-23 20:37:06 +00:00
|
|
|
if (/top/.test(direction)) {
|
2019-10-11 14:39:29 +00:00
|
|
|
setSnapped(event, 'y', targetTRBL.top - offset.y);
|
|
|
|
} else if (/bottom/.test(direction)) {
|
|
|
|
setSnapped(event, 'y', targetTRBL.bottom - offset.y);
|
2019-05-23 20:37:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (/left/.test(direction)) {
|
2019-10-11 14:39:29 +00:00
|
|
|
setSnapped(event, 'x', targetTRBL.left - offset.x);
|
|
|
|
} else if (/right/.test(direction)) {
|
|
|
|
setSnapped(event, 'x', targetTRBL.right - offset.x);
|
2019-05-23 20:37:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-26 13:35:18 +00:00
|
|
|
function areAll(elements, type) {
|
|
|
|
return elements.every(function(el) {
|
|
|
|
return is(el, type);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function isContainer(element) {
|
|
|
|
if (is(element, 'bpmn:SubProcess') && isExpanded(element)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return is(element, 'bpmn:Participant');
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-23 20:37:06 +00:00
|
|
|
function setSnappedIfConstrained(event) {
|
|
|
|
var context = event.context,
|
|
|
|
createConstraints = context.createConstraints;
|
|
|
|
|
|
|
|
if (!createConstraints) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var top = createConstraints.top,
|
|
|
|
right = createConstraints.right,
|
|
|
|
bottom = createConstraints.bottom,
|
|
|
|
left = createConstraints.left;
|
|
|
|
|
|
|
|
if ((left && left >= event.x) || (right && right <= event.x)) {
|
|
|
|
setSnapped(event, 'x', event.x);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((top && top >= event.y) || (bottom && bottom <= event.y)) {
|
|
|
|
setSnapped(event, 'y', event.y);
|
|
|
|
}
|
2019-06-17 05:39:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function includes(array, value) {
|
|
|
|
return array.indexOf(value) !== -1;
|
2019-10-11 14:39:29 +00:00
|
|
|
}
|