【发布时间】:2018-03-25 16:22:32
【问题描述】:
在下面的示例中,如果我的新数据集有新条目并且删除了一些记录(添加了墨西哥卷饼,删除了苹果),我如何同时反映这些更改?到目前为止,代码推入了一个新栏,但没有删除第一个栏,即使我尝试重新设置 x 轴域,轴也没有更新。
块引用
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
<meta charset="utf-8">
<title>D3: Loading data from a CSV file</title>
</head>
<body>
<p>Click on this text to update the chart with new data values (once).</p>
<script type="text/javascript">
var margin = {top: 20, right: 20, bottom: 30, left: 40},
w = 600 - margin.left - margin.right,
h = 300 - margin.top - margin.bottom;
var padding = 40;
var data = [
{ "Food": "Apples", "Deliciousness": 9, "new":4 },
{ "Food": "Green Beans", "Deliciousness": 5, "new":4 },
{ "Food": "Egg Salad Sandwich", "Deliciousness": 4, "new":4 },
{ "Food": "Cookies", "Deliciousness": 10, "new":4 },
{ "Food": "Liver", "Deliciousness": 2, "new":4 },
];
data.forEach(function(d) {
d.Deliciousness = +d.Deliciousness;
});
//define key
var key = function(d) {
return d.Food;
}
var svg = d3.select("body")
.append("svg")
.attr("width", w + margin.left + margin.right + padding)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left+"," +
margin.top+")");
//initial state
//scale and axis
var xScale = d3.scaleBand()
.domain(d=>d.Food)
.range([0,w])
.paddingInner(0.2);
xScale.domain(data.map(function(d) { return d.Food; }));
var yScale = d3.scaleLinear()
.domain([0, d3.max(data, d=>d.Deliciousness)])
.rangeRound([h,0]);
var xAxis = d3.axisBottom()
.scale(xScale)
.ticks(5);
var yAxis = d3.axisLeft()
.scale(yScale)
.ticks(5);
//draw rect
svg.selectAll('rect')
.data(data, key)
.enter()
.append('rect')
.attr('x',(d,i) => margin.left + i * ((w + 20 ) / data.length))
.attr('y',d=>yScale(d.Deliciousness))
.attr('width', xScale.bandwidth())
.attr('height',d =>h-yScale(d.Deliciousness))
.attr('fill',function(d){
if (d===30) return "red";
return "rgb(0,0,"+d.Deliciousness*10+")" ;});
//text label
svg.selectAll("text")
.data(data)
.enter()
.append("text")
.text(d=>d.Deliciousness)
.attr('x',(d,i) => margin.left + i * ((w + 20 ) / data.length) + 0.4*w/ data.length)
.attr("y", d=>yScale(d.Deliciousness)+15)
.attr("fill","white")
.attr("text-anchor", "middle");
//draw axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + padding + ",0)")
.call(yAxis);
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + margin.left + "," + h + ")")
.call(xAxis);
//transition
d3.select("p")
.on("click", function() {
//New values for dataset
data = [
{ "Food": "Green Beans", "Deliciousness": 5, "new":4 },
{ "Food": "Egg Salad Sandwich", "Deliciousness": 4, "new":4 },
{ "Food": "Cookies", "Deliciousness": 10, "new":4 },
{ "Food": "Liver", "Deliciousness": 2, "new":4 },
{ "Food": "Burrito", "Deliciousness": 7, "new":4 }];
xScale.domain(data.map(function(d) { return d.Food; }));
//Update all rects
var bars = svg.selectAll("rect")
.data(data, key);
bars.enter()
.append("rect")
// <-- This makes it a smooth transition!
.attr("x", w)
.attr('y',d=>yScale(d.Deliciousness))
.attr("width", xScale.bandwidth())
.attr('height',d =>h-yScale(d.Deliciousness))
.merge(bars) //Merges the enter selection with the update selection
.transition() //Initiate a transition on all elements in the update selection (all rects)
.duration(500)
.attr('x',(d,i) => margin.left + i * ((w + 20 ) / data.length))
.attr('y',d=>yScale(d.Deliciousness))
.attr('width', xScale.bandwidth())
.attr('height',d =>h-yScale(d.Deliciousness))
});
</script>
</body>
</html>
【问题讨论】:
标签: d3.js data-binding transition