123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- import {
- isObject,
- sortBy
- } from 'min-dash';
- import {
- pointDistance
- } from '../util/Geometry';
- import intersectPaths from 'path-intersection';
- export function roundBounds(bounds) {
- return {
- x: Math.round(bounds.x),
- y: Math.round(bounds.y),
- width: Math.round(bounds.width),
- height: Math.round(bounds.height)
- };
- }
- export function roundPoint(point) {
- return {
- x: Math.round(point.x),
- y: Math.round(point.y)
- };
- }
- /**
- * Convert the given bounds to a { top, left, bottom, right } descriptor.
- *
- * @param {Bounds|Point} bounds
- *
- * @return {Object}
- */
- export function asTRBL(bounds) {
- return {
- top: bounds.y,
- right: bounds.x + (bounds.width || 0),
- bottom: bounds.y + (bounds.height || 0),
- left: bounds.x
- };
- }
- /**
- * Convert a { top, left, bottom, right } to an objects bounds.
- *
- * @param {Object} trbl
- *
- * @return {Bounds}
- */
- export function asBounds(trbl) {
- return {
- x: trbl.left,
- y: trbl.top,
- width: trbl.right - trbl.left,
- height: trbl.bottom - trbl.top
- };
- }
- /**
- * Get the mid of the given bounds or point.
- *
- * @param {Bounds|Point} bounds
- *
- * @return {Point}
- */
- export function getMid(bounds) {
- return roundPoint({
- x: bounds.x + (bounds.width || 0) / 2,
- y: bounds.y + (bounds.height || 0) / 2
- });
- }
- // orientation utils //////////////////////
- /**
- * Get orientation of the given rectangle with respect to
- * the reference rectangle.
- *
- * A padding (positive or negative) may be passed to influence
- * horizontal / vertical orientation and intersection.
- *
- * @param {Bounds} rect
- * @param {Bounds} reference
- * @param {Point|Number} padding
- *
- * @return {String} the orientation; one of top, top-left, left, ..., bottom, right or intersect.
- */
- export function getOrientation(rect, reference, padding) {
- padding = padding || 0;
- // make sure we can use an object, too
- // for individual { x, y } padding
- if (!isObject(padding)) {
- padding = { x: padding, y: padding };
- }
- var rectOrientation = asTRBL(rect),
- referenceOrientation = asTRBL(reference);
- var top = rectOrientation.bottom + padding.y <= referenceOrientation.top,
- right = rectOrientation.left - padding.x >= referenceOrientation.right,
- bottom = rectOrientation.top - padding.y >= referenceOrientation.bottom,
- left = rectOrientation.right + padding.x <= referenceOrientation.left;
- var vertical = top ? 'top' : (bottom ? 'bottom' : null),
- horizontal = left ? 'left' : (right ? 'right' : null);
- if (horizontal && vertical) {
- return vertical + '-' + horizontal;
- } else {
- return horizontal || vertical || 'intersect';
- }
- }
- // intersection utils //////////////////////
- /**
- * Get intersection between an element and a line path.
- *
- * @param {PathDef} elementPath
- * @param {PathDef} linePath
- * @param {Boolean} cropStart crop from start or end
- *
- * @return {Point}
- */
- export function getElementLineIntersection(elementPath, linePath, cropStart) {
- var intersections = getIntersections(elementPath, linePath);
- // recognize intersections
- // only one -> choose
- // two close together -> choose first
- // two or more distinct -> pull out appropriate one
- // none -> ok (fallback to point itself)
- if (intersections.length === 1) {
- return roundPoint(intersections[0]);
- } else if (intersections.length === 2 && pointDistance(intersections[0], intersections[1]) < 1) {
- return roundPoint(intersections[0]);
- } else if (intersections.length > 1) {
- // sort by intersections based on connection segment +
- // distance from start
- intersections = sortBy(intersections, function(i) {
- var distance = Math.floor(i.t2 * 100) || 1;
- distance = 100 - distance;
- distance = (distance < 10 ? '0' : '') + distance;
- // create a sort string that makes sure we sort
- // line segment ASC + line segment position DESC (for cropStart)
- // line segment ASC + line segment position ASC (for cropEnd)
- return i.segment2 + '#' + distance;
- });
- return roundPoint(intersections[cropStart ? 0 : intersections.length - 1]);
- }
- return null;
- }
- export function getIntersections(a, b) {
- return intersectPaths(a, b);
- }
|