我正在研究用于学习d3的个人财务的可视化,其中有些东西感觉像是一个有用的项目.我已经设法按照我想要的方式制作图表(每日+或减去).现在我希望能够从一个月改为下一个月.如果旧月(更新前)有更多天(也称为数据点)而不是新月(更新后),则此方法有效.如果旧数据点的数据点少于新数据点,则会在图表顶部添加其他数据点.我将条形图中的每个数据点添加为一个组(条形本身,数据标签+日期标签).我正在为每个新的一天向下翻译整个小组.我需要弄清楚的是,如果在更新后我有更多或更少的数据点,如果我有更少,我需要向下翻译新的数据点.你知道我的意思?这是我最初添加条形图的代码:
bar = chart.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * barHeight + ")"; });
//bar
//grey background bars
bar.append("rect")
.attr("class", "backgroundBar")
.attr("x", 10)
.attr("width", (width-30))
.attr("height", barHeight-1)
.attr("fill", "#dddddd")
.attr("fill-opacity", "0.3");
//dateLabel
bar.append("text")
.attr("class", "dateLabel")
.attr("x", width/2-20)
.attr("y", barHeight-5)
.attr("fill", "black")
.text(function(d){ return d.key})
bar.append("rect")
.attr("class", "bar")
.attr("x", function(d) { if(scale(d.values.total)<0){return width/2+widthDateLabel;}else{return width/2-scale(d.values.total)-widthDateLabel;}})
.attr("width", function(d) { return Math.abs(scale(d.values.total)); })
.attr("height", barHeight - 1)
.attr("fill", function(d) { if(scale(d.values.total)<0){ return "DeepPink"}else{return "MediumSeaGreen"}});
//BarLabel
bar.append("text")
.attr("class", "barLabel")
.attr("x",function(d) { if(scale(d.values.total)<0){return window.width/2-scale(d.values.total)+5+widthDateLabel;}else{return window.width/2-scale(d.values.total)-5-widthDateLabel;}})
.attr("y", barHeight/2)
.attr("dy", ".35em")
.attr("text-anchor", function(d) { if(scale(d.values.total)<0){ return "start"}else{return "end"}})
.attr("fill", function(d) { if(scale(d.values.total)<0){ return "DeepPink"}else{return "MediumSeaGreen"}})
.text(function(d) { return Math.round(d.values.total*100)/100; });
Run Code Online (Sandbox Code Playgroud)
我显然不能与小组合作但是翻译每个y坐标,但感觉就像一个肮脏的解决方案,不是吗?以下是问题的屏幕截图:
编辑:这是我目前的更新功能.有效,但在屏幕截图中产生结果
//update the bar itself
var bar=chartgroups.selectAll(".bar")
.data(data);
bar.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { if(scale(d.values.total)<0){return width/2+widthDateLabel;}else{return width/2-scale(d.values.total)-widthDateLabel;}})
.attr("width", function(d) { return Math.abs(scale(d.values.total)); })
.attr("height", barHeight - 1)
.attr("fill", function(d) { if(scale(d.values.total)<0){ return "DeepPink"}else{return "MediumSeaGreen"}});
bar.exit().remove();
bar
.transition().duration(750)
.attr("height", barHeight - 1)
.attr("x", function(d) { if(scale(d.values.total)<0){return width/2+widthDateLabel;}else{return width/2-scale(d.values.total)-widthDateLabel;}})
.attr("width", function(d) { return Math.abs(scale(d.values.total)); })
.attr("fill", function(d) { if(scale(d.values.total)<0){ return "DeepPink"}else{return "MediumSeaGreen"}});
//update the barLabel
var barLabel=chart.selectAll(".barLabel").data(data);
barLabel.enter().append("text")
.attr("x",function(d) { if(scale(d.values.total)<0){return window.width/2-scale(d.values.total)+5+widthDateLabel;}else{return window.width/2-scale(d.values.total)-5-widthDateLabel;}})
.attr("y", barHeight/2)
.attr("dy", ".35em")
.attr("text-anchor", function(d) { if(scale(d.values.total)<0){ return "start"}else{return "end"}})
.attr("fill", function(d) { if(scale(d.values.total)<0){ return "DeepPink"}else{return "MediumSeaGreen"}})
.text(function(d) { return Math.round(d.values.total*100)/100; });
barLabel.exit().remove();
barLabel
.transition().duration(750)
.attr("x",function(d) { if(scale(d.values.total)<0){return window.width/2-scale(d.values.total)+5+widthDateLabel;}else{return window.width/2-scale(d.values.total)-5-widthDateLabel;}})
.attr("y", barHeight/2)
.attr("text-anchor", function(d) { if(scale(d.values.total)<0){ return "start"}else{return "end"}})
.attr("fill", function(d) { if(scale(d.values.total)<0){ return "DeepPink"}else{return "MediumSeaGreen"}})
.text(function(d) { return Math.round(d.values.total*100)/100; });
//update dates
var dateLabel=chart.selectAll(".dateLabel").data(data);
dateLabel.enter().append("text")
.attr("class", "dateLabel")
.attr("x", width/2-20)
.attr("y", barHeight-5)
.attr("fill", "black")
.text(function(d){ return d.key})
dateLabel.exit().remove();
dateLabel
.transition().duration(750)
.text(function(d){ return d.key})
.attr("y", barHeight-5)
//update background bars
var backgroundBar=chart.selectAll(".backgroundBar").data(data);
backgroundBar.enter().append("rect")
.attr("class", "backgroundBar")
.attr("x", 10)
.attr("width", (width-30))
.attr("height", barHeight-1)
.attr("fill", "#dddddd")
.attr("fill-opacity", "0.3");
backgroundBar.exit().remove();
backgroundBar
.transition().duration(750)
.attr("height", barHeight-1)
Run Code Online (Sandbox Code Playgroud)
您需要做一些事情:
一个简单的例子:
data.unshift(newData); // #1; add new data at the beginning
// (You could also remove stuff; update data in the middle; do whatever you need.)
var selection = chart.selectAll("g")
.data(data, function(d) { return d.id; }));
selection.enter() // #2; Add the new stuff just like you did before
.append("g")
.attr("transform", function(d, i) { return "translate(0," + i * barHeight + ")"; });
// . . . all the other setup goes here, too
selection.exit() // #3; Hide any removed elements (should slide them down and turn them invisible)
.transition().duration(400)
.attr("transform", function(d, i) { return "translate(0," + (i + 1) * barHeight + ")"; });
.style("opacity", 0)
.remove();
selection // #4; Move everything to the right location
.transition().duration(400)
.attr("transform", function(d, i) { return "translate(0," + i * barHeight + ")"; });
Run Code Online (Sandbox Code Playgroud)
本系列中有一些关于如何进行此类更新的非常好的示例:常规更新模式。
需要明确注意的一个问题涉及关键功能。您必须包含一个与我上面添加的类似的关键功能 - 通读通用更新模式文章,它应该解释您需要了解的内容。