D3JS更具交互性的网络图节点菜单

时间:2014-11-25 18:23:57

标签: javascript d3.js graph

我想使用D3JS做netwok图,我已在jsFiddle准备了力导向图。 但是当网络越来越复杂时,图形变得非常混乱。所以我环顾四周,发现了d3js想要实现的东西。主页上此图表中的ZoomCharts是每个节点上的上下文菜单,子节点按需加载,并且可能在每个节点上显示另一个图表(工具提示)。

我在d3js开始了,所以我将很感激如何实现它。

  1. 向节点添加上下文菜单
  2. 当选择一些上下文菜单项时显示另一个图形(如饼图)
  3. 如果可以按需加载daata(当用户点击父节点时)..
  4. 如果您曾经见过这样的想法(一些示例代码),请分享!

    感谢您的建议!

    EDIT1: 我为菜单准备基础甜甜圈图表。我需要添加一些悬停操作,并通过数据集中的图标名称加载文本标签的图标。如果有人帮我这个,我会很高兴的。这个菜单可以帮助很多人。 Edit2 :我更新了菜单图表,现在支持悬停效果。现在它通过有用的结合力导向图。当有人点击节点饼图菜单显示时。

    var dataset = [
        {
            size: 2,
            label: "Item 1"
        },
        {
            size: 1,
            label: "Item 2"
        },    
        {
            size: 65,
            label: "Item 3"
        },    
        {
            size: 45,
            label: "Item 4"
        },    
        {
            size: 50,
            label: "Item 5"
        }
    ];
    
    var width = 460,
        height = 300,
        radius = Math.min(width, height) / 2;
    
    
    var color = d3.scale.category20();
    var pie = d3.layout.pie()
        .sort(null)
        .value(function(d) { return Object.keys(dataset).length; }); // zde je nutné zadat celkovou populaci - početz prvků v 
    
    // Menu
    
    // Arc setting
    var arc = d3.svg.arc()
        .innerRadius(radius - 100)
        .outerRadius(radius - 50);
    
    // Graph space
    var svg = d3.select("body").append("svg")
        .attr("width", width)
        .attr("height", height)
        .append("g")
        .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
    
    // Prepare graph and load data
    var g = svg.selectAll(".arc")
        .data(pie(dataset))
        .enter().append("g")
        .attr("class", "arc");
    
    // Add colors
    var path =  g.append("path")
        .attr("d", arc)
        .attr("fill", function (d) { return color(d.data.size);})
    
    // Add labels
    var asdfd =  g.append("text")
        .attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
        .attr("dy", ".35em")
        .style("text-anchor", "middle")
        .text(function(d) { return d.data.label; });
    
    var oldColor;
    
    // Add hover action
      path.on("mouseenter", function(d,i) {
                  console.log("mousein"+ d.data.label)
                  
                  var thisPath = d3.select(this);
                  
                      oldColor = thisPath.attr("fill"); // save old color
          
                      thisPath
                      .attr("fill", "blue")
                      .attr("cursor", "pointer")
                      .attr("class", "on");
         
          
      })
     
      path.on("mouseout", function(d) {
                     d3.select(this)
                     .attr("fill", oldColor)
                     .attr("class", "off");
       });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

    如果组合结果看起来像这样会很棒:

    enter image description here

    **我解决了大部分问题,这里是代码,但我有性能问题。如果有人可以帮助我会很高兴。图表滞后,我有箭头ind行的问题。 **

    var json = {
        "nodes": [{
            "id": -1146034065,
                "name": "/",
                "group": 0
        }, {
            "id": -990073683,
                "name": "/blog/",
                "group": 0
        }, {
            "id": -1724280020,
                "name": "/menu/",
                "group": 0
        }, {
            "id": 1176095248,
                "name": "/napojovy-listek/",
                "group": 0
        }, {
            "id": -2085082741,
                "name": "/fotogalerie/",
                "group": 0
        }, {
            "id": 883542796,
                "name": "/rezervace/",
                "group": 0
        }, {
            "id": 369131020,
                "name": "/kontakt/",
                "group": 0
        }, {
            "id": -1276353015,
                "name": "/en/",
                "group": 0
        }, {
            "id": -1557747058,
                "name": "/o-nas/",
                "group": 404
        }, {
            "id": 890427810,
                "name": "/en/about-us/",
                "group": 0
        }, {
            "id": -978700858,
                "name": "/en/menu-2/",
                "group": 0
        }, {
            "id": 1436673749,
                "name": "/en/napojovy-listek/",
                "group": 0
        }, {
            "id": -489730654,
                "name": "/en/photograph/",
                "group": 0
        }, {
            "id": -1461616187,
                "name": "/en/reservation/",
                "group": 0
        }, {
            "id": 1520755615,
                "name": "/en/contact/",
                "group": 0
        }, {
            "id": 37644686,
                "name": "/en//kontakt/",
                "group": 0
        }, {
            "id": 1131720527,
                "name": "/en//o-nas/",
                "group": 404
        }],
            "links": [{
            "source": -990073683,
                "target": -1146034065,
                "value": 1
        }, {
            "source": -1724280020,
                "target": -1146034065,
                "value": 1
        }, {
            "source": 1176095248,
                "target": -1146034065,
                "value": 1
        }, {
            "source": -2085082741,
                "target": -1146034065,
                "value": 1
        }, {
            "source": 883542796,
                "target": -1146034065,
                "value": 1
        }, {
            "source": 369131020,
                "target": -1146034065,
                "value": 1
        }, {
            "source": -1276353015,
                "target": -1146034065,
                "value": 1
        }, {
            "source": -1557747058,
                "target": -1146034065,
                "value": 1
        }, {
            "source": 890427810,
                "target": -990073683,
                "value": 1
        }, {
            "source": -978700858,
                "target": -1724280020,
                "value": 1
        }, {
            "source": 1436673749,
                "target": 1176095248,
                "value": 1
        }, {
            "source": -489730654,
                "target": -2085082741,
                "value": 1
        }, {
            "source": -1461616187,
                "target": 883542796,
                "value": 1
        }, {
            "source": 1520755615,
                "target": 369131020,
                "value": 1
        }, {
            "source": 37644686,
                "target": -1276353015,
                "value": 1
        }, {
            "source": 1131720527,
                "target": -1276353015,
                "value": 1
        }, {
            "source": -1146034065,
                "target": -1146034065,
                "count": 1,
                "value": 1
        }, {
            "source": -1146034065,
                "target": -990073683,
                "count": 1,
                "value": 1
        }, {
            "source": -1146034065,
                "target": -1724280020,
                "count": 3,
                "value": 1
        }, {
            "source": -1146034065,
                "target": 1176095248,
                "count": 3,
                "value": 1
        }, {
            "source": -1146034065,
                "target": -2085082741,
                "count": 3,
                "value": 1
        }, {
            "source": -1146034065,
                "target": 883542796,
                "count": 3,
                "value": 1
        }, {
            "source": -1146034065,
                "target": 369131020,
                "count": 3,
                "value": 1
        }, {
            "source": -1146034065,
                "target": -1276353015,
                "count": 1,
                "value": 1
        }, {
            "source": -1146034065,
                "target": -1557747058,
                "count": 2,
                "value": 1
        }, {
            "source": -990073683,
                "target": -1146034065,
                "count": 1,
                "value": 1
        }, {
            "source": -990073683,
                "target": -990073683,
                "count": 1,
                "value": 1
        }, {
            "source": -990073683,
                "target": -1724280020,
                "count": 1,
                "value": 1
        }, {
            "source": -990073683,
                "target": 1176095248,
                "count": 1,
                "value": 1
        }, {
            "source": -990073683,
                "target": -2085082741,
                "count": 1,
                "value": 1
        }, {
            "source": -990073683,
                "target": 883542796,
                "count": 1,
                "value": 1
        }, {
            "source": -990073683,
                "target": 369131020,
                "count": 1,
                "value": 1
        }, {
            "source": -990073683,
                "target": 890427810,
                "count": 1,
                "value": 1
        }, {
            "source": -1724280020,
                "target": -1146034065,
                "count": 1,
                "value": 1
        }, {
            "source": -1724280020,
                "target": -990073683,
                "count": 1,
                "value": 1
        }, {
            "source": -1724280020,
                "target": -1724280020,
                "count": 1,
                "value": 1
        }, {
            "source": -1724280020,
                "target": 1176095248,
                "count": 1,
                "value": 1
        }, {
            "source": -1724280020,
                "target": -2085082741,
                "count": 1,
                "value": 1
        }, {
            "source": -1724280020,
                "target": 883542796,
                "count": 1,
                "value": 1
        }, {
            "source": -1724280020,
                "target": 369131020,
                "count": 1,
                "value": 1
        }, {
            "source": -1724280020,
                "target": -978700858,
                "count": 1,
                "value": 1
        }, {
            "source": 1176095248,
                "target": -1146034065,
                "count": 1,
                "value": 1
        }, {
            "source": 1176095248,
                "target": -990073683,
                "count": 1,
                "value": 1
        }, {
            "source": 1176095248,
                "target": -1724280020,
                "count": 1,
                "value": 1
        }, {
            "source": 1176095248,
                "target": 1176095248,
                "count": 1,
                "value": 1
        }, {
            "source": 1176095248,
                "target": -2085082741,
                "count": 1,
                "value": 1
        }, {
            "source": 1176095248,
                "target": 883542796,
                "count": 1,
                "value": 1
        }, {
            "source": 1176095248,
                "target": 369131020,
                "count": 1,
                "value": 1
        }, {
            "source": 1176095248,
                "target": 1436673749,
                "count": 1,
                "value": 1
        }, {
            "source": -2085082741,
                "target": -1146034065,
                "count": 1,
                "value": 1
        }, {
            "source": -2085082741,
                "target": -990073683,
                "count": 1,
                "value": 1
        }, {
            "source": -2085082741,
                "target": -1724280020,
                "count": 1,
                "value": 1
        }, {
            "source": -2085082741,
                "target": 1176095248,
                "count": 1,
                "value": 1
        }, {
            "source": -2085082741,
                "target": -2085082741,
                "count": 1,
                "value": 1
        }, {
            "source": -2085082741,
                "target": 883542796,
                "count": 1,
                "value": 1
        }, {
            "source": -2085082741,
                "target": 369131020,
                "count": 1,
                "value": 1
        }, {
            "source": -2085082741,
                "target": -489730654,
                "count": 1,
                "value": 1
        }, {
            "source": 883542796,
                "target": -1146034065,
                "count": 1,
                "value": 1
        }, {
            "source": 883542796,
                "target": -990073683,
                "count": 1,
                "value": 1
        }, {
            "source": 883542796,
                "target": -1724280020,
                "count": 1,
                "value": 1
        }, {
            "source": 883542796,
                "target": 1176095248,
                "count": 1,
                "value": 1
        }, {
            "source": 883542796,
                "target": -2085082741,
                "count": 1,
                "value": 1
        }, {
            "source": 883542796,
                "target": 883542796,
                "count": 1,
                "value": 1
        }, {
            "source": 883542796,
                "target": 369131020,
                "count": 1,
                "value": 1
        }, {
            "source": 883542796,
                "target": -1461616187,
                "count": 1,
                "value": 1
        }, {
            "source": 369131020,
                "target": -1146034065,
                "count": 1,
                "value": 1
        }, {
            "source": 369131020,
                "target": -990073683,
                "count": 1,
                "value": 1
        }, {
            "source": 369131020,
                "target": -1724280020,
                "count": 1,
                "value": 1
        }, {
            "source": 369131020,
                "target": 1176095248,
                "count": 1,
                "value": 1
        }, {
            "source": 369131020,
                "target": -2085082741,
                "count": 1,
                "value": 1
        }
    
        ]
    }
    
    
    var width = 960,
        height = 700
    
    var svg = d3.select("body").append("svg")
        .attr("width", width)
        .attr("height", height);
        // Per-type markers, as they don't inherit styles.
        svg.append("defs").selectAll("marker")
        .data(["a"])
        .enter().append("marker")
        .attr("id", function(d) { return d; })
        .attr("viewBox", "0 -5 10 10")
        .attr("refX", 15)
        .attr("refY", -1.5)
        .attr("markerWidth", 6)
        .attr("markerHeight", 6)
        .attr("orient", "auto")
        .append("path")
        .attr("d", "M0,-5L10,0L0,5");
    
    var edges = [];
    var fill = d3.scale.category10();
    
    json.links.forEach(function (e) {
        // Get the source and target nodes
        var sourceNode = json.nodes.filter(function (n) {
            return n.id === e.source;
        })[0],
            targetNode = json.nodes.filter(function (n) {
                return n.id === e.target;
            })[0],
            count = e.count;
    
        // Add the edge to the array
        edges.push({
            source: sourceNode,
            target: targetNode,
            count: count,
            type: "a"
        });
    });
    
    var force = d3.layout.force()
        .gravity(0.01)
        .distance(500)
        .charge(-300)
        .linkDistance(300)
        .size([width, height])
        .nodes(json.nodes)
        .links(edges)
        .start();
    
    
    
    var link =  svg.append("g").selectAll("link")
        .data(edges)
        .enter().append("path")
        .attr("class", "link")
        //.attr("marker-end", function(d) { return "url(#" + d.targetNode + ")"; })
        .style("stroke-width", function (d) {
        return Math.sqrt(d.count * 1, 5);
    });
    
    
    
    // Přidáme k uzlu kontextové menu a zvýrazníme sousedy
    var node = svg.selectAll("node")
        .data(json.nodes)
        .enter().append("g")
        .attr("class", "node")
        .style("fill", function (d) {
        return fill(d.group);
    })
        .call(force.drag).on("mouseover", fade(.1)).on("mouseout", fade(1))
        .on("click", function (d, i) {
            svg.selectAll(".node").style("fill", function (d) { return fill(d.group);});
            d3.select(".menu").remove();
            
        var thisNode = d3.select(this);
        thisNode.attr('r', 25).style("fill", "lightcoral");
    
        var menuDataSet = [{
            size: 2,
            label: "Item 1"
        }, {
            size: 1,
            label: "Item 2"
        }, {
            size: 65,
            label: "Item 3"
        }, {
            size: 45,
            label: "Item 4"
        }, {
            size: 50,
            label: "Item 5"
        }];
    
        // Barvy menu
        var color = d3.scale.category20();
        var pie = d3.layout.pie()
            .sort(null)
            .value(function (d) {
            return Object.keys(menuDataSet).length;
        }); // zde je nutné zadat celkovou populaci - početz prvků v 
    
        // Menu
        var widthMenu = 180,
            heightMenu = 180,
            radiusMenu = Math.min(widthMenu, heightMenu) / 2;
    
        // Arc setting
        var arc = d3.svg.arc()
            .innerRadius(radiusMenu - 70)
            .outerRadius(radiusMenu - 25);
    
        // Graph space
        var svgMenu = thisNode.append("svg")
            .attr("width", widthMenu)
            .attr("height", heightMenu)
            .attr("class","menu")
            .attr("x", -90)
            .attr("y", -90)
            .append("g")
            .attr("transform", "translate(" + widthMenu / 2 + "," + heightMenu / 2 + ")");
    
    
        // Prepare graph and load data
        var g = svgMenu.selectAll(".arc")
            .data(pie(menuDataSet))
            .enter().append("g")
            .attr("class", "arc");
    
        // Add colors
        var path = g.append("path")
            .attr("d", arc)
            .attr("fill", function (d) {
            return color(d.data.size);
        })
    
        // Add labels
        var asdfd = g.append("text")
            .attr("transform", function (d) {
            return "translate(" + arc.centroid(d) + ")";
        })
            .attr("dy", ".35em")
            .style("text-anchor", "middle")
            .text(function (d) {
            return d.data.label;
        });
    
        // Add hover action
        path.on("mouseenter", function (d, i) {
    
            var thisPath = d3.select(this);
            thisPath.attr("fill", "blue")
                .attr("cursor", "pointer")
                .attr("class", "on");
        })
    
        path.on("mouseout", function (d) {
            d3.select(this)
                .attr("fill", function (d) {
                return color(d.data.size);
            })
                .attr("class", "off");
        });
    
    });
    
    
    
    
    
    /*
      node.append("image")
          .attr("xlink:href", "https://github.com/favicon.ico")
          .attr("x", -8)
          .attr("y", -8)
          .attr("width", 16)
          .attr("height", 16);
    */
    node.append("circle").attr("r", 10);
    
    node.append("text")
        .attr("dx", 12)
        .attr("dy", ".35em")
        .text(function (d) {
        return d.name
    });
    
    // přidá popisky k hranám
    var labels = svg.selectAll('text')
        .data(edges)
        .enter().append('text')
        .attr("x", function (d) {
        return (d.source.y + d.target.y) / 2;
    })
        .attr("y", function (d) {
        return (d.source.x + d.target.x) / 2;
    })
        .attr("text-anchor", "middle")
        .text(function (d) {
        return d.count;
    });
    
    
    force.on("tick", function () {
    
        link.attr("d", function linkArc(d) {
      var dx = d.target.x - d.source.x,
          dy = d.target.y - d.source.y,
          dr = Math.sqrt(dx * dx + dy * dy);
      return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
    }
    );
        
        node.attr("transform", function (d) {
            return "translate(" + d.x + "," + d.y + ")";
        });
    
        labels.attr("x", function (d) {
            return (d.source.x + d.target.x + 10) / 2;
        })
            .attr("y", function (d) {
            return (d.source.y + d.target.y + 10) / 2;
        })
    
    
    });
    
    
    
    function transform(d) {
      return "translate(" + d.x + "," + d.y + ")";
    }
    
    var linkedByIndex = {};
    edges.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 fade(opacity) {
        return function (d) {
    
            // přidá popisky k hranám
            var labels = svg.selectAll('text')
                .data(edges)
                .enter().append('text')
                .attr("x", function (o) {
                return (o.source.y + o.target.y) / 2;
            })
                .attr("y", function (o) {
                return (o.source.x + o.target.x) / 2;
            })
                .attr("text-anchor", "middle")
                .text(function (o) {
                return o.count;
            });
    
            node.style("stroke-opacity", function (o) {
                thisOpacity = isConnected(d, o) ? 1 : opacity;
                this.setAttribute('fill-opacity', thisOpacity);
                return thisOpacity;
            });
    
            link.style("stroke-opacity", function (o) {
                return o.source === d || o.target === d ? 1 : opacity;
            });
        };
    }
    body {
        font-family:"Helvetica Neue", Helvetica, Arial, sans-serif;
        margin: auto;
        position: relative;
        width: 960px;
    }
    .link {
      fill: none;
      stroke: #666;
      stroke-width: 1.5px;
      stroke-dasharray: 0,4 1;
    }
    
    text {
        font: 10px sans-serif;
    }
    form {
        position: absolute;
        right: 10px;
        top: 10px;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

0 个答案:

没有答案