发散堆积条形图 Ember 组件中的过渡行为不正确
Incorrect transition behavior in diverging stacked bar chart Ember component
继 之后,我一直在处理用 D3v4 编写的发散堆栈图。该图表旨在用作 ember 组件。
图表在初始加载时正确呈现,但当数据刷新并过渡到一组新的条形图时,它会显示许多不良行为。此类行为包括:
- 当日期倒退时,条形图无法正确移除
- 当日期向前移动时,最右边的柱被移除
X 轴未相应更新。
我不确定为什么会这样。我知道提供给图表的数据是正确的,并且初始渲染始终正确显示。
component.js文件拆分如下:
didInsertElement() {
var data = this.get('data')
var margin = { top: 35, right: 145, bottom: 35, left: 45 };
var width = 800
var height = 350
var svg = select("#chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
this.set("svg", svg)
var x = scaleBand()
.rangeRound([0, width])
.padding(0.1);
this.set("x", x)
var y = scaleLinear()
.rangeRound([height, 0]);
this.set("y", y)
var z = scaleOrdinal()
.range(["steelblue", "darkorange", "red"]);
this.set("z", z)
svg.append("g")
.attr("class", "x-axis axisWhite");
svg.append("g")
.attr("class", "y-axis axisWhite");
this.buildChart()
},
然后是 didUpdateAttrs 挂钩:
didUpdateAttrs() {
this.buildChart()
},
然后是构建图表的函数:
buildChart() {
var data = this.get('data')
var keys = ["count1", "count2", "count3"];
var series = stack()
.keys(keys)
.offset(stackOffsetDiverging)
(data);
this.get("x").domain(data.map(d => d.label));
this.get("y").domain([
min(series, stackMin),
max(series, stackMax)
]).nice();
var barGroups = this.get("svg").selectAll("g.layer")
.data(series);
barGroups.exit().remove();
barGroups.enter().insert("g", ".x-axis")
.classed('layer', true);
this.get("svg").selectAll("g.layer")
.attr("fill", d => this.get("z")(d.key));
var bars = this.get("svg").selectAll("g.layer").selectAll("rect")
.data(function(d) { return d; });
bars.exit().remove()
bars = bars
.enter()
.append("rect")
.attr("width", this.get("x").bandwidth())
.attr("x", d => this.get("x")(d.data.label))
.merge(bars)
bars.transition()
.attr("y", d => this.get("y")(d[1]))
.attr("height", d => Math.abs(this.get("y")(d[0])) - this.get("y")(d[1]));
this.get("svg").selectAll(".x-axis").transition()
.attr("transform", "translate(0," + this.get("y")(0) + ")")
.call(axisBottom(this.get("x")));
this.get("svg").selectAll(".y-axis").transition()
.call(axisLeft(this.get("y")));
function stackMin(serie) {
return min(serie, function(d) { return d[0]; });
}
function stackMax(serie) {
return max(serie, function(d) { return d[1]; });
}
}
不幸的是,我无法使用 ember-d3 模块获得适当的 Twiddle。
上述行为是由于重新绘制图表时未重新计算条形宽度造成的。
所以这个:
bars.transition()
.attr("y", d => this.get("y")(d[1]))
.attr("height", d => Math.abs(this.get("y")(d[0])) - this.get("y")(d[1]));
变成了这个:
bars.transition()
.attr("y", d => y(d[1]))
.attr("height", d => Math.abs(y(d[0])) - y(d[1]))
.attr("width", x.bandwidth())
.attr("x", d => x(d.data.label));
继
图表在初始加载时正确呈现,但当数据刷新并过渡到一组新的条形图时,它会显示许多不良行为。此类行为包括:
- 当日期倒退时,条形图无法正确移除
- 当日期向前移动时,最右边的柱被移除 X 轴未相应更新。
我不确定为什么会这样。我知道提供给图表的数据是正确的,并且初始渲染始终正确显示。
component.js文件拆分如下:
didInsertElement() {
var data = this.get('data')
var margin = { top: 35, right: 145, bottom: 35, left: 45 };
var width = 800
var height = 350
var svg = select("#chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
this.set("svg", svg)
var x = scaleBand()
.rangeRound([0, width])
.padding(0.1);
this.set("x", x)
var y = scaleLinear()
.rangeRound([height, 0]);
this.set("y", y)
var z = scaleOrdinal()
.range(["steelblue", "darkorange", "red"]);
this.set("z", z)
svg.append("g")
.attr("class", "x-axis axisWhite");
svg.append("g")
.attr("class", "y-axis axisWhite");
this.buildChart()
},
然后是 didUpdateAttrs 挂钩:
didUpdateAttrs() {
this.buildChart()
},
然后是构建图表的函数:
buildChart() {
var data = this.get('data')
var keys = ["count1", "count2", "count3"];
var series = stack()
.keys(keys)
.offset(stackOffsetDiverging)
(data);
this.get("x").domain(data.map(d => d.label));
this.get("y").domain([
min(series, stackMin),
max(series, stackMax)
]).nice();
var barGroups = this.get("svg").selectAll("g.layer")
.data(series);
barGroups.exit().remove();
barGroups.enter().insert("g", ".x-axis")
.classed('layer', true);
this.get("svg").selectAll("g.layer")
.attr("fill", d => this.get("z")(d.key));
var bars = this.get("svg").selectAll("g.layer").selectAll("rect")
.data(function(d) { return d; });
bars.exit().remove()
bars = bars
.enter()
.append("rect")
.attr("width", this.get("x").bandwidth())
.attr("x", d => this.get("x")(d.data.label))
.merge(bars)
bars.transition()
.attr("y", d => this.get("y")(d[1]))
.attr("height", d => Math.abs(this.get("y")(d[0])) - this.get("y")(d[1]));
this.get("svg").selectAll(".x-axis").transition()
.attr("transform", "translate(0," + this.get("y")(0) + ")")
.call(axisBottom(this.get("x")));
this.get("svg").selectAll(".y-axis").transition()
.call(axisLeft(this.get("y")));
function stackMin(serie) {
return min(serie, function(d) { return d[0]; });
}
function stackMax(serie) {
return max(serie, function(d) { return d[1]; });
}
}
不幸的是,我无法使用 ember-d3 模块获得适当的 Twiddle。
上述行为是由于重新绘制图表时未重新计算条形宽度造成的。
所以这个:
bars.transition()
.attr("y", d => this.get("y")(d[1]))
.attr("height", d => Math.abs(this.get("y")(d[0])) - this.get("y")(d[1]));
变成了这个:
bars.transition()
.attr("y", d => y(d[1]))
.attr("height", d => Math.abs(y(d[0])) - y(d[1]))
.attr("width", x.bandwidth())
.attr("x", d => x(d.data.label));