123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- import inherits from 'inherits';
- import {
- assign
- } from 'min-dash';
- import BaseLayouter from 'diagram-js/lib/layout/BaseLayouter';
- import {
- repairConnection,
- withoutRedundantPoints
- } from 'diagram-js/lib/layout/ManhattanLayout';
- import {
- getMid,
- getOrientation
- } from 'diagram-js/lib/layout/LayoutUtil';
- import {
- isExpanded
- } from '../../util/DiUtil';
- import { is } from '../../util/ModelUtil';
- export default function BpmnLayouter() {}
- inherits(BpmnLayouter, BaseLayouter);
- BpmnLayouter.prototype.layoutConnection = function(connection, hints) {
- hints = hints || {};
- var source = connection.source,
- target = connection.target,
- waypoints = connection.waypoints,
- start = hints.connectionStart,
- end = hints.connectionEnd;
- var manhattanOptions,
- updatedWaypoints;
- if (!start) {
- start = getConnectionDocking(waypoints && waypoints[0], source);
- }
- if (!end) {
- end = getConnectionDocking(waypoints && waypoints[waypoints.length - 1], target);
- }
- // TODO(nikku): support vertical modeling
- // and invert preferredLayouts accordingly
- if (is(connection, 'bpmn:Association') ||
- is(connection, 'bpmn:DataAssociation')) {
- if (waypoints && !isCompensationAssociation(connection)) {
- return [].concat([ start ], waypoints.slice(1, -1), [ end ]);
- }
- }
- // manhattan layout sequence / message flows
- if (is(connection, 'bpmn:MessageFlow')) {
- manhattanOptions = getMessageFlowManhattanOptions(source, target);
- } else
- // layout all connection between flow elements h:h,
- //
- // except for
- //
- // (1) outgoing of BoundaryEvents -> layout based on attach orientation and target orientation
- // (2) incoming / outgoing of Gateway -> v:h (outgoing), h:v (incoming)
- // (3) loops from / to the same element
- //
- if (is(connection, 'bpmn:SequenceFlow') ||
- isCompensationAssociation(connection)) {
- if (source === target) {
- manhattanOptions = {
- preferredLayouts: [ 'b:l' ]
- };
- } else
- if (is(source, 'bpmn:BoundaryEvent')) {
- manhattanOptions = {
- preferredLayouts: getBoundaryEventPreferredLayouts(source, target)
- };
- } else
- if (is(source, 'bpmn:Gateway')) {
- manhattanOptions = {
- preferredLayouts: [ 'v:h' ]
- };
- } else
- if (is(target, 'bpmn:Gateway')) {
- manhattanOptions = {
- preferredLayouts: [ 'h:v' ]
- };
- }
- else {
- manhattanOptions = {
- preferredLayouts: [ 'h:h' ]
- };
- }
- }
- if (manhattanOptions) {
- manhattanOptions = assign(manhattanOptions, hints);
- updatedWaypoints =
- withoutRedundantPoints(
- repairConnection(
- source, target,
- start, end,
- waypoints,
- manhattanOptions
- )
- );
- }
- return updatedWaypoints || [ start, end ];
- };
- function getAttachOrientation(attachedElement) {
- var hostElement = attachedElement.host,
- padding = -10;
- return getOrientation(getMid(attachedElement), hostElement, padding);
- }
- function getMessageFlowManhattanOptions(source, target) {
- return {
- preferredLayouts: [ 'straight', 'v:v' ],
- preserveDocking: getMessageFlowPreserveDocking(source, target)
- };
- }
- function getMessageFlowPreserveDocking(source, target) {
- // (1) docking element connected to participant has precedence
- if (is(target, 'bpmn:Participant')) {
- return 'source';
- }
- if (is(source, 'bpmn:Participant')) {
- return 'target';
- }
- // (2) docking element connected to expanded sub-process has precedence
- if (isExpandedSubProcess(target)) {
- return 'source';
- }
- if (isExpandedSubProcess(source)) {
- return 'target';
- }
- // (3) docking event has precedence
- if (is(target, 'bpmn:Event')) {
- return 'target';
- }
- if (is(source, 'bpmn:Event')) {
- return 'source';
- }
- return null;
- }
- function getConnectionDocking(point, shape) {
- return point ? (point.original || point) : getMid(shape);
- }
- function isCompensationAssociation(connection) {
- var source = connection.source,
- target = connection.target;
- return is(target, 'bpmn:Activity') &&
- is(source, 'bpmn:BoundaryEvent') &&
- target.businessObject.isForCompensation;
- }
- function isExpandedSubProcess(element) {
- return is(element, 'bpmn:SubProcess') && isExpanded(element);
- }
- function isSame(a, b) {
- return a === b;
- }
- function isAnyOrientation(orientation, orientations) {
- return orientations.indexOf(orientation) !== -1;
- }
- var oppositeOrientationMapping = {
- 'top': 'bottom',
- 'top-right': 'bottom-left',
- 'top-left': 'bottom-right',
- 'right': 'left',
- 'bottom': 'top',
- 'bottom-right': 'top-left',
- 'bottom-left': 'top-right',
- 'left': 'right'
- };
- var orientationDirectionMapping = {
- top: 't',
- right: 'r',
- bottom: 'b',
- left: 'l'
- };
- function getHorizontalOrientation(orientation) {
- var matches = /right|left/.exec(orientation);
- return matches && matches[0];
- }
- function getVerticalOrientation(orientation) {
- var matches = /top|bottom/.exec(orientation);
- return matches && matches[0];
- }
- function isOppositeOrientation(a, b) {
- return oppositeOrientationMapping[a] === b;
- }
- function isOppositeHorizontalOrientation(a, b) {
- var horizontalOrientation = getHorizontalOrientation(a);
- var oppositeHorizontalOrientation = oppositeOrientationMapping[horizontalOrientation];
- return b.indexOf(oppositeHorizontalOrientation) !== -1;
- }
- function isOppositeVerticalOrientation(a, b) {
- var verticalOrientation = getVerticalOrientation(a);
- var oppositeVerticalOrientation = oppositeOrientationMapping[verticalOrientation];
- return b.indexOf(oppositeVerticalOrientation) !== -1;
- }
- function isHorizontalOrientation(orientation) {
- return orientation === 'right' || orientation === 'left';
- }
- function getBoundaryEventPreferredLayouts(source, target) {
- var sourceMid = getMid(source),
- targetMid = getMid(target),
- attachOrientation = getAttachOrientation(source),
- sourceLayout,
- targetLayout;
- var isLoop = isSame(source.host, target);
- var attachedToSide = isAnyOrientation(attachOrientation, [ 'top', 'right', 'bottom', 'left' ]);
- var targetOrientation = getOrientation(targetMid, sourceMid, {
- x: source.width / 2 + target.width / 2,
- y: source.height / 2 + target.height / 2
- });
- // source layout
- sourceLayout = getBoundaryEventSourceLayout(attachOrientation, targetOrientation, attachedToSide, isLoop);
- // target layout
- targetLayout = getBoundaryEventTargetLayout(attachOrientation, targetOrientation, attachedToSide, isLoop);
- return [ sourceLayout + ':' + targetLayout ];
- }
- function getBoundaryEventSourceLayout(attachOrientation, targetOrientation, attachedToSide, isLoop) {
- // attached to either top, right, bottom or left side
- if (attachedToSide) {
- return orientationDirectionMapping[attachOrientation];
- }
- // attached to either top-right, top-left, bottom-right or bottom-left corner
- // loop, same vertical or opposite horizontal orientation
- if (isLoop ||
- isSame(
- getVerticalOrientation(attachOrientation), getVerticalOrientation(targetOrientation)
- ) ||
- isOppositeOrientation(
- getHorizontalOrientation(attachOrientation), getHorizontalOrientation(targetOrientation)
- )) {
- return orientationDirectionMapping[getVerticalOrientation(attachOrientation)];
- }
- // fallback
- return orientationDirectionMapping[getHorizontalOrientation(attachOrientation)];
- }
- function getBoundaryEventTargetLayout(attachOrientation, targetOrientation, attachedToSide, isLoop) {
- // attached to either top, right, bottom or left side
- if (attachedToSide) {
- if (isHorizontalOrientation(attachOrientation)) {
- // orientation is 'right' or 'left'
- // loop or opposite horizontal orientation or same orientation
- if (
- isLoop ||
- isOppositeHorizontalOrientation(attachOrientation, targetOrientation) ||
- isSame(attachOrientation, targetOrientation)
- ) {
- return 'h';
- }
- // fallback
- return 'v';
- } else {
- // orientation is 'top' or 'bottom'
- // loop or opposite vertical orientation or same orientation
- if (
- isLoop ||
- isOppositeVerticalOrientation(attachOrientation, targetOrientation) ||
- isSame(attachOrientation, targetOrientation)
- ) {
- return 'v';
- }
- // fallback
- return 'h';
- }
- }
- // attached to either top-right, top-left, bottom-right or bottom-left corner
- // orientation is 'right', 'left'
- // or same vertical orientation but also 'right' or 'left'
- if (isHorizontalOrientation(targetOrientation) ||
- (isSame(getVerticalOrientation(attachOrientation), getVerticalOrientation(targetOrientation)) &&
- getHorizontalOrientation(targetOrientation))) {
- return 'h';
- } else {
- return 'v';
- }
- }
|