这个 React 组件库如何能够在 SVG 上使用拖放功能?

问题描述 投票:0回答:1

首先,这不是所有其他试图为 svgs 实现拖放的问题的重复,而回答者告诉他们不能 - 不知何故,我正在阅读的这段代码已经做到了,但我不知道如何做到这一点.

我正在开发一个名为react-hexgrid 的项目。 它是一个使用各种函数使用 svg 绘制六边形的库。 该库有拖放代码,但我不知道如何使用它。

这个例子使用一些旧的类...扩展了react语法来实现拖放,以及一个名为“react-scripts”的库。 您可以在here查看拖放道具/功能的一些实现。 如果您要克隆、安装并运行该示例,您会发现拖放确实有效。

gif

但是,我尝试编写一些这样的代码:

import React from 'react';
import { Hexagon, HexGrid, Layout } from 'react-hexgrid';

function App() {
  return (
    <HexGrid width="100%" height="100%">
      <Layout>
        {/* drag and drop the colors! }
      {/* the drag source */}
        <Hexagon
          q={0}
          r={0}
          s={0}
          style={{ fill: 'red' }}
          onDrop={() => {
            console.log('drag');
          }}
          onDragStart={() => {
            console.log('drag');
          }}
          onDrag={() => {
            console.log('drag');
          }}
        ></Hexagon>
      </Layout>
    </HexGrid>
  );
}

export default App;

无论我在任何元素上单击、鼠标悬停或拖动多少次,此代码都不起作用。我不明白为什么这不起作用,但上面链接的旧代码可以。 有什么想法吗?

stackblitz 链接

javascript reactjs svg drag-and-drop
1个回答
0
投票

这里有一个普通的 JavaScript 示例。在示例中,可拖动元素不是 SVG,而是 HTML 元素。

const board = document.querySelector('section');

board.querySelectorAll('div').forEach(positionHex);

function positionHex(elm){
  let q = parseInt(elm.dataset.q);
  let r = parseInt(elm.dataset.r);
  let s = parseInt(elm.dataset.s);
  let elm_box = elm.getBoundingClientRect();
  let section = elm.closest('section');
  let section_box = section.getBoundingClientRect();
  let zero = {
    left: section_box.width / 2 - elm_box.width / 2,
    top: section_box.height / 2 - elm_box.height / 2
  };
  elm.style.left = `${zero.left + q * elm_box.width * .75}px`;
  elm.style.top = `${zero.top + -s * elm_box.height / 2 + r * elm_box.height / 2}px`;
}

board.addEventListener('dragstart', e => {
  e.dataTransfer.setData('text/plain', e.target.dataset.cat);
});

board.addEventListener('dragover', e => {
  e.preventDefault();
});

board.addEventListener('drop', e => {
  e.preventDefault();
  let target = e.target.closest('.hex');
  if(!target || target.dataset.cat) return;
  let cat_id = e.dataTransfer.getData('text/plain');
  let board = target.closest('section');
  let source = board.querySelector(`div[data-cat = "${cat_id}"]`);
  source.draggable = false;
  delete source.dataset.cat;
  target.dataset.cat = cat_id;
  target.draggable = true;
});
body {
  background-color: DarkCyan;
}

section {
  position: relative;
  border: solid thin black;
  width: 500px;
  height: 500px;
  box-sizing: border-box;
}

.hex {
  position: absolute;
  width: 100px;
  aspect-ratio: 40/34.64;
  background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-22 -19.32 44 38.64"><path d="M-10-17.32 10-17.32 20 0 10 17.32-10 17.32-20 0Z" fill="MediumTurquoise" stroke="PaleTurquoise" stroke-width="1" /></svg>');
  background-size: cover;
  font-size: small;
  align-content: center;
  text-align: center;
}

.hex::before {
  content: attr(data-q)','attr(data-r)','attr(data-s);
}

.hex[data-cat] {
  background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-22 -19.32 44 38.64"><path d="M-10-17.32 10-17.32 20 0 10 17.32-10 17.32-20 0Z" fill="skyblue" stroke="PaleTurquoise" stroke-width="1" /></svg>');
}

.hex[data-cat]::before {
  content: 'Cat #'attr(data-cat);
}
<section>
  <div data-q="-1" data-r="0" data-s="1" data-cat="1" class="hex" draggable="true"></div>
  <div data-q="0" data-r="0" data-s="0" class="hex"></div>
  <div data-q="-1" data-r="1" data-s="0" class="hex"></div>
  <div data-q="1" data-r="0" data-s="-1" data-cat="2" class="hex" draggable="true"></div>
  <div data-q="0" data-r="-1" data-s="1" class="hex"></div>
  <div data-q="1" data-r="-1" data-s="0" class="hex"></div>
  <div data-q="2" data-r="-1" data-s="-1" class="hex"></div>
  <div data-q="2" data-r="-2" data-s="0" class="hex"></div>
  <div data-q="1" data-r="-2" data-s="1" class="hex"></div>
</section>

© www.soinside.com 2019 - 2024. All rights reserved.