2016-02-25 26 views
0

我按照本教程構建了可重複使用的圖表:https://bost.ocks.org/mike/chart/。完整的代碼在問題的最後。我有以下問題:在d3可重複使用的圖表中只更新顏色比例域

正如您所看到的,特定組件上的'click'事件觸發了一個查詢,該查詢會更新整個圖表以檢索新數據。我指的是這一行:

selection.datum(relatedConcepts).call(chart);  // Update this vis 

現在,這更新的偉大工程,但當然,考慮到在函數「圖表」我也有

color.domain(data.map(function(d){ return d[0]})); 

色階的領域也將更新,我不想那樣。 所以問題是:如何在第一次創建圖表時設置顏色比例域?

d3.custom = d3.custom || {}; 
d3.custom.conceptsVis = function() { 

    var color = d3.scale.category20(); 

    // To get events out of the module we use d3.dispatch, declaring a "conceptClicked" event 
    var dispatch = d3.dispatch('conceptClicked'); 

    function chart(selection) { 

     selection.each(function (data) { 

      //TODO: This should be executed only the first time 
      color.domain(data.map(function(d){ return d[0]})); 

      // Data binding 
      var concepts = selection.selectAll(".progress").data(data, function (d) {return d[0]}); 

      // Enter 
      concepts.enter() 
       .append("div") 
       .classed("progress", true) 
       .append("div") 
       .classed("progress-bar", true) 
       .classed("progress-bar-success", true) 
       .style("background-color", function (d) { 
        return color(d[0]) 
       }) 
       .attr("role", "progressbar") 
       .attr("aria-valuenow", "40") 
       .attr("aria-valuemin", "0") 
       .attr("aria-valuemax", "100") 
       .append("span") // (http://stackoverflow.com/questions/12937470/twitter-bootstrap-center-text-on-progress-bar) 
       .text(function (d) { 
        return d[0] 
       }) 
       .on("click", function (d) { 

        // Update the concepts vis 
        d3.json("api/concepts" + "?concept=" + d[0], function (error, relatedConcepts) { 
         if (error) throw error; 
         selection.datum(relatedConcepts).call(chart);  // Update this vis 
         dispatch.conceptClicked(relatedConcepts, color); // Push the event outside 
        }); 
       }); 

      // Enter + Update 
      concepts.select(".progress-bar").transition().duration(500) 
       .style("width", function (d) { 
        return (d[1] * 100) + "%" 
       }); 

      // Exit 
      concepts.exit().select(".progress-bar").transition().duration(500) 
       .style("width", "0%"); 

     }); 
    } 

    d3.rebind(chart, dispatch, "on"); 
    return chart; 
}; 

ANSWER 最後我做什麼meetamit建議我加入這個:

// Getter/setter 
chart.colorDomain = function(_) { 
    if (!arguments.length) return color.domain(); 
    color.domain(_); 
    return chart; 
}; 

我conceptsVis功能,這樣從外面我可以這樣做:

.... = d3.custom.conceptsVis().colorDomain(concepts); 

當然我刪除了這一行:

color.domain(data.map(function(d){ return d[0]})); 

回答

1

您可以檢查是否域是一個空數組,僅填充它,如果它是:

if(color.domain().length == 0) { 
    color.domain(data.map(function(d){ return d[0]})); 
} 

話雖這麼說,這種行爲似乎根本錯誤的,或者至少容易出錯。這意味着填充域是第一個渲染的副作用。但是,第一次渲染是什麼使它不同於後續調用,因此值得設置域?如果以後發生什麼事情,隨着應用程序的發展,您決定首先渲染不同的數據集,然後渲染當前的第一個數據集?那麼你可能會得到一個不同的域名。在圖表的代碼之外顯式計算域,然後通過setter將域傳遞給圖表似乎更爲合理。例如:

chart.colorDomain(someArrayOfValuesThatYouPreComputeOrHardCode) 
+1

您的回答闡明瞭更深層次的問題。我剛開始玩這個可重複使用的圖表,我不太確定要寫什麼......謝謝。 – valenz