-
Notifications
You must be signed in to change notification settings - Fork 743
/
get-offset.js
84 lines (71 loc) · 2.42 KB
/
get-offset.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import { getTargetRects, getTargetSize } from '../dom';
import { getBoundingRect } from './get-bounding-rect';
import { isPointInRect } from './is-point-in-rect';
import { getRectCenter } from './get-rect-center';
import rectHasMinimumSize from './rect-has-minimum-size';
/**
* Get the offset between target A and neighbor B. This assumes that the target is undersized and needs to check the spacing exception.
* @method getOffset
* @memberof axe.commons.math
* @param {VirtualNode} vTarget
* @param {VirtualNode} vNeighbor
* @param {Number} radius
* @returns {number}
*/
export default function getOffset(vTarget, vNeighbor, minRadiusNeighbour = 12) {
const targetRects = getTargetRects(vTarget);
const neighborRects = getTargetRects(vNeighbor);
if (!targetRects.length || !neighborRects.length) {
return 0;
}
const targetBoundingBox = targetRects.reduce(getBoundingRect);
const targetCenter = getRectCenter(targetBoundingBox);
// calculate distance to the closest edge of each neighbor rect
let minDistance = Infinity;
for (const rect of neighborRects) {
if (isPointInRect(targetCenter, rect)) {
return 0;
}
const closestPoint = getClosestPoint(targetCenter, rect);
const distance = pointDistance(targetCenter, closestPoint);
minDistance = Math.min(minDistance, distance);
}
const neighborTargetSize = getTargetSize(vNeighbor);
if (rectHasMinimumSize(minRadiusNeighbour * 2, neighborTargetSize)) {
return minDistance;
}
const neighborBoundingBox = neighborRects.reduce(getBoundingRect);
const neighborCenter = getRectCenter(neighborBoundingBox);
// subtract the radius of the circle from the distance to center to get distance to edge of the neighbor circle
const centerDistance =
pointDistance(targetCenter, neighborCenter) - minRadiusNeighbour;
return Math.max(0, Math.min(minDistance, centerDistance));
}
function getClosestPoint(point, rect) {
let x;
let y;
if (point.x < rect.left) {
x = rect.left;
} else if (point.x > rect.right) {
x = rect.right;
} else {
x = point.x;
}
if (point.y < rect.top) {
y = rect.top;
} else if (point.y > rect.bottom) {
y = rect.bottom;
} else {
y = point.y;
}
return { x, y };
}
/**
* Distance between two points
* @param {Point} pointA
* @param {Point} pointB
* @returns {number}
*/
function pointDistance(pointA, pointB) {
return Math.hypot(pointA.x - pointB.x, pointA.y - pointB.y);
}