chore(layouter): refactor
This commit is contained in:
parent
5c5656aceb
commit
0ed0492641
|
@ -22,195 +22,8 @@ import {
|
|||
|
||||
import { is } from '../../util/ModelUtil';
|
||||
|
||||
|
||||
var BOUNDARY_TO_HOST_THRESHOLD = 40;
|
||||
|
||||
export default function BpmnLayouter() {}
|
||||
|
||||
inherits(BpmnLayouter, BaseLayouter);
|
||||
|
||||
|
||||
BpmnLayouter.prototype.layoutConnection = function(connection, hints) {
|
||||
if (!hints) {
|
||||
hints = {};
|
||||
}
|
||||
|
||||
var source = hints.source || connection.source,
|
||||
target = hints.target || connection.target,
|
||||
waypoints = hints.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(source, target)) {
|
||||
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(source, target)) {
|
||||
|
||||
if (source === target) {
|
||||
manhattanOptions = {
|
||||
preferredLayouts: getLoopPreferredLayout(source, connection)
|
||||
};
|
||||
} else
|
||||
|
||||
if (is(source, 'bpmn:BoundaryEvent')) {
|
||||
|
||||
manhattanOptions = {
|
||||
preferredLayouts: getBoundaryEventPreferredLayouts(source, target, end)
|
||||
};
|
||||
|
||||
} 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(source, 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 ATTACH_ORIENTATION_PADDING = -10,
|
||||
BOUNDARY_TO_HOST_THRESHOLD = 40;
|
||||
|
||||
var oppositeOrientationMapping = {
|
||||
'top': 'bottom',
|
||||
|
@ -230,6 +43,162 @@ var orientationDirectionMapping = {
|
|||
left: 'l'
|
||||
};
|
||||
|
||||
|
||||
export default function BpmnLayouter() {}
|
||||
|
||||
inherits(BpmnLayouter, BaseLayouter);
|
||||
|
||||
|
||||
BpmnLayouter.prototype.layoutConnection = function(connection, hints) {
|
||||
if (!hints) {
|
||||
hints = {};
|
||||
}
|
||||
|
||||
var source = hints.source || connection.source,
|
||||
target = hints.target || connection.target,
|
||||
waypoints = hints.waypoints || connection.waypoints,
|
||||
connectionStart = hints.connectionStart,
|
||||
connectionEnd = hints.connectionEnd;
|
||||
|
||||
var manhattanOptions,
|
||||
updatedWaypoints;
|
||||
|
||||
if (!connectionStart) {
|
||||
connectionStart = getConnectionDocking(waypoints && waypoints[ 0 ], source);
|
||||
}
|
||||
|
||||
if (!connectionEnd) {
|
||||
connectionEnd = 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(source, target)) {
|
||||
return [].concat([ connectionStart ], waypoints.slice(1, -1), [ connectionEnd ]);
|
||||
}
|
||||
}
|
||||
|
||||
if (is(connection, 'bpmn:MessageFlow')) {
|
||||
manhattanOptions = getMessageFlowManhattanOptions(source, target);
|
||||
} else if (is(connection, 'bpmn:SequenceFlow') || isCompensationAssociation(source, target)) {
|
||||
|
||||
// layout all connection between flow elements h:h, except for
|
||||
// (1) outgoing of boundary events -> layout based on attach orientation and target orientation
|
||||
// (2) incoming/outgoing of gateways -> v:h for outgoing, h:v for incoming
|
||||
// (3) loops
|
||||
if (source === target) {
|
||||
manhattanOptions = {
|
||||
preferredLayouts: getLoopPreferredLayout(source, connection)
|
||||
};
|
||||
} else if (is(source, 'bpmn:BoundaryEvent')) {
|
||||
manhattanOptions = {
|
||||
preferredLayouts: getBoundaryEventPreferredLayouts(source, target, connectionEnd)
|
||||
};
|
||||
} 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,
|
||||
connectionStart,
|
||||
connectionEnd,
|
||||
waypoints,
|
||||
manhattanOptions
|
||||
));
|
||||
}
|
||||
|
||||
return updatedWaypoints || [ connectionStart, connectionEnd ];
|
||||
};
|
||||
|
||||
|
||||
// helpers //////////
|
||||
|
||||
function getAttachOrientation(attachedElement) {
|
||||
var hostElement = attachedElement.host;
|
||||
|
||||
return getOrientation(getMid(attachedElement), hostElement, ATTACH_ORIENTATION_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(source, 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;
|
||||
}
|
||||
|
||||
function getHorizontalOrientation(orientation) {
|
||||
var matches = /right|left/.exec(orientation);
|
||||
|
||||
|
@ -312,8 +281,8 @@ function getBoundaryEventPreferredLayouts(source, target, end) {
|
|||
}
|
||||
|
||||
function getBoundaryEventLoopLayout(attachOrientation, attachedToSide, source, target, end) {
|
||||
|
||||
var sourceLayout = orientationDirectionMapping[attachedToSide ? attachOrientation : getVerticalOrientation(attachOrientation)],
|
||||
var orientation = attachedToSide ? attachOrientation : getVerticalOrientation(attachOrientation),
|
||||
sourceLayout = orientationDirectionMapping[ orientation ],
|
||||
targetLayout;
|
||||
|
||||
if (attachedToSide) {
|
||||
|
@ -334,20 +303,23 @@ function shouldConnectToSameSide(axis, source, target, end) {
|
|||
|
||||
return !(
|
||||
areCloseOnAxis(axis, end, target, threshold) ||
|
||||
areCloseOnAxis(axis, end, { x: target.x + target.width, y: target.y + target.height }, threshold) ||
|
||||
areCloseOnAxis(axis, end, {
|
||||
x: target.x + target.width,
|
||||
y: target.y + target.height
|
||||
}, threshold) ||
|
||||
areCloseOnAxis(axis, end, getMid(source), threshold)
|
||||
);
|
||||
}
|
||||
|
||||
function areCloseOnAxis(axis, a, b, threshold) {
|
||||
return Math.abs(a[axis] - b[axis]) < threshold;
|
||||
return Math.abs(a[ axis ] - b[ axis ]) < threshold;
|
||||
}
|
||||
|
||||
function getBoundaryEventSourceLayout(attachOrientation, targetOrientation, attachedToSide) {
|
||||
|
||||
// attached to either top, right, bottom or left side
|
||||
if (attachedToSide) {
|
||||
return orientationDirectionMapping[attachOrientation];
|
||||
return orientationDirectionMapping[ attachOrientation ];
|
||||
}
|
||||
|
||||
// attached to either top-right, top-left, bottom-right or bottom-left corner
|
||||
|
@ -358,11 +330,11 @@ function getBoundaryEventSourceLayout(attachOrientation, targetOrientation, atta
|
|||
) || isOppositeOrientation(
|
||||
getHorizontalOrientation(attachOrientation), getHorizontalOrientation(targetOrientation)
|
||||
)) {
|
||||
return orientationDirectionMapping[getVerticalOrientation(attachOrientation)];
|
||||
return orientationDirectionMapping[ getVerticalOrientation(attachOrientation) ];
|
||||
}
|
||||
|
||||
// fallback
|
||||
return orientationDirectionMapping[getHorizontalOrientation(attachOrientation)];
|
||||
return orientationDirectionMapping[ getHorizontalOrientation(attachOrientation) ];
|
||||
}
|
||||
|
||||
function getBoundaryEventTargetLayout(attachOrientation, targetOrientation, attachedToSide) {
|
||||
|
@ -371,7 +343,7 @@ function getBoundaryEventTargetLayout(attachOrientation, targetOrientation, atta
|
|||
if (attachedToSide) {
|
||||
if (isHorizontalOrientation(attachOrientation)) {
|
||||
|
||||
// orientation is 'right' or 'left'
|
||||
// orientation is right or left
|
||||
|
||||
// opposite horizontal orientation or same orientation
|
||||
if (
|
||||
|
@ -385,7 +357,7 @@ function getBoundaryEventTargetLayout(attachOrientation, targetOrientation, atta
|
|||
return 'v';
|
||||
} else {
|
||||
|
||||
// orientation is 'top' or 'bottom'
|
||||
// orientation is top or bottom
|
||||
|
||||
// opposite vertical orientation or same orientation
|
||||
if (
|
||||
|
@ -402,8 +374,8 @@ function getBoundaryEventTargetLayout(attachOrientation, targetOrientation, atta
|
|||
|
||||
// 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'
|
||||
// orientation is right, left
|
||||
// or same vertical orientation but also right or left
|
||||
if (isHorizontalOrientation(targetOrientation) ||
|
||||
(isSame(getVerticalOrientation(attachOrientation), getVerticalOrientation(targetOrientation)) &&
|
||||
getHorizontalOrientation(targetOrientation))) {
|
||||
|
|
Loading…
Reference in New Issue