【问题标题】:For loop does not work in D3.jsFor 循环在 D3.js 中不起作用
【发布时间】:2016-07-17 05:45:09
【问题描述】:

我是 Javascript 和 D3.js 的新手,并尝试在 for 循环中不断更改圆形元素。 这意味着每秒改变圆的半径,但事实证明,半径只是跳到 50,忽略了 26 到 49。

这是我的代码。

<!DOCTYPE html>
<meta charset="utf-8">
<style>

</style>
<body>
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script>
    var width = 960,
            height = 1160;
    var svg = d3.select("body").append("svg")
            .attr("width", width)
            .attr("height", height);

    svg.append("circle").attr("cx", 100).attr("cy", 100).attr("r", 25).style("fill", "purple").attr('id','cc');

    for(i=26;i<=50;i++){
        var now=d3.select('#cc');
        now.transition().duration(1000).attr("r",i);
    }
</script>

【问题讨论】:

    标签: javascript for-loop d3.js


    【解决方案1】:

    在 JavaScript 中,当你说:

    for(i=26;i<=50;i++){
        var now=d3.select('#cc');
        now.transition().duration(1000).attr("r",i);
    }
    

    不要认为 for 循环会等待 i=26 转换完成,然后再转到 i=27。事实上,它为i=26 调用语句now.transition().duration(1000).attr("r",i);,然后立即进入循环的下一个迭代。由于循环的i=26i=50 迭代之间的时间差是无限小的(速度仅受处理器速度的限制,今天以GHz 为单位),您可以认为所有转换是一起调用的,并且观察到最后一个的效果,立即

    执行此操作的一种方法是在每次调用之前设置时间延迟,并记住,时间延迟必须是绝对的,因为几乎在同一时刻调用所有迭代。例如,

    0 秒后调用的第一条语句。
    第二条语句在 1 秒后调用。
    第三个语句在 2 秒后调用。

    只有这样,您才会看到调用之间的相对差异为 1 秒。

    另一种方法是使用setTimeout() 例程递归地执行此操作。 建议使用此方法。

    var i = 26;
    
    function myLoop () {
        setTimeout(function () {
            var now=d3.select('#cc');
            now.transition().duration(1000).attr("r",i);
            i++;
            if (i < 50) {
                myLoop();
            }
        }, 1000) // change this time (in milliseconds) to whatever you desire
    }
    
    myLoop(); // first call
    

    【讨论】:

    • 谢谢你的解释,我现在明白问题出在哪里了:)
    • 很高兴我能帮上忙。您可能会考虑支持/接受这个答案,因为这就是 StackOverflow 的工作原理:)
    • 嗨,我已经投了赞成票,它告诉我“感谢您的反馈!声望低于 15 人的投票将被记录,但不会更改公开显示的帖子得分。而且我点了左边绿色的√,是不是可以接受?
    【解决方案2】:

    问题是您的 for 循环只是立即迭代所有这些更改。您需要在每次调用 transition 之间等待 1 秒。这样的事情应该可以工作,尽管d3 在当前过渡结束后可能有更好的方法来做某事?

    function changeRadius(i) {
        d3.select('#cc').transition().duration(1000).attr("r", i);
    
        // "loop" by calling ourselves 1 second later with the next radius
        if (i < 50) {
            window.setTimeout(function () {
                changeRadius(i + 1);
            }, 1000);
        }
    }
    // first change
    changeRadius(26);
    

    看着the d3 documentation,我认为这可能有效:

    var current = d3.select('#cc');
    for (var i = 26; i <= 50; i++) {
        current = current.transition().duration(1000).attr("r", i);
    }
    

    【讨论】:

      【解决方案3】:

      您可以对半径进行补间,而不是创建多个过渡或弄乱延迟。 Demo

      d3.select('#cc')
        .transition()
        .duration(25*1000)
        .attrTween('r', function() {
            return d3.interpolateNumber(25, 50)
        })
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-04-13
        • 2013-12-31
        • 2017-01-14
        • 2011-07-21
        • 2016-02-05
        • 2014-02-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多