间隔内更新时的第一个 d3 转换未转换

ess*_*see 5 javascript d3.js

我有一个圆环图,它被用作显示进展的一种方式。我没有办法向您展示圆环图,但代码很简单,可以复制和粘贴。

我添加了代码来向您展示一个示例。我尝试了各种不合理的方法来使过渡工作第一次。但由于某种原因,它仍然无法正常工作。网上的所有例子都非常相似,所以我不确定为什么会这样。

    var data = [95, 5];
    var pie = d3.pie().sort(null);
    var svg = d3.select("svg"),
        width = svg.attr("width"),
        height = svg.attr("height"),
        radius = Math.min(width, height) / 2;
    var arc = d3.arc()
        .innerRadius(60)
        .outerRadius(radius);

    function createdonut() {
            g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
        //Inner SVG Circle
        svg.append("svg:circle")
            .attr("cx", width / 2)
            .attr("cy", height / 2)
            .attr("r", 60)
            .style("fill", "#ead4d4")
            .append("g");
        var color = d3.scaleOrdinal(['#4daf4a', '#377eb8', '#ff7f00', '#984ea3', '#e41a1c']);
        
        //Generate groups

        var arcs = g.selectAll("arc")
            .data(pie(data))
            .enter()
            .append("g")
            .attr("class", "arc")

        //Draw arc paths
        arcs.append("path")
            .attr("fill", function (d, i) {
                return color(i);
            })
            .attr("d", arc)
            .on('mouseover', mouseover);

        function mouseover(d, i) {
            $('#percentage').html(i.data + ' units');
        }
    }
    function updateDoNut(update) {
        data[0] = data[0] - update;
        data[1] = data[1] + update;

        var path = d3.select("svg").selectAll("path").data(pie(data));
        
        /*path.enter().append("path")
            .attr("fill", function (d, i) {
                return color[i];
            })
            .attr("d", arc);*/

        path.transition().duration(100).attrTween("d", arcTween);
    }
    function arcTween(a) {
        var i = d3.interpolate(this._current, a);
        this._current = i(0);
        return function (t) {
            return arc(i(t));
        };
    }

    createdonut();
    //updateDoNut(0);
    var inter = setInterval(function () { updateDoNut(5); },  3000);
Run Code Online (Sandbox Code Playgroud)
<script src="https://d3js.org/d3.v6.min.js"></script>
<div id="my_dataviz">
    <svg width="300" height="200"> </svg>
    <div id="percentage">0 units</div>
</div>
Run Code Online (Sandbox Code Playgroud)

And*_*eid 3

如果我们查看你的补间函数,我们会发现一个问题:

    var i = d3.interpolate(this._current, a);
    this._current = i(0);
Run Code Online (Sandbox Code Playgroud)

this.current当您第一次开始转换时未定义 - 那么 D3 如何在未定义和包含弧属性的对象之间进行插值?事实并非如此。导致您看到的非转换。this._current附加圆弧时设置:

 arcs.append("path")
     .attr("fill", function (d, i) {
        return color(i);
     })
     .attr("d", arc)     
     .each(function(d) {
          this._current = d;
        })
     .on('mouseover', mouseover);
Run Code Online (Sandbox Code Playgroud)

现在,当您更新圆时,插值器有一个有效的起点,您应该看到一个过渡:

    var i = d3.interpolate(this._current, a);
    this._current = i(0);
Run Code Online (Sandbox Code Playgroud)
 arcs.append("path")
     .attr("fill", function (d, i) {
        return color(i);
     })
     .attr("d", arc)     
     .each(function(d) {
          this._current = d;
        })
     .on('mouseover', mouseover);
Run Code Online (Sandbox Code Playgroud)

为什么未定义和对象之间的插值不会生成错误?那么 D3-interpolate 会非常努力地尝试插值。在这种情况下,在 undefined 和对象之间,它将使用 d3-interpolateObject,它将按如下方式插值:

对于 b 中的每个属性,如果 a 中存在相应的属性,则使用 interpolate 为这两个元素创建通用插值器。如果没有这样的属性,则在模板中使用 b 的静态值。(文档

因此,由于未定义中没有属性,插值器仅对插值中的每个点使用静态值,因此在第一次更新时缺乏转换:每个插值点都是相同的:终点值。