JS/d3.js:突出显示相邻链接的步骤 [英] JS / d3.js: Steps to Highlighting of adjacent links

查看:70
本文介绍了JS/d3.js:突出显示相邻链接的步骤的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

美好的一天

我对此项目的较早问题是:

D3.js:动态根据相同的json值生成源和目标

我是d3.js的新手,尤其是在数据处理和节点图领域..我想问几个有关创建节点图的数据处理问题.在执行我的项目时,这是我遇到的几个问题,导致了几个问题:

1)源值和目标值在本质上是否必须唯一?

如果源/目标值不唯一,链接会起作用吗?

2)一种突出显示/更改连接到当前所选节点的链接的属性的方法

到目前为止,我只能使用以下方式更改当前节点的属性:

var simulation = d3.forceSimulation(graphData)
.force("charge", d3.forceManyBody().strength(-300))
.force("link", d3.forceLink().id(function(d) { return d[idSel]; }).distance(70))
.force("x", d3.forceX(width/2))
.force("y", d3.forceY(height/2))
.on("tick", ticked);

var g = svg.append("g"),
    link = g.append("g").attr("stroke-width", 1.5).selectAll(".link"),
    node = g.append("g").attr("stroke-width", 1.5).selectAll(".node");

simulation.nodes(graphData);
simulation.force("link").links(links);

link = link
    .data(links)
    .enter().append("line")
    .attr("class", "link");
    node = node
    .data(graphData)
    .enter().append("circle")
    .attr("class", "node")
    .attr("r", 6)
    .style("fill", function(d, i) { return colors(d[idSel]); })
    .on("click", function (d, i, l) {

        //Node Effect - Change only selected node's size        
        d3.selectAll(".node").attr("r", 6);
        d3.select(this).attr("r", 12);

        //Link Effect - Highlight adjacent Links
        ... Need help here ...

    });

function ticked() 
{
    link.attr("x1", function(d) { return d.source.x; })
        .attr("y1", function(d) { return d.source.y; })
        .attr("x2", function(d) { return d.target.x; })
        .attr("y2", function(d) { return d.target.y; });

    node.attr("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; });
}   

我从以下示例中获得了仿真示例: http://bl.ocks.org/mbostock/1095795 但是,我确实知道这也是低效的,但是鉴于我对d3的了解有限,我没有其他办法可以做到这一点.

  • 我周围有个很好的例子来学习如何突出显示链接吗?
  • 另外,我看到我必须使用:

    函数restart() { node.exit().remove(); link.exit().remove(); Simulation.nodes(节点); Simulation.force("link").links(links); Simulation.alpha(1).restart(); }

要重新启动仿真,否则任何错误都将导致程序无法计算x/y值.但是,当我将此代码实现为重新启动功能时,新创建的节点不再具有x/y值.我做错了吗?

对于这个模糊的问题,我们深表歉意.任何指导都将不胜感激.谢谢SO社区! :)

解决方案

仅回答有关如何突出显示链接的问题(由于您未提供links数组,因此以下基于您的先前的代码):

node.on("click", function(d) {
    var thisNode = d.id

    d3.selectAll(".circleNode").attr("r", 6);
    d3.select(this).attr("r", 12);

    link.attr("opacity", function(d) {
        return (d.source.id == thisNode || d.target.id == thisNode) ? 1 : 0.1
    });

});

此代码的作用是什么?

首先,我们获得被点击节点的ID:

var thisNode = d.id

然后,我们扫描链接以查看源或目标是否具有相同的ID:

(d.source.id == thisNode || d.target.id == thisNode)

如果是这样,我们使用三元运算符设置不透明度:

(condition) ? 1 : 0.1

这是演示,单击节点:

 var nodes = [{
    "id": "red",
    "value": "1"
}, {
    "id": "orange",
    "value": "2"
}, {
    "id": "yellow",
    "value": "3"
}, {
    "id": "green",
    "value": "1"
}, {
    "id": "blue",
    "value": "1"
}, {
    "id": "violet",
    "value": "3"
},{
    "id": "white",
    "value": "1"
},{
    "id": "gray",
    "value": "1"
},{
    "id": "teal",
    "value": "3"
}
];

