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

如何计算SVG饼图扇区的动态文本坐标?

在动态SVG饼图扇区中心添加文本的解决方案

我来帮你搞定这个文本定位的问题!要在每个饼图扇区的中间显示文本,核心是计算每个扇区的中间角度,再把这个极坐标转换成笛卡尔坐标,同时考虑扇区的宽度来确定文本的半径位置。以下是具体实现步骤和修改后的代码:

关键思路

  1. 计算扇区中间角度:每个扇区的起始角度加上该扇区角度的一半(360/nbCateg / 2),这个角度就是扇区中心的角度。
  2. 确定文本的半径:因为你的饼图是用stroke-width实现的环形扇区,所以文本的半径应该是外半径减去扇区宽度的一半(radius - segmentWidth/2),这样文本刚好落在扇区的中间位置。
  3. 利用极坐标转笛卡尔函数:复用你现有的polarToCartesian函数,传入中心坐标、文本半径、中间角度,就能得到文本的X、Y坐标。
  4. 文本居中处理:给SVG文本元素设置text-anchor="middle"和dominant-baseline="middle",确保文本在坐标点上居中显示。

修改后的完整代码

var svg = document.getElementById('categSVG');
var startAngle = -89.999;
var nbCateg = 6;
var svgMiddleX = svg.width / 2;
var svgMiddleY = svg.height / 2;
var segmentWidth = 100;
var outerRadius = 100;
// 文本的半径:外半径减去扇区宽度的一半
var textRadius = outerRadius - segmentWidth / 2;

function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
    var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;
    return {
        x: centerX + (radius * Math.cos(angleInRadians)),
        y: centerY + (radius * Math.sin(angleInRadians))
    };
}

function describeArc(x, y, radius, startAngle, endAngle) {
    var start = polarToCartesian(x, y, radius, endAngle);
    var end = polarToCartesian(x, y, radius, startAngle);
    var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
    var d = [
        "M", start.x, start.y,
        "A", radius, radius, 0, largeArcFlag, 0, end.x, end.y
    ];
    return d.join(" ");
}

function createSectorText(sectorId, centerX, centerY, angle) {
    // 创建SVG文本元素(要使用命名空间)
    var text = document.createElementNS('http://www.w3.org/2000/svg', "text");
    text.setAttribute("id", "text-" + sectorId);
    // 设置文本内容为扇区ID
    text.textContent = sectorId;
    // 计算文本的坐标
    var textCoords = polarToCartesian(centerX, centerY, textRadius, angle);
    text.setAttribute("x", textCoords.x);
    text.setAttribute("y", textCoords.y);
    // 文本居中样式
    text.setAttribute("text-anchor", "middle");
    text.setAttribute("dominant-baseline", "middle");
    text.setAttribute("fill", "#fff");
    text.setAttribute("font-size", "16px");
    svg.appendChild(text);
}

function pathGen(nSegment) {
    var newPath;
    var sectorAngle = 360 / nbCateg;
    for (var i = 1; i <= nSegment; i++) {
        // 计算当前扇区的结束角度
        var endAngle = startAngle + sectorAngle;
        // 创建扇区路径
        newPath = document.createElementNS('http://www.w3.org/2000/svg', "path");
        newPath.setAttribute("id", "arc" + i);
        newPath.setAttribute("stroke", '#' + (Math.random() * 0xFFFFFF << 0).toString(16));
        newPath.setAttribute("d", describeArc(150, 150, outerRadius, startAngle, endAngle));
        newPath.setAttribute("stroke-width", segmentWidth);
        svg.appendChild(newPath);
        
        // 计算扇区中间角度,创建文本
        var middleAngle = startAngle + sectorAngle / 2;
        createSectorText("arc" + i, 150, 150, middleAngle);
        
        // 更新起始角度
        startAngle = endAngle;
    }
}

function init() {
    pathGen(nbCateg);
    var elem;
    for (var i = 1; i <= nbCateg; i++) {
        document.getElementById("arc" + i).addEventListener("click", function() {
            console.log('I would redirect to ' + this.id);
            //will change
        });
    }
}

init();
svg { height: 1000px; width: 1000px; }
path { fill: none; }
<svg id="categSVG"></svg>

代码解释

  • 文本半径计算:textRadius = outerRadius - segmentWidth / 2,确保文本在环形扇区的中间层。
  • 中间角度计算:middleAngle = startAngle + sectorAngle / 2,每个扇区的中心角度是起始角度加上扇区角度的一半。
  • 文本元素创建:使用createElementNS创建SVG文本元素,设置text-anchor和dominant-baseline实现完美居中,同时设置白色文本让深色扇区的文字更清晰。
  • 动态适配:不管nbCateg设置为多少,代码都会自动计算每个扇区的中间位置,完全支持动态扇区数量。

这样修改后,每个饼图扇区的中心就会显示对应的ID文本啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 10:03:07