diff --git a/src/connectors/jumpover.mjs b/src/connectors/jumpover.mjs index 0e3c5462f..9935a893c 100644 --- a/src/connectors/jumpover.mjs +++ b/src/connectors/jumpover.mjs @@ -21,6 +21,46 @@ var IGNORED_CONNECTORS = ['smooth']; var _13 = 1 / 3; var _23 = 2 / 3; +function sortPointsAscending(p1, p2) { + + let { x: x1, y: y1 } = p1; + let { x: x2, y: y2 } = p2; + + if (x1 > x2) { + + let swap = x1; + x1 = x2; + x2 = swap; + + swap = y1; + y1 = y2; + y2 = swap; + } + + if (y1 > y2) { + let swap = x1; + x1 = x2; + x2 = swap; + + swap = y1; + y1 = y2; + y2 = swap; + } + + return [new g.Point(x1, y1), new g.Point(x2, y2)]; +} + +function overlapExists(line1, line2) { + + const [{ x: x1, y: y1 }, { x: x2, y: y2 }] = sortPointsAscending(line1.start, line1.end); + const [{ x: x3, y: y3 }, { x: x4, y: y4 }] = sortPointsAscending(line2.start, line2.end); + + const xMatch = x1 <= x4 && x3 <= x2; + const yMatch = y1 <= y4 && y3 <= y2; + + return xMatch && yMatch; +} + /** * Transform start/end and route into series of lines * @param {g.point} sourcePoint start point @@ -377,12 +417,19 @@ export const jumpover = function(sourcePoint, targetPoint, route, opt) { // esli var jumpingLines = thisLines.reduce(function(resultLines, thisLine) { // iterate all links and grab the intersections with this line // these are then sorted by distance so the line can be split more easily - var intersections = links.reduce(function(res, link, i) { // don't intersection with itself if (link !== thisModel) { - var lineIntersections = findLineIntersections(thisLine, linkLines[i]); + const linkLinesToTest = linkLines[i].slice(); + const overlapIndex = linkLinesToTest.findIndex((line) => overlapExists(thisLine, line)); + + // Overlap occurs and the end point of one segment lies on thisLine + if (overlapIndex > -1 && thisLine.containsPoint(linkLinesToTest[overlapIndex].end)) { + // Remove the next segment because there will never be a jump + linkLinesToTest.splice(overlapIndex + 1, 1); + } + const lineIntersections = findLineIntersections(thisLine, linkLinesToTest); res.push.apply(res, lineIntersections); } return res; diff --git a/test/jointjs/connectors.js b/test/jointjs/connectors.js index 2faa298b9..185c17d38 100644 --- a/test/jointjs/connectors.js +++ b/test/jointjs/connectors.js @@ -354,4 +354,40 @@ QUnit.module('connectors', function(hooks) { assert.checkDataPath(pathData, 'M 335.31 300.31 C 384.148 328.507 435 343.607 435 400', 'curve link with rotate was correctly rendered'); }); + + QUnit.test('jumpover connector - stacked links do not cause jumps', function(assert) { + const element1 = new joint.shapes.standard.Rectangle({ + position: { x: 50, y: 50 }, + size: { width: 50, height: 50 }, + }); + + const element2 = element1.clone(); + element2.position(50, 150); + + const link1 = new joint.shapes.standard.Link({ + source: { x: 25, y: 300 }, + target: { id: element1.id }, + connector: { name: 'jumpover' }, + vertices: [ + { x: 25, y: 75 } + ], + }); + + const link2 = new joint.shapes.standard.Link({ + source: { x: 25, y: 300 }, + target: { id: element2.id }, + connector: { name: 'jumpover' }, + vertices: [ + { x: 25, y: 175 } + ] + }); + + this.graph.addCells([element1, element2, link2, link1]); + + const linkView = link1.findView(this.paper); + const pathData = linkView.metrics.data; + + // The link consists of two straight lines - no jumps + assert.checkDataPath(pathData, 'M 25 300 L 25 75 L 50 75'); + }); });