使用流数据更新嵌套的d3气泡图

时间:2016-03-30 13:17:09

标签: javascript d3.js svg bubble-chart

我一直在尝试为我的项目实现嵌套的气泡图,我必须在其中显示网络中不​​同客户端的内容。我用的例子显示在: https://bl.ocks.org/mbostock/7607535

以下是我正在使用的代码:

    /// <reference path="../bower_components/dt-d3/d3.d.ts" />
    var margin = 20, diameter = 960;
    var color = d3.scale.linear()
        .domain([-1, 4])
        .range(["#ff8080", "#b30000"])
        .interpolate(d3.interpolateHcl);
    var pack = d3.layout.pack()
        .padding(2)
        .size([diameter - margin, diameter - margin])
        .value(function (d) { return d.size; });
    var svg = d3.select("body").select("#parent").select("#svg1").append("svg")
    .attr("width", diameter)
    .attr("height", diameter)
  .append("g")
    .attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");
    var svg2 = d3.select("body").select("#parent").select("#svg2").append("svg")
        .attr("width", 100)
        .attr("height", 100)
        .append("g")
        .attr("transform", "translate(" + margin + "," + margin + ")");
    function draw(fileToRead){
        console.log(fileToRead);
        d3.json(fileToRead, function (error, root) {
            if (error)
                throw error;
        var focus = root, nodes = pack.nodes(root), view;
        var circle = svg.selectAll("circle").data(nodes);
        circle.attr("class","update");
        circle.enter().append("circle")
            .attr("class", function (d) { return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root"; })        .style("fill", function (d) { return d.children ? d.children.length > 3 ? color(d.depth) : "white" : d.size > 0.02 ? "#660000" : "#003366"; })
            .style("fill", function (d) { return d.children ? "white" : d.size > 0.02 ? "#660000" : "#003366"; })
            .on("click", function (d) { if (focus !== d)
            zoom(d), d3.event.stopPropagation(); });
        circle.exit().remove();
        var text = svg.selectAll("text").data(nodes);
        text.attr("class","update");
        text.enter().append("text")
            .attr("class", "label")
            .style("fill-opacity", function (d) { return d.parent === root ? 1 : 0; })
            .style("display", function (d) { return d.parent === root ? "inline" : "none"; })
            .style("fill", "black")
            .text(function (d) { return d.name; });
        text.exit().remove();
        var node = svg.selectAll("circle,text");
        d3.select("body")
            .style("background", color(-1))
            .on("click", function () { zoom(root); });
        zoomTo([root.x, root.y, root.r * 2 + margin]);
        function zoom(d) {
            var focus0 = focus;
            focus = d;
            if (focus.depth == 2) {
                circle2.style("fill", "white");
            } else {
                circle2.style("fill", "black");
            }
            var transition = d3.transition()
                .duration(d3.event.altKey ? 7500 : 750)
                .tween("zoom", function (d) {
                var i = d3.interpolateZoom(view, [focus.x, focus.y, focus.r * 2 + margin]);
                return function (t) { zoomTo(i(t)); };
            });
            transition.selectAll("text")
                .filter(function (d) { return d.parent === focus || this.style.display === "inline"; })
                .style("fill-opacity", function (d) { return d.parent === focus ? 1 : 0; })
                .each("start", function (d) { if (d.parent === focus)
                this.style.display = "inline"; })
                .each("end", function (d) { if (d.parent !== focus)
                this.style.display = "none"; });
        }
        function zoomTo(v) {
            var k = diameter / v[2];
            view = v;
            node.attr("transform", function (d) { return "translate(" + (d.x - v[0]) * k + "," + (d.y - v[1]) * k + ")"; });
            circle.attr("r", function (d) { return d.r * k; });
        }
        });
    }
    d3.select(self.frameElement).style("height", diameter + "px");

我遇到的问题是我不断将新数据流式传输到用户界面。每次我用一个完整的json文件调用“Draw”,其中包含数据库中的所有数据。我已经读过,enter(),exit(),remove()负责更新DOM元素,但似乎我遗漏了一些东西。当调用draw()函数时,它似乎在现有的上面绘制气泡,并且诸如圆形边框颜色或文本边框颜色之类的东西消失。 我想知道我是否以正确的方式使用enter()和exit()命令。我想让draw()函数接收json文件,只更新泡泡图中的新信息,并且不存在任何DOM元素,但它似乎只是重新创建所有DOM元素。

提前谢谢你, 的Georgi

PS:我有两个svg是因为我试图将屏幕分成两部分,左侧被气泡图占据,而右侧则在我们将内部气泡放大时显示额外信息

EDIT1:这是我传递给draw()函数的数据示例:

{"name": "", 
    "children": 
        [{"name": "10.0.0.64", "children": 
            [{"name": "unidentified", "children": 
                [{"name": "datasource", "size": 0.002551020408163265}, {"name": "datasource", "size": 0.0031746031746031746}, {"name": "datasource", "size": 0.0017123779389460522}, {"name": "average", "size": 0.008550406895439414}, {"name": "datasource", "size": 0.019020266320109332}]}, 
            {"name": "www.quefaire.be", "children":                 
                [{"name": "average", "size": 0.002270490544565449}, {"name": "datasource", "size": 0.023243328100470965}]}, {"name": "tnsinternet.be", "children": [{"name": "average", "size": 0.002199967070440535}, {"name": "datasource", "size": 0.022009167303284966}]}, 
            {"name": "hy.sachinese.com", "children":                    
                [{"name": "average", "size": 0.0022121416372369493}, {"name": "datasource", "size": 0.022222222222222223}]}, {"name": "pagesdor.be", "children": [{"name": "average", "size": 0.0030411250824668935}, {"name": "datasource", "size": 0.03672943251374624}]}, 
            {"name": "r.254a.com", "children": 
                [{"name": "average", "size": 0.0018942905665264935}, {"name": "datasource", "size": 0.015873015873015872}]}, 
            {"name": "i.ctnsnet.com", "children": 
                [{"name": "average", "size": 0.0018942905665264935}, {"name": "datasource", "size": 0.015873015873015872}]}, 
            {"name": "link.carrefour.eu", "children": 
                [{"name": "average", "size": 0.0019793245801319357}, {"name": "datasource", "size": 0.017857142857142856}]}, 
            {"name": "goudengids.be", "children": 
                [{"name": "average", "size": 0.00457041828122788}, {"name": "datasource", "size": 0.06349206349206349}]}, {"name": "www.inmemoriam.be", "children": [{"name": "average", "size": 0.0018443560093702978}, {"name": "datasource", "size": 0.014707876206037973}]}, 
            {"name": "www1.gfk-wi.com", "children": 
                [{"name": "datasource", "size": 0.011986645572622365}, {"name": "average", "size": 0.0017277318393667718}]}, {"name": "bootstrapcdn.com", "children": [{"name": "average", "size": 0.008550406895439414}, {"name": "datasource", "size": 0.13314186424076532}]}, 
            {"name": "maxcdn.bootstrapcdn.com", "children": 
                [{"name": "datasource", "size": 0.031746031746031744}, {"name": "average", "size": 0.0027563593243117796}]}]}]}

这也是我的CSS:

.svg-container {
    display: flex;
    position: relative;
    width: 100%;
    padding-bottom: 100%; /* aspect ratio */
    vertical-align: top;
    overflow: hidden;
}

.svg-content-responsive {
    display: inline-block;
    position: absolute;
    top: 10px;
    left: 0;
}

.container {
  float: left;
}

.node {
    cursor: pointer;
    stroke: darkgrey;
}

.node:hover {
    stroke: #000;
    stroke-width: 1.5px;
}

.node--leaf {
    fill: white;
}

.label {
    font: 11px "Helvetica Neue", Helvetica, Arial, sans-serif;
    text-anchor: middle;
    text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff, 0 -1px 0 #fff;
}

.label,
.node--root,
.node--leaf {
    pointer-events: none;
}

1 个答案:

答案 0 :(得分:2)

首先,确保所有节点都具有唯一名称,或者必须具有一些id才能唯一地定义节点。 使用如下所示的唯一键来唯一标识数据。 在您的数据集中,我的解决方案无法工作原因是很少有节点具有非唯一名称,如数据集等。

以下解决方案仅在有唯一名称时才有效。

而不是

var circle = svg.selectAll("circle").data(nodes);

这样做

var circle = svg.selectAll("circle").data(nodes, function(d){return d.name});

而不是这个

var text = svg.selectAll("text").data(nodes);

这样做

var text = svg.selectAll("text").data(nodes, function(d){return d.name});

由于上述原因,exit()功能无法正常工作。

了解关键功能here