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

基于D3.js的半饼图添加进度箭头及颜色控制功能需求

D3.js半饼图添加进度箭头及实时更新实现方案

下面是满足你需求的完整实现代码,包含进度跟随箭头、颜色配置、实时更新以及中心裁剪圆的颜色控制功能:

<html>
<head>
    <title>D3.js 半饼图带进度箭头</title>
    <script src="https://d3js.org/d3.v4.min.js" charset="utf-8"></script>
    <style>
        .arrow-path {
            stroke-linecap: round;
            stroke-linejoin: round;
        }
    </style>
</head>
<body>
    <button onclick="updateProgress(75)">更新到75%</button>
    <button onclick="updateProgress(30)">更新到30%</button>

    <script>
        // 可配置参数
        const config = {
            width: 120,
            height: 120,
            outerRadius: 60,
            innerRadius: 50,
            centerCircleRadius: 45,
            centerCircleColor: '#ffffff', // 中心裁剪圆颜色
            arrowColor: '#ff0000', // 箭头颜色
            pieColors: ['#046395', '#d62828'] // 饼图分段颜色
        };

        // 初始化数据
        let currentProgress = 60;
        const data = [
            {"label": "Completed", "value": currentProgress},
            {"label": "Remaining", "value": 100 - currentProgress}
        ];

        // 清除已有SVG
        d3.select("body").selectAll('svg').remove();

        // 创建SVG容器
        const svg = d3.select("body")
            .append('svg')
            .attr('width', config.width)
            .attr('height', config.height)
            .append('g')
            .attr('class', 'piechart')
            .attr('transform', `translate(${config.width / 2}, ${config.height / 2})`);

        // 绘制中心裁剪圆
        svg.append('circle')
            .attr('r', config.centerCircleRadius)
            .attr('fill', config.centerCircleColor);

        // 创建饼图生成器
        const pie = d3.pie()
            .startAngle(-90 * (Math.PI / 180))
            .endAngle(90 * (Math.PI / 180))
            .padAngle(.02)
            .sort(null)
            .value(d => d.value);

        // 创建弧生成器
        const arc = d3.arc()
            .outerRadius(config.outerRadius)
            .innerRadius(config.innerRadius);

        // 绘制饼图分段
        const segments = svg.append('g').attr('class', 'segments');
        let slices = segments.selectAll('.arc')
            .data(pie(data))
            .enter()
            .append('g')
            .attr('class', 'arc');

        slices.append('path')
            .attr('d', arc)
            .attr('fill', (d, i) => config.pieColors[i])
            .transition()
            .attrTween('d', function(d) {
                const i = d3.interpolate(d.startAngle + 0.1, d.endAngle);
                return t => {
                    d.endAngle = i(t);
                    return arc(d);
                }
            });

        // 绘制进度箭头
        const arrowGroup = svg.append('g').attr('class', 'arrow-group');
        const arrowLength = config.centerCircleRadius - 5;
        arrowGroup.append('path')
            .attr('class', 'arrow-path')
            .attr('d', `M0,0 L${arrowLength},0 L${arrowLength - 8},-5 L${arrowLength},0 L${arrowLength - 8},5`)
            .attr('stroke', config.arrowColor)
            .attr('stroke-width', 2)
            .attr('fill', 'none');

        // 初始化箭头位置
        updateArrowPosition(currentProgress);

        // 实时更新函数
        function updateProgress(newProgress) {
            currentProgress = Math.max(0, Math.min(100, newProgress));
            // 更新数据
            data[0].value = currentProgress;
            data[1].value = 100 - currentProgress;

            // 更新饼图
            slices = segments.selectAll('.arc').data(pie(data));
            // 处理更新过渡
            slices.select('path')
                .transition()
                .duration(750)
                .attrTween('d', function(d) {
                    const currentArc = d3.select(this).attr('d');
                    const oldAngle = arc.invert(currentArc).endAngle;
                    const i = d3.interpolate(oldAngle, d.endAngle);
                    return t => {
                        d.endAngle = i(t);
                        return arc(d);
                    }
                });

            // 更新箭头位置
            updateArrowPosition(currentProgress);
        }

        // 更新箭头角度
        function updateArrowPosition(progress) {
            // 计算角度:从-90度到90度对应0-100%
            const angle = -90 + (progress / 100) * 180;
            arrowGroup.transition()
                .duration(750)
                .attr('transform', `rotate(${angle})`);
        }
    </script>
</body>
</html>

关键功能说明

  • 集中配置管理:所有可自定义的参数(颜色、尺寸等)都放在config对象中,修改调整更便捷
  • 中心裁剪圆:通过circle元素绘制,颜色由centerCircleColor控制,覆盖在饼图中心形成视觉裁剪效果
  • 进度箭头:用SVG路径绘制箭头,通过旋转容器组实现跟随进度;箭头颜色由arrowColor控制,旋转角度根据百分比线性计算(0%对应-90度,100%对应90度)
  • 实时更新机制:updateProgress函数接收新百分比,同步更新饼图数据与箭头位置,全程带平滑过渡动画
  • 流畅过渡效果:饼图分段和箭头都使用D3过渡动画,保证更新过程自然顺滑

内容的提问来源于stack exchange,提问作者The Old County

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 02:21:04