Fix snapping for non-overlapping boxes

Boxes were snapping together even if they were not overlapping in the
non-snapping axis:

    ###
    #A#
    ###

        ###
        #B#
        ###

Although A and B are near eachother on the X axis they should not snap
together, since they are far apart on the Y axis. Now they don't.
This commit is contained in:
Jordan Eldredge 2016-08-10 18:09:28 -07:00
parent 299b4cac77
commit 9dde8dfc9c
2 changed files with 81 additions and 12 deletions

View file

@ -6,7 +6,9 @@ import {
left,
right,
near,
snap
snap,
overlapY,
overlapX
} from '../snapUtils';
describe('side functions', () => {
@ -46,6 +48,51 @@ describe('near function', () => {
});
});
describe('overlap functions', () => {
it('overlapY detects when the boxes overlap in the Y axis', () => {
const a = {y: 10, height: 50};
const b = {y: 40, height: 50};
const actual = overlapY(a, b);
const expected = true;
expect(actual).toEqual(expected);
});
it('overlapY detects when the boxes are within SNAP_DISTANCE on the Y axis', () => {
const a = {y: 10, height: 50};
const b = {y: 70, height: 50};
const actual = overlapY(a, b);
const expected = true;
expect(actual).toEqual(expected);
});
it('overlapY detects when the boxes do not overlap in the Y axis', () => {
const a = {y: 10, height: 50};
const b = {y: 90, height: 50};
const actual = overlapY(a, b);
const expected = false;
expect(actual).toEqual(expected);
});
it('overlapX detects when the boxes overlap in the X axis', () => {
const a = {x: 10, width: 50};
const b = {x: 40, width: 50};
const actual = overlapX(a, b);
const expected = true;
expect(actual).toEqual(expected);
});
it('overlapX detects when the boxes are within SNAP_DISTANCE on the X axis', () => {
const a = {x: 10, width: 50};
const b = {x: 70, width: 50};
const actual = overlapX(a, b);
const expected = true;
expect(actual).toEqual(expected);
});
it('overlapX detects when the boxes do not overlap in the X axis', () => {
const a = {x: 10, width: 50};
const b = {x: 90, width: 50};
const actual = overlapX(a, b);
const expected = false;
expect(actual).toEqual(expected);
});
});
describe('snap function', () => {
it('does not snap if A and B are obviously far apart', () => {
const a = {x: 10, y: 10, width: 100, height: 100};
@ -82,4 +129,18 @@ describe('snap function', () => {
const expected = {y: 110};
expect(actual).toEqual(expected);
});
it('does not snap to the X axis if A is below B', () => {
const a = {x: 10, y: 10, width: 100, height: 100};
const b = {x: 110, y: 150, width: 100, height: 100};
const actual = snap(a, b);
const expected = {};
expect(actual).toEqual(expected);
});
it('snaps in both axis if the corners are within SNAP_DISTANCE', () => {
const a = {x: 10, y: 10, width: 100, height: 100};
const b = {x: 120, y: 120, width: 100, height: 100};
const actual = snap(a, b);
const expected = {x: 20, y: 20};
expect(actual).toEqual(expected);
});
});

View file

@ -9,23 +9,31 @@ export const right = (box) => box.x + box.width;
export const near = (a, b) => Math.abs(a - b) < SNAP_DISTANCE;
// http://stackoverflow.com/a/3269471/1263117
export const overlapX = (a, b) => left(a) <= right(b) + SNAP_DISTANCE && left(b) <= right(a) + SNAP_DISTANCE;
export const overlapY = (a, b) => top(a) <= bottom(b) + SNAP_DISTANCE && top(b) <= bottom(a) + SNAP_DISTANCE;
export const snap = (boxA, boxB) => {
let x, y;
if (near(left(boxA), right(boxB))) {
x = right(boxB);
if (overlapY(boxA, boxB)) {
if (near(left(boxA), right(boxB))) {
x = right(boxB);
}
if (near(right(boxA), left(boxB))) {
x = left(boxB) - boxA.width;
}
}
if (near(right(boxA), left(boxB))) {
x = left(boxB) - boxA.width;
}
if (overlapX(boxA, boxB)) {
if (near(top(boxA), bottom(boxB))) {
y = bottom(boxB);
}
if (near(top(boxA), bottom(boxB))) {
y = bottom(boxB);
}
if (near(bottom(boxA), top(boxB))) {
y = top(boxB) - boxA.height;
if (near(bottom(boxA), top(boxB))) {
y = top(boxB) - boxA.height;
}
}
return {x, y};
};