javascript - d3 v5 中更新路径的平滑过渡

标签 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 ,但在“点击”而不是“开始”事件上。

最佳答案

你没有转换任何东西:

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>

关于javascript - d3 v5 中更新路径的平滑过渡,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50158606/

相关文章:

javascript - 移动滚动条

javascript - 如何正确地从 navigator.geolocation 调用 stopObserving()?

jquery - 通过jquery插入后,基础表单验证不起作用

html - 如何在 css 和 html 中用箭头设置相反的语音气泡

JavaScript 性能

javascript - 如何触发外部点击事件?

Codemirror 编辑器的 Jquery 断言和期望

jquery - 使用 jQuery 进行 React 组件而不需要 - jest 单元测试

jquery - CSS3 3D图像过渡组合

html - 对齐动态图像数django模板