d3.js:从父节点向子节点传递数据onclick事件



我正在使用d3制作堆叠条形图。

由于前面的问题,我正在使用parentNode将与父节点关联的数据绑定到子节点。__data__.key.

数据是一个数组,每个栏有一个对象(例如"点赞")。然后,每个对象都包含一组值,这些值驱动每个条的各个矩形:

data =  [{
key = 'likes', values = [
{key = 'blue-frog', value = 1}, 
{key = 'goodbye', value = 2}
]
}, {
key = 'dislikes, values = [
{key = 'blue-frog', value = 3},
{key = 'goodbye', value = 4}
]
}]

图表运行良好,将父度量数据绑定到子svg属性也是如此:

// Create canvas
bars = svg.append("g");
// Create individual bars, and append data
// 'likes' are bound to first bar, 'dislikes' to second
bar = bars.selectAll(".bar")
.data(data)        
.enter()
.append("g");
// Create rectangles per bar, and append data
// 'blue-frog' is bound to first rectangle, etc.
rect = bar.selectAll("rect")
.data(function(d) { return d.values;})
.enter()
.append("rect");
// Append parent node information (e.g. 'likes') to each rectangle    
// per the SO question referenced above        
rect.attr("metric", function(d, i, j) {
return rect[j].parentNode.__data__.key;
});

这样就可以为每个矩形创建工具提示,上面写着"赞:2"。到目前为止还不错。

问题是如何将这些相同的信息与点击事件相关联,建立在:之上

rect.on("click", function(d) {
return _this.onChartClick(d);
});
// or
rect.on("click", this.onChartClick.bind(this));

这是有问题的,因为onChartClick方法需要访问绑定数据(d)和图表执行上下文(this)。如果没有,我可以切换执行上下文并在onChartClick方法中调用d3.select(this).attr("metric")

我的另一个想法是将度量作为一个额外的参数传递,但在这里使用函数(d,I,j)的技巧似乎不起作用,因为它在点击事件发生之前不会运行。

你能提出一个解决方案吗?

您可以使用闭包来保留对父数据的引用,如下所示:

bar.each(function(dbar) {            // dbar refers to the data bound to the bar
d3.select(this).selectAll("rect")
.on("click", function(drect) { // drect refers to the data bound to the rect
console.log(dbar.key);       // dbar.key will be either 'likes' or 'dislikes'
});
});

更新:

请参阅以下内容,了解访问DOM结构中不同级别的各种方法。混搭!查看此内容的实时版本,然后尝试单击.rrect-dvs:http://bl.ocks.org/4235050

var data =  [
{
key: 'likes',
values: [{ key: 'blue-frog', value: 1 }, { key: 'goodbye', value: 2 }]
}, 
{
key: 'dislikes',
values: [{ key: 'blue-frog', value: 3 }, { key: 'goodbye', value: 4 }]
}];
var chartdivs = d3.select("body").selectAll("div.chart")
.data([data]) // if you want to make multiple charts: .data([data1, data2, data3])
.enter().append("div")
.attr("class", "chart")
.style("width", "500px")
.style("height", "400px");
chartdivs.call(chart); // chartdivs is a d3.selection of one or more chart divs. The function chart is responsible for creating the contents in those divs
function chart(selection) { // selection is one or more chart divs
selection.each(function(d,i) { // for each chartdiv do the following
var chartdiv = d3.select(this);
var bar = chartdiv.selectAll(".bar")
.data(d)
.enter().append("div")
.attr("class", "bar")
.style("width", "100px")
.style("height", "100px")
.style("background-color", "red");  
var rect = bar.selectAll(".rect")
.data(function(d) { return d.values; })
.enter().append("div")
.attr("class", "rect")
.text(function(d) { return d.key; })
.style("background-color", "steelblue");
bar.each(function(dbar) {
var bardiv = d3.select(this);
bardiv.selectAll(".rect")
.on("click", function(drect) { 
d3.select(this).call(onclickfunc, bardiv);
});
});
function onclickfunc(rect, bar) { // has access to chart, bar, and rect
chartdiv.style("background-color", bar.datum().key === 'likes' ? "green" : "grey");
console.log(rect.datum().key); // will print either 'blue-frog' or 'goodbye'
}
});
}

rect.on("click", this.onChartClick.bind(this));不起作用,因为您不是在传递函数,而是在传递函数的返回值(通过附加(this))。

如果您想传递this和数据(d),请尝试以下操作:

// assuming you have this somewhere earlier
var onChartClick = function () {}
// change your parent click to
rect.on("click", function(d) {
return onChartClick.call(this, d);
});

另一种方法可以是f.e传递一个对象/json,或者在我的情况下,传递一个创建矩形的类实例到事件,以便在中访问它

var rect = svgContainer.append("rect");
rect.datum(this);
rect.on('click', function(d){
alert(d);
alert(d.id); // etc.
});

最新更新