显示动态圆 Children

Display a Circle with Dynamic Children

我正在创建一个使用圆形作为布局的动态阵列显示。数组的每个元素将占据圆内 space 的相同部分。如果数组中有 3 个元素,则需要在 3 个相等的 space 秒内填满 100% 的圆。我已经让它工作到显示 4 个相同大小的元素的程度。我需要帮助找出一个公式来根据数组的大小调整正方形的大小。

我的方法是单独创建每个元素。我需要控制圆圈内的每个 child,同时将 child 内的文本居中。我也乐于接受新想法,我觉得代码有点乱。如果您有更清洁的方法,请分享!

下面是我的代码:

import React, { useState, forwardRef } from "react";
import {dataFlow} from './database'

const PieDisplay = forwardRef(({ showWindow }, ref) => {
  const [display, setDisplay] = useState(dataFlow.map((item) => item));

  const getPieStyle = (index) => {
    let pieButtonStyle = {
      transform: "",
    };
    const rotX = (360 / display.length) * index; //set the angle for each element of the pie
    pieButtonStyle.transform = `rotate(${rotX}deg) skewY(0deg)`;
    return pieButtonStyle;
  };

  const getPieTextStyle = (index) => {
    let pieButtonStyle = {
      transform: "",
    };
    const rotX = 360 / display.length / 2; //set the angle for each element's text of the pie
    pieButtonStyle.transform = `rotate(${rotX}deg) skewY(0deg)`;
    return pieButtonStyle;
  };

  let i = 0;
  let j = 0;
  return (
   <div className="background">
    <div className="pie-parent">
      {display.map((elem) => (
        <div
          className="pie-button"
          style={getPieStyle(i += 1)}
          key={elem.name}
          onClick={
            elem.items ? () => updateDisplay(elem.name) : () => showWindow()
          }
          ref={ref}
        >
          <pre 
          className="pie-button--text"
          style={getPieTextStyle(j += 1)}
          >
           {elem.name}
          </pre>
        </div>
      ))}
    </div>
   </div>
  );
});

export default PieDisplay;

CSS:

.background {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    color: var(--white);
    font-size: 48px;
    width: 320px;
    height: 320px;
    padding: 20px;
    border-radius: 50rem;
    box-shadow: 0px 0px 30px 10px rgba(255, 255, 255, 0.2) inset, 0px 0px 30px 10px rgba(255, 255, 255, 0.2);
}

.pie-parent {
    position: absolute;
    box-shadow: 0px 0px 30px 10px rgba(255, 255, 255, 0.2) inset, 0px 0px 30px 10px rgba(255, 255, 255, 0.2);
    padding: 0;
    margin: 1em auto;
    width: 225%;
    height: 225%;
    border-radius: 50%;
    overflow: hidden;
}

.pie-button {
    overflow: hidden;
    position: absolute;
    top: 0;
    right: 0;
    width: 50%;
    height: 50%;
    transform-origin: 0% 100%;
    z-index: 2;
}

.pie-button--text {
    position: absolute;
    left: -100%;
    width: 200%;
    height: 200%;
    text-align: center;
    padding-top: 50px;
  }

.pie-button:hover {
    background-color: grey;
    cursor: pointer;
}

.pie-button:nth-child(1) {
    background-color: red;
}
.pie-button:nth-child(2) {
    background-color: blue;
}
.pie-button:nth-child(3) {
    background-color: yellow;
}
.pie-button:nth-child(4) {
    background-color: green;
}

测试数据:

export const dataFlow = [
    {
        name: 'Contact',
    },
    {
        name: 'About',
    },
    {
        name: 'Projects',
        items: [
            {
                name: "Test1",
            },
            {
                name: 'Test2',
            },
            {
                name: 'Test3',
            },
            {
                name: 'Test4',
            },
            {
                name: 'Test5'
            },
        ]
    },
    {
        name: "Professional\nExperience",
        items: [
            {
            name: 'Test1',
        },
        {
            name: 'Test2',
        },
        {
            name: 'Test3',
        }
    ]
    },
];

我能够根据数组的长度应用 skewY 和旋转值的正确组合来解决我的问题。基本上,skewY 值会根据要显示的元素数量发生巨大变化。下面是我想出的table:

N Elements SkewY
12 -60
11 -55
10 -50
9 -45
8 -40
7 -35
6 -30
5 -15
4 -0
3 30

3 = 30,比例 1.2 ~ 文本 -30,比例 0.8

对于 3 个元素,我需要应用比例 属性 来填补缺失的 space。父元素增加了大小,文本需要减少相同的数量,以便文本保持居中。

需要记住的一点是,为元素设置的 skewY 需要与文本相反。如果给元素 skewY 30deg,文本需要有 skewY -30deg。为了使文本在元素中间居中,我使用了旋转 属性。此外,文本需要先有 skewY,然后是旋转 属性。父元素首先有旋转,然后是 skewY 属性.

我无法显示 2 个元素,因为这需要在 90 度上有 skewY,然后元素消失。我想应该有一种显示它们的方法,但我还没有弄清楚。

非常感谢这位作者:https://microeducate.tech/how-to-divide-a-circle-into-12-equal-parts-with-color-using-css3-javascript/

下面是最终代码:

import React, { useState, forwardRef } from "react";
import {dataFlow} from './database'

const PieDisplay = forwardRef(({ showWindow }, ref) => {
  const [display, setDisplay] = useState(dataFlow.map((item) => item));


  const getPieStyle = (index) => {
    let pieButtonStyle = {
      transform: "",
    };
    const rotX = (360 / display.length) * index; //get the rotation for each element
    if (display.length === 3) pieButtonStyle.transform = `rotate(${rotX}deg) skewY(30deg) scale(1.2)`;
    else if (display.length === 4) pieButtonStyle.transform = `rotate(${rotX}deg) skewY(0deg)`;
    else if (display.length === 5) pieButtonStyle.transform = `rotate(${rotX}deg) skewY(-15deg)`;
    else if (display.length > 5) {
      const skewY = (5 * display.length) * -1 //set the skewY in intervals of 5 for 6+ elements
      pieButtonStyle.transform = `rotate(${rotX}deg) skewY(${skewY}deg)`;}
    return pieButtonStyle;
  };


  const getPieTextStyle = () => {
    let pieButtonStyle = {
      transform: "",
    };
    if (display.length === 3) pieButtonStyle.transform = `skewY(-30deg) rotate(55deg) scale(0.8)`;
    else if (display.length === 4) pieButtonStyle.transform = `skewY(0deg) rotate(45deg)`;
    else if (display.length === 5) pieButtonStyle.transform = `skewY(15deg) rotate(35deg)`;
    else if (display.length > 5) {
      const skewY = (5 * display.length)
      const rotX = 30 / (skewY / 30); //get the proper rotation based on skewY
      pieButtonStyle.transform = `skewY(${skewY}deg) rotate(${rotX}deg)`;
    }
    return pieButtonStyle;
  };

  let i = 0;
  return (
    <ul className="pie-parent">
      {display.map((elem) => (
        <li
          className="pie-button"
          style={getPieStyle(i += 1)}
          key={elem.name}
          onClick={
            elem.items ? () => updateDisplay(elem.name) : () => showWindow()
          }
          ref={ref}
        >
          <pre className="pie-button--text" style={getPieTextStyle()}>
            {elem.name}
          </pre>
        </li>
      ))}
    </ul>
  );
});

export default PieDisplay;