在单场淘汰赛中用奇数玩家连接线 - 反应

Connecting Lines in a Single Elimination UI with an Odd Number of Players - react

提问人:smack cherry 提问时间:11/1/2023 最后编辑:smack cherry 更新时间:11/5/2023 访问量:294

问:

我正在构建一个使用 和 ,并且在尝试连接玩家之间的线路时遇到了问题。Single Elimination UIReactCSS

我试过这种方式。在上面画了一条线。但是结构失败了。这是我尝试 https://codesandbox.io/s/single-elimination-torunament-forked-qqlxm4?file=/src/SingleElimination.jsx 的代码 但由于盒子结构不当,它失败了。如果线条不在视口下,则不会绘制线条

enter image description here

所需的结构是

enter image description here

请向我提出一些解决方案。

javascript html reactjs, css-selectors

评论

0赞 m4n0 11/2/2023
我希望人们可以在 SO 上的所有其他问题上展示这样的演示。理解;)的简单方法
0赞 Brumazzi DB 11/5/2023
也许您可以使用 canvas 或 svg,也可以在 svg 子标签中应用 css
0赞 smack cherry 11/5/2023
@BrumazziDB,是的。我用svg画线。

答:

1赞 Damzaky 11/5/2023 #1

老实说,我更愿意使用另一个 HTML 作为连接线,但我不想为此更改您的代码,因此在此解决方案中,我坚持使用 SVG 来绘制线条。

首先,要制作类似于第二张图片的结构,您需要添加“幽灵”框,所以我添加了以下内容:

const players15 = {
    round1: [
      [], // need to add this
      [8, 9],
...

然后我制作了 CSS,使框垂直居中(许多 CSS 代码经过调整,无法真正显示哪些代码,因为太多了)。

CSS修复后,我意识到您将一些框连接到错误的框:

      drawConnectorsBetweenMatches(".round1match2", ".round2match1", newLines);
      drawConnectorsBetweenMatches(".round1match2", ".round2match2", newLines);
      drawConnectorsBetweenMatches(".round1match3", ".round2match1", newLines);

我假设你不想连接,同时也连接(比如为什么一个盒子会在下一轮连接到两个盒子?),所以我也根据第二张图片修复了它们:round1match2round2match1round1match2round2match2

      // round 1 to 2
      drawConnectorsBetweenMatches(".round1match2", ".round2match1", newLines);
      drawConnectorsBetweenMatches(".round1match3", ".round2match2", newLines);
      drawConnectorsBetweenMatches(".round1match4", ".round2match2", newLines);
      drawConnectorsBetweenMatches(".round1match5", ".round2match3", newLines);
      drawConnectorsBetweenMatches(".round1match6", ".round2match3", newLines);
      drawConnectorsBetweenMatches(".round1match7", ".round2match4", newLines);
      drawConnectorsBetweenMatches(".round1match8", ".round2match4", newLines);

      // round 2 to 3
      drawConnectorsBetweenMatches(".round2match1", ".round3match1", newLines);
      drawConnectorsBetweenMatches(".round2match2", ".round3match1", newLines);
      drawConnectorsBetweenMatches(".round2match3", ".round3match2", newLines);
      drawConnectorsBetweenMatches(".round2match4", ".round3match2", newLines);

      // round 3 to 4
      drawConnectorsBetweenMatches(".round3match1", ".round4match1", newLines);
      drawConnectorsBetweenMatches(".round3match2", ".round4match1", newLines);

在那之后,我意识到线条仍然没有正确渲染,所以我不得不调整线条的位置。基本上,我将您的代码更改为:

    let midPointX =
      (match1Rect.right + match2Rect.left) / 2 + scrollLeft - playoffTableLeft;

    newLines.push({
      x1: midPointX,
      y1: match1Rect.top + match1Rect.height / 2 + window.scrollY - offsetTop,
      x2: midPointX,
      y2: match2Rect.top + match2Rect.height / 2 + window.scrollY - offsetTop
    });
    newLines.push({
      x1: match1Rect.right + scrollLeft - 20 - playoffTableLeft,
      y1: match1Rect.top + match1Rect.height / 2 + window.scrollY - offsetTop,
      x2: midPointX,
      y2: match1Rect.top + match1Rect.height / 2 + window.scrollY - offsetTop
    });
    newLines.push({
      x1: match2Rect.left + scrollLeft + 20 - playoffTableLeft,
      y1: match2Rect.top + match2Rect.height / 2 + window.scrollY - offsetTop,
      x2: midPointX,
      y2: match2Rect.top + match2Rect.height / 2 + window.scrollY - offsetTop
    });

基本上,我添加了它们,以便计算将反映到视口更改中。

然后我也删除了这一行,因为我不确定它是否仍然有必要:

    playoffTable.addEventListener("scroll", handleScroll);

这是现在的样子:enter image description here

下面是分叉的沙盒:

编辑 single-elimination-torunament-forked-zxp277

编辑:

由于 OP 说他们不能手动添加空框,因此我提供了自动添加空框的解决方案,该解决方案甚至可以自动连接线路。

因此,由于它本质上是一个二叉树数据结构,我们可以从根(最后一轮)迭代,看看是否有任何不是“tbd”的值,如果它不是“tbd”,我们可以在上一轮添加空框,以便 CSS 能够坚持下去,这是函数:

  function populateTree(obj) {
    const newObj = JSON.parse(JSON.stringify(obj));
    const round = Math.max(
      ...Object.keys(newObj).map((key) =>
        parseInt(key.replace(/[A-Za-z$-]/g, ""))
      )
    );

    let pointer = round;

    while (pointer !== 1) {
      const currRound = newObj[`round${pointer}`].flat(Infinity);

      for (let i = 0; i < currRound.length; i++) {
        if (currRound[i] !== "tbd") {
          newObj[`round${pointer - 1}`].splice(i, 0, [null, null]);
        }
      }
      pointer--;
    }

    return newObj;
  }

这现在可以处理已经有赢家的情况:

enter image description here

这是新的分叉代码沙箱:

编辑 single-elimination-torunament-forked-jj5xty

评论

0赞 smack cherry 11/5/2023
谢谢。但是我不能在数组中添加空框。它们来自后端。就像 5 名玩家一样,它会是这样的 const players5 = { round1: [[4, 5]], round2: [ [“1”, “tbd”], [2, 3] ], round3: [[“tbd”, “tbd”]] };所以我不知道在哪里添加空框。他们不会送轮空比赛。
0赞 Damzaky 11/5/2023
@smackcherry好吧,这难道不意味着我们可以在下一列上没有 tbd 的框中添加空框吗?
0赞 smack cherry 11/5/2023
是的。我认为它会奏效的......
0赞 Damzaky 11/5/2023
@smackcherry请查看我更新的答案
0赞 smack cherry 11/6/2023
是否可以减少空白空间。图片链接: postimg.cc/tY6Z57Vk