我正在按照本教程构建可重用的图表:https://bost.ocks.org/mike/chart/。完整的代码就在问题的最后。我有以下问题:
正如您所看到的,特定组件上的“click”事件会触发一个查询,该查询会更新检索新数据的整个图表。我指的是这一行:
selection.datum(relatedConcepts).call(chart); // Update this vis
现在这个更新很有效,但是当然在函数“chart”中我也有
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]}));
答案 0 :(得分:1)
您可以检查域是否为空数组,并且仅在以下情况下填充它:
if(color.domain().length == 0) {
color.domain(data.map(function(d){ return d[0]}));
}
话虽这么说,这种行为似乎从根本上说是错误的,或者至少容易出错。这意味着填充域是第一个渲染的副作用。但是,第一次渲染使它与后续调用不同,因此值得设置域是什么?如果稍后,随着您的应用程序的发展,您决定首先渲染不同的数据集,然后渲染当前第一个数据集,会发生什么?那么你最终可能会得到一个不同的域名。在图表代码之外显式计算域似乎更合理,然后通过setter将域传递到图表中。类似的东西:
chart.colorDomain(someArrayOfValuesThatYouPreComputeOrHardCode)