bpmn-js
Version:
A bpmn 2.0 toolkit and web modeler
266 lines (210 loc) • 7.55 kB
JavaScript
import { is } from '../../../util/ModelUtil';
import {
isExpanded,
isHorizontal
} from '../../../util/DiUtil';
import {
asTRBL
} from 'diagram-js/lib/layout/LayoutUtil';
import {
collectLanes,
getLanesRoot
} from '../util/LaneUtil';
var HIGH_PRIORITY = 1500;
/**
* @typedef {import('diagram-js/lib/core/EventBus').default} EventBus
*
* @typedef {import('../../../model/Types').Shape} Shape
*
* @typedef {import('diagram-js/lib/util/Types').Dimensions} Dimensions
* @typedef {import('diagram-js/lib/util/Types').Direction} Direction
* @typedef {import('diagram-js/lib/util/Types').RectTRBL} RectTRBL
*/
/**
* @type {Dimensions}
*/
export var GROUP_MIN_DIMENSIONS = { width: 140, height: 120 };
/**
* @type {Dimensions}
*/
export var LANE_MIN_DIMENSIONS = { width: 300, height: 60 };
/**
* @type {Dimensions}
*/
export var VERTICAL_LANE_MIN_DIMENSIONS = { width: 60, height: 300 };
/**
* @type {Dimensions}
*/
export var PARTICIPANT_MIN_DIMENSIONS = { width: 300, height: 150 };
/**
* @type {Dimensions}
*/
export var VERTICAL_PARTICIPANT_MIN_DIMENSIONS = { width: 150, height: 300 };
/**
* @type {Dimensions}
*/
export var SUB_PROCESS_MIN_DIMENSIONS = { width: 140, height: 120 };
/**
* @type {Dimensions}
*/
export var TEXT_ANNOTATION_MIN_DIMENSIONS = { width: 50, height: 30 };
/**
* Set minimum bounds/resize constraints on resize.
*
* @param {EventBus} eventBus
*/
export default function ResizeBehavior(eventBus) {
eventBus.on('resize.start', HIGH_PRIORITY, function(event) {
var context = event.context,
shape = context.shape,
direction = context.direction,
balanced = context.balanced;
if (is(shape, 'bpmn:Lane') || is(shape, 'bpmn:Participant')) {
context.resizeConstraints = getParticipantResizeConstraints(shape, direction, balanced);
}
if (is(shape, 'bpmn:SubProcess') && isExpanded(shape)) {
context.minDimensions = SUB_PROCESS_MIN_DIMENSIONS;
}
if (is(shape, 'bpmn:TextAnnotation')) {
context.minDimensions = TEXT_ANNOTATION_MIN_DIMENSIONS;
}
});
}
ResizeBehavior.$inject = [ 'eventBus' ];
var abs = Math.abs,
min = Math.min,
max = Math.max;
function addToTrbl(trbl, attr, value, choice) {
var current = trbl[attr];
// make sure to set the value if it does not exist
// or apply the correct value by comparing against
// choice(value, currentValue)
trbl[attr] = current === undefined ? value : choice(value, current);
}
function addMin(trbl, attr, value) {
return addToTrbl(trbl, attr, value, min);
}
function addMax(trbl, attr, value) {
return addToTrbl(trbl, attr, value, max);
}
var LANE_PADDING = { top: 20, left: 50, right: 20, bottom: 20 },
VERTICAL_LANE_PADDING = { top: 50, left: 20, right: 20, bottom: 20 };
/**
* @param {Shape} laneShape
* @param {Direction} resizeDirection
* @param {boolean} [balanced=false]
*
* @return { {
* min: RectTRBL;
* max: RectTRBL;
* } }
*/
export function getParticipantResizeConstraints(laneShape, resizeDirection, balanced) {
var lanesRoot = getLanesRoot(laneShape);
var isFirst = true,
isLast = true;
var allLanes = collectLanes(lanesRoot, [ lanesRoot ]);
var laneTrbl = asTRBL(laneShape);
var maxTrbl = {},
minTrbl = {};
var isHorizontalLane = isHorizontal(laneShape);
var minDimensions = isHorizontalLane ? LANE_MIN_DIMENSIONS : VERTICAL_LANE_MIN_DIMENSIONS;
if (/n/.test(resizeDirection)) {
minTrbl.top = laneTrbl.bottom - minDimensions.height;
} else if (/e/.test(resizeDirection)) {
minTrbl.right = laneTrbl.left + minDimensions.width;
} else if (/s/.test(resizeDirection)) {
minTrbl.bottom = laneTrbl.top + minDimensions.height;
} else if (/w/.test(resizeDirection)) {
minTrbl.left = laneTrbl.right - minDimensions.width;
}
// min/max size based on related lanes
allLanes.forEach(function(other) {
var otherTrbl = asTRBL(other);
// lane flags
if (isHorizontalLane) {
if (otherTrbl.top < (laneTrbl.top - 10)) {
isFirst = false;
}
if (otherTrbl.bottom > (laneTrbl.bottom + 10)) {
isLast = false;
}
}
else {
if (otherTrbl.left < (laneTrbl.left - 10)) {
isFirst = false;
}
if (otherTrbl.right > (laneTrbl.right + 10)) {
isLast = false;
}
}
if (/n/.test(resizeDirection)) {
// max top size (based on next element)
if (balanced && abs(laneTrbl.top - otherTrbl.bottom) < 10) {
addMax(maxTrbl, 'top', otherTrbl.top + minDimensions.height);
}
// min top size (based on self or nested element)
if (abs(laneTrbl.top - otherTrbl.top) < 5) {
addMin(minTrbl, 'top', otherTrbl.bottom - minDimensions.height);
}
}
if (/e/.test(resizeDirection)) {
// max right size (based on previous element)
if (balanced && abs(laneTrbl.right - otherTrbl.left) < 10) {
addMin(maxTrbl, 'right', otherTrbl.right - minDimensions.width);
}
// min right size (based on self or nested element)
if (abs(laneTrbl.right - otherTrbl.right) < 5) {
addMax(minTrbl, 'right', otherTrbl.left + minDimensions.width);
}
}
if (/s/.test(resizeDirection)) {
// max bottom size (based on previous element)
if (balanced && abs(laneTrbl.bottom - otherTrbl.top) < 10) {
addMin(maxTrbl, 'bottom', otherTrbl.bottom - minDimensions.height);
}
// min bottom size (based on self or nested element)
if (abs(laneTrbl.bottom - otherTrbl.bottom) < 5) {
addMax(minTrbl, 'bottom', otherTrbl.top + minDimensions.height);
}
}
if (/w/.test(resizeDirection)) {
// max left size (based on next element)
if (balanced && abs(laneTrbl.left - otherTrbl.right) < 10) {
addMax(maxTrbl, 'left', otherTrbl.left + minDimensions.width);
}
// min left size (based on self or nested element)
if (abs(laneTrbl.left - otherTrbl.left) < 5) {
addMin(minTrbl, 'left', otherTrbl.right - minDimensions.width);
}
}
});
// max top/bottom/left/right size based on flow nodes
var flowElements = lanesRoot.children.filter(function(s) {
return !s.hidden && !s.waypoints && (is(s, 'bpmn:FlowElement') || is(s, 'bpmn:Artifact'));
});
var padding = isHorizontalLane ? LANE_PADDING : VERTICAL_LANE_PADDING;
flowElements.forEach(function(flowElement) {
var flowElementTrbl = asTRBL(flowElement);
// vertical lane will resize from top with respect to flow element irrespective of first or last lane
if (/n/.test(resizeDirection) && (!isHorizontalLane || isFirst)) {
addMin(minTrbl, 'top', flowElementTrbl.top - padding.top);
}
// horizonal lane will resize from right with respect to flow element irrespective of first or last lane
if (/e/.test(resizeDirection) && (isHorizontalLane || isLast)) {
addMax(minTrbl, 'right', flowElementTrbl.right + padding.right);
}
// vertical lane will resize from bottom with respect to flow element irrespective of first or last lane
if (/s/.test(resizeDirection) && (!isHorizontalLane || isLast)) {
addMax(minTrbl, 'bottom', flowElementTrbl.bottom + padding.bottom);
}
// horizonal lane will resize from left with respect to flow element irrespective of first or last lane
if (/w/.test(resizeDirection) && (isHorizontalLane || isFirst)) {
addMin(minTrbl, 'left', flowElementTrbl.left - padding.left);
}
});
return {
min: minTrbl,
max: maxTrbl
};
}