Как перетащить несколько объектов одновременно в React? - PullRequest
0 голосов
/ 28 апреля 2020

Я хотел бы перетаскивать несколько объектов одновременно (сохраняя их позиции в DOM). Поэтому, если объекты перекрываются, порядок перекрытия должен оставаться прежним.

enter image description here

Я пытался добиться этого с помощью реагирующее перетаскивание или response-dnd - самые популярные платформы перетаскивания в Google.

В response-dnd предлагаемое решение будет отслеживать выбранные элементы и реализовывать пользовательский drag-layer . Однако при этом положение в DOM будет потеряно, поэтому визуально объекты будут перекрывать друг друга по-разному.

Я не нашел, как это сделать в реагировать-перетаскиваемым . Может быть, есть способ иметь какой-то атрибут draggableGroup для указания группы перетаскиваемых объектов? Кто-нибудь реализовывал что-то подобное раньше?

Вот мои эксперименты с реагирующим перетаскиванием: codepen.io / markvital / pen / gOaRMNX .

Можно выбрать несколько объектов , но только один перетаскивается.

const canvasSize = {width:"600", height:"400"}

function DraggableItem({id, selected, onSelect, children}) {
    const [isDragging, setIsDragging] = React.useState(false);
    const isSelected = selected && selected.indexOf(id) >= 0;

    function handleClick (e, idx) {
        if (e.shiftKey) {
            onSelect(idx);
        }
    }

    return (
        <ReactDraggable
            onStart={ () => setIsDragging(true) }
            onStop={ () => { setIsDragging(false); } }
            disabled={!isSelected}
        >
            <g>
                <g className={`item ${isSelected ? "selected" : ""} ${isDragging ? "dragging" : ""}`} onClick={e => handleClick(e, id)}>
                    {children}
                </g>
            </g>
        </ReactDraggable>
    )
}

function DraggableElements(props) {
    const {children, ...restProps } = props;
    const draggable = children.map((child, idx) => <DraggableItem key={idx} id={idx} {...restProps}>{child}</DraggableItem>);
    return(
        <>{draggable}</>
    )
}

function Canvas(props) {
    const [selected, setSelected] = React.useState([]);
    function select(idx){
        const newSelection = selected.indexOf(idx) >= 0 ? selected.filter(item => item != idx) : [...selected, idx];
        setSelected( newSelection );
    }

    return (
            <svg className="canvas" {...canvasSize} xmlns="http://www.w3.org/2000/svg"  >
                <DraggableElements selected={selected} onSelect={select}>
                    <rect x="120" y="250" width="100" height="100" fill="lightgrey" />
                    <circle cx="400" cy="100" r="75"  fill="lightblue" />
                    <polygon points="160,300 200,100 350,230" fill="grey" />
                    <rect x="50" y="50" width="200" height="100" fill="lightgreen" />
                    <rect x="465" y="70" width="100" height="150" rx="25" fill="pink" />
                    <ellipse cx="400" cy="260" rx="130" ry="75" fill="lightyellow" />
                </DraggableElements>
            </svg>
    );
}

function App() {
  return (
    <div className="App">
        <Canvas />
        <div> Hold SHIFT key to select multiple figures, than drag </div>
    </div>
  );
}



let mountNode = document.getElementById("app");
ReactDOM.render(<App />, mountNode);

1 Ответ

0 голосов
/ 28 апреля 2020

Одним из решений, использующих реагирующее-перетаскивание, было бы сохранение некоторого состояния delta в родительском компоненте, которое описывает смещение позиции курсора при перетаскивании:

function Canvas(props) {
  const [delta, setDelta] = useState(null); // cursor offset while dragging, {x:0, y:0}
  const [selected, setSelected] = useState([]);

  return (
      // draggable elements, each wrapped in react-draggable
      <DraggableElements delta={delta} onDrag={handleDrag}>
        //..
      </DraggableElements>
  )
}

, а затем передает это delta to children, завернутые в перетаскиваемый компонент

<ReactDraggable onDrag={ (e, data) => { onDrag({x: data.x, y: data.y }, id) } }>
   <g style={delta ? {transform: `translate(${delta.x}px, ${delta.y}px)`} }>
      //...
   </g> 
</ReactDraggable>

Вот рабочая версия, основанная на моем предыдущем примере: codepen.io / markvital / pen / vYNZXgW

Хотелось бы увидеть более оптимальное решение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...