D3强制布局缩放和平移不起作用

时间:2015-04-29 07:43:34

标签: d3.js zoom force-layout

我刚开始使用D3的强制布局,并通过引用实现了径向图实现:http://flowingdata.com/2012/08/02/how-to-make-an-interactive-network-visualization/

我面临的问题是缩放不起作用。这是我提到的代码:http://jsfiddle.net/blt909/aVhd8/20/用于缩放功能

这是我的代码:

var w = $("#network-plot").width(),
        h = 800,
        r = 6,
        fill = d3.scale.category20();

    var payload={js:'mis1'}
    $.ajax({
        url: "/getSource",
        type: "post",
        async: false,
        data: payload,
        success: function (data) {
            mis1=JSON.parse(data);
        },
    });

    var force = d3.layout.force()
                .charge(-30)
                .linkDistance(310)
                .size([w, h]);

    var zoom = d3.behavior.zoom()
            .scaleExtent([1, 10])
            .on("zoom", zoomed);

    var svgnt = d3.select("#network-plot-svg")
                .attr("width", w)
                .attr("height", h)
                .style('margin-top', h/15)
                .call(zoom);

    var vis = svgnt.append("svg:g");

    var rect = vis.append("svg:rect")
                .attr("width", w)
                .attr("height", h)
                .attr("fill", '#fff')
                .style("pointer-events", "all");

    function zoomed() {
          vis.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
    }

    var radius = d3.scale.log();

    var mis1;

    //**********RADIAL CODE****************
        var unsortednodes = {};
        var sortednodes = [];
        var sortagainst = [];
        var heaviest_node_length = 0;
        for(var i = 0; i < mis1.nodes.length; i++) {
            var count_conn = 0;
            var heaviest_node;
            for(var j = 0; j < mis1.links.length; j++) {
                if(mis1.links[j].source == mis1.nodes[i].group || mis1.links[j].target == mis1.nodes[i].group) {
                    count_conn++;
                }
            }
            if(count_conn > heaviest_node_length) {
                heaviest_node_length = count_conn;
                heaviest_node = i;
            }
            unsortednodes[i] = 10 + count_conn;
            sortagainst[i] = 10 + count_conn;
        }
        sortagainst.sort();
        sortagainst.reverse();
        for(i in unsortednodes) {
            var index = sortagainst.indexOf(unsortednodes[i]);
            sortednodes[index] = i;
            sortagainst[index] = '';
        }
        var c = {"x":w/2, "y":h/2};
        var negativeY = 0;
        var positiveY = 0;
        var negativeX = 0;
        var positiveX = 0;
        var groupcenters = radialPlacement(c, 300, 18, sortednodes);
        //following lines for readjustment code in case svg container is outgrown by graph
        h = Math.abs(negativeY) + Math.abs(positiveY) + 100; //TBD: extra padding needs to be dynamic
        w = Math.abs(negativeX) + Math.abs(positiveX) + 200;
        c = {"x":w/2, "y":h/2};
        groupcenters = radialPlacement(c, 300, 18, sortednodes);
        svgnt.attr("height", h);
        vis.attr("height", h);
        svgnt.attr("width", w);
        vis.attr("width", w);

        function radialLocation(center, angle, radius) {
            x = (center.x + radius * Math.cos(angle * Math.PI / 180));
            y = (center.y + radius * Math.sin(angle * Math.PI / 180));
            if(y < negativeY) {
                negativeY = y;
            } 
            if(y > positiveY) {
                positiveY = y;
            }
            if(x < negativeX) {
                negativeX = x;
            }
            if(x > positiveX) {
                positiveX = x;
            }
            return {"x":x,"y":y};
        }

        function radialPlacement(center, radius, increment, keys) {
            var values_circle = {};
            var increment;
            var start = -90;
            var current = start;
            var total_nodes = keys.length;
            var circles = Math.floor(Math.sqrt((total_nodes - 1)/5));
            if(circles == 0) {
                circles = 1;
            }
            var ratio;
            var r = [];
            var circleKeys = [];
            var radius = 140;
            r[0] = radius;
            var sum_r = r[0];
            for(var j = 1; j < circles; j++){
                r[j] = r[j-1] + 100 //TBD: should radius be linearly incremented like this?
                sum_r += r[j];
            }
            ratio = 1/sum_r;
            var temp = 0;
            for(j = 0; j < circles; j++) {
                if(j == circles - 1) 
                    circleKeys[j] = total_nodes - temp;
                else {
                    circleKeys[j] = Math.floor(total_nodes * r[j] * ratio);
                    temp += circleKeys[j];
                }
            }
            var k = 0;
            for(var i = 0; i < circleKeys.length; i++) {
                increment = 360/circleKeys[i];
                for(j = 0; j < circleKeys[i]; j++, k++) {
                    if(k == 0) {
                        values_circle[keys[k]] = radialLocation(center, -90, 0);
                    }
                    else {
                        values_circle[keys[k]] = radialLocation(center, current, r[i]);;
                        current += increment; 
                    }
                }
            }
            return values_circle;
        }

        //************RADIAL CODE ENDS***************

    d3.json(mis1, function() {

        var link = svgnt.selectAll("line")
                    .data(mis1.links)
                    .enter()
                    .append("svg:line")
                    .style("stroke","#ddd");
        var node = svgnt.selectAll("circle")
                    .data(mis1.nodes)
                    .enter()
                    .append("svg:circle")
                    .attr("r", function(d, j){
                        var count = 0;
                        for(var i=0; i<mis1.links.length; i++) {
                            if(mis1.links[i].source == d.group || mis1.links[i].target == d.group){
                                count ++;
                            }
                        }
                        return (10+count);
                    })
                    .style("fill", function(d) {
                        return fill(d.group);
                    })
                    .on("mouseover", fade(.1))
                    .on("mouseout", fade(1));

        texts = svgnt.selectAll("text.label")
                    .data(mis1.nodes)
                    .enter().append("text")
                    .attr("class", "label")
                    .attr("fill", "black")
                    .text(function(d) {  return d.name;  });

        force.nodes(mis1.nodes).links(mis1.links).on("tick", tick).start();
        var linkedByIndex = {};
        mis1.links.forEach(function(d) {
            linkedByIndex[d.source.index + "," + d.target.index] = 1;
        });

        function isConnected(a, b) {
            return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index] || a.index == b.index;
        }

        function tick() {
            node.attr("cx", function(d, i) {
                return d.x = groupcenters[i].x;
            }).attr("cy", function(d, i) {
                return d.y = groupcenters[i].y;
            });

            link.attr("x1", function(d) {
                return d.source.x;
            }).attr("y1", function(d) {
                return d.source.y;
            }).attr("x2", function(d) {
                return d.target.x;
            }).attr("y2", function(d) {
                return d.target.y;
            });
            texts.attr("transform", function(d) {
                return "translate(" + d.x + "," + d.y + ")";
            });
        }

知道我做错了什么吗?图表显示正常,但没有任何缩放功能。

1 个答案:

答案 0 :(得分:2)

问题是,您将所有节点和链接直接附加到svg而不是g元素。由于缩放转换应用于visg元素),因此节点和链接不会缩放/平移。

所以代替下面的代码

var link = svgnt.selectAll("line")
        .data(mis1.links)
        .enter()
        .append("svg:line")
        .style("stroke","#ddd");

var node = svgnt.selectAll("circle")
        .data(mis1.nodes)
        .enter()
        .append("svg:circle")
---------------------- 
---------------------- 
----------------------     

试试这段代码。

var link = vis.selectAll("line")
        .data(mis1.links)
        .enter()
        .append("svg:line")
        .style("stroke","#ddd");

var node = vis.selectAll("circle")
        .data(mis1.nodes)
        .enter()
        .append("svg:circle")
---------------------- 
---------------------- 
----------------------