d3.js:如何在此关系图中绘制和突出显示链接? [英] d3.js: How do I draw and highlight links in this relationship graph?

查看:84
本文介绍了d3.js:如何在此关系图中绘制和突出显示链接?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经尝试解决这个图形问题了两周了……对于D3.js来说还很新,所以看起来很简单的事情仍然让我难以理解.

I've been trying to solve this graph problem for a couple weeks now... still pretty new to D3.js, so things that seem like they might be simple still elude me.

以下是我正在尝试做的事情的说明:

Here's an illustration of what I'm trying to do:

目标:

  1. 我想显示行业节点/大小节点与 产品节点.

  1. I want to show relationships between Industry Nodes/Size Nodes and Product Nodes.

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

When I hover a Product node, I want to highlight the Link, Source (Industry or Size) and Target (Product) of each relevant relationship.

当我将鼠标悬停在行业"或规模"节点上时,我想突出显示它是所有相关产品的链接.

When I hover an Industry or Size Node, I want to highlight it's links to all relevant Products.

问题

  1. 如何绘制链接?我知道它某种程度上涉及使用d3.map ...但无法弄清楚.

  1. How do I draw the links? I know it somehow involves using d3.map... but can't figure it out.

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

How do I highlight the nodes and links (goals 2 and 3)?

如果有一种更好,更有效的方式来获得这种布局和行为,请让我知道-努力学习技巧!

If there is a better, more efficient way of getting this layout and behavior, please let me know - trying hard to learn the tricks!

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

The Fiddle renders the basic layout from a simplified set of data: 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();

感谢您的帮助!

推荐答案

好吧,由于我遇到了同样的问题,因此我尝试使此示例正常工作.为了后代,我也在这里回答.也许有人会遇到相同的问题或找到更简单的解决方案.
我对javascript还是很陌生(过去一周试图学一点),所以这可能不是最好的解决方案.文件和结果位于 jsfiddle 中.我不会提供完整的代码,而只会指出更改.

Ok so I tried to make this example work since I have the same sort of problem. For the sake of posterity I am answering here as well. Maybe someone will have the same problem or finds an easier solution.
I am fairly new to javascript (tried to learn a bit in the past week) so this may not be the best solution. The files and the result is available in jsfiddle. I'll not provide the whole codes and only point to the changes.

  • 为了能够添加任意数量的列,我更改了json文件,并将type替换为lvl级.我还用名为Nodes的类别替换了IndustriyProductsize.

  • In order to be able to add arbitrary number of columns I changed the json file and replaced the type with level lvl. I also replaced Industriy, Product and size with a category called Nodes.

在javascript文件中创建的svg中的每个矩形和直线都使用id进行设置,以便以后可以引用(更改颜色时).

Each rectangle and line in the svg created in the javascript file is setup with an id so that it can be referred to later (when changing its color).

相关代码是

  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是一个函数,该函数查找带有传递给它的名称的节点.

The method find used here is a function that finds the node with the name passed to it.

  • mouseovermouseout事件更新如下:

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

它使用方法mouse_action来接受起始节点及其状态(活动或不活动).在这种方法中,我们访问每个链接,对其进行处理并更改其状态.该方法在鼠标输入的节点上沿两个方向(左和右)遍历,而在其他节点上仅向左或向右遍历.

It uses a methods, mouse_action which accepts the starting node and the state it will be (active or inactive). In this method we visit each link, process it and change its state. The method traverses in both directions (left and right) on the node that the mouse entered and traverses only left or right on other nodes.

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

这篇关于d3.js:如何在此关系图中绘制和突出显示链接?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