1

几个星期以来,我一直在尝试解决这个图形问题......对于 D3.js 来说还是很新的东西,所以看起来很简单的事情仍然让我难以理解。

这是我正在尝试做的一个说明:

关系图

目标

  1. 我想显示行业节点/尺寸节点和产品节点之间的关系。

  2. 当我悬停产品节点时,我想突出显示每个相关关系的链接、来源(行业或规模)和目标(产品)。

  3. 当我悬停行业或规模节点时,我想突出显示它与所有相关产品的链接。

问题

  1. 如何绘制链接?我知道它以某种方式涉及使用 d3.map ......但无法弄清楚。

  2. 如何突出显示节点和链接(目标 2 和 3)?

  3. 如果有更好、更有效的方法来获得这种布局和行为,请告诉我——努力学习技巧!

Fiddle从一组简化的数据中呈现基本布局:http: //jsfiddle.net/9hGbD/

数据当前如下所示:

    var data = {
    "Product": [
        {
            "type": "product",
            "name": "Product 1"
        },
        {
            "type": "product",
            "name": "Product 2"
        },
        {
            "type": "product",
            "name": "Product 3"
        },
        {
            "type": "product",
            "name": "Product 4"
        },
        {
            "type": "product",
            "name": "Product 5"
        }
    ],
    "Industry": [

        {
            "type": "industry",
            "name": "Industry 1"
        },
        {
            "type": "industry",
            "name": "Industry 2"
        },
        {
            "type": "industry",
            "name": "Industry 3"
        },
        {
            "type": "industry",
            "name": "Industry 4"
        },
        {
            "type": "industry",
            "name": "Industry 5"
        }
    ],
    "Size": [
        {
            "type": "size",
            "name": "Size 1"
        },
        {
            "type": "size",
            "name": "Size 2"
        },
        {
            "type": "size",
            "name": "Size 3"
        },
        {
            "type": "size",
            "name": "Size 4"
        },
        {
            "type": "size",
            "name": "Size 5"
        }
    ],
    "links": [
        {
            "source": "Industry 1",
            "target": "Product 1"
        },
        {
            "source": "Industry 3",
            "target": "Product 1"
        },
        {
            "source": "Industry 5",
            "target": "Product 1"
        },
        {
            "source": "Industry 2",
            "target": "Product 2"
        },
        ...etc..
    ]
};

我正在使用的 javascript如下所示:

function renderRelationshipGraph(){

        var width = 800,
            boxWidth = 200,
            boxHeight = 20,
            gap = 4,
            margin = {top: 16, right: 16, bottom: 16, left: 16},
            height = (data.Product.length * (boxHeight + gap)) + margin.top + margin.bottom;

        var pNodes = [];
        var iNodes = [];
        var sNodes = [];
        var links = [];

        data.Product.forEach(function(d, i) {
            d.x = ((width-margin.left-margin.right)/3)/2 - boxWidth/2;
            d.y = margin.top + (boxHeight+ 4)*i;
            pNodes.push(d);
        });

        data.Industry.forEach(function(d, i) {
            d.x = 0;
            d.y = margin.top + (boxHeight+ 4)*i; 
            iNodes.push(d);
        });

        data.Size.forEach(function(d, i) {
            d.x = ((width-margin.left-margin.right)/3) - boxWidth;
            d.y = margin.top + (boxHeight+ 4)*i; 
            sNodes.push(d);
        });

        var svg = d3.select("#graph").append("svg")
                .attr("width", width)
                .attr("height", height)
                .append("g");

        svg.append("g")
                .attr("class", "industries");


        svg.append("g")
                .attr("class", "products")
                .attr("transform", "translate("+ (width-margin.left-margin.right)/3 + ", 0)"); 

        svg.append("g")
                .attr("class", "sizes")
                .attr("transform", "translate("+ 2*((width-margin.left-margin.right)/3) + ", 0)"); 

        var products = svg.select(".products");
        var product = products.selectAll("g")
                .data(pNodes)
                .enter()
                .append("g")
                .attr("class", "unit");

                product.append("rect")
                .attr("x", function(d) {return d.x;})
                .attr("y", function(d) {return d.y;})
                .attr("width", boxWidth)
                .attr("height", boxHeight)
                .attr("class", "product")
                .attr("rx", 6)
                .attr("ry", 6)
                .on("mouseover", function() { d3.select(this).classed("active", true); })
                .on("mouseout", function() { d3.select(this).classed("active", false); });

                product.append("text")
                .attr("class", "label")
                .attr("x", function(d) {return d.x + 14;})
                .attr("y", function(d) {return d.y + 15;})
                .text(function(d) {return d.name;});

        var industries = svg.select(".industries");
        var industry = industries.selectAll("g")
                .data(iNodes)
                .enter()
                .append("g")
                .attr("class", "unit");

                industry.append("rect")
                .attr("x", function(d) {return d.x;})
                .attr("y", function(d) {return d.y;})
                .attr("width", boxWidth)
                .attr("height", boxHeight)
                .attr("class", "industry")
                .attr("rx", 6)
                .attr("ry", 6)
                .on("mouseover", function() { d3.select(this).classed("active", true); })
                .on("mouseout", function() { d3.select(this).classed("active", false); });

                industry.append("text")
                .attr("class", "label")
                .attr("x", function(d) {return d.x + 14;})
                .attr("y", function(d) {return d.y + 15;})
                .text(function(d) {return d.name;});

        var sizes = svg.select(".sizes");
        var size = sizes.selectAll("g")
                .data(sNodes)
                .enter()
                .append("g")
                .attr("class", "unit");

                size.append("rect")
                .attr("x", function(d) {return d.x;})
                .attr("y", function(d) {return d.y;})
                .attr("width", boxWidth)
                .attr("height", boxHeight)
                .attr("class", "size")
                .attr("rx", 6)
                .attr("ry", 6)
                .on("mouseover", function() { d3.select(this).classed("active", true); })
                .on("mouseout", function() { d3.select(this).classed("active", false); });

                size.append("text")
                .attr("class", "label")
                .attr("x", function(d) {return d.x + 14;})
                .attr("y", function(d) {return d.y + 15;})
                .text(function(d) {return d.name;});
    }

    renderRelationshipGraph();

