I am building a reusable chart following this tutorial: https://bost.ocks.org/mike/chart/. The full code is at the end of the question. I have the following problem:
As you can see the 'click' event on a specific component triggers a query that updates the whole chart retrieving new data. I am referring to this line:
selection.datum(relatedConcepts).call(chart); // Update this vis
Now this update works great, but of course given that in the function "chart" I also have
color.domain(data.map(function(d){ return d[0]}));
the domain of the color scale will be also updated and I don't want that. So the question is: how do I set the color scale domain ONLY the first time the chart gets created?
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 I ended up doing what meetamit suggested and I added this:
// Getter/setter
chart.colorDomain = function(_) {
if (!arguments.length) return color.domain();
color.domain(_);
return chart;
};
to my conceptsVis function, so that from the outside I can do:
.... = d3.custom.conceptsVis().colorDomain(concepts);
Of course I deleted the line:
color.domain(data.map(function(d){ return d[0]}));