You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中使用SVG定位环形图分段及添加文本的问题

SVG环形分段定位与文本添加(React环境)

问题描述

在React中编写的SVG环形图代码如下,尝试将绿色环形分段旋转至90°、180°和270°位置时,修改rotate或translate属性后分段会消失。需要解决:

  1. 如何正确定位12.5%的环形分段到指定角度
  2. 如何为每个分段添加文本标注
const Donut = () => {
    return (
        <div className='rounded p-20' > 
        <svg height="30em" width="30em" viewBox="0 0 20 20">
        <circle r="10" cx="10" cy="10" fill="white" />
        <circle r="5" cx="10" cy="10" fill="bisque"
                stroke="tomato"
                stroke-width="10"
                stroke-dasharray="calc(12.5 * 31.42 / 100) 31.42" 
                transform="rotate(-90) translate(-20)"
                />
        <circle r="5" cx="10" cy="10" fill="none"
                stroke="green"
                stroke-width="10"
                stroke-dasharray="calc(12.5 * 31.42 / 100) 31.42" 
                transform="rotate(90) translate(-20)"
                />
        <circle r="5" cx="10" cy="10" fill="white" />
        </svg>
    </div>
    )
}

一、解决环形分段定位问题

问题原因

之前的transform="rotate(XX) translate(-20)"顺序错误:SVG的transform是从右到左执行,先执行translate(-20)再执行旋转,导致旋转中心偏移到SVG viewBox之外,修改角度后分段会被移出可见区域。

正确定位方法

应将旋转中心固定为环形的圆心(10,10),通过translate先把坐标系原点移到圆心,旋转后再移回,确保旋转始终围绕圆心进行:

transform="translate(10,10) rotate(起始角度) translate(-10,-10)"

关键参数说明:

  • 12.5%的分段对应45°范围(360°×12.5%=45°)
  • SVG默认0°在右侧,角度顺时针递增:顶部为-90°(或270°)、底部为90°、左侧为180°

修正后的分段代码示例

将绿色分段分别定位到90°(底部)、180°(左侧)、270°(顶部)的代码:

// 番茄色分段:顶部起始(-90°)
<circle r="5" cx="10" cy="10" fill="bisque"
        stroke="tomato"
        strokeWidth="10"
        strokeDasharray="calc(12.5 * 31.42 / 100) 31.42" 
        transform="translate(10,10) rotate(-90) translate(-10,-10)"
/>

// 绿色分段:底部起始(90°)
<circle r="5" cx="10" cy="10" fill="none"
        stroke="green"
        strokeWidth="10"
        strokeDasharray="calc(12.5 * 31.42 / 100) 31.42" 
        transform="translate(10,10) rotate(90) translate(-10,-10)"
/>

// 绿色分段:左侧起始(180°)
<circle r="5" cx="10" cy="10" fill="none"
        stroke="green"
        strokeWidth="10"
        strokeDasharray="calc(12.5 * 31.42 / 100) 31.42" 
        transform="translate(10,10) rotate(180) translate(-10,-10)"
/>

// 绿色分段:顶部起始(270°)
<circle r="5" cx="10" cy="10" fill="none"
        stroke="green"
        strokeWidth="10"
        strokeDasharray="calc(12.5 * 31.42 / 100) 31.42" 
        transform="translate(10,10) rotate(270) translate(-10,-10)"
/>

二、为分段添加文本标注

利用SVG的<text>元素,通过三角函数计算分段中心坐标,设置文本居中对齐:

  1. 计算分段中心角度:起始角度 + 22.5°(45°分段的中点偏移量)
  2. 将角度转为弧度:Math.PI / 180 * 中心角度
  3. 计算文本坐标:取环形中间半径7.5(外半径10、内半径5的中间值),则:
    • x = 10 + 7.5 * Math.cos(弧度)
    • y = 10 + 7.5 * Math.sin(弧度)
  4. 设置textAnchor="middle"和dominantBaseline="middle"确保文本居中

带文本的完整代码示例

const Donut = () => {
  // 计算文本位置的工具函数
  const getTextPosition = (startAngle) => {
    const centerAngle = startAngle + 22.5;
    const radian = Math.PI / 180 * centerAngle;
    const radius = 7.5;
    return {
      x: 10 + radius * Math.cos(radian),
      y: 10 + radius * Math.sin(radian)
    };
  };

  return (
    <div className='rounded p-20'> 
      <svg height="30em" width="30em" viewBox="0 0 20 20">
        {/* 背景圆环 */}
        <circle r="10" cx="10" cy="10" fill="white" />
        
        {/* 番茄色分段 + 文本 */}
        <circle r="5" cx="10" cy="10" fill="bisque"
                stroke="tomato"
                strokeWidth="10"
                strokeDasharray="calc(12.5 * 31.42 / 100) 31.42" 
                transform="translate(10,10) rotate(-90) translate(-10,-10)"
        />
        <text {...getTextPosition(-90)} 
              textAnchor="middle" 
              dominantBaseline="middle"
              fontSize="1.5em"
              fill="tomato">
          12.5%
        </text>

        {/* 绿色分段(底部) + 文本 */}
        <circle r="5" cx="10" cy="10" fill="none"
                stroke="green"
                strokeWidth="10"
                strokeDasharray="calc(12.5 * 31.42 / 100) 31.42" 
                transform="translate(10,10) rotate(90) translate(-10,-10)"
        />
        <text {...getTextPosition(90)} 
              textAnchor="middle" 
              dominantBaseline="middle"
              fontSize="1.5em"
              fill="green">
          12.5%
        </text>

        {/* 中心遮罩圆 */}
        <circle r="5" cx="10" cy="10" fill="white" />
      </svg>
    </div>
  )
}

补充说明

  • stroke-dasharray中的31.42是环形周长(2×π×5≈31.42),如需更精确可替换为calc(2 * 3.1416 * 5)
  • React中SVG属性建议用驼峰式命名(如strokeWidth代替stroke-width),更符合React规范

内容的提问来源于stack exchange,提问作者psykx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 12:05:29