2

我已经实现了这个 d3 可视化http://bl.ocks.org/4745936,加载动态数据而不是 .tsv

就我而言,一旦我的服务器将新信息传递给选择器,第二个图表就会在第一个图表下呈现,而不是修改现有图表的内容。

我相信这与这种append方法有关。

var svg = d3.select(selector).append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

所以我尝试exit().remove()在图例和城市变量之后立即添加其他方法,append('g');但我的 javascript 控制台说该exit()方法此时不存在。

我觉得我的方法完全错误,如何更新这样的现有图表?与之前的图表一起生成第二个和第三个图表根本不是我想要的结果

4

4 回答 4

2

没错,append 方法每次都添加一个新的 svg 元素。为了防止重复图表,您需要检查 svg 元素是否已经存在。所以在开始时尝试这样的事情:

var svg = d3.select("#mycontainer > svg")
if (svg.empty())
    svg = d3.select(selector).append("svg");
...

exit() 文档中所述,此方法仅在数据运算符返回的选择上定义。因此,请确保您在从.data(..).

于 2013-02-13T20:06:31.257 回答
1

斯科特的回答是确保初始化只发生一次的一种方法。

但是,我更喜欢一种更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);

在我看来,代码完全遵循了进入-更新-退出的循环。

于 2013-02-13T20:29:08.110 回答
1

我能够用一些 jQuery 和 CSS voodoo 解决这个问题

基本上,因为我的 d3 图将 svg 元素添加到现有选择器(在我的情况下为 div),我能够动态检查它的名称

var svgtest = d3.select(selector+" > svg"); 获取该 div 的 svg 子子元素。然后我可以使用 jquery 完全从 dom 中删除该元素,然后让 d3 继续运行并附加 svg 的所有内容!

 var svgtest = d3.select(selector+" > svg");
    if(!svgtest.empty())
    {
        $(selector+" > svg").remove();
    }
于 2013-02-14T22:01:54.540 回答
1

首先你应该删除旧的 svg,然后你可以添加更新的图表。为此,您应该在附加 svg 之前只添加一行。及其工作。

 var flag=d3.select("selector svg").remove();

//----您的旧代码将从这里开始-----

var svg = d3.select(selector).append("svg")
于 2014-02-25T12:56:48.983 回答