2012-12-06 169 views
3

我正在使用d3制作堆叠条形图。d3.js:将数据从父节点传递给子节点onclick事件

感谢this previous question我使用parentNode .__ data __。key将与父节点关联的数据绑定到子节点。

数据是一个数组,每个数据条有一个对象(例如'likes')。然后,每个对象包含驱动每列中的各个矩形值的数组:

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”。到现在为止还挺好。

的问题是如何与一个click事件相同的信息相关联,建立在:

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

// or 

rect.on("click", this.onChartClick.bind(this)); 

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

我的另一个想法是将度量作为附加参数传递,但这里使用函数(d,i,j)的技巧似乎并不奏效,因为直到发生单击事件时才运行该函数。

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

回答

5

您可以使用封闭的参考保持像这样父数据:

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结构中不同级别的方法。连连看!看到这个实时版本,并尝试点击正确的div: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' 
    } 
    }); 
} 
+0

谢谢。这非常有帮助。恐怕我仍然陷在如何引用onChartClick函数的中间。它存在于整个图表/类的上下文中,而不是矩形。 –

+0

查看更新的答案给你一些想法。 – nautat

+0

我只是看着它。真正的大师级!这需要花一点时间才能完成,并确保我理解。我想知道,你认为这个问题的标题应该是什么? –

0

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); 
}); 
+0

谢谢布莱恩。我所苦苦挣扎的不仅仅是传递数据,而是传递数据,这是和度量信息(例如'喜欢') –

+0

不是数据中的喜欢吗? –

+0

likes的值是(即2),但是关键字(即“喜欢”)位于数据的顶层。这意味着'喜欢'被绑定到第一个栏,'不喜欢'第二个等等。然后绑定到栏内每个矩形的是例如{key ='blue-frog',value = 1},即没有任何信息表示'喜欢'我可以改变数据,但是这在多个地方使用,所以我宁愿找到另一种方式。 –