与d3可重用模式的交互性 [英] Interactivity with the d3 reusable pattern
问题描述
在D3:
我试图使用可重复使用的图表模式,它允许我添加在实际图表之外处理的事件。例如,我有一个简单的barchart,我可以点击每个单独的酒吧。现在不是只处理图表组件内的点击事件,我想能够从创建图表实例的地方处理它。例如,我想编辑对应于点击的bar元素的数据,或者我想更新一些其他元素的位置,取决于我点击的栏的位置。为了保持图表组件尽可能模块化和独立,我不想在其中执行某些任务。
In D3: I'm trying to implement a chart using the reusable charts pattern which allows me to add events which are handled outside the actual chart. For instance I have a simple barchart where I can click on each individual bar. Now instead of just handling the click event inside the chart component I want to be able to handle it from where I create a chart instance. For example I want to edit the data which corresponds to the clicked bar element or I want to update the position of some other element depending on the position of the bar I clicked on. To keep the chart component as modular and independent as possible I don't want certain tasks to be done inside it.
我想出了一个非常直接的解决方案,但我觉得有必要有一个更好的解决方案。这样,我必须考虑外部世界可能感兴趣的每一个可能的事件。 JSFiddle p>
I came up with a pretty straight forward solution but I feel like there must be a better solution to this. This way I have to account for every possible event that the outside world might be interested in. JSFiddle
function clickHandler(d, i) {
// do something with the element/event/data
}
var svg = d3.select('#container')
.append('svg');
var myChart = chart()
.onClick(clickHandler);
svg.append('g')
.datum(data)
.call(chart);
function chart() {
var onClick = function() {};
function _chart(selection) {
selection.each(function(d, i) {
selection.selectAll('rect')
.data(d)
.enter()
.append('rect')
.attr('x', 0)
.attr('y', function(d, i) {return i * 11;})
.attr('width', function(d, i) {return d;})
.attr('height', 10);
.on('click', _onClick);
});
}
function _onClick(d, i) {
d3.select(this)
.attr('fill', 'red');
onClick(d, i);
}
_chart.onClick = function(_) {
if(!arguments.length) return onClick;
onClick = _;
return _chart;
}
return _chart;
}
是否有任何类型的标准方法/最佳实践来处理这种情况?
Is there any kind of standard way/best practice to handle this type of situation? Or is this just not really a common situation?
推荐答案
您正在寻找的是在您的核心应用程序代码和可以重用的代码之间创建一个分隔。这是一个好主意,因为它保持您的应用程序的代码小,使您更容易更改它和向前移动。在可重复使用的图表中,您希望发送非常通用的事件,例如 clicked
,而在您的应用程式中,您需要的活动必须非常明确您的网域,例如。 addSugar
。
What you're looking for is to create a separation between your core application code and code that can be reused. This is a good idea because it keeps your application's code small, making it easier for you to change it and move it forward. In a reusable chart you want to send a very generic events, e.g. clicked
, while in your application you need the events to be very specific to your domain, e.g. addSugar
.
您需要两种成分: d3.dispatch 和 d3.rebind 。前者帮助您创建一个清晰的内部API,后者则帮助您将调度的事件暴露给外部世界。
There are two ingredients you need: d3.dispatch and d3.rebind. The former helps you create a clear internal API, while the latter helps you expose the dispatched events to the outside world.
转到此处查找示例。您要查找的是三件事:
Go here to find an example of this. What you want to look for is three things:
- 在可重复使用的图表中,您创建了一个具有要发布到外部世界的事件的调度器:
var myDispatch = d3.dispatch('myclick','mydrag')
- 然后在可重复使用的图表的事件处理程序中,事件像这样:
myDispatch.myclick(argumentsyouwanttopass)
- 作为最后一步,使这些事件可用于外部:
return d3.rebind(_chart,myDispatch,on);
- 然后你可以绑定到外面的这些事件:
myChart.on('myclick',function(){})
- Inside the reusable chart you create a dispatcher with events you want to publish to the outside world:
var myDispatch = d3.dispatch('myclick', 'mydrag')
- Then in your reusable chart's event handlers you publish these events like so:
myDispatch.myclick(argumentsyouwanttopass)
- As a last step you make these events available to the outside:
return d3.rebind(_chart, myDispatch, "on");
- Then you can bind to these events on the outside:
myChart.on('myclick', function(){})
重写后的内容可能如下所示:
So your example, rewritten could look like this:
function chart() {
var dispatch = d3.dispatch('click');
function _chart(selection) {
selection.each(function(d, i) {
selection.selectAll('rect')
.data(d)
.enter()
.append('rect')
.attr('x', 0)
.attr('y', function(d, i) {return i * 11;})
.attr('width', function(d, i) {return d;})
.attr('height', 10);
.on('click', dispatch.click);
});
}
return d3.rebind(_chart, dispatch, 'on');
}
注册多个事件处理程序,你需要命名空间他们(像你必须为常规d3事件),例如 chart.on('click.foo',handlerFoo)
, chart.on('click.bar',handlerBar)
等。
Additional note: to register multiple event handlers, you need to namespace them (like you have to for regular d3 events), e.g. chart.on('click.foo', handlerFoo)
, chart.on('click.bar', handlerBar)
etc.
这篇关于与d3可重用模式的交互性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!