var links = [];

for (var i = 0; i < nodes.length; i++) {
    for (var j = i + 1; j < nodes.length; j++) {
        if (nodes[i].value === nodes[j].value) {
            links.push({
                source: nodes[i].id,
                target: nodes[j].id
            });
        }
    }
};

var width = 300,
    height = 300;

var svg = d3.select("body")
    .append("svg")
    .attr("width", width)
    .attr("height", height);

var simulation = d3.forceSimulation()
    .force("link", d3.forceLink().id(function(d) {
        return d.id;
    }).distance(50))
    .force("charge", d3.forceManyBody())
    .force("center", d3.forceCenter(width / 2, height / 2));

var link = svg.append("g")
    .attr("class", "links")
    .selectAll("line")
    .data(links)
    .enter().append("line")
    .attr("stroke-width", 1)
    .attr("stroke", "gray")
    .attr("fill", "none");

var node = svg.append("g")
    .attr("class", "nodes")
    .selectAll("circle")
    .data(nodes)
    .enter().append("circle")
    .attr("r", 6)
    .attr("class", "circleNode")
    .attr("stroke", "gray")
    .attr("fill", function(d) {
        return d.id;
    });

node.on("click", function(d) {
    var thisNode = d.id

    d3.selectAll(".circleNode").attr("r", 6);
    d3.select(this).attr("r", 12);

    link.attr("opacity", function(d) {
        return (d.source.id == thisNode || d.target.id == thisNode) ? 1 : 0.1
    });

});

simulation
    .nodes(nodes)
    .on("tick", ticked);

simulation.force("link")
    .links(links);

function ticked() {
    link
        .attr("x1", function(d) {
            return d.source.x;
        })
        .attr("y1", function(d) {
            return d.source.y;
        })
        .attr("x2", function(d) {
            return d.target.x;
        })
        .attr("y2", function(d) {
            return d.target.y;
        });

    node
        .attr("cx", function(d) {
            return d.x;
        })
        .attr("cy", function(d) {
            return d.y;
        });
} 

 <script src="https://d3js.org/d3.v4.min.js"></script> 

Good day,

My earlier question for this project would be:

D3.js: Dynamically generate source and target based on identical json values

I am new to d3.js, especially in the data manipulation and node graphs area.. I would like to ask several questions regarding data manipulation with regards to creating node graphs. While carrying out my project, here are several problems I have encountered, leading to several questions:

1) Must the source and target values be unique in nature?

Will the linking work if the source/target values are non-unique?

2) A way to highlight/change attributes of links connected to the current selected node

So far, I am only able to change the current node's properties using:

var simulation = d3.forceSimulation(graphData)
.force("charge", d3.forceManyBody().strength(-300))
.force("link", d3.forceLink().id(function(d) { return d[idSel]; }).distance(70))
.force("x", d3.forceX(width/2))
.force("y", d3.forceY(height/2))
.on("tick", ticked);

var g = svg.append("g"),
    link = g.append("g").attr("stroke-width", 1.5).selectAll(".link"),
    node = g.append("g").attr("stroke-width", 1.5).selectAll(".node");

simulation.nodes(graphData);
simulation.force("link").links(links);

link = link
    .data(links)
    .enter().append("line")
    .attr("class", "link");
    node = node
    .data(graphData)
    .enter().append("circle")
    .attr("class", "node")
    .attr("r", 6)
    .style("fill", function(d, i) { return colors(d[idSel]); })
    .on("click", function (d, i, l) {

        //Node Effect - Change only selected node's size        
        d3.selectAll(".node").attr("r", 6);
        d3.select(this).attr("r", 12);

        //Link Effect - Highlight adjacent Links
        ... Need help here ...

    });

