Регулировка радиуса прямоугольника путем перетаскивания угловой ручки

#javascript #reactjs #trigonometry

Вопрос:

Я создаю инструмент проектирования и застрял в понимании того, как создать эту функциональность. У меня есть хороший кусок этого здесь https://codesandbox.io/s/sharp-mendeleev-dsgvx?file=/src/App.tsx но это немного шатко.

Функцию, которую я пытаюсь воссоздать, можно найти в Figma или эскизе, вот запись 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 amp;amp; e.target amp;amp; 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 на случай, если вы пропустили это выше.

Ответ №1:

Измените следующую строку…

 const val = Math.round(Math.atan2(y, x) * 100);
 

…чтобы…

 const val = Math.sqrt( x * x   y * y );
 

Короче говоря, исходный код получает угол (в радианах) курсора к углу, поэтому после захвата контрольной точки, если вы обычно перемещаете курсор влево или вправо, вы увидите плавный угловой переход, поскольку вы плавно перемещаете угол курсора относительно угла.

Предлагаемый код просто измеряет расстояние от курсора до угла.

Тем не менее, это не решает всей проблемы. Когда handleMouseDown происходит событие, необходимо зафиксировать текущее местоположение курсора, текущее расстояние до угла прямоугольника И текущий радиус угла прямоугольника. Затем это позволит вам рассчитать изменение расстояния до угла от исходного местоположения курсора, а затем изменение радиуса прямоугольника…