Skip to content

Commit

Permalink
feat: add clippable keepRatio
Browse files Browse the repository at this point in the history
  • Loading branch information
daybrush committed May 29, 2022
1 parent 42fe6f3 commit 37da849
Show file tree
Hide file tree
Showing 10 changed files with 288 additions and 27 deletions.
2 changes: 1 addition & 1 deletion packages/react-moveable/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-moveable",
"version": "0.32.7",
"version": "0.32.8-beta.3",
"description": "A React Component that create Moveable, Draggable, Resizable, Scalable, Rotatable, Warpable, Pinchable, Groupable.",
"main": "./dist/moveable.cjs.js",
"module": "./dist/moveable.esm.js",
Expand Down
30 changes: 15 additions & 15 deletions packages/react-moveable/src/react-moveable/ables/Clippable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -298,18 +298,18 @@ function getClipPath(
}
function addClipPath(moveable: MoveableManagerInterface<ClippableProps>, e: any) {
const [distX, distY] = calculatePointerDist(moveable, e);
const { clipPath, index } = e.datas;
const { clipPath, clipIndex } = e.datas;
const {
type: clipType,
poses: clipPoses,
splitter,
} = (clipPath as ReturnType<typeof getClipPath>)!;
const poses = clipPoses.map(pos => pos.pos);
if (clipType === "polygon") {
poses.splice(index, 0, [distX, distY]);
poses.splice(clipIndex, 0, [distX, distY]);
} else if (clipType === "inset") {
const horizontalIndex = HORIZONTAL_RADIUS_ORDER.indexOf(index);
const verticalIndex = VERTICAL_RADIUS_ORDER.indexOf(index);
const horizontalIndex = HORIZONTAL_RADIUS_ORDER.indexOf(clipIndex);
const verticalIndex = VERTICAL_RADIUS_ORDER.indexOf(clipIndex);
const length = clipPoses.length;

addRadiusPos(
Expand Down Expand Up @@ -344,7 +344,7 @@ function addClipPath(moveable: MoveableManagerInterface<ClippableProps>, e: any)
}));
}
function removeClipPath(moveable: MoveableManagerInterface<ClippableProps>, e: any) {
const { clipPath, index } = e.datas;
const { clipPath, clipIndex } = e.datas;
const {
type: clipType,
poses: clipPoses,
Expand All @@ -353,13 +353,13 @@ function removeClipPath(moveable: MoveableManagerInterface<ClippableProps>, e: a
const poses = clipPoses.map(pos => pos.pos);
const length = poses.length;
if (clipType === "polygon") {
clipPoses.splice(index, 1);
poses.splice(index, 1);
clipPoses.splice(clipIndex, 1);
poses.splice(clipIndex, 1);
} else if (clipType === "inset") {
if (index < 8) {
if (clipIndex < 8) {
return;
}
removeRadiusPos(clipPoses, poses, index, 8, length);
removeRadiusPos(clipPoses, poses, clipIndex, 8, length);

if (length === clipPoses.length) {
return;
Expand Down Expand Up @@ -389,6 +389,7 @@ export default {
clippable: Boolean,
defaultClipPath: String,
customClipPath: String,
keepRatio: Boolean,
clipRelative: Boolean,
clipArea: Boolean,
dragWithClip: Boolean,
Expand Down Expand Up @@ -659,7 +660,7 @@ export default {
datas.isControl = className && className.indexOf("clip-control") > -1;
datas.isLine = className.indexOf("clip-line") > -1;
datas.isArea = className.indexOf("clip-area") > -1 || className.indexOf("clip-ellipse") > -1;
datas.index = inputTarget ? parseInt(inputTarget.getAttribute("data-clip-index"), 10) : -1;
datas.clipIndex = inputTarget ? parseInt(inputTarget.getAttribute("data-clip-index"), 10) : -1;
datas.clipPath = clipPath;
datas.isClipStart = true;
state.clipPathState = clipText;
Expand All @@ -673,7 +674,7 @@ export default {
if (!datas.isClipStart) {
return false;
}
const { isControl, isLine, isArea, index, clipPath } = datas as {
const { isControl, isLine, isArea, clipIndex, clipPath } = datas as {
clipPath: ReturnType<typeof getClipPath>,
[key: string]: any,
};
Expand Down Expand Up @@ -708,17 +709,17 @@ export default {
distX = -distX;
distY = -distY;
}
const isAll = !isControl || clipPoses[index].direction === "nesw";
const isAll = !isControl || clipPoses[clipIndex].direction === "nesw";
const isRect = clipType === "inset" || clipType === "rect";
let dists = clipPoses.map(() => [0, 0]);

if (isControl && !isAll) {
const { horizontal, vertical } = clipPoses[index];
const { horizontal, vertical } = clipPoses[clipIndex];
const dist = [
distX * Math.abs(horizontal),
distY * Math.abs(vertical),
];
dists = moveControlPos(clipPoses, index, dist, isRect);
dists = moveControlPos(clipPoses, clipIndex, dist, isRect);
} else if (isAll) {
dists = poses.map(() => [distX, distY]);
}
Expand Down Expand Up @@ -772,7 +773,6 @@ export default {
guideYPoses = guidePoses.filter((_, i) => dists[i][1]).map(pos => pos[1]);
}
const boundDelta = [0, 0];

const {
horizontal: horizontalSnapInfo,
vertical: verticalSnapInfo,
Expand Down
5 changes: 5 additions & 0 deletions packages/react-moveable/src/react-moveable/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2230,6 +2230,11 @@ export interface ClippableOptions {
* @default false
*/
clippable?: boolean;
/**
* Whether to keep the ratio of size if your clipPath is 'inset', 'rect', 'ellipse' type
* @default false
*/
keepRatio?: boolean;
/**
* You can force the custom clipPath. (defaultClipPath < style < customClipPath < dragging clipPath)
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from "./4-SnapGrid.stories";
export * from "./5-BoundScalable.stories";
export * from "./6-BoundResizable.stories";
export * from "./7-SnapContainer.stories";
export * from "./8-InnerBoundResizable.stories";
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { DEFAULT_REACT_CODESANDBOX } from "storybook-addon-preview";
import "../common.css";
import "../templates/default.css";
import { convertPath, convertReactTemplate, makeArgs } from "../utils";
import App from "./apps/ReactInnerBoundResizableApp";
import RawReactApp from "!!raw-loader!./apps/ReactInnerBoundResizableApp";
import {
DEFAULT_INNER_BOUNDS_CONTROLS,
} from "../controls/default";

export const InnerBoundResizableTemplate = App as any;

InnerBoundResizableTemplate.storyName = "InnerBound (Draggable & Resizable)";
InnerBoundResizableTemplate.argTypes = {
...DEFAULT_INNER_BOUNDS_CONTROLS,
};
InnerBoundResizableTemplate.args = {
...makeArgs(InnerBoundResizableTemplate.argTypes),
};


InnerBoundResizableTemplate.parameters = {
preview: [
{
tab: "React",
template: convertReactTemplate(convertPath(RawReactApp)),
codesandbox: DEFAULT_REACT_CODESANDBOX(["react-moveable"]),
language: "tsx",
},
],
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
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={{
width: "500px",
height: "500px",
border: "1px solid #ccc",
}}>
<div className="target">Target</div>
<Moveable
target={".target"}
draggable={true}
resizable={true}
keepRatio={props.keepRatio}
snappable={true}
innerBounds={props.innerBounds}
onDrag={e => {
e.target.style.transform = e.transform;
}}
onResize={e => {
e.target.style.width = `${e.width}px`;
e.target.style.height = `${e.height}px`;
e.target.style.transform = e.drag.transform;
}}
/>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default function App(props: Record<string, any>) {
<Moveable
target={targetRef}
draggable={true}
resizable={true}
clippable={true}
dragWithClip={false}
clipTargetBounds={true}
Expand All @@ -27,6 +28,11 @@ export default function App(props: Record<string, any>) {
onDrag={e => {
e.target.style.transform = e.transform;
}}
onResize={e => {
e.target.style.width = `${e.width}px`;
e.target.style.height = `${e.height}px`;
e.target.style.transform = e.drag.transform;
}}
onClip={e => {
e.target.style.clipPath = e.clipStyle;
}} />
Expand Down
6 changes: 3 additions & 3 deletions packages/react-moveable/stories/controls/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,10 +266,10 @@ export const DEFAULT_INNER_BOUNDS_CONTROLS = {
description: makeLink("Snappable", "snappable"),
defaultValue: true,
}),
bounds: makeArgType({
innerBounds: makeArgType({
type: "object",
description: makeLink("Snappable", "bounds"),
defaultValue: { left: 0, top: 0, right: 500, bottom: 500 },
description: makeLink("Snappable", "innerBounds"),
defaultValue: { left: 0, top: 0, width: 100, height: 100 },
}),
};

Expand Down

0 comments on commit 37da849

Please sign in to comment.