通过拖动角手柄调整矩形的半径
Adjusting the radius of a rectangle by dragging a corner handle
我正在构建一个设计工具并且无法理解如何构建此功能。我在这里完成了大部分工作 https://codesandbox.io/s/sharp-mendeleev-dsgvx?file=/src/App.tsx 但它有点靠不住。
我要重现的功能可以在Figma或Sketch中找到,这里是录音https://share.getcloudapp.com/yAuDed8k
import { FC, useEffect, useState, useCallback } from "react";
import { RadiusControlWrap, RadiusControlStyle, CornerKnob } from "./Styles";
interface IRadiusControlProps {
size: any;
radius: number;
onRadiusChange: (radius: number) => void;
}
const RadiusControl: FC<IRadiusControlProps> = ({
size,
radius,
onRadiusChange
}) => {
const [mouseDown, setMouseDown] = useState<any>(false);
const handleMouseMove = useCallback(
(e: any) => {
if (mouseDown && e.target && e.target.parentElement) {
const rect = e.target.parentElement.getBoundingClientRect();
const x = Math.round(Number(e.clientX - rect.left));
const y = Math.round(Number(e.clientY - rect.top));
const val = Math.round(Math.atan2(y, x) * 100);
// TODO: Understand how to set the correct value
onRadiusChange(val);
}
},
[mouseDown, onRadiusChange]
);
const handleMouseUp = (e: any) => {
setMouseDown(false);
};
const handleMouseDown = (e: any) => {
setMouseDown(true);
};
useEffect(() => {
if (mouseDown) {
document.addEventListener("mouseup", handleMouseUp);
document.addEventListener("mousemove", handleMouseMove);
} else {
document.removeEventListener("mousemove", handleMouseMove);
}
return () => {
document.removeEventListener("mouseup", handleMouseUp);
document.removeEventListener("mousemove", handleMouseMove);
};
}, [handleMouseMove, mouseDown]);
// TODO: how to scale the knobs like Figma or Sketch
return (
<RadiusControlWrap>
<RadiusControlStyle
style={{
width: size.width - 30 - radius,
height: size.height - 30 - radius
}}
>
<CornerKnob corner="tl" onMouseDown={handleMouseDown} />
<CornerKnob corner="bl" />
<CornerKnob corner="tr" />
<CornerKnob corner="br" />
</RadiusControlStyle>
</RadiusControlWrap>
);
};
export default RadiusControl;
我最纠结的数学在里面handleMouseMove
。我使用的是 y 和 x 坐标的反正切、舍入和乘以 100——显然是错误的。
正如您在 Figma 屏幕共享中看到的那样,那里的数学与对象的中心完全成比例,半径似乎是根据边缘和中心之间的反正切差计算的,相应地设置圆度。
此外,手柄看起来呈矩形,并按比例缩小,直到它们在中间相交——或者当它们在 x 轴上相交时呈矩形。
希望这是有道理的,并且有一些 JS 和三角学经验的人可以提供帮助。
您可以在这里找到所有代码 https://codesandbox.io/s/sharp-mendeleev-dsgvx?file=/src/RadiusControl.tsx:0-1987 以防您在上面错过了它。
更改以下行...
const val = Math.round(Math.atan2(y, x) * 100);
...到...
const val = Math.sqrt( x * x + y * y );
简而言之,原始代码是获取光标到角的角度(以弧度为单位),因此在抓取控制点后,如果将光标大致向左或向右移动,您将看到一个平滑的角过渡,如下所示您正在平滑地转换光标相对于角的角度。
建议的代码只是测量光标到角的距离。
话虽这么说,但这并不能解决全部问题。当 handleMouseDown
事件发生时,需要捕获当前光标位置和到矩形角的当前距离以及当前矩形角半径。然后,这将允许您计算从原始光标位置到角点的距离变化,以及随后矩形半径的变化...
我正在构建一个设计工具并且无法理解如何构建此功能。我在这里完成了大部分工作 https://codesandbox.io/s/sharp-mendeleev-dsgvx?file=/src/App.tsx 但它有点靠不住。
我要重现的功能可以在Figma或Sketch中找到,这里是录音https://share.getcloudapp.com/yAuDed8k
import { FC, useEffect, useState, useCallback } from "react";
import { RadiusControlWrap, RadiusControlStyle, CornerKnob } from "./Styles";
interface IRadiusControlProps {
size: any;
radius: number;
onRadiusChange: (radius: number) => void;
}
const RadiusControl: FC<IRadiusControlProps> = ({
size,
radius,
onRadiusChange
}) => {
const [mouseDown, setMouseDown] = useState<any>(false);
const handleMouseMove = useCallback(
(e: any) => {
if (mouseDown && e.target && e.target.parentElement) {
const rect = e.target.parentElement.getBoundingClientRect();
const x = Math.round(Number(e.clientX - rect.left));
const y = Math.round(Number(e.clientY - rect.top));
const val = Math.round(Math.atan2(y, x) * 100);
// TODO: Understand how to set the correct value
onRadiusChange(val);
}
},
[mouseDown, onRadiusChange]
);
const handleMouseUp = (e: any) => {
setMouseDown(false);
};
const handleMouseDown = (e: any) => {
setMouseDown(true);
};
useEffect(() => {
if (mouseDown) {
document.addEventListener("mouseup", handleMouseUp);
document.addEventListener("mousemove", handleMouseMove);
} else {
document.removeEventListener("mousemove", handleMouseMove);
}
return () => {
document.removeEventListener("mouseup", handleMouseUp);
document.removeEventListener("mousemove", handleMouseMove);
};
}, [handleMouseMove, mouseDown]);
// TODO: how to scale the knobs like Figma or Sketch
return (
<RadiusControlWrap>
<RadiusControlStyle
style={{
width: size.width - 30 - radius,
height: size.height - 30 - radius
}}
>
<CornerKnob corner="tl" onMouseDown={handleMouseDown} />
<CornerKnob corner="bl" />
<CornerKnob corner="tr" />
<CornerKnob corner="br" />
</RadiusControlStyle>
</RadiusControlWrap>
);
};
export default RadiusControl;
我最纠结的数学在里面handleMouseMove
。我使用的是 y 和 x 坐标的反正切、舍入和乘以 100——显然是错误的。
正如您在 Figma 屏幕共享中看到的那样,那里的数学与对象的中心完全成比例,半径似乎是根据边缘和中心之间的反正切差计算的,相应地设置圆度。
此外,手柄看起来呈矩形,并按比例缩小,直到它们在中间相交——或者当它们在 x 轴上相交时呈矩形。
希望这是有道理的,并且有一些 JS 和三角学经验的人可以提供帮助。
您可以在这里找到所有代码 https://codesandbox.io/s/sharp-mendeleev-dsgvx?file=/src/RadiusControl.tsx:0-1987 以防您在上面错过了它。
更改以下行...
const val = Math.round(Math.atan2(y, x) * 100);
...到...
const val = Math.sqrt( x * x + y * y );
简而言之,原始代码是获取光标到角的角度(以弧度为单位),因此在抓取控制点后,如果将光标大致向左或向右移动,您将看到一个平滑的角过渡,如下所示您正在平滑地转换光标相对于角的角度。
建议的代码只是测量光标到角的距离。
话虽这么说,但这并不能解决全部问题。当 handleMouseDown
事件发生时,需要捕获当前光标位置和到矩形角的当前距离以及当前矩形角半径。然后,这将允许您计算从原始光标位置到角点的距离变化,以及随后矩形半径的变化...