4

I'm trying to create a graph with d3.js that shows relationships or links between items.

the basic idea is this: enter image description here

when I hover or click on one of the items, the related items highlight

I've looked at d3.layout.tree https://github.com/mbostock/d3/wiki/Tree-Layout but it seems different from what I'm trying to do.

I saw this fiddle: http://jsfiddle.net/bmdhacks/qsEbd/5/ which seemed like it might be a start in the right direction

Based on that fiddle, I built this fiddle with my own data set http://jsfiddle.net/Ps4Fe/1/ and at first it looked like it would work. But then I realized that I was getting circles overlaid on other circles, and multiple copies... and I see why.

There may be a problem in the way I built the data. That can be changed.

    var data = {
    "Product": [
        {
            "type": "product",
            "name": "Product 1",
            "links": [
                {
                    "name": "Industry 1",
                    "type": "industry",
                    "percent": 0.12,
                    "count": 149
                },
                {
                    "name": "Industry 2",
                    "type": "industry",
                    "percent": 0.18,
                    "count": 180
                },
                {
                    "name": "Industry 3",
                    "type": "industry",
                    "percent": 0.17,
                    "count": 152
                },
                {
                    "name": "Industry 4",
                    "type": "industry",
                    "percent": 0.16,
                    "count": 175
                },
                {
                    "name": "Industry 5",
                    "type": "industry",
                    "percent": 0.25,
                    "count": 21
                },
                {
                    "name": "Size A",
                    "type": "size",
                    "percent": 0.24,
                    "count": 21
                },
                {
                    "name": "Size B",
                    "type": "size",
                    "percent": 0.15,
                    "count": 49
                },
                {
                    "name": "Size C",
                    "type": "size",
                    "percent": 0.15,
                    "count": 83
                },
                {
                    "name": "Size D",
                    "type": "size",
                    "percent": 0.17,
                    "count": 128
                },
                {
                    "name": "Size E",
                    "type": "size",
                    "percent": 0.13,
                    "count": 241
                },
                {
                    "name": "Size F",
                    "type": "size",
                    "percent": 0.08,
                    "count": 161
                }            ]
        },
        {
            "type": "product",
            "name": "Product 2",
            "links": [
                {
                    "name": "Industry 1",
                    "type": "industry",
                    "percent": 0.06,
                    "count": 15
                },
                {
                    "name": "Industry 3",
                    "type": "industry",
                    "percent": 0.21,
                    "count": 52
                },
                {
                    "name": "Industry 5",
                    "type": "industry",
                    "percent": 0.15,
                    "count": 39
                },
                {
                    "name": "Size C",
                    "type": "size",
                    "percent": 0.28,
                    "count": 78
                },
                {
                    "name": "Size D",
                    "type": "size",
                    "percent": 0.13,
                    "count": 73
                }
            ]
        },
        {
            "type": "product",
            "name": "Product 3",
            "links": [
                {
                    "name": "Industry 4",
                    "type": "industry",
                    "percent": 0.18,
                    "count": 15
                },
                {
                    "name": "Industry 5",
                    "type": "industry",
                    "percent": 0.19,
                    "count": 52
                },
                {
                    "name": "Size A",
                    "type": "size",
                    "percent": 0.15,
                    "count": 3
                },
                {
                    "name": "Size D",
                    "type": "size",
                    "percent": 0.18,
                    "count": 55
                },
                {
                    "name": "Size E",
                    "type": "size",
                    "percent": 0.14,
                    "count": 47
                },
                {
                    "name": "Size F",
                    "type": "size",
                    "percent": 0.13,
                    "count": 24
                }
            ]
        },
        {
            "type": "product",
            "name": "Product 4",
            "links": [
                {
                    "name": "Industry 2",
                    "type": "industry",
                    "percent": 0.1,
                    "count": null
                },
                {
                    "name": "Industry 3",
                    "type": "industry",
                    "percent": 0.01,
                    "count": null
                },
                {
                    "name": "Size A",
                    "type": "size",
                    "percent": 0.21,
                    "count": null
                },
                {
                    "name": "Size B",
                    "type": "size",
                    "percent": 0.11,
                    "count": null
                },
                {
                    "name": "Size C",
                    "type": "size",
                    "percent": 0.18,
                    "count": null
                },
                {
                    "name": "Size D",
                    "type": "size",
                    "percent": 0.14,
                    "count": null
                }            
            ]
        },
        {
            "type": "product",
            "name": "Product 5",
            "links": [
                {
                    "name": "Industry 1",
                    "type": "industry",
                    "percent": 0.1,
                    "count": null
                },
                {
                    "name": "Industry 2",
                    "type": "industry",
                    "percent": 0.15,
                    "count": null
                },
                {
                    "name": "Industry 3",
                    "type": "industry",
                    "percent": 0.03,
                    "count": null
                },
                {
                    "name": "Industry 4",
                    "type": "industry",
                    "percent": 0.08,
                    "count": null
                },
                {
                    "name": "Size 2",
                    "type": "size",
                    "percent": 0.08,
                    "count": null
                },
                {
                    "name": "Size 3",
                    "type": "size",
                    "percent": 0.18,
                    "count": null
                },
                {
                    "name": "Size 5",
                    "type": "size",
                    "percent": 0.25,
                    "count": null
                }
            ]
        }
    ],
    "Industry": [
        {
            "type": "industry",
            "name": "Agriculture, Forestry & Fishery"
        },
        {
            "type": "industry",
            "name": "Arts & Entertainment"
        },
        {
            "type": "industry",
            "name": "Construction"
        },
        {
            "type": "industry",
            "name": "Educational Services"
        },
        {
            "type": "industry",
            "name": "Finance & Insurance"
        },
        {
            "type": "industry",
            "name": "Health Care & Social Assistance"
        },
        {
            "type": "industry",
            "name": "Manufacturing"
        },
        {
            "type": "industry",
            "name": "Mining"
        },
        {
            "type": "industry",
            "name": "Professional Services"
        },
        {
            "type": "industry",
            "name": "Public Administration"
        },
        {
            "type": "industry",
            "name": "Real Estate"
        },
        {
            "type": "industry",
            "name": "Retail Trade"
        },
        {
            "type": "industry",
            "name": "Services - Other"
        },
        {
            "type": "industry",
            "name": "Technology & Communication"
        },
        {
            "type": "industry",
            "name": "Transportation & Warehousing"
        },
        {
            "type": "industry",
            "name": "Utilities"
        },
        {
            "type": "industry",
            "name": "Wholesale Trade"
        }
    ],
    "Size": [
        {
            "type": "size",
            "name": "Size A"
        },
        {
            "type": "size",
            "name": "Size B"
        },
        {
            "type": "size",
            "name": "Size C"
        },
        {
            "type": "size",
            "name": "Size D"
        },
        {
            "type": "size",
            "name": "Size E"
        },
        {
            "type": "size",
            "name": "Size F"
        },
        {
            "type": "size",
            "name": "Size G"
        },
        {
            "type": "size",
            "name": "Size H"
        }
    ]
};

