在d3 v5中更新路径时平滑过渡

时间:2018-05-03 15:19:46

标签: javascript jquery css d3.js

我正在尝试构建一个d3折线图,用于在每次点击时更新图表数据。 到目前为止,这是我的进展:

var n = 10,
  random = d3.randomNormal(0, .2),
  data = d3.range(n).map(random);

var svg = d3.select("svg"),
  margin = {
    top: 20,
    right: 20,
    bottom: 20,
    left: 40
  },
  width = +svg.attr("width") - margin.left - margin.right,
  height = +svg.attr("height") - margin.top - margin.bottom,
  g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var x = d3.scaleLinear()
  .domain([0, n - 1])
  .range([0, width]);

var y = d3.scaleLinear()
  .domain([-1, 1])
  .range([height, 0]);

var line = d3.line()
  .x(function(d, i) {
    return x(i);
  })
  .y(function(d, i) {
    return y(d);
  });

g.append("defs").append("clipPath")
  .attr("id", "clip")
  .append("rect")
  .attr("width", width)
  .attr("height", height);

g.append("g")
  .attr("class", "axis axis--x")
  .attr("transform", "translate(0," + y(0) + ")")
  .call(d3.axisBottom(x));

g.append("g")
  .attr("class", "axis axis--y")
  .call(d3.axisLeft(y));

g.append("g")
  .attr("clip-path", "url(#clip)")
  .append("path")
  .datum(data)
  .attr("class", "line")
  .attr('d', line)

function tick() {

  // Push a new data point onto the back.
  data.push(random());

  // Redraw the line.
  d3.select(".line")
    .attr("d", line)
    .attr("transform", null)
    .transition()
    .duration(300)

  // Slide it to the left.
  d3.select(".line")
    .attr("transform", "translate(" + x(-1) + ",0)")
    .transition()
    .duration(300)

  // Pop the old data point off the front.
  data.shift();

}

d3.select("#translate")
  .on("click", tick)
.line {
  fill: none;
  stroke: #000;
  stroke-width: 1.5px;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<button id="translate">Translate</button>
<svg width="960" height="500"></svg>

目前,图表立即更新而没有任何转换(即使我在更新功能中添加了转换)。我在这里做错了什么?

我希望实现类似https://bl.ocks.org/mbostock/1642874的功能,但需要“点击”而不是“开始”事件。

1 个答案:

答案 0 :(得分:4)

你没有过渡任何东西:

d3.select(".line")
  .attr("...")
  .transition()
  .duration()

这并未指定您正在转换任何内容。前两行返回选择,后两行返回一个转换 - 您需要在转换上使用.attr()来实际转换某些内容。如果.attr()用于选择,它只是更新该属性。所以,你需要使用这种模式:

d3.select(".line")
  .transition()
  .duration()
  .attr("...")  // attribute to be transitioned

或者:

d3.select(".line")
  .transition()
  .attr("...")  // attribute to be transitioned
  .duration()

此外,您无需转换两次,添加新数据,然后移动图表:

// Redraw the line.
d3.select(".line")
  .attr("d", line)
  .attr("transform", null)
  .transition()
  .attr("transform", "translate(" + x(-1) + ",0)")
  .duration(300)

段:

var n = 10,
            random = d3.randomNormal(0, .2),
            data = d3.range(n).map(random);

        var svg = d3.select("svg"),
            margin = {
                top: 20,
                right: 20,
                bottom: 20,
                left: 40
            },
            width = +svg.attr("width") - margin.left - margin.right,
            height = +svg.attr("height") - margin.top - margin.bottom,
            g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        var x = d3.scaleLinear()
            .domain([0, n - 1])
            .range([0, width]);

        var y = d3.scaleLinear()
            .domain([-1, 1])
            .range([height, 0]);

        var line = d3.line()
            .x(function(d, i) {
                return x(i);
            })
            .y(function(d, i) {
                return y(d);
            });

        g.append("defs").append("clipPath")
            .attr("id", "clip")
            .append("rect")
            .attr("width", width)
            .attr("height", height);

        g.append("g")
            .attr("class", "axis axis--x")
            .attr("transform", "translate(0," + y(0) + ")")
            .call(d3.axisBottom(x));

        g.append("g")
            .attr("class", "axis axis--y")
            .call(d3.axisLeft(y));

        g.append("g")
            .attr("clip-path", "url(#clip)")
            .append("path")
            .datum(data)
            .attr("class", "line")
            .attr('d', line)

        function tick() {

            // Push a new data point onto the back.
            data.push(random());

            // Redraw the line.
            d3.select(".line")
                .attr("d", line)
                .attr("transform", null)
				.transition()
                .attr("transform", "translate(" + x(-1) + ",0)")
                .duration(300)
				
            // Pop the old data point off the front.
            data.shift();

        }

        d3.select("#translate")
            .on("click", tick)
.line {
            fill: none;
            stroke: #000;
            stroke-width: 1.5px;
        }
<script src="https://d3js.org/d3.v5.min.js"></script>
   <button id="translate">Translate</button>
<svg width="960" height="500"></svg>