Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arrow direction issue #146

Open
albingroen opened this issue May 20, 2021 · 7 comments
Open

Arrow direction issue #146

albingroen opened this issue May 20, 2021 · 7 comments

Comments

@albingroen
Copy link

Issue

When you have two items where the source anchor is on the same x point as the target anchor, the arrow get pointed in the wrong direction.

CleanShot 2021-05-20 at 13 44 31

<ArcherElement
  id={String(event.id)}
  relations={event.connections?.map(targetId => ({
    targetId,
    sourceAnchor: 'right',
    targetAnchor: 'left',
  }))}
  key={event.id}
>
@pierpo pierpo added bug Something isn't working drawing shape and removed bug Something isn't working labels May 25, 2021
@pierpo
Copy link
Owner

pierpo commented May 25, 2021

Hello!

Thank you for the issue! The lib needs many drawing enhancements indeed.

How would you expect the arrows to be drawn? In that case, I'm not sure what we'd expect.

@albingroen
Copy link
Author

albingroen commented May 25, 2021

In this case, I would expect to act something like this:

CleanShot 2021-05-25 at 14 17 03

@pierpo
Copy link
Owner

pierpo commented May 26, 2021

Mmmmh in terms of API I wouldn't expect { targetAnchor: 'left' } to give this result.

For such a result, this should be { targetAnchor: 'top' } since the arrow goes on top. Right now, this would give you a centered arrow, but one could imagine having a new offset prop that would allow you to put a continuous value between -1 and 1 that would shift the arrow alongside the border. For example here this would be { targetAnchor: 'top', targetAnchorLateralOffset: -0.8 }.

This is just a rough idea 🤔

@albingroen
Copy link
Author

Sure, but to be fair, this one has { sourceAnchor: 'right' } and still shows up on the bottom, nicely, so I don't see why the target couldn't 🤷‍♂️

118973232-bc81d380-b971-11eb-938c-e5677a19f916

@pierpo
Copy link
Owner

pierpo commented May 26, 2021

Haha good point, but try putting down the opacity of your green block. I think you'll notice that the arrow goes backward, starting from the right border 😅

@albingroen
Copy link
Author

Ah I see 😄

Anyway, I think the package should solve this issue, and that it shouldn't be up to the user to try to find out exactly when the source and the target area on the same x position, and then manually have to set some sort of offset. Maybe you could add a prop to opt-out or into this though.

@hata6502
Copy link

hata6502 commented Aug 15, 2021

I resolved the arrow direction issue in myself.

simplescreenrecorder-2021-08-15_23.52.56.mp4

Commit: hata6502/troopa-wasm@c305689

By using useEffect(), the arrow direction is updated every 200 ms.

  useEffect(() => {
    const handle = () =>
      setRelations(
        getRelations({
          anchorlessRelations: [
            ...anchorlessRelations,
            ...(connectionCuror ? [{ targetId: cursorID }] : []),
          ],
          sourceId: radioID,
        })
      );

    handle();

    const intervalID = setInterval(handle, 200);

    return () => clearInterval(intervalID);
  }, [anchorlessRelations, connectionCuror, cursorID, radioID]);

Then, detect arrow direction by getting DOMRects.

const arrowLength = 40;

const detectAnchors = ({
  sourceCenterX,
  sourceCenterY,
  targetCenterX,
  targetCenterY,
}: {
  sourceCenterX: number;
  sourceCenterY: number;
  targetCenterX: number;
  targetCenterY: number;
}): Pick<Relation, "sourceAnchor" | "targetAnchor"> => {
  if (Math.abs(sourceCenterX - targetCenterX) >= arrowLength) {
    return sourceCenterX < targetCenterX
      ? {
          sourceAnchor: "right",
          targetAnchor: "left",
        }
      : {
          sourceAnchor: "left",
          targetAnchor: "right",
        };
  }

  if (Math.abs(sourceCenterY - targetCenterY) >= arrowLength) {
    return sourceCenterY < targetCenterY
      ? {
          sourceAnchor: "bottom",
          targetAnchor: "top",
        }
      : {
          sourceAnchor: "top",
          targetAnchor: "bottom",
        };
  }

  return {
    sourceAnchor: "middle",
    targetAnchor: "middle",
  };
};

const getRelations = ({
  anchorlessRelations,
  sourceId,
}: {
  anchorlessRelations: AnchorlessRelation[];
  sourceId: string;
}) => {
  const sourceElement = document.getElementById(sourceId);

  if (!sourceElement) {
    throw new Error(`Could not find element with id "${sourceId}"`);
  }

  const soruceDOMRect = sourceElement.getBoundingClientRect();
  const sourceCenterX = soruceDOMRect.left + soruceDOMRect.width / 2;
  const sourceCenterY = soruceDOMRect.top + soruceDOMRect.height / 2;

  return anchorlessRelations.map((anchorlessRelation): Relation => {
    const targetElement = document.getElementById(anchorlessRelation.targetId);

    if (!targetElement) {
      throw new Error(
        `Could not find element with id "${anchorlessRelation.targetId}"`
      );
    }

    const targetDOMRect = targetElement.getBoundingClientRect();
    const targetCenterX = targetDOMRect.left + targetDOMRect.width / 2;
    const targetCenterY = targetDOMRect.top + targetDOMRect.height / 2;

    return {
      ...anchorlessRelation,
      ...detectAnchors({
        sourceCenterX,
        sourceCenterY,
        targetCenterX,
        targetCenterY,
      }),
    };
  });
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants