【发布时间】:2017-08-14 21:03:42
【问题描述】:
我有一个可重用图表上的方法,它可以传递一个选择并返回一个值,如果它传递一个d3.select('#id') 选择或一个值数组,如果它传递一个d3.selectAll('.class') 选择。我目前正在使用context._groups[0] instanceof NodeList 询问传递的参数,但使用未记录的属性感觉有点脆弱,因为这可能会在未来的版本中改变。是否有更内置的方法来确定选择是来自select 还是selectAll?
selection.size() 在这里无济于事,因为它只告诉我们选择的结果,而不是它的调用方式。
编辑: 这是使用的上下文。我正在使用 Mike Bostock 的 reusable chart pattern,这个实例包括一个获取/设置甜甜圈标签的方法。
对我而言,此 API 用法遵循 principle of least astonishment,因为这是我期望返回结果的方式。
var donut = APP.rotatingDonut();
// set label for one element
d3.select('#donut1.donut')
.call(donut.label, 'Donut 1')
d3.select('#donut2.donut')
.call(donut.label, 'Donut 2')
// set label for multiple elements
d3.selectAll('.donut.group-1')
.call(donut.label, 'Group 1 Donuts')
// get label for one donut
var donutOneLabel = d3.select('#donut1').call(donut.label)
// donutOnelabel === 'Donut 1'
// get label for multiple donuts
var donutLables = d3.selectAll('.donut').call(donut.label)
// donutLabels === ['Donut 1', 'Donut 2', 'Group 1 Donuts', 'Group 1 Donuts']
以及内部方法定义:
App.rotatingDonut = function() {
var label = d3.local();
function donut() {}
donut.label = function(context, value) {
var returnArray;
var isList = context._groups[0] instanceof NodeList;
if (typeof value === 'undefined' ) {
// getter
returnArray = context.nodes()
.map(function (node) {return label.get(node);});
return isList ? returnArray : returnArray[0];
}
// settter
context.each(function() {label.set(this, value);});
// allows method chaining
return donut;
};
return donut
}
【问题讨论】:
-
非常好的和有趣的问题。我写了一个答案,这不是您期望的答案。如果有人证明我错了,我会很乐意删除它。
-
只是好奇:为什么你要这样做?为什么不简单地将第二个参数传递给函数,告知方法的类型?你看,这是XY problem 的有力候选人
-
我已经更新了我的帖子以提供完整的上下文。这里的目标是找到实现这个 getter/setter 方法的“最类似 d3”的方式。 “最佳”答案将是 d3 对其一种方法执行相同操作的示例。
标签: d3.js