2017-08-14 39 views
2

我有一個可重複使用的圖表上的方法,如果它通過d3.select('#id')選擇或通過d3.selectAll('.class')選擇傳遞值的數組可傳遞選擇並返回一個值。我目前正在用context._groups[0] instanceof NodeList審覈已通過的論點,但使用未記錄的屬性會感覺有點脆弱,因爲這可能會在將來的版本中發生變化。是否有更多內置的方式來確定選擇是來自select還是selectAll檢查是否d3.select或d3.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 
} 
+0

非常好的和有趣的問題。我寫了一個答案,這不是你所期望的答案。如果有人證明我錯了,我會很樂意刪除它。 –

+0

只是一個好奇心:*爲什麼*你這樣做?爲什麼不簡單地向函數傳遞第二個參數,告知方法的類型?你看,這是一個很有希望成爲[XY問題]的候選人(https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) –

+0

我已更新我的文章以提供全文上下文。這裏的目標是找到實現這種getter/setter方法的「最類似d3」的方式。 「最好」的答案將是d3爲其中一種方法做同樣的事情的一個例子。 –

回答

2

嗯,有時候一個問題在這裏S.O.根本沒有答案(它有happened before)。

這似乎是你的這個問題的情況:「是否有更多內置的方式來確定選擇是來自select還是selectAll?。可能沒有。

爲了證明,讓我們來看看源代碼d3.selectd3.selectAll重要:那些selection.selectselection.selectAll,其彼此非常不同)。

首先,d3.select

export default function(selector) { 
    return typeof selector === "string" 
     ? new Selection([[document.querySelector(selector)]], [document.documentElement]) 
     : new Selection([[selector]], root); 
} 

現在,d3.selectAll

export default function(selector) { 
    return typeof selector === "string" 
     ? new Selection([document.querySelectorAll(selector)], [document.documentElement]) 
     : new Selection([selector == null ? [] : selector], root); 
} 

正如你所看到的,我們只有差異在這裏:

  1. d3.selectAll接受null。這不會幫助你。
  2. d3.selectAll使用querySelectorAll,而d3.select使用querySelector

這第二個區別是適合你的,你也知道現在唯一的一個,因爲querySelectorAll

返回文檔中的元素列表(使用深度優先前序遍歷與指定的選擇器組相匹配的文檔節點)。返回的對象是一個節點列表。(重點煤礦)

而且只有querySelector ...:

返回指定選擇,或選擇的組相匹配的文檔中的第一個元素。

因此,無證(和哈克,因爲你正在使用_groups,這是不是一個好主意)selection._groups[0] instanceof NodeList你使用的是現在似乎是告訴通過d3.select從創建的選擇創建一個選擇的唯一途徑通過d3.selectAll