Skip to content

Commit

Permalink
fix: fix snap bug for rotated group #786
Browse files Browse the repository at this point in the history
  • Loading branch information
daybrush committed Nov 10, 2022
1 parent c699af1 commit 3ac47da
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 38 deletions.
55 changes: 39 additions & 16 deletions packages/react-moveable/src/react-moveable/MoveableGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import ChildrenDiffer from "@egjs/children-differ";
import { getAbleGesto, getTargetAbleGesto } from "./gesto/getAbleGesto";
import Groupable from "./ables/Groupable";
import { MIN_NUM, MAX_NUM, TINY_NUM } from "./consts";
import { getAbsolutePosesByState, equals, unset } from "./utils";
import {
getAbsolutePosesByState, equals, unset, rotatePosesInfo,
convertTransformOriginArray,
} from "./utils";
import { minus, plus } from "@scena/matrix";
import { getIntersectionPointsByConstants, getMinMaxs } from "overlap-area";
import { find, isArray, throttle } from "@daybrush/utils";
Expand Down Expand Up @@ -39,6 +42,8 @@ function getGroupRect(parentPoses: number[][][], rotation: number): GroupRect {
pos4,
minX: 0,
minY: 0,
maxX: 0,
maxY: 0,
width,
height,
rotation,
Expand Down Expand Up @@ -144,7 +149,7 @@ function getGroupRect(parentPoses: number[][][], rotation: number): GroupRect {

[pos1, pos2, pos3, pos4] = changedX;
}
const { minX, minY } = getMinMaxs([pos1, pos2, pos3, pos4]);
const { minX, minY, maxX, maxY } = getMinMaxs([pos1, pos2, pos3, pos4]);

return {
pos1,
Expand All @@ -155,6 +160,8 @@ function getGroupRect(parentPoses: number[][][], rotation: number): GroupRect {
height,
minX,
minY,
maxX,
maxY,
rotation,
};
}
Expand Down Expand Up @@ -290,14 +297,32 @@ class MoveableGroup extends MoveableManager<GroupableProps> {
}

this.renderGroupRects = renderGroupRects;
const transformOrigin = this.transformOrigin;
const rotation = this.rotation;
const scale = this.scale;
const { width, height, minX, minY } = rootGroupRect;
const posesInfo = rotatePosesInfo(
[
[0, 0],
[width, 0],
[0, height],
[width, height],
],
convertTransformOriginArray(transformOrigin, width, height),
this.rotation / 180 * Math.PI,
);

// tslint:disable-next-line: max-line-length
const transform = `rotate(${rotation}deg) scale(${scale[0] >= 0 ? 1 : -1}, ${scale[1] >= 0 ? 1 : -1})`;
target.style.cssText += `left:0px;top:0px; transform-origin: ${this.transformOrigin}; width:${width}px; height:${height}px;`
+ `transform:${transform}`;
const { minX: deltaX, minY: deltaY } = getMinMaxs(posesInfo.result);
const rotateScale = ` rotate(${rotation}deg)`
+ ` scale(${scale[0] >= 0 ? 1 : -1}, ${scale[1] >= 0 ? 1 : -1})`;
const transform = `translate(${-deltaX}px, ${-deltaY}px)${rotateScale}`;

this.controlBox.getElement().style.transform
= `translate3d(${minX}px, ${minY}px, ${this.props.translateZ || 0})`;
target.style.cssText += `left:0px;top:0px;`
+ `transform-origin:${transformOrigin};`
+ `width:${width}px;height:${height}px;`
+ `transform: ${transform}`;
state.width = width;
state.height = height;

Expand All @@ -320,25 +345,23 @@ class MoveableGroup extends MoveableManager<GroupableProps> {

const minPos = getMinMaxs([pos1, pos2, pos3, pos4]);
const delta = [minPos.minX, minPos.minY];
const direction = scale[0] * scale[1] > 0 ? 1 : -1;

info.pos1 = minus(pos1, delta);
info.pos2 = minus(pos2, delta);
info.pos3 = minus(pos3, delta);
info.pos4 = minus(pos4, delta);
// info.left = info.left + delta[0];
// info.top = info.top + delta[1];
info.left = minX - info.left! + delta[0];
info.top = minY - info.top! + delta[1];
info.origin = minus(plus(pos, info.origin!), delta);
info.beforeOrigin = minus(plus(pos, info.beforeOrigin!), delta);
info.originalBeforeOrigin = plus(pos, info.originalBeforeOrigin!);
// info.transformOrigin = minus(plus(pos, info.transformOrigin!), delta);

const clientRect = info.targetClientRect!;
const direction = scale[0] * scale[1] > 0 ? 1 : -1;

clientRect.top += info.top - state.top;
clientRect.left += info.left - state.left;

target.style.transform = `translate(${-delta[0]}px, ${-delta[1]}px) ${transform}`;

info.transformOrigin = minus(plus(pos, info.transformOrigin!), delta);
target.style.transform
= `translate(${-deltaX - delta[0]}px, ${-deltaY - delta[1]}px)`
+ rotateScale;
this.updateState(
{
...info,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function setCustomDrag(
isConvert: boolean,
ableName = "draggable",
) {
const result = state.gestos[ableName].move(delta, e.inputEvent);
const result = state.gestos[ableName]?.move(delta, e.inputEvent) ?? {};
const datas = result.originalDatas || result.datas;
const ableDatas = datas[ableName] || (datas[ableName] = {});

Expand Down
2 changes: 2 additions & 0 deletions packages/react-moveable/src/react-moveable/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2843,6 +2843,8 @@ export interface GroupRect {
pos4: number[];
minX: number;
minY: number;
maxX: number;
maxY: number;
width: number;
height: number;
rotation: number;
Expand Down
85 changes: 85 additions & 0 deletions packages/react-moveable/src/react-moveable/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
createScaleMatrix,
plus,
convertMatrixtoCSS,
rotate,
} from "@scena/matrix";
import {
MoveableManagerState, Able, MoveableClientRect,
Expand Down Expand Up @@ -1465,3 +1466,87 @@ export function getOffsetSizeDist(
distHeight,
};
}

export function convertTransformUnit(
origin: string,
xy?: boolean,
): { x?: string; y?: string; value?: string; } {
if (xy) {
if (origin === "left") {
return { x: "0%", y: "50%" };
} else if (origin === "top") {
return { x: "50%", y: "50%" };
} else if (origin === "center") {
return { x: "50%", y: "50%" };
} else if (origin === "right") {
return { x: "100%", y: "50%" };
} else if (origin === "bottom") {
return { x: "50%", y: "100%" };
}
const [left, right] = origin.split(" ");
const leftOrigin = convertTransformUnit(left || "");
const rightOrigin = convertTransformUnit(right || "");
const originObject = {
...leftOrigin,
...rightOrigin,
};

const nextOriginObject = {
x: "50%",
y: "50%",
};
if (originObject.x) {
nextOriginObject.x = originObject.x;
}
if (originObject.y) {
nextOriginObject.y = originObject.y;
}
if (originObject.value) {
if (originObject.x && !originObject.y) {
nextOriginObject.y = originObject.value;
}
if (!originObject.x && originObject.y) {
nextOriginObject.x = originObject.value;
}
}
return nextOriginObject;
}
if (origin === "left") {
return { x: "0%" };
}
if (origin === "right") {
return { x: "100%" };
}
if (origin === "top") {
return { y: "0%" };
}
if (origin === "bottom") {
return { y: "100%" };
}
if (!origin) {
return {};
}
if (origin === "center") {
return { value: "50%" };
}
return { value: origin };
}
export function convertTransformOriginArray(transformOrigin: string, width: number, height: number) {
const { x, y } = convertTransformUnit(transformOrigin, true);

return [
convertUnitSize(x!, width) || 0,
convertUnitSize(y!, height) || 0,
];
}

export function rotatePosesInfo(poses: number[][], origin: number[], rad: number) {
const prevPoses = poses.map((pos) => minus(pos, origin));
const nextPoses = prevPoses.map((pos) => rotate(pos, rad));

return {
prev: prevPoses,
next: nextPoses,
result: nextPoses.map(pos => plus(pos, origin)),
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ group.add("Snap Elements", {
argsTypes: {
...DEFAULT_SNAPPABLE_CONTROLS,
...DEFAULT_SNAPPABLE_ELEMENTS_CONTROLS,
...DEFAULT_DRAGGABLE_CONTROLS,
...DEFAULT_SCALABLE_CONTROLS,
},
});

Expand Down Expand Up @@ -125,5 +123,12 @@ group.add("Set maximum distance for guidelines", {
});


group.add("Snap Elements (group)", {
app: require("./ReactSnapElementsGroupApp").default,
path: require.resolve("./ReactSnapElementsGroupApp"),
});




// export * from "./9-maxSnapElement.stories";
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,9 @@ export default function App(props: Record<string, any>) {
<Moveable
ref={moveableRef}
target={targetRef}
draggable={props.draggable}
throttleDrag={props.throttleDrag}
edgeDraggable={props.edgeDraggable}
startDragRotate={props.startDragRotate}
throttleDragRotate={props.throttleDragRotate}
scalable={props.scalable}
keepRatio={props.keepRatio}
throttleScale={props.throttleScale}
draggable={true}
scalable={true}
rotatable={true}
snappable={props.snappable}
isDisplaySnapDigit={props.isDisplaySnapDigit}
isDisplayInnerSnapDigit={props.isDisplayInnerSnapDigit}
Expand All @@ -55,14 +50,8 @@ export default function App(props: Record<string, any>) {
snapThreshold={props.snapThreshold}
maxSnapElementGuidelineDistance={props.maxSnapElementGuidelineDistance}
elementGuidelines={[".element1", ".element2", ".element3"]}
onBeforeRenderStart={e => {
e.setTransform(e.target.style.transform);
}}
onDrag={e => {
e.target.style.transform = e.transform;
}}
onScale={e => {
e.target.style.transform = e.drag.transform;
onRender={e => {
e.target.style.cssText += e.cssText;
}}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as React from "react";
import Moveable from "@/react-moveable";

export default function App(props: Record<string, any>) {
return (
<div className="root">
<div className="container" style={{
left: "200px",
top: "100px",
width: "500px",
height: "500px",
border: "1px solid #ccc",
}}>
<div className="target target1">Target 1</div>
<div className="target target2">Target 2</div>
<div className="target target3">Target 3</div>
<Moveable
target={".target"}
draggable={true}
rotatable={true}
snappable={true}
verticalGuidelines={[0, 100]}
elementGuidelines={[".container"]}
onRenderGroup={e => {
e.events.forEach(ev => {
ev.target.style.cssText += ev.cssText;
});
}}
/>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ group.add("Clippable with Drag, Resize, Rotate", {
});


group.add("Drag, Resize, Rotate with Clipped Area", {
group.add("Drag, Resize, Rotate with Clipped Area (Testing)", {
app: require("./ReactClippedAreaApp").default,
path: require.resolve("./ReactClippedAreaApp"),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ export default function App() {
dragWithClip={false}
defaultClipPath={"inset"}
clipTargetBounds={true}
clipVerticalGuidelines={[]}
clipHorizontalGuidelines={[]}
clipVerticalGuidelines={[0, 100, 200]}
clipHorizontalGuidelines={[0, 100, 200]}
snapThreshold={5}
onClip={(e) => {
if (e.clipType === "rect") {
Expand Down

0 comments on commit 3ac47da

Please sign in to comment.