bpmn-js
Version:
A bpmn 2.0 toolkit and web modeler
156 lines (121 loc) • 3.37 kB
JavaScript
import inherits from 'inherits-browser';
import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
import { pointsAligned } from 'diagram-js/lib/util/Geometry';
import {
assign
} from 'min-dash';
/**
* @typedef {import('diagram-js/lib/core/EventBus').default} EventBus
* @typedef {import('diagram-js/lib/features/grid-snapping/GridSnapping').default} GridSnapping
* @typedef {import('../../modeling/Modeling').default} Modeling
*
* @typedef {import('diagram-js/lib/util/Types').Point} Point
*/
var HIGH_PRIORITY = 3000;
/**
* Snaps connections with Manhattan layout.
*
* @param {EventBus} eventBus
* @param {GridSnapping} gridSnapping
* @param {Modeling} modeling
*/
export default function GridSnappingLayoutConnectionBehavior(eventBus, gridSnapping, modeling) {
CommandInterceptor.call(this, eventBus);
this._gridSnapping = gridSnapping;
var self = this;
this.postExecuted([
'connection.create',
'connection.layout'
], HIGH_PRIORITY, function(event) {
var context = event.context,
connection = context.connection,
hints = context.hints || {},
waypoints = connection.waypoints;
if (hints.connectionStart || hints.connectionEnd || hints.createElementsBehavior === false) {
return;
}
if (!hasMiddleSegments(waypoints)) {
return;
}
modeling.updateWaypoints(connection, self.snapMiddleSegments(waypoints));
});
}
GridSnappingLayoutConnectionBehavior.$inject = [
'eventBus',
'gridSnapping',
'modeling'
];
inherits(GridSnappingLayoutConnectionBehavior, CommandInterceptor);
/**
* Snap middle segments of a given connection.
*
* @param {Point[]} waypoints
*
* @return {Point[]}
*/
GridSnappingLayoutConnectionBehavior.prototype.snapMiddleSegments = function(waypoints) {
var gridSnapping = this._gridSnapping,
snapped;
waypoints = waypoints.slice();
for (var i = 1; i < waypoints.length - 2; i++) {
snapped = snapSegment(gridSnapping, waypoints[i], waypoints[i + 1]);
waypoints[i] = snapped[0];
waypoints[i + 1] = snapped[1];
}
return waypoints;
};
// helpers //////////
/**
* Check whether a connection has a middle segments.
*
* @param {Point[]} waypoints
*
* @return {boolean}
*/
function hasMiddleSegments(waypoints) {
return waypoints.length > 3;
}
/**
* Check whether an alignment is horizontal.
*
* @param {string} aligned
*
* @return {boolean}
*/
function horizontallyAligned(aligned) {
return aligned === 'h';
}
/**
* Check whether an alignment is vertical.
*
* @param {string} aligned
*
* @return {boolean}
*/
function verticallyAligned(aligned) {
return aligned === 'v';
}
/**
* Get middle segments from a given connection.
*
* @param {Point[]} waypoints
*
* @return {Point[]}
*/
function snapSegment(gridSnapping, segmentStart, segmentEnd) {
var aligned = pointsAligned(segmentStart, segmentEnd);
var snapped = {};
if (horizontallyAligned(aligned)) {
// snap horizontally
snapped.y = gridSnapping.snapValue(segmentStart.y);
}
if (verticallyAligned(aligned)) {
// snap vertically
snapped.x = gridSnapping.snapValue(segmentStart.x);
}
if ('x' in snapped || 'y' in snapped) {
segmentStart = assign({}, segmentStart, snapped);
segmentEnd = assign({}, segmentEnd, snapped);
}
return [ segmentStart, segmentEnd ];
}