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 шт):
Выбрать несколько элементов и за один раз переместить выбранные элементы по экрану - можно.
У каждого элемента созданного компонентом Draggable
есть позиция, а у активно перетаскиваемого элемента есть дальность перемещения - deltaX
и deltaY
- в итоге решение состоит из 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;
Но решение не идеальное, желательно попробовать оптимизировать, чтобы не перерендеривать все дочерние компоненты, а так же добавление/удаление по клику - активность удаляется при перетаскивании.