d3 版本 4 路径线平滑过渡与迈克·博斯托克的例子



我第一次在这里提问。我正在转换我的版本3 d3路径行转换代码到版本4,我有一个艰难的时间。

首先,我看到了Mike的例子(两天前发布的),在版本4中使用非时间x轴的平滑线过渡,所以我做了类似于他在版本3中使用时间x轴的例子。路径线平滑移动,但x轴不平滑。此外,对于我的工作,我不能触发他在这个例子中所做的转换,所以我不能在tick函数中使用变量"this"。下面是代码:

<!DOCTYPE html>
<head>
    <meta charset="utf-8">
    <script src="//d3js.org/d3.v4.min.js"></script>
    <style>
        .line {
            fill: none;
            stroke: #000;
            stroke-width: 1.5px;
        }
    </style>
</head>
<body>
    <svg width="960" height="500"></svg>
    <script>
        (function() {
            var n = 243,
                duration = 750,
                now = new Date(Date.now() - duration),
                count = 0,
                data = d3.range(n).map(function() { return 0; });
                random = d3.randomNormal(0, .2),
                data = d3.range(n).map(random);
            var margin = {top: 6, right: 0, bottom: 20, left: 40},
                width = 960 - margin.right,
                height = 120 - margin.top - margin.bottom;
            var x = d3.scaleTime()
                .domain([now - (n - 2) * duration, now - duration])
                .range([0, width]);
            var y = d3.scaleLinear()
                .range([height, 0]);
            var line = d3.line()
                .x(function(d, i) { return x(now - (n - 1 - i) * duration); })
                .y(function(d, i) { return y(d); });
            var svg = d3.select("body").append("p").append("svg")
                .attr("width", width + margin.left + margin.right)
                .attr("height", height + margin.top + margin.bottom)
                .style("margin-left", -margin.left + "px")
                .append("g")
                .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
            svg.append("defs").append("clipPath")
                .attr("id", "clip")
              .append("rect")
                .attr("width", width)
                .attr("height", height);
            var axis = svg.append("g")
                .attr("class", "x axis")
                .attr("transform", "translate(0," + height + ")")
                .call(x.axis = d3.axisBottom().scale(x));
            var timeline = svg.append("g")
                .attr("clip-path", "url(#clip)")
                .append("path")
                .datum(data)
                .attr("class", "line")
                .transition()
                .duration(500)
                .ease(d3.easeLinear)
                .on("start", tick);

            var transition = d3.select({}).transition()
                .duration(750)
                .ease(d3.easeLinear);

            function tick() {
                data.push(random());
                now = new Date();
                x.domain([now - (n - 2) * duration, now - duration]);
                y.domain([0, d3.max(data)]);
                // redraw the line
                svg.select(".line")
                    .attr("d", line)
                    .attr("transform", null);
                // slide the x-axis left
                axis.call(x.axis);
                // slide the line left
                d3.active(this)
                    .attr("transform", "translate(" + x(now - (n - 1) * duration) + ")")
                    .transition().on("start", tick);
                // pop the old data point off the front
                data.shift();
            }
        })()
    </script>
</body>

在tick函数中,有一个"this",从调试中,我发现它是一个路径,所以我试图用d3.active(d3.selectAll("path"))或d3.active(d3.selectAll(".line"))替换它,两者都不起作用。我还尝试为路径分配一个可变的时间轴,所以我尝试了d3.active(时间轴)。它也不工作。

在这个问题上我已经无计可施了。我在d3谷歌组发帖,没有人回答。我希望这里有人能给我一些建议。

感谢戴安娜

转换到v4确实不容易。和你有同样的问题。试试下面的代码:

<!DOCTYPE html>
<head>
    <meta charset="utf-8">
    <script src="//d3js.org/d3.v4.min.js"></script>
    <style>
        .line {
            fill: none;
            stroke: #000;
            stroke-width: 1.5px;
        }
    </style>
</head>
<body>
<svg width="960" height="500"></svg>
<script>
    (function() {
        var n = 243,
                duration = 750,
                now = new Date(Date.now() - duration),
                count = 0,
                data = d3.range(n).map(function() {
                    return 0;
                });
        random = d3.randomNormal(0, .2),
                data = d3.range(n).map(random);
        var margin = {top: 6, right: 0, bottom: 20, left: 40},
                width = 960 - margin.right,
                height = 120 - margin.top - margin.bottom;
        var x = d3.scaleTime()
                .domain([now - (n - 2) * duration, now - duration])
                .range([0, width]);
        var y = d3.scaleLinear()
                .range([height, 0]);
        var line = d3.line()
                .x(function(d, i) {
                    return x(now - (n - 1 - i) * duration);
                })
                .y(function(d, i) {
                    return y(d);
                });
        var svg = d3.select("body").append("p").append("svg")
                .attr("width", width + margin.left + margin.right)
                .attr("height", height + margin.top + margin.bottom)
                .style("margin-left", -margin.left + "px")
                .append("g")
                .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
        svg.append("defs").append("clipPath")
                .attr("id", "clip")
                .append("rect")
                .attr("width", width)
                .attr("height", height);
        var axis = svg.append("g")
                .attr("class", "x axis")
                .attr("transform", "translate(0," + height + ")")
                .call(x.axis = d3.axisBottom().scale(x));
        var timeline = svg.append("g")
                .attr("clip-path", "url(#clip)")
                .append("path")
                .datum(data)
                .attr("class", "line")
                .transition()
                .duration(500)
                .ease(d3.easeLinear);
        var transition = d3.select({}).transition()
                .duration(750)
                .ease(d3.easeLinear);
        (function tick() {
            transition = transition.each(function() {
                data.push(random());
                now = new Date();
                x.domain([now - (n - 2) * duration, now - duration]);
                y.domain([0, d3.max(data)]);
                // redraw the line
                svg.select(".line")
                        .attr("d", line)
                        .attr("transform", null);
                // slide the x-axis left
                axis.call(d3.axisBottom(x));
                // slide the line left
                //d3.active(this).attr("transform", "translate(" + x(now - (n - 1) * duration) + ")");
                // pop the old data point off the front
                data.shift();
            }).transition().on("start", tick);
        })();
    })()
</script>
</body>

诀窍是链式转换和使用transition().on而不是transition().each。要更新轴,你需要调用d3.axisBottom(x)在相同的方式,你实例化轴。

最新更新