在此道歉,我的问题不包括代码,而是有关D3的一个高级问题,以及如何正确构建我的应用程序。我将尝试使我的问题尽可能简洁明了:
我正在构建一个React / D3应用程序,该应用程序创建NBA球队徽标的散点图,允许用户单击按钮以选择X和Y轴的变量。用户还可以过滤该图表,使其仅包括某些球队(NBA特定部门的球队)。
以下是该应用程序的快速演示gif,它具有我遇到的主要问题:
。 。 。 here是有兴趣的人到我的应用程序的链接。
当我更改X轴或Y轴按钮(gif的第二部分)时,团队徽标正确地滑到了新位置。
当我更改分区(gif的前半部分)时,它更改了显示的5个团队徽标,这是正确的。但是,动画(我在gif中几次显示)不正确。旧徽标应仅在适当位置消失,而新徽标应仅在适当位置出现。相反,徽标会更改并滑动。
我知道动画为什么要这样做-D3在更新之前看到5个数据点,在更新之后看到5个数据点,但是并不能区分我的点是唯一的(不同的团队徽标)。由于更新的数据点具有新的(x,y)位置(每个团队的统计信息不同),因此只需将旧徽标设置为新徽标的位置即可。
我认为我的应用程序的结构在修复此问题上会滞后。当前,我有一个容器组件,用于加载数据,过滤团队(基于所选的部门),然后将过滤后的数据(具有团队统计信息的对象数组)传递到创建徽标散点图的图形组件中。
另一方面,如果我将全部对象(全部30个团队)传递给图形组件,则我可以解决此问题吗?只需让D3更改该对象的“填充”标记被滤除时变成透明的?这样,尽管有25个徽标是不可见的,但始终会绘制30个徽标,并且徽标应正确显示动画。
提前感谢您的想法!
编辑:如果帖子不清楚,请让我知道,我将尽力澄清。我尽力避免发布没有代码的Q,但这是一个相当高水平的Q,重点是D3常规更新模式的工作方式以及如何在常规更新模式框架内使用特定动画构建图形。 >
Edit2:单选按钮内置在容器组件中。使用我的API从我的数据库中获取数据,然后使用这些单选按钮过滤数据,这些操作都在容器组件中完成。我正在考虑将这些单选按钮引入图形组件,并使用D3构建它们。我想可能必须。
Edit3:应该早先共享,这是构成这些标记的D3代码:
const update = svg.select('g.points')
.selectAll("rect")
.data(graphData);
// Second exit and remove
update.exit().remove();
// Third Update
update
.enter()
.append("rect")
.attr("transform", d => `translate(${(xScale(+d[xColname]) - logoRadius)}, ${(yScale(+d[yColname]) - logoRadius)})`)
.attr("x", 0).attr("y", 0)
.attr("height", logoRadius)
.attr("width", logoRadius)
.attr("fill", d => `url(#teamlogo-${d.teamAbbrev})`)
.attr("opacity", 0.95);
// And Fourth transition
update
.transition()
.duration(750)
.delay((d, i) => i * 15)
.attr("transform", d => `translate(${(xScale(+d[xColname]) - logoRadius)}, ${(yScale(+d[yColname]) - logoRadius)})`)
.attr("x", 0).attr("y", 0)
.attr("height", logoRadius)
.attr("width", logoRadius)
.attr("fill", d => `url(#teamlogo-${d.teamAbbrev})`)
.attr("opacity", 0.95);
答案 0 :(得分:3)
这里的问题似乎只是数据联接期间缺少关键功能。
您在comments section中询问:
D3常规更新模式不只是在查找数据数组中的对象数量吗?
如果您设置了按键功能,答案为否。事实是...
如果未指定键功能,则将数据中的第一个数据分配给第一个选定元素,将第二个数据分配给第二个选定元素,依此类推。通过计算每个数据和元素的字符串标识符,可以指定键函数来控制将哪个数据分配给哪个元素,从而替换默认的按索引联接。 (source)
因此,如果您没有设置关键功能,因为您总是只有5个团队,那么在更改部门时,您实际上没有有效的输入和退出选择,而只是更新了一个:根据他们的顺序绑定数据,D3认为芝加哥公牛队和亚特兰大老鹰队是同一支球队。
解决方案:设置关键功能。
使用团队缩写(假设它们是唯一)可以很简单:
const update = svg.select('g.points')
.selectAll("rect")
.data(graphData, function(d){
return d.teamAbbrv;
});
PS:只是一个与您的问题无关的问题:为什么要在此处附加rect?由于您拥有logoRadius
,因此添加圆圈似乎不是更自然吗?最重要的是,由于圆的中心(无论其大小如何)都在正确的基准坐标处,因此数据表示将更加准确。矩形不是这种情况,在矩形中,坐标(x
,y
)代表其左上角。