React-draggable перемещение нескольких элементов единовременно

В моем проекте используется библиотека react-draggable, данные в виде таблиц (те самые draggable элементы) перемещаются по экрану и их перемещение может фиксироваться. Можно ли с помощью этой библиотеки выбрать несколько элементов и за один раз переместить выбранные элементы по экрану? Так выглядит часть кода:

           <Draggable
                onDrag={onDrag}
                onStop={onChangePositionHandler}
                nodeRef={nodeRef}
                position={{ x: table.position.x, y: table.position.y }}
                zIndex="8"
            >
                <div
                    className={styles.MainContainer}
                    id={table.name}
                >
                {table.name}
               </div>
            </Draggable>

И вот функция, которая срабатывает при перемещении объекта, позволяя потом сохранить новые координаты.

const onChangePositionHandler = (event, dragElement) => {
        onStop();
        const changedTable = {
            id: table.id,
            name: table.name,
            isCreatedByUser: table.isCreatedByUser,
            isAssociator: table.isAssociator,
            color: tableColor,
            position: {
                x: dragElement.x,
                y: dragElement.y
            },
            columns: table.columns
        };

        onChangeTableHandler(changedTable, areaName);
    };

Есть идея собрать массив из объектов Draggable, а затем сместить весь этот массив. Не знаю только, как высчитать новые координаты каждой и присвоить. Кто-то сталкивался с похожей проблемой? В проекте есть еще либа react-zoom-pan-pinch, но с помощью ее обертки перемещаются все таблицы в диаграмме. А нужно только избранные перемещать. Как можно прикрутить такую фичу?


Ответы (1 шт):

Автор решения: Arbery

Выбрать несколько элементов и за один раз переместить выбранные элементы по экрану - можно. У каждого элемента созданного компонентом Draggable есть позиция, а у активно перетаскиваемого элемента есть дальность перемещения - deltaX и deltaY - в итоге решение состоит из 2х пунктов:

  1. Повыделять нужные элементы изменяя им состояние
  2. При перетаскивании получить дельты и передать куда-нибудь выше, чтобы затем изменять позицию всех активных на эти дельты

В упрощенном виде выглядит так:

App.js - родитель

import React, { useState } from 'react';
import DragElement from './DragElement'

function App() {
  const [delta, setDelta] = useState({x: 0, y: 0})

  return (
    <div className='App'>
      <DragElement
        text='Блок 1'
        changeDelta={setDelta}
        delta={delta}
      />
      <DragElement
        text='Блок 2'
        changeDelta={setDelta}
        delta={delta}
      />
    </div>
  );
}
export default App;

Дочерний компонент DragElement :

import React, { useState, useEffect } from 'react';
import Draggable from 'react-draggable';

const DragElement = ({text, changeDelta, delta}) => {
  const [position, setPosition] = useState({x: 0, y: 0});
  const [active, setActive] = useState(false);

  const onDrag = (e, dragElement) => {
    changeDelta({x: dragElement.deltaX, y: dragElement.deltaY})
  };

  useEffect(() => {
    if (!active) return;
    setPosition( prev => ({ x: prev.x + (delta?.x || 0), y: prev.y + (delta?.y || 0)}) );
  }, [delta])

  return (
    <div>
      <Draggable
        position={position}
        onDrag={onDrag}
      >
        <div>
          <div>
            <button
              className={`button${active ? ' button--active' : ''}`}
              onClick={() => setActive(prev => !prev)}
            >
              {text}
            </button>
          </div>
        </div>
      </Draggable>
    </div>
  );
};

export default DragElement;

Но решение не идеальное, желательно попробовать оптимизировать, чтобы не перерендеривать все дочерние компоненты, а так же добавление/удаление по клику - активность удаляется при перетаскивании.

Edit some-drag

→ Ссылка