React-dnd: ドロップターゲットコンテナを基準にしたドロップアイテムの座標を取得するにはどうすればよいですか?

作成日 2015年05月13日  ·  15コメント  ·  ソース: react-dnd/react-dnd

私は1.0.0-rcで作業しています。

drag-around-naive

const boxTarget = {
  drop(props, monitor, component) {
    const item = monitor.getItem();
    const delta = monitor.getDifferenceFromInitialOffset();
    const left = Math.round(item.left + delta.x);
    const top = Math.round(item.top + delta.y);

    component.moveBox(item.id, left, top);
  }
};

現在、元のアイテムのページからオフセットを取得する必要があるようです。次に、ドロップした場所のページからのオフセットを見つけることができます。次に、ページからドロップコンテナのオフセットを見つける必要があります。次に、その計算と私は私のドロップターゲットコンテナ内の相対的な位置を持っています。

これはかなり一般的な何かのための多くの仕事のようです...

enhancement

最も参考になるコメント

ええ、私たちは対称性のためにこれを持つことができると思います。 今のところ、 findDOMNode(component).getBoundingClientRect()使用できますが、より多くの人が音声サポートを提供する場合は、これを追加してもかまいません。 これを開いたままにして、他の人の言うことを見てみましょう。

全てのコメント15件

getClientOffsetは、ビューポートに対する相対的な位置を返すようです。 したがって、私がしなければならないのは、ドロップターゲットでオフセットを見つけることだけです。 ドロップターゲットに比べて便利な方法をとる価値はまだあると思いますか?

ええ、私たちは対称性のためにこれを持つことができると思います。 今のところ、 findDOMNode(component).getBoundingClientRect()使用できますが、より多くの人が音声サポートを提供する場合は、これを追加してもかまいません。 これを開いたままにして、他の人の言うことを見てみましょう。

私もこういうものが欲しいです。 ドロップターゲットの境界の長方形/座標を取得する必要があるので、何かをその上に置くと、ドロップターゲットの内側の左側、右側、上部、または下部にあるかどうかを計算できます。

相対座標は、他のユースケースで役立ちます。 Trelloのようなアプリの場合、カードをリストの上にドラッグすると、ドロップ領域の下部にカーソルを合わせるとリストが下にスクロールし、上部にカーソルを合わせるとリストが上にスクロールします。

ユーザースペースに実装するのは簡単です。

また、境界矩形にアクセスするとブラウザでリフローが発生し、多少コストがかかることを読んだことをぼんやりと覚えています。 これがまだ当てはまるかどうかはわかりません。

アイテムが移動したかどうかわからないため、実際にgetBoundingClientRectにアクセスせずにこれを行う方法はないと思います。

Trelloのようなアプリの場合、カードをリストの上にドラッグすると、ドロップ領域の下部にカーソルを合わせるとリストが下にスクロールし、上部にカーソルを合わせるとリストが上にスクロールします。

これは素晴らしいユースケースです。

パフォーマンスペナルティは確かに重要であり、React DnDに追加されても、アプリがそれを使用しない場合は無駄になります。 したがって、これをReactDnDに追加したくありません。

ユーザーランドでの実装は簡単で、 getBoundingClientRect呼び出しを抑制したり、関連するスクロールコードをアニメーションフレームに配置したりすることができます。

ソート可能なストレステストに_例として_「下部のホバーでスクロール」を追加することを歓迎します。 これには、 hoverのみをリッスンし、アニメーションフレーム内でスクロールするコンテナレベルで別のドロップターゲットを追加することが含まれます。

ただし、上記の理由により、DOM座標メソッドをReactDnDに追加しません。

@gaearon一般化されたソリューションに興味があります。 react-dnd-html5-backend代わりにgetBoundingClientRect直接使用するにはどうすればよいですか?

DropTargetMonitor関数getInitialSourceClientOffsetgetSourceClientOffsetonDropイベント内のコールバック関数に渡すことでこれを解決しました。 このようにして、私のコールバック関数はビューポートに関連する正しい座標を計算できます。

// some code before...

const [, dropRef] = useDrop({
    accept: 'STICKY',
    drop(item, monitor) {
      move(
        item.id,
        monitor.getInitialSourceClientOffset(),
        monitor.getSourceClientOffset()
      );
    },
  });

// I'm updating my state with npm immer (immutable helper) throuthg the produce function...

const move = (id, initialPosition, finalPosition) => {
    setList(
      produce(list, draft => {
        list.map(item => {
          if (item.id === id) {
            item.position = getCorrectDroppedOffsetValue(
              initialPosition,
              finalPosition
            );
          }
          return item;
        });
      })
    );
  };

// and finally, my getCorrectDroppedOffsetValue function
const getCorrectDroppedOffsetValue = (initialPosition, finalPosition) => {
    // get the container (view port) position by react ref...
    const dropTargetPosition = ref.current.getBoundingClientRect();

    const { y: finalY, x: finalX } = finalPosition;
    const { y: initialY, x: initialX } = initialPosition;

    // calculate the correct position removing the viewport position.
   // finalY > initialY, I'm dragging down, otherwise, dragging up
    const newYposition =
      finalY > initialY
        ? initialY + (finalY - initialY) - dropTargetPosition.top
        : initialY - (initialY - finalY) - dropTargetPosition.top;

    const newXposition =
      finalX > initialX
        ? initialX + (finalX - initialX) - dropTargetPosition.left
        : initialX - (initialX - finalX) - dropTargetPosition.left;

    return {
      x: newXposition,
      y: newYposition,
    };
  };

findDOMNodeは機能コンポーネントでは機能せず、 useDrop#dropcomponentを渡しません。コンポーネントのrefを取得したい場合は、個別に保管し、手動でドロップコネクタを呼び出して渡します。 これを行うためのより簡潔な方法はありますか?

function useCustomDrop(onDrop: (info: unknown, xy: Point) => void) {

    const ref = useRef<Element>();

    const [, dropTarget] = useDrop<any, void, unknown>({
        accept: 'item-type',
        drop(item, monitor) {
            const offset = monitor.getSourceClientOffset();
            if (offset && ref.current) {
                const dropTargetXy = ref.current.getBoundingClientRect();
                onDrop(item.data, {
                    x: offset.x - dropTargetXy.left,
                    y: offset.y - dropTargetXy.top,
                });
            }
        }
    });

    return (elem) => {
        ref.current = elem;
        dropTarget(ref);
    };
}

@quanganhtran共有したい完全なコードサンプルはありますか?

@dendrochronology

不自然な例: https

ref自分で保存する必要がない場合、APIはより優れています( useGlobalDropuseLocalDrop )。 ここで、 react-dndすでに取得していると想定しているrefのみが、どこかのmonitorオブジェクトにアタッチされている場合( dropでアクセス可能)、意見)、それはこれを解決します。

このソリューションは、特にブラウザを拡大したり、デバイスの解像度を変更したりする場合は信頼できません。 何か案が?

同じ質問があります@ sepehr09

数回のグーグル検索の後に通り過ぎるだけです...元の質問の更新はありますか? (ドロップターゲットに対するドロップアイテムのx / yを取得する)

私はこれを必要とする人々のリストに加わると思います。 何か助けてください?

この機能は非常に必要であり、ライブラリに追加する必要があると思います。 今、誰もがそれを使って作業しました、私たちを助けてください!

このページは役に立ちましたか?
0 / 5 - 0 評価