This commit is contained in:
hanjian
2024-08-14 15:17:51 +08:00
parent 20a221c1a2
commit b610f94b2e
3483 changed files with 650965 additions and 0 deletions

View File

@@ -0,0 +1,207 @@
import {
mid,
setSnapped
} from 'diagram-js/lib/features/snapping/SnapUtil';
import { isCmd } from 'diagram-js/lib/features/keyboard/KeyboardUtil';
import {
getOrientation
} from 'diagram-js/lib/layout/LayoutUtil';
import { is } from '../../util/ModelUtil';
import {
every,
some
} from 'min-dash';
import { isAny } from '../modeling/util/ModelingUtil';
var HIGHER_PRIORITY = 1250;
var BOUNDARY_TO_HOST_THRESHOLD = 40;
var TARGET_BOUNDS_PADDING = 20;
var TARGET_CENTER_PADDING = 20;
var AXES = [ 'x', 'y' ];
var abs = Math.abs;
/**
* Snap during connect.
*
* @param {EventBus} eventBus
* @param {Rules} rules
*/
export default function BpmnConnectSnapping(eventBus, rules) {
eventBus.on([
'connect.hover',
'connect.move',
'connect.end',
], HIGHER_PRIORITY, function(event) {
var context = event.context,
source = context.source,
target = context.target;
if (event.originalEvent && isCmd(event.originalEvent)) {
return;
}
if (!context.initialSourcePosition) {
context.initialSourcePosition = context.sourcePosition;
}
var connectionAttrs = rules.allowed('connection.create', {
source: source,
target: target
});
if (target && connectionAttrs) {
snapInsideTarget(event, target, getTargetBoundsPadding(target));
}
if (target && isAnyType(connectionAttrs, [
'bpmn:Association',
'bpmn:DataInputAssociation',
'bpmn:DataOutputAssociation',
'bpmn:SequenceFlow'
])) {
// snap source
context.sourcePosition = mid(source);
if (isAny(target, ['bpmn:Event', 'bpmn:Gateway'])) {
snapToPosition(event, mid(target));
}
if (is(target, 'bpmn:Task')) {
snapTargetMidOnCenter(event, target);
}
if (is(source, 'bpmn:BoundaryEvent') && target === source.host) {
snapBoundaryEventLoop(event, source, target);
}
} else if (isType(connectionAttrs, 'bpmn:MessageFlow')) {
if (is(source, 'bpmn:Event')) {
// snap source
context.sourcePosition = mid(source);
}
if (is(target, 'bpmn:Event')) {
// snap target
snapToPosition(event, mid(target));
}
} else {
// un-snap source
context.sourcePosition = context.initialSourcePosition;
}
});
}
BpmnConnectSnapping.$inject = [
'eventBus',
'rules'
];
function snapInsideTarget(event, target, padding) {
AXES.forEach(function(axis) {
var matchingTargetDimension = getDimensionForAxis(axis, target),
newCoordinate;
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);
}
});
}
// snap to target mid if event position in center area
function snapTargetMidOnCenter(event, target) {
var isCenter = every(AXES, function(axis) {
var coordinate = event[axis],
matchingTargetDimension = getDimensionForAxis(axis, target);
return coordinate > target[axis] + TARGET_CENTER_PADDING
&& coordinate < target[axis] + matchingTargetDimension - TARGET_CENTER_PADDING;
});
if (isCenter) {
snapToPosition(event, mid(target));
}
}
// snap outside of Boundary Event surroundings
function snapBoundaryEventLoop(event, source, target) {
var sourceMid = mid(source),
orientation = getOrientation(sourceMid, target, -10),
snappingAxes = [];
if (/top|bottom/.test(orientation)) {
snappingAxes.push('x');
}
if (/left|right/.test(orientation)) {
snappingAxes.push('y');
}
snappingAxes.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;
}
else {
newCoordinate = sourceMid[axis] - BOUNDARY_TO_HOST_THRESHOLD;
}
setSnapped(event, axis, newCoordinate);
}
});
}
// helpers //////////
function snapToPosition(event, position) {
setSnapped(event, 'x', position.x);
setSnapped(event, 'y', position.y);
}
function isType(attrs, type) {
return attrs && attrs.type === type;
}
function isAnyType(attrs, types) {
return some(types, function(type) {
return isType(attrs, type);
});
}
function getDimensionForAxis(axis, element) {
return axis === 'x' ? element.width : element.height;
}
function getTargetBoundsPadding(target) {
if (is(target, 'bpmn:Task')) {
return 10;
} else {
return TARGET_BOUNDS_PADDING;
}
}

