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; }