Skip to content

Commit 69312fd

Browse files
committed
feat: add direciton on snap event #949
1 parent c3eb9c7 commit 69312fd

File tree

9 files changed

+156
-373
lines changed

9 files changed

+156
-373
lines changed

packages/react-moveable/src/ables/Snappable.tsx

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import {
33
SnappableProps,
44
SnappableState,
55
SnapGuideline,
6-
SnapInfo,
76
ScalableProps,
87
SnapPosInfo,
98
RotatableProps,
@@ -12,6 +11,7 @@ import {
1211
SnappableRenderType,
1312
BoundType,
1413
MoveableGroupInterface,
14+
SnapDirectionInfo,
1515
} from "../types";
1616
import {
1717
prefix,
@@ -27,6 +27,7 @@ import {
2727
abs,
2828
} from "../utils";
2929
import {
30+
find,
3031
findIndex, hasClass, throttle,
3132
} from "@daybrush/utils";
3233
import {
@@ -494,18 +495,24 @@ export function startCheckSnapDrag(
494495

495496

496497
function getSnapGuidelines(posInfos: SnapPosInfo[]) {
497-
const guidelines: SnapGuideline[] = [];
498+
const guidelines: Array<{ guideline: SnapGuideline, posInfo: SnapPosInfo }> = [];
498499

499500
posInfos.forEach((posInfo) => {
500501
posInfo.guidelineInfos.forEach(({ guideline }) => {
501-
if (guidelines.indexOf(guideline) > -1) {
502+
if (find(guidelines, info => info.guideline === guideline)) {
502503
return;
503504
}
504-
guidelines.push(guideline);
505+
guideline.direction = "";
506+
guidelines.push({ guideline, posInfo });
505507
});
506508
});
507509

508-
return guidelines;
510+
return guidelines.map(({ guideline, posInfo }) => {
511+
return {
512+
...guideline,
513+
direction: posInfo.direction,
514+
};
515+
});
509516
}
510517

511518
function addBoundGuidelines(
@@ -695,8 +702,8 @@ color: #f55;
695702
const verticalGuidelines: SnapGuideline[] = [];
696703
const horizontalGuidelines: SnapGuideline[] = [];
697704
const snapInfos: Array<{
698-
vertical: SnapInfo;
699-
horizontal: SnapInfo;
705+
vertical: SnapDirectionInfo;
706+
horizontal: SnapDirectionInfo;
700707
}> = [];
701708
const { width, height, top, left, bottom, right } = getRect(poses);
702709
const targetRect = { left, right, top, bottom, center: (left + right) / 2, middle: (top + bottom) / 2 };
@@ -758,6 +765,7 @@ color: #f55;
758765
} as const)
759766
)
760767
);
768+
761769
verticalGuidelines.push(...getSnapGuidelines(verticalPosInfos));
762770
horizontalGuidelines.push(...getSnapGuidelines(horizontalPosInfos));
763771
});

packages/react-moveable/src/ables/snappable/getTotalGuidelines.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ export function getGapGuidelines(
237237
gap,
238238
hide: true,
239239
gapRects: [snapRect1, snapRect2],
240+
direction: "",
240241
});
241242
});
242243
});
@@ -268,6 +269,7 @@ export function getGridGuidelines(
268269
className: prefix("grid-guideline"),
269270
size: containerWidth!,
270271
hide: !isDisplayGridGuidelines,
272+
direction: "",
271273
});
272274
}
273275
}
@@ -282,6 +284,7 @@ export function getGridGuidelines(
282284
className: prefix("grid-guideline"),
283285
size: containerHeight!,
284286
hide: !isDisplayGridGuidelines,
287+
direction: "",
285288
});
286289
}
287290
}
@@ -394,6 +397,7 @@ export function getElementGuidelines(
394397
sizes,
395398
className,
396399
elementRect: snapRect,
400+
direction: "",
397401
});
398402
});
399403
horizontal.forEach(pos => {
@@ -405,6 +409,7 @@ export function getElementGuidelines(
405409
sizes,
406410
className,
407411
elementRect: snapRect,
412+
direction: "",
408413
});
409414
});
410415
});
@@ -460,6 +465,7 @@ export function getDefaultGuidelines(
460465
],
461466
size: snapWidth,
462467
className: posInfo.className,
468+
direction: "",
463469
});
464470
});
465471
getObjectGuidelines(verticalGuidelines, snapWidth).forEach(posInfo => {
@@ -471,6 +477,7 @@ export function getDefaultGuidelines(
471477
],
472478
size: snapHeight,
473479
className: posInfo.className,
480+
direction: "",
474481
});
475482
});
476483
return guidelines;

packages/react-moveable/src/ables/snappable/render.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,12 +216,14 @@ export function groupByElementGuidelines(
216216
pos: nextPos1,
217217
size: 0,
218218
elementRect: elementRect1,
219+
direction: "",
219220
});
220221
end.push({
221222
type,
222223
pos: nextPos2,
223224
size: 0,
224225
elementRect: elementRect2,
226+
direction: "",
225227
});
226228
// inner.push(guideline);
227229
}

