2015-04-22 07:08:38 +00:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
var inherits = require('inherits');
|
|
|
|
|
|
|
|
var assign = require('lodash/object/assign');
|
|
|
|
|
|
|
|
var BaseLayouter = require('diagram-js/lib/layout/BaseLayouter'),
|
|
|
|
ManhattanLayout = require('diagram-js/lib/layout/ManhattanLayout');
|
|
|
|
|
2015-07-29 13:11:54 +00:00
|
|
|
var LayoutUtil = require('diagram-js/lib/layout/LayoutUtil');
|
|
|
|
|
2017-12-10 11:29:54 +00:00
|
|
|
var pointsOnLine = require('diagram-js/lib/util/Geometry').pointsOnLine;
|
|
|
|
|
2016-06-22 12:36:44 +00:00
|
|
|
var isExpanded = require('../../util/DiUtil').isExpanded;
|
|
|
|
|
2015-07-29 13:11:54 +00:00
|
|
|
var getMid = LayoutUtil.getMid,
|
|
|
|
getOrientation = LayoutUtil.getOrientation;
|
|
|
|
|
2015-04-27 14:50:09 +00:00
|
|
|
var is = require('../../util/ModelUtil').is;
|
2015-04-22 07:08:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
function BpmnLayouter() {}
|
|
|
|
|
|
|
|
inherits(BpmnLayouter, BaseLayouter);
|
|
|
|
|
|
|
|
module.exports = BpmnLayouter;
|
|
|
|
|
|
|
|
|
2016-06-22 12:38:44 +00:00
|
|
|
BpmnLayouter.prototype.layoutConnection = function(connection, hints) {
|
|
|
|
|
|
|
|
hints = hints || {};
|
|
|
|
|
2015-04-22 07:08:38 +00:00
|
|
|
var source = connection.source,
|
|
|
|
target = connection.target,
|
|
|
|
waypoints = connection.waypoints,
|
2016-06-22 12:38:44 +00:00
|
|
|
start = hints.connectionStart,
|
|
|
|
end = hints.connectionEnd;
|
2015-04-22 07:08:38 +00:00
|
|
|
|
2015-07-29 13:11:54 +00:00
|
|
|
var manhattanOptions,
|
2015-04-22 07:08:38 +00:00
|
|
|
updatedWaypoints;
|
|
|
|
|
2016-06-26 22:29:54 +00:00
|
|
|
if (!start) {
|
|
|
|
start = getConnectionDocking(waypoints && waypoints[0], source);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!end) {
|
|
|
|
end = getConnectionDocking(waypoints && waypoints[waypoints.length - 1], target);
|
|
|
|
}
|
2015-07-29 13:11:54 +00:00
|
|
|
|
2016-06-22 12:36:44 +00:00
|
|
|
// TODO(nikku): support vertical modeling
|
2015-07-29 13:11:54 +00:00
|
|
|
// and invert preferredLayouts accordingly
|
|
|
|
|
2016-01-27 08:45:05 +00:00
|
|
|
if (is(connection, 'bpmn:Association') ||
|
|
|
|
is(connection, 'bpmn:DataAssociation')) {
|
|
|
|
|
|
|
|
if (waypoints && !isCompensationAssociation(connection)) {
|
2016-06-26 22:29:54 +00:00
|
|
|
return [].concat([ start ], waypoints.slice(1, -1), [ end ]);
|
2016-01-27 08:45:05 +00:00
|
|
|
}
|
2015-10-13 09:07:35 +00:00
|
|
|
}
|
2015-04-22 07:08:38 +00:00
|
|
|
|
|
|
|
// manhattan layout sequence / message flows
|
|
|
|
if (is(connection, 'bpmn:MessageFlow')) {
|
2015-07-29 13:11:54 +00:00
|
|
|
manhattanOptions = {
|
2016-06-21 09:59:33 +00:00
|
|
|
preferredLayouts: [ 'v:v' ]
|
2015-04-22 07:08:38 +00:00
|
|
|
};
|
2015-08-24 09:28:54 +00:00
|
|
|
|
2016-06-21 09:59:33 +00:00
|
|
|
if (is(target, 'bpmn:Participant')) {
|
|
|
|
manhattanOptions = {
|
|
|
|
preferredLayouts: [ 'straight', 'v:v' ]
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-06-22 12:36:44 +00:00
|
|
|
if (isExpandedSubProcess(target)) {
|
|
|
|
manhattanOptions = {
|
|
|
|
preferredLayouts: [ 'straight', 'v:v' ]
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isExpandedSubProcess(source) && is(target, 'bpmn:FlowNode')) {
|
|
|
|
manhattanOptions = {
|
|
|
|
preferredLayouts: [ 'straight', 'v:v' ],
|
|
|
|
preserveDocking: isExpandedSubProcess(target) ? 'source' : 'target'
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-06-21 09:59:33 +00:00
|
|
|
if (is(source, 'bpmn:Participant') && is(target, 'bpmn:FlowNode')) {
|
|
|
|
manhattanOptions = {
|
|
|
|
preferredLayouts: [ 'straight', 'v:v' ],
|
2016-06-22 12:36:44 +00:00
|
|
|
preserveDocking: 'target'
|
2016-06-21 09:59:33 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2015-08-24 09:28:54 +00:00
|
|
|
if (is(target, 'bpmn:Event')) {
|
|
|
|
manhattanOptions = {
|
|
|
|
preferredLayouts: [ 'v:v' ]
|
|
|
|
};
|
|
|
|
}
|
2015-07-29 13:11:54 +00:00
|
|
|
} else
|
|
|
|
|
2015-04-22 07:08:38 +00:00
|
|
|
|
2015-07-29 13:11:54 +00:00
|
|
|
// layout all connection between flow elements h:h,
|
|
|
|
//
|
|
|
|
// except for
|
|
|
|
//
|
|
|
|
// (1) outgoing of BoundaryEvents -> layout h:v or v:h based on attach orientation
|
|
|
|
// (2) incoming / outgoing of Gateway -> v:h (outgoing), h:v (incoming)
|
|
|
|
//
|
2016-01-27 08:45:05 +00:00
|
|
|
if (is(connection, 'bpmn:SequenceFlow') ||
|
|
|
|
isCompensationAssociation(connection)) {
|
2015-07-29 13:11:54 +00:00
|
|
|
|
|
|
|
// make sure boundary event connections do
|
|
|
|
// not look ugly =:>
|
|
|
|
if (is(source, 'bpmn:BoundaryEvent')) {
|
|
|
|
|
|
|
|
var orientation = getAttachOrientation(source);
|
|
|
|
|
|
|
|
if (/left|right/.test(orientation)) {
|
|
|
|
manhattanOptions = {
|
|
|
|
preferredLayouts: [ 'h:v' ]
|
|
|
|
};
|
|
|
|
} else
|
|
|
|
|
|
|
|
if (/top|bottom/.test(orientation)) {
|
|
|
|
manhattanOptions = {
|
|
|
|
preferredLayouts: [ 'v:h' ]
|
|
|
|
};
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
|
|
|
|
if (is(source, 'bpmn:Gateway')) {
|
|
|
|
|
|
|
|
manhattanOptions = {
|
|
|
|
preferredLayouts: [ 'v:h' ]
|
|
|
|
};
|
|
|
|
} else
|
|
|
|
|
|
|
|
if (is(target, 'bpmn:Gateway')) {
|
|
|
|
|
|
|
|
manhattanOptions = {
|
|
|
|
preferredLayouts: [ 'h:v' ]
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// apply horizontal love <3
|
|
|
|
else {
|
|
|
|
manhattanOptions = {
|
|
|
|
preferredLayouts: [ 'h:h' ]
|
|
|
|
};
|
|
|
|
}
|
2015-04-22 07:08:38 +00:00
|
|
|
}
|
|
|
|
|
2015-07-29 13:11:54 +00:00
|
|
|
if (manhattanOptions) {
|
2015-04-22 07:08:38 +00:00
|
|
|
|
2016-06-22 12:38:44 +00:00
|
|
|
manhattanOptions = assign(manhattanOptions, hints);
|
2015-04-22 07:08:38 +00:00
|
|
|
|
|
|
|
updatedWaypoints =
|
|
|
|
ManhattanLayout.repairConnection(
|
2015-07-29 13:11:54 +00:00
|
|
|
source, target,
|
|
|
|
start, end,
|
2015-04-22 07:08:38 +00:00
|
|
|
waypoints,
|
2015-07-29 13:11:54 +00:00
|
|
|
manhattanOptions);
|
2017-12-10 11:29:54 +00:00
|
|
|
|
|
|
|
// filter un-needed waypoints that may be the result of
|
|
|
|
// bundle collapsing
|
|
|
|
updatedWaypoints = updatedWaypoints && updatedWaypoints.reduce(function(points, p, idx) {
|
|
|
|
|
|
|
|
var previous = points[points.length - 1],
|
|
|
|
next = updatedWaypoints[idx + 1];
|
|
|
|
|
|
|
|
if (!pointsOnLine(previous, next, p, 0)) {
|
|
|
|
points.push(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
return points;
|
|
|
|
}, []);
|
2015-04-22 07:08:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return updatedWaypoints || [ start, end ];
|
2015-07-13 08:37:43 +00:00
|
|
|
};
|
2015-07-29 13:11:54 +00:00
|
|
|
|
|
|
|
|
|
|
|
function getAttachOrientation(attachedElement) {
|
|
|
|
|
|
|
|
var hostElement = attachedElement.host,
|
|
|
|
padding = -10;
|
|
|
|
|
|
|
|
return getOrientation(getMid(attachedElement), hostElement, padding);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-26 22:29:54 +00:00
|
|
|
function getConnectionDocking(point, shape) {
|
|
|
|
return point ? (point.original || point) : getMid(shape);
|
2015-07-29 13:11:54 +00:00
|
|
|
}
|
2016-01-27 08:45:05 +00:00
|
|
|
|
|
|
|
function isCompensationAssociation(connection) {
|
|
|
|
|
|
|
|
var source = connection.source,
|
|
|
|
target = connection.target;
|
|
|
|
|
|
|
|
return is(target, 'bpmn:Activity') &&
|
|
|
|
is(source, 'bpmn:BoundaryEvent') &&
|
|
|
|
target.businessObject.isForCompensation;
|
2016-06-21 09:59:33 +00:00
|
|
|
}
|
2016-06-22 12:36:44 +00:00
|
|
|
|
|
|
|
|
|
|
|
function isExpandedSubProcess(element) {
|
|
|
|
return is(element, 'bpmn:SubProcess') && isExpanded(element);
|
|
|
|
}
|