View File

@@ -0,0 +1,228 @@
import inherits from 'inherits';
import CreateMoveSnapping from 'diagram-js/lib/features/snapping/CreateMoveSnapping';
import {
isSnapped,
setSnapped,
topLeft,
bottomRight
} from 'diagram-js/lib/features/snapping/SnapUtil';
import {
isExpanded
} from '../../util/DiUtil';
import { is } from '../../util/ModelUtil';
import {
asTRBL,
getMid
} from 'diagram-js/lib/layout/LayoutUtil';
import { getBoundaryAttachment } from './BpmnSnappingUtil';
import { forEach } from 'min-dash';
var HIGH_PRIORITY = 1500;
/**
* Snap during create and move.
*
* @param {BpmnRules} bpmnRules
* @param {EventBus} eventBus
* @param {Injector} injector
*/
export default function BpmnCreateMoveSnapping(bpmnRules, eventBus, injector) {
injector.invoke(CreateMoveSnapping, this);
// creating first participant
eventBus.on([ 'create.move', 'create.end' ], HIGH_PRIORITY, setSnappedIfConstrained);
function canAttach(shape, target, position) {
return bpmnRules.canAttach([ shape ], target, null, position) === 'attach';
}
// snap boundary events
eventBus.on([
'create.move',
'create.end',
'shape.move.move',
'shape.move.end'
], HIGH_PRIORITY, function(event) {
var context = event.context,
target = context.target,
shape = context.shape;
if (target && canAttach(shape, target, event) && !isSnapped(event)) {
snapBoundaryEvent(event, target);
}
});
}
inherits(BpmnCreateMoveSnapping, CreateMoveSnapping);
BpmnCreateMoveSnapping.$inject = [
'bpmnRules',
'eventBus',
'injector'
];
BpmnCreateMoveSnapping.prototype.initSnap = function(event) {
var snapContext = CreateMoveSnapping.prototype.initSnap.call(this, event);
var shape = event.shape;
// 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
});
});
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);
var snapTargets = this.getSnapTargets(shape, target);
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));
}
});
// 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);
});
// 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);
if (/top/.test(direction)) {
setSnapped(event, 'y', targetTRBL.top);
} else
if (/bottom/.test(direction)) {
setSnapped(event, 'y', targetTRBL.bottom);
}
if (/left/.test(direction)) {
setSnapped(event, 'x', targetTRBL.left);
} else
if (/right/.test(direction)) {
setSnapped(event, 'x', targetTRBL.right);
}
}
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');
}
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);
}
}
function includes(array, value) {
return array.indexOf(value) !== -1;
}

View File

@@ -0,0 +1,12 @@
import { getOrientation } from 'diagram-js/lib/layout/LayoutUtil';
export function getBoundaryAttachment(position, targetBounds) {
var orientation = getOrientation(position, targetBounds, -15);
if (orientation !== 'intersect') {
return orientation;
} else {
return null;
}
}

View File

@@ -0,0 +1,13 @@
import BpmnConnectSnapping from './BpmnConnectSnapping';
import BpmnCreateMoveSnapping from './BpmnCreateMoveSnapping';
import SnappingModule from 'diagram-js/lib/features/snapping';
export default {
__depends__: [ SnappingModule ],
__init__: [
'connectSnapping',
'createMoveSnapping'
],
connectSnapping: [ 'type', BpmnConnectSnapping ],
createMoveSnapping: [ 'type', BpmnCreateMoveSnapping ]
};