如何正确过渡d3.js中的堆叠条形图 [英] How to correctly transition stacked bars in d3.js
问题描述
我正在尝试获取堆积的条形图,以随着条形图的来回正确地设置动画.可能在某个地方有一个很好的例子(也许我会作为一个单独的问题来问),但是我发现的例子没有显示退出和进入各个堆栈元素的过渡,我想确保随着酒吧的退出,他们将其上方的条形图向下拖动,并在进入时将其上方的条形图向上推.而且我不希望过渡期间出现任何差距或重叠.
有人能指出我的例子吗?
更正我的问题: Ashitaka用一个有用的jsfiddle回答了这个问题.他的回答促使我更仔细地研究 d3堆栈布局,其中我读到:
在最简单的情况下,图层是值的二维数组.所有第二维数组的长度必须相同.
因此,我得出的结论是我要解决所有这些错误.我根本不应该尝试删除堆栈栏.如果数据中的条形消失,则应将其保留在数据中并将其高度更改为零.这样,过渡效果很好.我还不必处理出现的新酒吧.
转换堆积图(通常与SVG一起使用)的一个令人困惑的方面是坐标系原点位于左上角,这意味着y向下增加.
首先,我们的数据应具有2 y个相关属性:
-
y
,条的高度 -
和
y0
,即条形图在其他条形图上方的基线或y位置.这应该由d3.layout.stack()
计算.
然后,我们应该创建2个音阶:
-
一个高度,完全符合预期:
var heightScale = d3.scale.linear() .domain([0, maxStackY]) .range([0, height]);
-
其中一个用于y位置,其作用相反:
var yScale = d3.scale.linear() .domain([0, maxStackY]) .range([height, 0]);
使用这两个比例尺,我们可以创建一些函数来计算条形的适当y位置和高度:
var barBaseY = function (d) { return yScale(d.y0); };
var barTopY = function (d) { return yScale(d.y0 + d.y); };
var barHeight = function (d) { return heightScale(d.y); };
接下来,至关重要的是,我们创建一个键函数,以便使元素绑定到正确的数据:
var joinKey = function (d) { return d.name; };
如果没有此功能,D3将使用其索引连接数据,这将破坏所有内容.
现在,要从堆栈中删除或添加一组柱,我们执行以下步骤:
-
重新计算堆栈:
var newStack = stack(enabledSeries());
-
layers = layers.data(newStack, joinKey);
借助我们的键功能,D3可以确定要添加,删除或更新的小节.
-
访问相应的栏:
-
layers.enter()
包含输入选择",即要添加的一组新的条. -
layers.exit()
包含退出选择",即要删除的一组条形. -
layers
仅包含更新选择",即要更新的条.但是,在enter.append之后添加修改更新选择"以包含输入和更新元素.不过,在D3 v4中,这种情况已经改变.
-
-
使条形动起来:
-
对于添加的条,我们使用
height
0和y
位置barBaseY
创建它们. 然后,为所有钢筋的height
和y
属性设置动画. -
对于已删除的条,我们将它们设置为
height
0和y
位置barBaseY
的动画,这与添加条完全相反.然后,为其余所有条的height
和y
属性设置动画. D3足够聪明,可以同时渲染所有这些动画.
-
这是我在第一条评论中链接到的堆叠图表的精简版本./p>
和这是为什么必须同时将y
和height
属性设置为动画的直观解释.模拟尺寸下降"的条形.
I'm trying to get a stacked bar chart to animate correctly as bars come and go. There's probably a good example of this somewhere (maybe I'll ask as a separate question), but the examples I'm finding don't show transitions with individual stack elements exiting and entering I want to make sure that as bars are exiting, they drag down the bars above them, and as they're entering, they push up the bars above them. And I don't want any gaps or overlaps midway through the transition.
Can anyone point me to an example that does this?
Correcting my wrong-headed question: Ashitaka answered the question with a helpful jsfiddle. His answer prompted me to look at the d3 stack layout more closely, where I read:
In the simplest case, layers is a two-dimensional array of values. All of the 2nd-dimensional arrays must be the same length.
So, I concluded I was going about this all wrong. I shouldn't have been trying to remove stack bars at all. If bars in my data were going to disappear, I should leave them in the data and change their height to zero. That way the transitions work great. I haven't yet had to deal with new bars appearing.
One confusing aspect of transitioning stacked charts (and working with SVG in general) is that the coordinate system origin is at the top-left corner, which means that y increases downwards.
First, our data should have 2 y related attributes:
y
, the height of the barAnd
y0
, the baseline or the y position of the bar when it's on top of other bars. This should be calculated byd3.layout.stack()
.
Then, we should create 2 scales:
One for height, which works exactly as expected:
var heightScale = d3.scale.linear() .domain([0, maxStackY]) .range([0, height]);
And one for the y position, which works in the reverse way:
var yScale = d3.scale.linear() .domain([0, maxStackY]) .range([height, 0]);
With these two scales, we can create some functions to calculate the appropriate y positions and heights of our bars:
var barBaseY = function (d) { return yScale(d.y0); };
var barTopY = function (d) { return yScale(d.y0 + d.y); };
var barHeight = function (d) { return heightScale(d.y); };
Next, it's critical that we create a key function so that elements are bound to the correct data:
var joinKey = function (d) { return d.name; };
Without this function D3 would join the data using its index, which would break everything.
Now, to remove or add a set of bars from the stack, we take these steps:
Recalculate the stack:
var newStack = stack(enabledSeries());
Join the new stack with the current selection of layers with the data function:
layers = layers.data(newStack, joinKey);
With our key function, D3 determines the bars that are to be added, removed or updated.
Access the appropriate bars:
layers.enter()
contains the "enter selection", that is, the new set of bars to be added.layers.exit()
contains the "exit selection", that is, the set of bars to be removed.And simply
layers
contains the "update selection", that is, the bars that are to be updated. However, after enter.append the "update selection" is modified to contain both entering and updating elements. This has changed in D3 v4 though.
Animate the bars:
For added bars, we create them with
height
0 andy
positionbarBaseY
. Then we animate all the bars'height
andy
attributes.For removed bars, we animate them to
height
0 andy
positionbarBaseY
, the exact opposite of adding bars. Then we animate all the remaining bars'height
andy
attributes. D3 is smart enough to render all these animations at the same time.
Here's a pared down version of the stacked chart I linked to in my first comment.
这篇关于如何正确过渡d3.js中的堆叠条形图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!