import inherits from 'inherits'; import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor'; import { pointsAligned } from 'diagram-js/lib/util/Geometry'; import { assign } from 'min-dash'; var HIGH_PRIORITY = 3000; /** * Snaps connections with Manhattan layout. */ export default function LayoutConnectionBehavior(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)); }); } LayoutConnectionBehavior.$inject = [ 'eventBus', 'gridSnapping', 'modeling' ]; inherits(LayoutConnectionBehavior, CommandInterceptor); /** * Snap middle segments of a given connection. * * @param {Array} waypoints * * @returns {Array} */ LayoutConnectionBehavior.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 {Array} waypoints * * @returns {boolean} */ function hasMiddleSegments(waypoints) { return waypoints.length > 3; } /** * Check whether an alignment is horizontal. * * @param {string} aligned * * @returns {boolean} */ function horizontallyAligned(aligned) { return aligned === 'h'; } /** * Check whether an alignment is vertical. * * @param {string} aligned * * @returns {boolean} */ function verticallyAligned(aligned) { return aligned === 'v'; } /** * Get middle segments from a given connection. * * @param {Array} waypoints * * @returns {Array} */ 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 ]; }