My thought was that I could match up the 'links' under each Product type with the matching Size or Industry types.

My javascript is here:

var width = 600,
    height = 600,
    margin = {top: 16, right: 16, bottom: 16, left: 16},
    radius = 10, 
    gap = 24;

var dProduct = data.Product;

// test layout
var nodes = [];
var links = [];
dProduct.forEach(function(d, i) {
    d.x = width/2;
    d.y = margin.top + gap*i;
    nodes.push(d);
    d.links.forEach(function(c, i) {
        if(c.type === 'industry'){
            c.x = margin.left;
            c.y = margin.top + gap * (i+1) -2*radius;
        }else if (c.type === 'size'){
            c.x = width-margin.right-radius*2;
            c.y = margin.top + gap * (i+1) -2*radius;
        }
        nodes.push(c);

        var a = {x:c.y, y:c.x};
        var b = {x:d.y, y:d.x};
        links.push({source: b, target: a});
    });
});

var color = d3.scale.category20();

var svg = d3.select("#chart").append("svg")
        .attr("width", width)
        .attr("height", height)
        .append("g");
var diagonal = d3.svg.diagonal()
        .projection(function(d) { return [d.y, d.x]; });

var link = svg.selectAll(".link")
        .data(links)
        .enter().append("path")
        .attr("class", "link")
        .attr("d", diagonal);

var circle = svg.selectAll(".circle")
        .data(nodes)
        .enter()
        .append("g")
        .attr("class", "circle");

var el = circle.append("circle")
        .attr("cx", function(d) {return d.x})
        .attr("cy", function(d) {return d.y})
        .attr("r", radius)
        .style("fill", function(d) {return color(d.name)})
        .append("title").text(function(d) {return d.name});

The main problem, I think is that I'm essentially creating the Size and Industry nodes from the links, rather than creating the full set of nodes and then linking them.

How can I layout the 3 types (Industry, Product, Size), and then create the links between the Products and the other two types? Or more precisely, how do I create the links after I layout the 3 types?

Thanks!

4

1 回答 1

0

如果我理解正确并且您说您的问题是您获得了多个节点副本,那么通过确保仅将节点添加到nodes数组中一次,这应该很容易解决。确保唯一性的一种方法是使用关联数组,例如d3.map

var nodeMap = d3.map();
var links = [];
dProduct.forEach(function(d, i) {
    d.x = width/2;
    d.y = margin.top + gap*i;
    nodeMap.set(d.name, d);
    d.links.forEach(function(c, i) {
        if(c.type === 'industry'){
            c.x = margin.left;
            c.y = margin.top + gap * (i+1) -2*radius;
        }else if (c.type === 'size'){
            c.x = width-margin.right-radius*2;
            c.y = margin.top + gap * (i+1) -2*radius;
        }
        nodeMap.set(c.name, c);

        var a = {x:c.y, y:c.x};
        var b = {x:d.y, y:d.x};
        links.push({source: b, target: a});
    });
});

var nodes = nodeMap.values();

请注意,与您所拥有的代码相比,此代码的唯一更改是在循环中使用nodeMap而不是在最后调用。nodesnodeMap.values()

在此之后,nodes应该是一组独特的节点,您可以使用它们来创建圆圈,并且links应该仍然包含与之前相同的所有信息以将所有内容连接起来。

于 2013-08-23T05:21:43.463 回答