我一直在尝试使用d3.js来显示一个使用两个输入字符串的表,我已添加下面的代码。显示第二个字符串时,仅显示索引大于字符串x长度的字符。
我认为这是与匿名函数相关的东西,当迭代第二个字符串时,我从它在第一个字符串中完成的索引值开始,例如,仅从第二个字符串而不是“fresihnfo”显示“fo” ”。谁能给我一些关于如何解决这个问题的指示?
谢谢!
var x = ["a", "e", "d", "i", "r", "z"];
var y = ["f", "r", "s", "i", "h", "n", "f", "o"];
var w = (x.length + 1) * 50;
var h = (y.length + 1) * 50;
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
/*Displays the first string*/
svg.selectAll("rect")
.data(x)
.enter()
.append("rect")
.attr("x", function(d, i) {
return (i * 45) + 45;
})
.attr("y", "0px")
.attr("width", "40px")
.attr("height", "40px")
.attr("fill", "rgb(0, 0, 102)");
svg.selectAll("text")
.data(x)
.enter()
.append("text")
.text(function(d) {
return d;
})
.attr("text-anchor", "middle")
.attr("x", function(d, i) {
return (i * 45) + 65;
})
.attr("y", "27px")
.attr("font-family", "sans-serif")
.attr("font-size", "20px")
.attr("fill", "white");
/*Displays the second string*/
svg.selectAll("rect")
.data(y)
.enter()
.append("rect")
.attr("x", "0px")
.attr("y", function(d, i) {
return ((i - x.length) * 45) + 45;
})
.attr("width", "40px")
.attr("height", "40px")
.attr("fill", "rgb(0, 0, 102)");
svg.selectAll("text")
.data(y)
.enter()
.append("text")
.text(function(d) {
return d;
})
.attr("text-anchor", "middle")
.attr("x", "20px")
.attr("y", function(d, i) {
return ((i - x.length) * 45) + 70;
})
.attr("font-family", "sans-serif")
.attr("font-size", "20px")
.attr("fill", "white");
当前输出:
所需的输出将是左列中显示字符串y的其余部分。
答案 0 :(得分:2)
正如Marc所说,问题在于您的每次第二次选择都被解释为第一次选择的更新,而不是一组新的元素。由于您只处理更新的enter()
部分,因此您甚至看不到已更改第一组矩形数据的事实。
要确认第一组矩形已从第二个数组中获取数据,请右键单击一个,选择“检查元素”,然后在检查器中打开属性选项卡 - __data__
property保存元素的D3数据对象。
那么你如何解决它?您需要一种在select语句中区分两组矩形的方法。有两种选择:
选项1:在SVG组元素上使用子选择(<g>
)
你有两组矩形,所以使用svg分组元素来保持它们的组织是有意义的。不是将矩形直接添加到svg,而是将一个组元素添加到svg,然后将矩形/文本添加到它。
svg.append("g").selectAll("rect") //etc.
对第二组矩形执行相同操作,并且它们都将很好地排列在第二组中,只要总是从组选择中调用select语句,它将只选择属于该组的元素基。
选项2:使用class属性区分两种元素类型
您有两种类型的值,x和y,因此您应该通过设置相应的类属性来区分svg元素属于哪种类型。然后,在select语句中,确保只选择正确类的元素。某个类的元素的CSS selector格式为elementName.ClassName
,因此您的代码如下所示:
.selectAll("rect.x")
.data(x)
enter()
.append("rect")
.classed("x", true)
// etc.
或 选项3:同时使用
如果您将来想要更新矩形,只需将它们分成两组就不够了 - 您还需要一种方法来区分这些组。因此,在附加<g>
元素时添加x或y类,并在创建时使用"g.x"
或"g.y"
选择器。
如果您想保持D3代码的正确性,我强烈建议您阅读选择,选择器,嵌套选择和更新过程。有list of tutorials on the wiki。
P.S。 您创建的i
值作为匿名函数的命名参数始终受限于该函数的范围。如果需要,可以给它们不同的名称,它们的值将始终是D3传递给它们的值 - 第一个参数的数据对象,以及第二个参数的当前选择中的索引。
答案 1 :(得分:0)
selectAll()
的主要目标是在使用data()
它会将数据与元素连接起来,所以我们可以
使用enter()
为新数据项添加新元素;
使用update()
更新与数据匹配的元素。
使用exit()
删除没有数据匹配的元素
当你使用svg.selectAll("rect").data(x).enter()
追加rect时,selectAll()将返回0元素
data(x).enter()将为每个数据生成占位符,以便您可以在x中追加所有数据
但是当使用svg.selectAll("rect").data(y).enter()
为y添加rect时。 selectAll()将返回6
rects,所以data(y).enter()将产品占位符为'f'和'o'这就是为什么你只得到两个
元素
解决方案:对x和y使用不同的选择器,例如不同的类名
svg.selectAll(".x").data(x).enter().append("rect").attr("class", "x"); // other operation
svg.selectAll(".y").data(x).enter().append("rect").attr("class", "y"); // other operation
您可以通过这些文章深入了解d3选择和数据连接: