bpmn-js/lib/features/auto-place/BpmnAutoPlaceUtil.js

148 lines
3.2 KiB
JavaScript

import { is } from '../../util/ModelUtil';
import { isAny } from '../modeling/util/ModelingUtil';
import {
getMid,
asTRBL,
getOrientation
} from 'diagram-js/lib/layout/LayoutUtil';
import {
findFreePosition,
generateGetNextPosition,
getConnectedDistance
} from 'diagram-js/lib/features/auto-place/AutoPlaceUtil';
/**
* Find the new position for the target element to
* connect to source.
*
* @param {djs.model.Shape} source
* @param {djs.model.Shape} element
*
* @return {Point}
*/
export function getNewShapePosition(source, element) {
if (is(element, 'bpmn:TextAnnotation')) {
return getTextAnnotationPosition(source, element);
}
if (isAny(element, [ 'bpmn:DataObjectReference', 'bpmn:DataStoreReference' ])) {
return getDataElementPosition(source, element);
}
if (is(element, 'bpmn:FlowNode')) {
return getFlowNodePosition(source, element);
}
}
/**
* Always try to place element right of source;
* compute actual distance from previous nodes in flow.
*/
export function getFlowNodePosition(source, element) {
var sourceTrbl = asTRBL(source);
var sourceMid = getMid(source);
var horizontalDistance = getConnectedDistance(source, {
filter: function(connection) {
return is(connection, 'bpmn:SequenceFlow');
}
});
var margin = 30,
minDistance = 80,
orientation = 'left';
if (is(source, 'bpmn:BoundaryEvent')) {
orientation = getOrientation(source, source.host, -25);
if (orientation.indexOf('top') !== -1) {
margin *= -1;
}
}
var position = {
x: sourceTrbl.right + horizontalDistance + element.width / 2,
y: sourceMid.y + getVerticalDistance(orientation, minDistance)
};
var nextPositionDirection = {
y: {
margin: margin,
minDistance: minDistance
}
};
return findFreePosition(source, element, position, generateGetNextPosition(nextPositionDirection));
}
function getVerticalDistance(orientation, minDistance) {
if (orientation.indexOf('top') != -1) {
return -1 * minDistance;
} else if (orientation.indexOf('bottom') != -1) {
return minDistance;
} else {
return 0;
}
}
/**
* Always try to place text annotations top right of source.
*/
export function getTextAnnotationPosition(source, element) {
var sourceTrbl = asTRBL(source);
var position = {
x: sourceTrbl.right + element.width / 2,
y: sourceTrbl.top - 50 - element.height / 2
};
if (isConnection(source)) {
position = getMid(source);
position.x += 100;
position.y -= 50;
}
var nextPositionDirection = {
y: {
margin: -30,
minDistance: 20
}
};
return findFreePosition(source, element, position, generateGetNextPosition(nextPositionDirection));
}
/**
* Always put element bottom right of source.
*/
export function getDataElementPosition(source, element) {
var sourceTrbl = asTRBL(source);
var position = {
x: sourceTrbl.right - 10 + element.width / 2,
y: sourceTrbl.bottom + 40 + element.width / 2
};
var nextPositionDirection = {
x: {
margin: 30,
minDistance: 30
}
};
return findFreePosition(source, element, position, generateGetNextPosition(nextPositionDirection));
}
function isConnection(element) {
return !!element.waypoints;
}