packages/react-moveable/src/ables/snappable/snap.ts

Lines changed: 101 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {
22
SnapInfo, SnappableProps, SnappableState,
33
SnapGuideline, ResizableProps, ScalableProps,
4-
SnapOffsetInfo, MoveableManagerInterface, SnapDirectionPoses,
4+
SnapOffsetInfo, MoveableManagerInterface, SnapDirectionPoses, SnapDirectionInfo,
55
} from "../../types";
66
import {
77
selectValue, getTinyDist, abs,
@@ -17,6 +17,8 @@ export function checkMoveableSnapPoses(
1717
moveable: MoveableManagerInterface<SnappableProps, SnappableState>,
1818
posesX: number[],
1919
posesY: number[],
20+
dirXs: string[] = [],
21+
dirYs: string[] = [],
2022
customSnapThreshold?: number,
2123
) {
2224
const props = moveable.props;
@@ -26,6 +28,8 @@ export function checkMoveableSnapPoses(
2628
moveable.state.guidelines,
2729
posesX,
2830
posesY,
31+
dirXs,
32+
dirYs,
2933
snapThreshold,
3034
);
3135
}
@@ -34,11 +38,13 @@ export function checkSnapPoses(
3438
guidelines: SnapGuideline[],
3539
posesX: number[],
3640
posesY: number[],
41+
dirXs: string[],
42+
dirYs: string[],
3743
snapThreshold: number,
3844
) {
3945
return {
40-
vertical: checkSnap(guidelines, "vertical", posesX, snapThreshold),
41-
horizontal: checkSnap(guidelines, "horizontal", posesY, snapThreshold),
46+
vertical: checkSnap(guidelines, "vertical", posesX, snapThreshold, dirXs),
47+
horizontal: checkSnap(guidelines, "horizontal", posesY, snapThreshold, dirYs),
4248
};
4349
}
4450
export function checkSnapKeepRatio(
@@ -142,19 +148,49 @@ export function checkSnapKeepRatio(
142148
};
143149
}
144150

151+
152+
function getStringDirection(dir: number | string) {
153+
let stringDirection = "";
154+
155+
if (dir === -1 || dir === "top" || dir === "left") {
156+
stringDirection = "start";
157+
} else if (dir === 0 || dir === "center" || dir === "middle") {
158+
stringDirection = "center";
159+
} else if (dir === 1 || dir === "right" || dir === "bottom") {
160+
stringDirection = "end";
161+
}
162+
return stringDirection;
163+
}
164+
165+
145166
export function checkSnaps(
146167
moveable: MoveableManagerInterface<SnappableProps, SnappableState>,
147168
rect: SnapDirectionPoses,
148169
customSnapThreshold?: number,
149-
) {
170+
): { vertical: SnapDirectionInfo; horizontal: SnapDirectionInfo } {
150171
const poses = splitSnapDirectionPoses(moveable.props.snapDirections, rect);
151172

152-
return checkMoveableSnapPoses(
173+
const result = checkMoveableSnapPoses(
153174
moveable,
154175
poses.vertical,
155176
poses.horizontal,
177+
poses.verticalNames.map(name => getStringDirection(name)),
178+
poses.horizontalNames.map(name => getStringDirection(name)),
156179
customSnapThreshold,
157180
);
181+
const horizontalDirection = getStringDirection(poses.horizontalNames[result.horizontal.index]);
182+
const verticalDirection = getStringDirection(poses.verticalNames[result.vertical.index]);
183+
184+
return {
185+
vertical: {
186+
...result.vertical,
187+
direction: verticalDirection,
188+
},
189+
horizontal: {
190+
...result.horizontal,
191+
direction: horizontalDirection,
192+
},
193+
};
158194
}
159195

160196
export function getNearestSnapGuidelineInfo(
@@ -191,18 +227,22 @@ function checkSnap(
191227
targetType: "horizontal" | "vertical",
192228
targetPoses: number[],
193229
snapThreshold: number,
230+
dirs: string[] = [],
194231
): SnapInfo {
195232
if (!guidelines || !guidelines.length) {
196233
return {
197234
isSnap: false,
198235
index: -1,
236+
direction: "",
199237
posInfos: [],
200238
};
201239
}
202240
const isVertical = targetType === "vertical";
203241
const posType = isVertical ? 0 : 1;
204242

205243
const snapPosInfos = targetPoses.map((targetPos, index) => {
244+
const direction = dirs[index] || "";
245+
206246
const guidelineInfos = guidelines.map(guideline => {
207247
const { pos } = guideline;
208248
const offset = targetPos - pos[posType];
@@ -211,6 +251,7 @@ function checkSnap(
211251
offset,
212252
dist: abs(offset),
213253
guideline,
254+
direction,
214255
};
215256
}).filter(({ guideline, dist }) => {
216257
const { type } = guideline;
@@ -230,6 +271,7 @@ function checkSnap(
230271
pos: targetPos,
231272
index,
232273
guidelineInfos,
274+
direction,
233275
};
234276
}).filter(snapPosInfo => {
235277
return snapPosInfo.guidelineInfos.length > 0;
@@ -241,54 +283,88 @@ function checkSnap(
241283
return {
242284
isSnap,
243285
index: isSnap ? snapPosInfos[0].index : -1,
286+
direction: snapPosInfos[0]?.direction ?? "",
244287
posInfos: snapPosInfos,
245288
};
246289
}
247290

248291
export function getSnapInfosByDirection(
249292
moveable: MoveableManagerInterface<SnappableProps & (ResizableProps | ScalableProps), SnappableState>,
293+
// pos1 pos2 pos3 pos4
250294
poses: number[][],
251295
snapDirection: number[],
252296
snapThreshold = 1,
253-
) {
254-
let nextPoses: number[][] = [];
297+
): { vertical: SnapDirectionInfo; horizontal: SnapDirectionInfo } {
298+
let dirs: number[][] = [];
299+
255300
if (snapDirection[0] && snapDirection[1]) {
256-
nextPoses = [
301+
dirs = [
257302
snapDirection,
258303
[-snapDirection[0], snapDirection[1]],
259304
[snapDirection[0], -snapDirection[1]],
260-
].map(direction => getPosByDirection(poses, direction));
305+
];
261306
} else if (!snapDirection[0] && !snapDirection[1]) {
262-
const alignPoses = [poses[0], poses[1], poses[3], poses[2], poses[0]];
263-
264-
for (let i = 0; i < 4; ++i) {
265-
nextPoses.push(alignPoses[i]);
266-
nextPoses.push([
267-
(alignPoses[i][0] + alignPoses[i + 1][0]) / 2,
268-
(alignPoses[i][1] + alignPoses[i + 1][1]) / 2,
307+
[
308+
[-1, -1],
309+
[1, -1],
310+
[1, 1],
311+
[-1, 1],
312+
].forEach((dir, i, arr) => {
313+
const nextDir = (arr[i + 1] || arr[0]);
314+
dirs.push(dir);
315+
dirs.push([
316+
(dir[0] + nextDir[0]) / 2,
317+
(dir[1] + nextDir[1]) / 2,
269318
]);
270-
}
319+
});
271320
} else {
272321
if (moveable.props.keepRatio) {
273-
nextPoses = [
322+
dirs.push(
274323
[-1, -1],
275324
[-1, 1],
276325
[1, -1],
277326
[1, 1],
278327
snapDirection,
279-
].map(dir => getPosByDirection(poses, dir));
328+
);
280329
} else {
281-
nextPoses = getPosesByDirection(poses, snapDirection);
330+
dirs.push(...getPosesByDirection([
331+
[-1, -1],
332+
[1, -1],
333+
[-1, -1],
334+
[1, 1],
335+
], snapDirection));
282336

283-
if (nextPoses.length > 1) {
284-
nextPoses.push([
285-
(nextPoses[0][0] + nextPoses[1][0]) / 2,
286-
(nextPoses[0][1] + nextPoses[1][1]) / 2,
337+
if (dirs.length > 1) {
338+
dirs.push([
339+
(dirs[0][0] + dirs[1][0]) / 2,
340+
(dirs[0][1] + dirs[1][1]) / 2,
287341
]);
288342
}
289343
}
290344
}
291-
return checkMoveableSnapPoses(moveable, nextPoses.map(pos => pos[0]), nextPoses.map(pos => pos[1]), snapThreshold);
345+
const nextPoses = dirs.map(dir => getPosByDirection(poses, dir));
346+
const xs = nextPoses.map(pos => pos[0]);
347+
const ys = nextPoses.map(pos => pos[1]);
348+
const result = checkMoveableSnapPoses(
349+
moveable,
350+
xs, ys,
351+
dirs.map(dir => getStringDirection(dir[0])),
352+
dirs.map(dir => getStringDirection(dir[1])),
353+
snapThreshold
354+
);
355+
const verticalDirection = getStringDirection(dirs.map(dir => dir[0])[result.vertical.index]);
356+
const horizontalDirection = getStringDirection(dirs.map(dir => dir[1])[result.horizontal.index]);
357+
358+
return {
359+
vertical: {
360+
...result.vertical,
361+
direction: verticalDirection,
362+
},
363+
horizontal: {
364+
...result.horizontal,
365+
direction: horizontalDirection,
366+
},
367+
};
292368
}
293369

294370
export function checkSnapBoundPriority(

packages/react-moveable/src/ables/snappable/snapBounds.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ export function checkSnapBounds(
348348
const {
349349
horizontal: horizontalSnapInfo,
350350
vertical: verticalSnapInfo,
351-
} = checkSnapPoses(guideines, posesX, posesY, snapThreshold);
351+
} = checkSnapPoses(guideines, posesX, posesY, [], [], snapThreshold);
352352

353353
const horizontalOffset = getSnapBound(
354354
horizontalBoundInfos[0],

0 commit comments

Comments
 (0)