2013-08-22 87 views
3

我想用d3.js创建一个图表,显示项目之间的关系或链接。d3.js:链接相关的项目

的基本思路是这样的: enter image description here

当我悬停或点击的项目之一,相关项目突出

我看了d3.layout.tree https://github.com/mbostock/d3/wiki/Tree-Layout但似乎不同从我想要做的事情。

我看到这个小提琴:http://jsfiddle.net/bmdhacks/qsEbd/5/ 这似乎像它可能是在正确的方向开始

基础上摆弄,我建这个拨弄着我自己的数据集 http://jsfiddle.net/Ps4Fe/1/ 起初它看起来像它会工作。但后来我意识到,我在其他圈子上叠加了圈子,并且有多个副本......我明白了原因。

我建立数据的方式可能存在问题。这可以改变。

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" 
     } 
    ] 
}; 

我的想法是,我可以匹配每个产品类型下的'链接'与匹配的大小或行业类型。

我的JavaScript是在这里:

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}); 

主要的问题,我想的是,我基本上是从链接创建规模和行业的节点,而不是创造的全套节点,然后将它们连接起来。

如何布置3种类型(行业,产品,尺寸),然后创建产品和其他两种类型之间的链接?或者更确切地说,我在布置3种类型后如何创建链接?

谢谢!

+0

找到任何解决方案?如果你能分享,会很高兴。 – Fr0zenFyr

+0

对不起@ Fr0zenFyr,我没有解决这个问题。我可能会在几个月内回到它,然后再试一次。 – rolfsf

+0

感谢您的回复。我也在处理你的问题中几乎确切的事情。如果我在您面前找到解决方案,我会发布答案。 – Fr0zenFyr

回答

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,而不是在循环nodes然后nodeMap.values()呼叫在结束。

之后,nodes应该是一个可用于创建圆圈的独特节点的数组,并且links应该仍然包含与之前链接所有信息的所有信息。

+0

谢谢Scott!昨天晚上花了一些时间阅读后,我认为答案可能涉及.map(),但不知道如何。我昨天实际修改了我的数据集,因此我拥有节点和链接,并且每个节点都有一个唯一的ID,每个链接都有一个源和目标键。但是使用你的例子和旧数据,你的例子消除了重复的节点,但它的路径无处可去:http://jsfiddle.net/gdTae/1/越来越近! – rolfsf