function ticked() 
{
    link.attr("x1", function(d) { return d.source.x; })
        .attr("y1", function(d) { return d.source.y; })
        .attr("x2", function(d) { return d.target.x; })
        .attr("y2", function(d) { return d.target.y; });

    node.attr("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; });
}   

I have gotten the simulation example from: http://bl.ocks.org/mbostock/1095795 However, I do understand this is inefficient as well, but I have no other way to do it given my limited knowledge on d3..

  • Is there a good example around for me to learn how to highlight the links as well?
  • Also, I see that I have to use:

    function restart() { node.exit().remove(); link.exit().remove(); simulation.nodes(nodes); simulation.force("link").links(links); simulation.alpha(1).restart(); }

To restart the simulation, else any errors will result in the program unable to calculate the x/y values. However, when I implement this code as a restart function, the newly created nodes do not have x/y values anymore.. Am i doing something wrong?

So sorry for the vague question.. any guidance is very much appreciated. Thank you SO Community! :)

解决方案

Answering only the question about how to highlight the links (since you didn't provide the links array, here is an answer based on your previous code):

node.on("click", function(d) {
    var thisNode = d.id

    d3.selectAll(".circleNode").attr("r", 6);
    d3.select(this).attr("r", 12);

    link.attr("opacity", function(d) {
        return (d.source.id == thisNode || d.target.id == thisNode) ? 1 : 0.1
    });

});

What does this code do?

First, we get the id of the clicked node:

var thisNode = d.id

Then, we scan the links to see if the source or the target has the same id:

(d.source.id == thisNode || d.target.id == thisNode)

If that is true, we set the opacity using a ternary operator:

(condition) ? 1 : 0.1

Here is the demo, click on the nodes:

var nodes = [{
    "id": "red",
    "value": "1"
}, {
    "id": "orange",
    "value": "2"
}, {
    "id": "yellow",
    "value": "3"
}, {
    "id": "green",
    "value": "1"
}, {
    "id": "blue",
    "value": "1"
}, {
    "id": "violet",
    "value": "3"
},{
    "id": "white",
    "value": "1"
},{
    "id": "gray",
    "value": "1"
},{
    "id": "teal",
    "value": "3"
}
];

var links = [];

for (var i = 0; i < nodes.length; i++) {
    for (var j = i + 1; j < nodes.length; j++) {
        if (nodes[i].value === nodes[j].value) {
            links.push({
                source: nodes[i].id,
                target: nodes[j].id
            });
        }
    }
};

var width = 300,
    height = 300;

var svg = d3.select("body")
    .append("svg")
    .attr("width", width)
    .attr("height", height);

var simulation = d3.forceSimulation()
    .force("link", d3.forceLink().id(function(d) {
        return d.id;
    }).distance(50))
    .force("charge", d3.forceManyBody())
    .force("center", d3.forceCenter(width / 2, height / 2));

var link = svg.append("g")
    .attr("class", "links")
    .selectAll("line")
    .data(links)
    .enter().append("line")
    .attr("stroke-width", 1)
    .attr("stroke", "gray")
    .attr("fill", "none");

var node = svg.append("g")
    .attr("class", "nodes")
    .selectAll("circle")
    .data(nodes)
    .enter().append("circle")
    .attr("r", 6)
    .attr("class", "circleNode")
    .attr("stroke", "gray")
    .attr("fill", function(d) {
        return d.id;
    });

node.on("click", function(d) {
    var thisNode = d.id

    d3.selectAll(".circleNode").attr("r", 6);
    d3.select(this).attr("r", 12);

    link.attr("opacity", function(d) {
        return (d.source.id == thisNode || d.target.id == thisNode) ? 1 : 0.1
    });

});

simulation
    .nodes(nodes)
    .on("tick", ticked);

simulation.force("link")
    .links(links);

function ticked() {
    link
        .attr("x1", function(d) {
            return d.source.x;
        })
        .attr("y1", function(d) {
            return d.source.y;
        })
        .attr("x2", function(d) {
            return d.target.x;
        })
        .attr("y2", function(d) {
            return d.target.y;
        });

    node
        .attr("cx", function(d) {
            return d.x;
        })
        .attr("cy", function(d) {
            return d.y;
        });
}

<script src="https://d3js.org/d3.v4.min.js"></script>

这篇关于JS/d3.js:突出显示相邻链接的步骤的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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