我制作了一个简单的条形图。我想通过在我的数据的不同子集之间切换来更新条形图(动态)。从我所看到的,似乎有两种方法:
我正在尝试选项2.这是我的代码:
// set dimensions
var margin = {top: 10, right: 20, bottom: 50, left: 100};
var height = 600 -margin.top - margin.bottom;
var width = 600 - margin.left - margin.right;
// set ranges
var x = d3.scale.linear().range([width, 0]);
var y = d3.scale.ordinal().rangeRoundBands([0, height], .05);
// define y axis
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
// add svg container
var svg = d3.select("#chart")
.append("svg")
.attr("height", height + margin.top + margin.bottom)
.attr("width", width + margin.left + margin.right)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// load data
d3.json("data.json", function(data) {
// format data
data.forEach(function(d) {
d.enrols = +d.enrols;
});
// register click event
d3.selectAll(".toggle").on("click", function() {
render(this.id);
});
// initialise
render("group-1");
function render(selection) {
// filter data
var subset = data.filter(function(d) { return d.group === selection} );
// scale range of data
x.domain([0, d3.max(subset, function(d) { return d.enrols; })]);
y.domain(subset.map(function(d) { return d.month; }));
// update selection
var bars = svg.selectAll(".bars")
.data(subset, function(d) { return d.month; });
// add bars
bars.enter()
.append("g")
.attr("class", "bar")
.attr("transform", function (d, i) {
return "translate(0," + y(d.month) + ")";
});
bars.append("rect")
.attr("height", y.rangeBand())
.attr("width", function (d) {
return width - x(d.enrols);
});
bars.append("text")
.attr("x", function (d) {
return width - x(d.enrols) - 15;
})
.attr("y", y.rangeBand() / 2)
.attr("dy", ".35em")
.text(function (d) {
return d.enrols;
});
bars.exit().remove();
// add y axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
}
});
问题是我的旧数据永远不会被退出,新条形图会被追加,但旧条形图仍然存在。我已经阅读了d3选择的理论,但我发现它们很难在实践中实现。
答案 0 :(得分:3)
非常好的是你选择了第一个选项:删除所有元素并再次绘制图表是一种非常懒惰的编码方式。
但是,在您的情况下,由于数据的长度没有变化,您不需要"输入","更新"和"退出"选择!
如果您在render
函数之外移动一些不变的部分,一切都会更容易:
y.domain(data.map(function(d) {
return d.month;
}));
var bars = svg.selectAll(".bars")
.data(data, function(d) {
return d.month;
}).enter()
.append("g")
.attr("class", "bar")
.attr("transform", function(d, i) {
return "translate(0," + y(d.month) + ")";
});
var rects = bars.append("rect")
.attr("height", y.rangeBand())
.attr("width", function(d) {
return width - x(d.enrols);
});
var texts = bars.append("text")
.attr("x", function(d) {
return width - x(d.enrols) - 15;
})
.attr("y", y.rangeBand() / 2)
.attr("dy", ".35em")
.text(function(d) {
return d.enrols;
});
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
只留下真正改变的内容:
它会更小:
function render(selection) {
// filter data
var subset = data.filter(function(d) {
return d.group === selection
});
// scale range of data
x.domain([0, d3.max(subset, function(d) {
return d.enrols;
})]);
bars.data(subset, function(d) {
return d.month;
});
rects.transition().duration(500).attr("width", function(d) {
return width - x(this.parentNode.__data__.enrols);
});
texts.transition().duration(500).attr("x", function(d) {
return width - x(this.parentNode.__data__.enrols) - 15;
})
.text(function(d) {
return this.parentNode.__data__.enrols;
});
}
以下是您的CodePen:http://codepen.io/anon/pen/qqBzWQ?editors=0010
PS:如果你摆脱这些组,直接附加矩形和文本,这将更容易。
答案 1 :(得分:0)
您的条形图只需要一个非常简单的修改。这是缺失的拼图:
当我们使用data()
函数时,D3会在现有DOM元素和数据值之间执行join
operation。您将此操作的结果存储在变量bars
上。我们可以在bars
上调用几种方法。
方法exit()
返回将要删除的元素。如果我们在DOM上有3个条形,并且我们使用只有2个数据值的数组调用data()
函数,exit()
将返回将被删除的条形。
同样,方法enter()
返回将要添加的元素。如果DOM上有2个条形,并且我们使用包含3个数据值的数组调用data()
函数,enter()
将返回将添加的新条形。
然后要更新的酒吧怎么样?好吧,它们是存储在bars
变量中的内容!
将其翻译成代码非常简单:
此:
bars.enter()
.append("g")
...
变成了这个:
var newBars = bars.enter()
.append("g")
...
然后每次出现:
bars.append(...)
变成了这个:
newBars.append(...)
每次有新栏时,我们{DOM}都要{DOM}。
每次我们需要更新一个条形码时,我们都会从DOM中append
。
select
指的是要更新的栏。所以我们添加此代码来更新现有的栏:
bars