【问题标题】:d3, updating multiple pathsd3、更新多条路径
【发布时间】:2020-10-28 21:49:54
【问题描述】:

以下代码在单个 d3.js 图上有多个路径。我有初始绘图工作,显示数据集d0。加载时看起来像这样:

我想在按下按钮时显示d1中的数据,所以它应该是这样的:

目前发生的事情是……什么都没有。控制台没有错误,显示没有变化,DOM 也没有变化(我能看到吗?)。

我已经阅读了十几个代码示例和教程,只是看不出这里出了什么问题。任何帮助将不胜感激(特别是如果解释我在概念上缺少的内容)。谢谢!

var d0 = [{
    id: "A",
    values: [{
      x: .25,
      y: .9
    }, {
      x: .75,
      y: 1
    }]
  },
  {
    id: "B",
    values: [{
      x: .25,
      y: .5
    }, {
      x: .8,
      y: .4
    }]
  },
  {
    id: "C",
    values: [{
      x: .1,
      y: .1
    }, {
      x: .9,
      y: .1
    }]
  }
]


var d1 = [{
    id: "A",
    values: [{
      x: 0,
      y: 1
    }, {
      x: 1,
      y: 1
    }]
  },
  {
    id: "B",
    values: [{
      x: 0,
      y: .5
    }, {
      x: 1,
      y: .5
    }]
  },
  {
    id: "C",
    values: [{
      x: 0,
      y: 0
    }, {
      x: 1,
      y: 0
    }]
  }
]

var svg = d3.select("svg")

var margin = {
  top: 20,
  right: 80,
  bottom: 30,
  left: 50
}
var width = svg.attr("width") - margin.left - margin.right
var height = svg.attr("height") - margin.top - margin.bottom

g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")")

var scaleX = d3.scaleLinear().range([0, width]).domain([0, 1])
var scaleY = d3.scaleLinear().range([height, 0]).domain([0, 1])

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

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

var line = d3.line()
  .x(function(d) {
    return scaleX(d.x)
  })
  .y(function(d) {
    return scaleY(d.y)
  });

var lineg = g.selectAll(".lineg")
  .data(d0)
  .enter()
  .append("g")
  .attr("class", "lineg");

lineg.append("path")
  .attr("class", "line")
  .attr("d", function(d) {
    return line(d.values)
  })

function update() {

  var i = g.selectAll(".lineg")
    .data(d1)

  i.enter()
    .append("g")
    .attr("class", "lineg")

  i.exit()
    .remove()

  g.selectAll(".line")
    .attr("d", function(d) {
      return line(d.values)
    })
}
.line {
  fill: none;
  stroke: steelblue;
  stroke-width: 1.5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
<svg width="500" height="300"></svg>
<br/>
<button onclick="update()">Change</button>

【问题讨论】:

    标签: javascript svg d3.js


    【解决方案1】:

    您调用 .data.datum 的每个 SVG 元素都有一个对数据对象的内部引用。在您的更新调用中,您更新了包含行的 g 元素的数据,但从未更新行本身的数据。

    我可以使用以下代码做到这一点:

    i.select(".line")
      .datum(function(d) {
        return d;
      })
      .attr("d", function(d) {
        return line(d.values)
      })
    

    这里,从新选择的组i开始,你已经给出了正确的数据,我选择了行,然后通过函数直接将g中的基准对象传递给它。这样,基准对象就会更新,调用 line(d.values) 现在实际上使用来自 d1 的条目,而不是 d0

    var d0 = [{
        id: "A",
        values: [{
          x: .25,
          y: .9
        }, {
          x: .75,
          y: 1
        }]
      },
      {
        id: "B",
        values: [{
          x: .25,
          y: .5
        }, {
          x: .8,
          y: .4
        }]
      },
      {
        id: "C",
        values: [{
          x: .1,
          y: .1
        }, {
          x: .9,
          y: .1
        }]
      }
    ]
    
    
    var d1 = [{
        id: "A",
        values: [{
          x: 0,
          y: 1
        }, {
          x: 1,
          y: 1
        }]
      },
      {
        id: "B",
        values: [{
          x: 0,
          y: .5
        }, {
          x: 1,
          y: .5
        }]
      },
      {
        id: "C",
        values: [{
          x: 0,
          y: 0
        }, {
          x: 1,
          y: 0
        }]
      }
    ]
    
    var svg = d3.select("svg")
    
    var margin = {
      top: 20,
      right: 80,
      bottom: 30,
      left: 50
    }
    var width = svg.attr("width") - margin.left - margin.right
    var height = svg.attr("height") - margin.top - margin.bottom
    
    g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    
    var scaleX = d3.scaleLinear().range([0, width]).domain([0, 1])
    var scaleY = d3.scaleLinear().range([height, 0]).domain([0, 1])
    
    g.append("g")
      .attr("class", "axis axis--x")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(scaleX));
    
    g.append("g")
      .attr("class", "axis axis--y")
      .call(d3.axisLeft(scaleY))
    
    var line = d3.line()
      .x(function(d) {
        return scaleX(d.x)
      })
      .y(function(d) {
        return scaleY(d.y)
      });
    
    var lineg = g.selectAll(".lineg")
      .data(d0)
      .enter()
      .append("g")
      .attr("class", "lineg");
    
    lineg.append("path")
      .attr("class", "line")
      .attr("d", function(d) {
        return line(d.values)
      })
    
    function update() {
      var i = g.selectAll(".lineg")
        .data(d1)
    
      i.enter()
        .append("g")
        .attr("class", "lineg")
    
      i.exit()
        .remove()
    
      i.select(".line")
        .datum(function(d) {
          return d;
        })
        .attr("d", function(d) {
          return line(d.values)
        })
    }
    .line {
      fill: none;
      stroke: steelblue;
      stroke-width: 1.5px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
    <svg width="500" height="300"></svg>
    <br/>
    <button onclick="update()">Change</button>

    【讨论】:

    • 感谢您,它运行良好。我注意到您使用 select() 而不是 selectAll()。 selectAll() 不起作用的原因是因为 datum() 需要单个元素吗?
    • 是的,那么您应该将元素包装在长度为 1 的数组中并使用 .data 我认为
    猜你喜欢
    • 2022-01-20
    • 2018-09-26
    • 2014-05-19
    • 2014-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-01
    • 1970-01-01
    相关资源
    最近更新 更多