感谢您对此的帮助!

4

1 回答 1

2

好的,因为我遇到了同样的问题,所以我试图让这个例子工作。为了后代,我也在这里回答。也许有人会遇到同样的问题或找到更简单的解决方案。
我对javascript相当陌生(在过去一周尝试学习一点),所以这可能不是最好的解决方案。文件和结果在jsfiddle中可用。我不会提供整个代码,只指出更改。

  • 为了能够添加任意数量的列,我更改了json文件并将其替换为typelevel lvl。我也换成了IndustriyProductsize用一个类叫Nodes

  • 在 javascript 文件中创建的每个矩形和线svg都设置了一个id,以便以后可以引用它(更改其颜色时)。

相关代码是

  data.Nodes.forEach(function (d, i) {
      d.x = margin.left + d.lvl * (boxWidth + gap.width);
      d.y = margin.top + (boxHeight + gap.height) * count[d.lvl];
      d.id = "n" + i;
      count[d.lvl] += 1;
      Nodes.push(d);
  });

  data.links.forEach(function (d) {
      links.push({
         source: find(d.source),
         target: find(d.target),
         id: "l" + find(d.source).id + find(d.target).id
      });
  });

这里使用的方法find是一个函数,它查找传递给它的名称的节点。

  • mouseover事件mouseout更新如下:

     .on("mouseover", function () {
         mouse_action(d3.select(this).datum(), true, true);
     })
     .on("mouseout", function () {
         mouse_action(d3.select(this).datum(), false, true);
     });
    

它使用一种方法,mouse_action该方法接受起始节点和它将处于的状态(活动或非活动)。在这种方法中,我们访问每个链接,对其进行处理并更改其状态。该方法在鼠标进入的节点上双向(左右)遍历,在其他节点上只向左或向右遍历。

function mouse_action(val, stat, direction) {
    "use strict";
    d3.select("#" + val.id).classed("active", stat);

    links.forEach(function (d) {
        if (direction == "root") {
            if (d.source.id === val.id) {
                d3.select("#" + d.id).moveToFront().classed("activelink", stat); // change link color
                d3.select("#" + d.id).moveToFront().classed("link", !stat); // change link color
                if (d.target.lvl < val.lvl)
                    mouse_action(d.target, stat, "left");
                else if (d.target.lvl > val.lvl)
                    mouse_action(d.target, stat, "right");
            }
            if (d.target.id === val.id) {
                d3.select("#" + d.id).moveToFront().classed("activelink", stat); // change link color
                d3.select("#" + d.id).moveToFront().classed("link", !stat); // change link color
                if (direction == "root") {
                    if(d.source.lvl < val.lvl)
                        mouse_action(d.source, stat, "left");
                    else if (d.source.lvl > val.lvl)
                        mouse_action(d.source, stat, "right");
                }
            }
        }else if (direction == "left") {
            if (d.source.id === val.id && d.target.lvl < val.lvl) {
                d3.select("#" + d.id).moveToFront().classed("activelink", stat); // change link color
                d3.select("#" + d.id).moveToFront().classed("link", !stat); // change link color
                mouse_action(d.target, stat, direction);
            }
            if (d.target.id === val.id && d.source.lvl < val.lvl) {
                d3.select("#" + d.id).moveToFront().classed("activelink", stat); // change link color
                d3.select("#" + d.id).moveToFront().classed("link", !stat); // change link color
                mouse_action(d.source, stat, direction);
            }
        }else if (direction == "right") {
            if (d.source.id === val.id && d.target.lvl > val.lvl) {
                d3.select("#" + d.id).moveToFront().classed("activelink", stat); // change link color
                d3.select("#" + d.id).moveToFront().classed("link", !stat); // change link color
                mouse_action(d.target, stat, direction);
            }
            if (d.target.id === val.id && d.source.lvl > val.lvl) {
                d3.select("#" + d.id).moveToFront().classed("activelink", stat); // change link color
                d3.select("#" + d.id).moveToFront().classed("link", !stat); // change link color
                mouse_action(d.source, stat, direction);
            }
        }
    });
}
于 2016-03-13T14:47:35.580 回答