Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP #60

Merged
merged 1 commit into from
Aug 25, 2017
Merged

WIP #60

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,31 +1,18 @@
// @flow
import memoizeOne from 'memoize-one';
import { distance } from './position';
import { closest } from './position';
import type {
Axis,
Position,
DimensionFragment,
DraggableId,
DroppableId,
DraggableDimension,
DroppableDimension,
DraggableDimensionMap,
DroppableDimensionMap,
} from '../types';

type DroppableCornerMap = {|
[id: DroppableId]: Position[],
|}

type GetBestDroppableArgs = {|
draggableId: DraggableId,
center: Position,
isMovingForward: boolean,
plane: 'main-axis' | 'cross-axis',
// the droppable the draggable is currently in
droppableId: DroppableId,
droppables: DroppableDimensionMap,
draggables: DraggableDimensionMap,
type DistanceToDroppable = {|
id: DroppableId,
distance: number,
|}

const sortOnCrossAxis = memoizeOne(
Expand All @@ -38,23 +25,35 @@ const sortOnCrossAxis = memoizeOne(
)
);

type IsWithResultFn = (number) => boolean;

const isWithin = (lowerBound: number, upperBound: number): IsWithResultFn =>
const isWithin = (lowerBound: number, upperBound: number): ((number) => boolean) =>
(value: number): boolean => value <= upperBound && value >= lowerBound;

const getCorners = (droppable: DroppableDimension): Position[] => {
const fragment: DimensionFragment = droppable.page.withMargin;

return [
{ x: fragment.left, y: fragment.top },
{ x: fragment.right, y: fragment.top },
{ x: fragment.left, y: fragment.bottom },
{ x: fragment.right, y: fragment.bottom },
];
};

type GetBestDroppableArgs = {|
isMovingForward: boolean,
center: Position,
droppableId: DroppableId,
droppables: DroppableDimensionMap,
|}

export default ({
isMovingForward,
draggableId,
center,
droppableId,
droppables,
draggables,
}: GetBestDroppableArgs): ?DroppableId => {
const draggable: DraggableDimension = draggables[draggableId];
const source: DroppableDimension = droppables[droppableId];
const axis: Axis = source.axis;

const sorted: DroppableDimension[] = sortOnCrossAxis(droppables, axis);

const candidates: DroppableDimension[] =
Expand All @@ -80,15 +79,15 @@ export default ({
sourceFragment[axis.start],
sourceFragment[axis.end]
);
const isBetweenDestBounds = isWithin(
const isBetweenDestinationBounds = isWithin(
destinationFragment[axis.start],
destinationFragment[axis.end]
);

return isBetweenSourceBounds(destinationFragment[axis.start]) ||
isBetweenSourceBounds(destinationFragment[axis.end]) ||
isBetweenDestBounds(sourceFragment[axis.start]) ||
isBetweenDestBounds(sourceFragment[axis.end]);
isBetweenDestinationBounds(sourceFragment[axis.start]) ||
isBetweenDestinationBounds(sourceFragment[axis.end]);
})
// 4. Find the droppables that have the same cross axis value as the first item
.filter((droppable: DroppableDimension, index: number, array: DroppableDimension[]): boolean =>
Expand All @@ -113,19 +112,17 @@ export default ({
// 1. Get the distance to all of the corner points
// 2. Find the closest corner to current center
// 3. in the event of a tie: choose the corner that is closest to {x: 0, y: 0}
const items: DroppableDimension[] =
candidates.map((droppable: DroppableDimension): DroppableCornerMap => {
const fragment: DimensionFragment = droppable.page.withMargin;
const first: Position = {
x: fragment[axis.crossAxisStart],
y: fragment[axis.start],
};
const second: Position = {
x: 2,
y: 3,
};
return {
[droppable.id]: [first, second],
};
});
const bestId: DroppableId =
candidates.map((droppable: DroppableDimension): DistanceToDroppable => ({
id: droppableId,
// two of the corners will be redundant, but it is *way* easier
// to pass every corner than to conditionally grab the right ones
distance: closest(center, getCorners(droppable)),
}))
// the item with the shortest distance will be first
.sort((a: DistanceToDroppable, b: DistanceToDroppable) => a.distance - b.distance)
// TODO: what if there is a tie?
.map(a => a.id)[0];

return bestId;
};
43 changes: 0 additions & 43 deletions src/state/get-best-droppable-rules.md

This file was deleted.

60 changes: 60 additions & 0 deletions src/state/get-best-main-axis-droppable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// @flow
import memoizeOne from 'memoize-one';
import { closest } from './position';
import type {
Axis,
Position,
DimensionFragment,
DroppableId,
DroppableDimension,
DroppableDimensionMap,
} from '../types';

type DistanceToDroppable = {|
id: DroppableId,
distance: number,
|}

const sortOnMainAxis = memoizeOne(
(droppables: DroppableDimensionMap, axis: Axis): DroppableDimension[] =>
Object.keys(droppables)
.map((key: DroppableId): DroppableDimension => droppables[key])
.sort((a: DroppableDimension, b: DroppableDimension) => (
a.page.withMargin[axis.start] - b.page.withMargin[axis.start]
)
)
);

const isWithin = (lowerBound: number, upperBound: number): ((number) => boolean) =>
(value: number): boolean => value <= upperBound && value >= lowerBound;

const getCorners = (droppable: DroppableDimension): Position[] => {
const fragment: DimensionFragment = droppable.page.withMargin;

return [
{ x: fragment.left, y: fragment.top },
{ x: fragment.right, y: fragment.top },
{ x: fragment.left, y: fragment.bottom },
{ x: fragment.right, y: fragment.bottom },
];
};

type GetBestDroppableArgs = {|
isMovingForward: boolean,
center: Position,
droppableId: DroppableId,
droppables: DroppableDimensionMap,
|}

export default ({
isMovingForward,
center,
droppableId,
droppables,
}: GetBestDroppableArgs): ?DroppableId => {
const source: DroppableDimension = droppables[droppableId];
const axis: Axis = source.axis;
const sorted: DroppableDimension[] = sortOnMainAxis(droppables, axis);

// ...
};
4 changes: 4 additions & 0 deletions src/state/position.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,7 @@ export const distance = (point1: Position, point2: Position): number =>
Math.pow((point2.x - point1.x), 2) +
Math.pow((point2.y - point1.y), 2)
);

// When given a list of points, it finds the smallest distance to any point
export const closest = (target: Position, points: Position[]): number =>
Math.min(...points.map((point: Position) => distance(target, point)));