斯科特的回答是确保初始化只发生一次的一种方法。
但是,我更喜欢一种更d3-ic的方式来处理这个问题:
var svg = d3.select(selector)
.selectAll('svg')
.data( [ dataFromTSV ] ); // 1 element array -> 1 svg element
// This will be empty if the `svg` element already exists.
var gEnter = svg.enter()
.append('svg')
.append('g');
gEnter.append( ... ); // Other elements to be appended only once like axis
svg.attr('width', ...)
.attr('height', ...);
// Finally, working with the elements which are surely in the DOM.
var g = svg.select("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
g.selectAll(...).attr(...);
这种方法在可重用图表示例的源代码中得到了例证。
我更喜欢这种方法,因为它通过隐藏初始化和更新的逻辑来保持代码的声明性和可视化的真实性。
我会修改原来的例子: http: //jsfiddle.net/8Axn7/5/到http://jsfiddle.net/3Ztt8/
图例和图表都是从svgElem
一个单一的数据元素定义的:
var svgElem = d3.select("#multiLinegraph").selectAll('svg')
.data([cities]);
// ...
var svg = svgElem.select('g');
// ...
var city = svg.selectAll(".city")
.data(
function (d) { return d; },
function (d) { return d.name; } // Object consistency
);
// ...
var legend = svg.selectAll('g.legend')
.data(
function(d) { return d; },
function (d) { return d.name; } // Object consistency
);
此外,静态属性仅在元素进入(或退出)时设置一次,而更新属性在每次更新时设置(转换):
gEnter.append("g")
.attr("class", "y multiLineaxis")
.append('text')
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Requests (#)");
svg.select('g.y.multiLineaxis').transition().call(yAxis);
在我看来,代码完全遵循了进入-更新-退出的循环。