Skip to content

Commit

Permalink
fix(manhattan-layout): relayout loops if necessary
Browse files Browse the repository at this point in the history
Related to bpmn.io/bpmn-js#1121
  • Loading branch information
philippfromme authored and Niklas Kiefer committed Aug 21, 2019
1 parent 3d2d345 commit 3a63db0
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 20 deletions.
20 changes: 11 additions & 9 deletions lib/layout/ManhattanLayout.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {
isArray,
assign,
find,
without,
assign
isArray,
without
} from 'min-dash';

import {
Expand Down Expand Up @@ -519,8 +519,7 @@ function tryRepairConnectionEnd(moved, other, newDocking, points) {
*/
function _tryRepairConnectionSide(moved, other, newDocking, points) {

function needsRelayout(moved, other, points) {

function needsRelayout(points) {
if (points.length < 3) {
return true;
}
Expand Down Expand Up @@ -571,13 +570,12 @@ function _tryRepairConnectionSide(moved, other, newDocking, points) {
return points;
}


// (0) only repair what has layoutable bendpoints

// (1) if only one bendpoint and on shape moved onto other shapes axis
// (horizontally / vertically), relayout

if (needsRelayout(moved, other, points)) {
if (needsRelayout(points)) {
return null;
}

Expand All @@ -593,11 +591,15 @@ function _tryRepairConnectionSide(moved, other, newDocking, points) {

// (3) if shape intersects with any bendpoint after repair,
// remove all segments up to this bendpoint and repair from there

slicedPoints = removeOverlapping(newPoints, moved, other);

if (slicedPoints !== newPoints) {
return _tryRepairConnectionSide(moved, other, newDocking, slicedPoints);
newPoints = _tryRepairConnectionSide(moved, other, newDocking, slicedPoints);
}

// (4) do NOT repair if repaired bendpoints are aligned
if (newPoints && pointsAligned(newPoints)) {
return null;
}

return newPoints;
Expand Down
64 changes: 54 additions & 10 deletions lib/util/Geometry.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import {
every,
isArray
} from 'min-dash';

/**
* Computes the distance between two points
*
Expand Down Expand Up @@ -49,33 +54,72 @@ export function pointsOnLine(p, q, r, accuracy) {
var ALIGNED_THRESHOLD = 2;

/**
* Returns whether two points are in a horizontal or vertical line.
* Check whether two points are horizontally or vertically aligned.
*
* @param {Point} a
* @param {Point} b
* @param {Array<Point>|Point}
* @param {Point}
*
* @return {String|Boolean} returns false if the points are not
* aligned or 'h|v' if they are aligned
* horizontally / vertically.
* @return {string|Boolean}
*/
export function pointsAligned(a, b) {
if (Math.abs(a.x - b.x) <= ALIGNED_THRESHOLD) {
return 'v';
var points;

if (isArray(a)) {
points = a;
} else {
points = [ a, b ];
}

if (Math.abs(a.y - b.y) <= ALIGNED_THRESHOLD) {
if (pointsAlignedHorizontally(points)) {
return 'h';
}

if (pointsAlignedVertically(points)) {
return 'v';
}

return false;
}

export function pointsAlignedHorizontally(a, b) {
var points;

if (isArray(a)) {
points = a;
} else {
points = [ a, b ];
}

var firstPoint = points.slice().shift();

return every(points, function(point) {
return Math.abs(firstPoint.y - point.y) <= ALIGNED_THRESHOLD;
});
}

export function pointsAlignedVertically(a, b) {
var points;

if (isArray(a)) {
points = a;
} else {
points = [ a, b ];
}

var firstPoint = points.slice().shift();

return every(points, function(point) {
return Math.abs(firstPoint.x - point.x) <= ALIGNED_THRESHOLD;
});
}



/**
* Returns true if the point p is inside the rectangle rect
*
* @param {Point} p
* @param {Rect} rect
* @param {Rect} rect
* @param {Number} tolerance
*
* @return {Boolean}
Expand Down
32 changes: 31 additions & 1 deletion test/spec/layout/ManhattanLayoutSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,35 @@ describe('layout/ManhattanLayout', function() {
]);
});


it('should relayout if points aligned', function() {

// given
var start = rect(100, 100, 100, 100);

var waypoints = [
{ x: 200, y: 150, original: { x: 150, y: 150 } },
{ x: 300, y: 150 },
{ x: 300, y: 250 },
{ x: 400, y: 250, original: { x: 450, y: 250 } }
];

// when
var repaired = repair(start, start, waypoints, {
connectionEnd: { x: 150, y: 150 },
preferredLayouts: [ 'r:b' ]
});

// then
expect(repaired).to.eql([
{ x: 200, y: 150, original: { x: 150, y: 150 } },
{ x: 220, y: 150 },
{ x: 220, y: 220 },
{ x: 150, y: 220 },
{ x: 150, y: 200, original: { x: 150, y: 150 } }
]);
});

});


Expand Down Expand Up @@ -853,7 +882,8 @@ describe('layout/ManhattanLayout', function() {
var repaired = repair(newStart, end, waypoints, { connectionStart: true });

// then
expect(repaired).to.eql([ { x: 250, y: 100 }, { x: 250, y: 300 } ].concat(waypoints.slice(2)));
expect(repaired).to.eql([ { x: 250, y: 150, original: { x: 250, y: 100 } } ]
.concat(waypoints[ waypoints.length - 1 ]));
});

});
Expand Down

0 comments on commit 3a63db0

Please sign in to comment.