diagram-js
Version:
A toolbox for displaying and modifying diagrams on the web
136 lines (106 loc) • 2.44 kB
JavaScript
import {
pointDistance
} from './Geometry';
import intersectPaths from 'path-intersection';
/**
* @typedef {import('../util/Types').Point} Point
*
* @typedef { {
* bendpoint?: boolean;
* index: number;
* point: Point;
* } } Intersection
*/
var round = Math.round,
max = Math.max;
function circlePath(center, r) {
var x = center.x,
y = center.y;
return [
[ 'M', x, y ],
[ 'm', 0, -r ],
[ 'a', r, r, 0, 1, 1, 0, 2 * r ],
[ 'a', r, r, 0, 1, 1, 0, -2 * r ],
[ 'z' ]
];
}
function linePath(points) {
var segments = [];
points.forEach(function(p, idx) {
segments.push([ idx === 0 ? 'M' : 'L', p.x, p.y ]);
});
return segments;
}
var INTERSECTION_THRESHOLD = 10;
/**
* @param {Point[]} waypoints
* @param {Point} reference
*
* @return {Intersection|null}
*/
function getBendpointIntersection(waypoints, reference) {
var i, w;
for (i = 0; (w = waypoints[i]); i++) {
if (pointDistance(w, reference) <= INTERSECTION_THRESHOLD) {
return {
point: waypoints[i],
bendpoint: true,
index: i
};
}
}
return null;
}
/**
* @param {Point[]} waypoints
* @param {Point} reference
*
* @return {Intersection|null}
*/
function getPathIntersection(waypoints, reference) {
var intersections = intersectPaths(circlePath(reference, INTERSECTION_THRESHOLD), linePath(waypoints));
var a = intersections[0],
b = intersections[intersections.length - 1],
idx;
if (!a) {
// no intersection
return null;
}
if (a !== b) {
if (a.segment2 !== b.segment2) {
// we use the bendpoint in between both segments
// as the intersection point
idx = max(a.segment2, b.segment2) - 1;
return {
point: waypoints[idx],
bendpoint: true,
index: idx
};
}
return {
point: {
x: (round(a.x + b.x) / 2),
y: (round(a.y + b.y) / 2)
},
index: a.segment2
};
}
return {
point: {
x: round(a.x),
y: round(a.y)
},
index: a.segment2
};
}
/**
* Returns the closest point on the connection towards a given reference point.
*
* @param {Point[]} waypoints
* @param {Point} reference
*
* @return {Intersection|null}
*/
export function getApproxIntersection(waypoints, reference) {
return getBendpointIntersection(waypoints, reference) || getPathIntersection(waypoints, reference);
}