【问题标题】:D3: How to refresh a chart with new data?D3:如何用新数据刷新图表?
【发布时间】:2016-03-09 09:33:33
【问题描述】:

我创建了一个 d3 圆环图。这是我的代码:

var width = 480;
var height = 480;
var radius = Math.min(width, height) / 2;
var doughnutWidth = 30;

var color = d3.scale.category10();

var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(radius - 70);

var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d[1]; });

var dataset = settings.dataset;
console.log(dataset);

var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

var path = svg.selectAll('path')
.data(pie(dataset))
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d, i) { 
  return color(d.data[0]);
})

我的网页上有一个简单的表单,其中显示了一个带有多个选项的下拉菜单。每次用户更改表单上的值时,都会向我的脚本 (settings.dataset) 发送一个新数据集,并在页面上重新绘制甜甜圈。

问题是,前一个数据集中的一些值保留在 DOM 中。在下面的控制台输出中,您可以看到第二个数据集只有两个元素。第三个来自之前的数据集。这弄乱了图表,因为它显示了一个不应该存在的值。

我的问题:如何清除旧值?我已经阅读了.exit().remove(),但我无法理解这些方法。

【问题讨论】:

  • 所以你上面粘贴的代码每次都会在 udate 执行?
  • 是的,每次用户在我的表单上选择不同的选项时都会调用该脚本。
  • 我可以看到的一个问题是 d3.select("body") .append("svg") 这意味着您每次更新时都会附加 svg。执行 d3.select("svg").remove() 以确保在更新时将其删除。
  • 将该行添加到脚本顶部?
  • 这里有一个很好的教程:jonsadka.com/blog/…

标签: d3.js


【解决方案1】:

创建一个在创建和更新时(重新)绘制饼图的函数。

应使用enter() 将新数据添加到饼图中,应使用exit().remove() 删除旧数据

就这么简单:

  path.enter().append("path")
            .attr("fill", function(d, i) { return color(i); })
            .attr("d", arc)
            .each(function(d) {this._current = d;} );

  path.transition()
            .attrTween("d", arcTween);

  path.exit().remove()

完整的工作代码 -> JSFIDDLE

【讨论】:

  • .each(function (d) {this._current = d;}) 是做什么的?
  • 我们如何为反应组件做到这一点?如果我将道具传递给 sunburst 组件以控制 sunburst 的缩放级别。我需要一种只更新渲染而不重新渲染整个组件的方法。
【解决方案2】:

实现你想要的“重绘”效果有两个步骤:

首先,我假设您希望在第一次加载页面时只绘制一次 svg 画布,然后更新 svg 中的图表,而不是删除并重绘 svg:

 var svg = d3.select("body")
              .selectAll("svg")
              .data([settings.dataset]);  
 // put data in an array with only one element

 // this ensures there is only one consistent svg on the page when data is updated(when the script gets executed) 
 svg.enter().append("svg")  

第二,了解enter()exit(),关于这个有很多很棒的教程。在你的情况下,我建议画这样的甜甜圈:

var path = svg.selectAll(".donut")  
           .data(settings.data)

// bind data to elements, now you have elements belong to one of those 
// three 'states', enter, exit, or update

// for `enter` selection, append elements
path.enter().append("path").attr("d", arc).attr("fill", "teal")

// for `update` selection, which means they are already binded with data
path.transition().attrTween("d", someFunction) // apply transition here if you want some animation for data change

// for `exit` selection, they shouldn't be on the svg canvas since there is no corresponding data, you can then remove them
 path.exit().remove()

【讨论】:

  • 我理解你的观点:绘制一次图表,然后根据用户选择进行更新。有点像这样:bl.ocks.org/mbostock/1346410。目前我只加载用户感兴趣的数据。在这种方法中,我需要加载所有数据并存储在一个更大的数组中——这不是一个大问题,因为它是少量数据。我将不得不重写传递数据的代码。感谢您的建议。
  • 我认为每次重绘图表会更适合我的用例。
  • 如果你的意思是每次都删除并重新附加路径,那么transition()和exit()就不需要了
  • 在我的问题的控制台输出中,第一个输出来自我的第一个甜甜圈的绘图。这是正确的,有三个值。第二个输出是一个新的甜甜圈,它应该只有两个值(anonymous 和 johnd),但它包含来自第一个甜甜圈的第三个值,博客 3。我需要在绘制第二个甜甜圈之前删除此值。
  • @24ma13wg 看来问题是settings.dataset引起的,和d3绘图关系不大,能否请您添加更多关于如何获取settings.dataset的代码?
【解决方案3】:
//remove and create svg
d3.select("svg").remove(); 
var svg = d3.select("body").append("svg").attr("width","960").attr("height", "600"),
inner = svg.append("g");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-02
    • 1970-01-01
    • 1970-01-01
    • 2020-11-24
    • 1970-01-01
    • 2013-11-23
    • 2018-08-03
    相关资源
    最近更新 更多