簡體   English   中英

如何在D3js強制有向圖中實現節點的高亮和過渡效果?

[英]How to implement highlight and transition effect for nodes in D3js force directed graph?

我正在嘗試在 D3 js 強制有向圖中的節點上實現 Higlight 效果。

這樣做時,我面臨以下問題。

高光效果:a. 在選定節點的鼠標懸停時,我正在更改其相鄰節點的顏色。 但是其他節點的顏色不應該改變(在我的情況下,它變成紅色並且不知道如何修復它)如何解決這個問題?。 在選定節點的鼠標懸停時,我想通過增加其半徑為所有互連節點添加過渡效果。 其他節點也應該淡出,這可能嗎?

請參考工作 js fiddle 以供參考:在此處輸入鏈接描述

var nodeElements =  g.append("g")
  .attr("class", "nodes")
  .selectAll("circle")
  .data(graph.nodes)
  .enter().append("circle")
  .attr("r", 40)
.attr("fill", function(d) { return color(d.id); })
  .attr("stroke", "#fff")
  .attr('stroke-width', 21)
  .attr("id", function(d) { return d.id })
      .on('mouseover', selectNode)
      .on('mouseout', releaseNode)
  .call(d3.drag()
    .on("start", dragstarted)
    .on("drag", dragged)
    .on("end", dragended));

function releaseNode() {
   nodeElements.attr("fill", function(d) { return color(d.id)
   })
}

function selectNode(selectedNode) {
  var neighbors = getNeighbors(selectedNode)
  nodeElements.attr('fill', function(node) {
    return getNodeColor(node, neighbors)
  })
}

function getNeighbors(node) {
  return graph.links.reduce(function(neighbors, link) {
    if (link.target.id === node.id) {
      neighbors.push(link.source.id)
    } else if (link.source.id === node.id) {
      neighbors.push(link.target.id)
    }
    return neighbors
  }, [node.id])
}

function getNodeColor(node, neighbors) {
  // If is neighbor
  if (Array.isArray(neighbors) && neighbors.indexOf(node.id) > -1) {
    return 'rgba(251, 130, 30, 1)'
    // return node.level === 1 ? '#9C4A9C' : 'rgba(251, 130, 30, 1)'
  } else {
    return 'red';
  }
  //return node.level === 0 ? '#91007B' : '#D8ABD8'
}
  1. 要在鼠標懸停時不更改其他節點的顏色,您必須更改下面的getNodeColor函數:

     function getNodeColor(node, neighbors) { // If is neighbor if ( neighbors.indexOf(node.id) > -1) { return 'rgba(251, 130, 30, 1)' } else { return color(node.id); } }
  2. 為了擴大節點,您必須在selectNode函數中調用另一個函數getNodeRadius ,該函數被調用on('mouseover', selectNode);

     function selectNode(selectedNode) { var neighbors = getNeighbors(selectedNode) nodeElements.transition() .duration(500) .attr('fill', function(node) { return getNodeColor(node, neighbors) }) .attr('r', function(node) { return getNodeRadius(node,neighbors); }) }

請注意.transition().duration(500)指示以 500 毫秒的持續時間動畫到此結束狀態。

getNodeRadius函數需要定義為:

function getNodeRadius(node, neighbors) {
  // If is neighbor
  if ( neighbors.indexOf(node.id) > -1) {
    return '60'
  } 
  else {
        return '40'
  }
}

下面的完整工作示例:

 var graph = { 'nodes':[ {'id':'Material_Definition','group':0}, {'id':'Lot1','group':1}, {'id':'Lot2','group':1}, {'id':'Lot3','group':1}, {'id':'Lot4','group':1}, {'id':'Lot5','group':1}, {'id':'Lot6','group':1}, {'id':'Lot7','group':1}, {'id':'Lot8','group':1}, {'id':'Lot9','group':1}, {'id':'Lot10','group':1}, {'id':'Lot11','group':1}, {'id':'Lot12','group':1}, {'id':'Lot13','group':1}, {'id':'Lot14','group':1}, {'id':'Lot15','group':1}, {'id':'Lot16','group':1}, {'id':'Lot17','group':1}, {'id':'Lot18','group':1}, {'id':'Lot19','group':1}, {'id':'Lot20','group':1}, {'id':'SubLot1_Lot1','group':2}, {'id':'SubLot2_Lot1','group':2}, {'id':'SubLot3_Lot1','group':2}, {'id':'SubLot4_Lot1','group':2}, {'id':'SubLot5_Lot1','group':2}, {'id':'SubLot6_Lot1','group':2}, {'id':'SubLot1_Lot2','group':2}, {'id':'SubLot2_Lot2','group':2}, {'id':'SubLot3_Lot2','group':2}, {'id':'SubLot4_Lot2','group':2}, {'id':'SubLot5_Lot2','group':2}, {'id':'SubLot6_Lot2','group':2}], 'links':[ /* Material Definition linked to Lots */ {'source':'Material_Definition','target':'Lot1','value':1,'type':'A'}, {'source':'Material_Definition','target':'Lot2','value':8,'type':'A'}, {'source':'Material_Definition','target':'Lot3','value':10,'type':'A'}, {'source':'Material_Definition','target':'Lot3','value':1,'type':'A'}, {'source':'Material_Definition','target':'Lot4','value':1,'type':'A'}, {'source':'Material_Definition','target':'Lot5','value':1,'type':'A'}, {'source':'Material_Definition','target':'Lot6','value':1,'type':'A'}, {'source':'Material_Definition','target':'Lot7','value':2,'type':'A'}, {'source':'Material_Definition','target':'Lot8','value':1,'type':'A'}, {'source':'Material_Definition','target':'Lot9','value':1,'type':'A'}, {'source':'Material_Definition','target':'Lot10','value':8,'type':'A'}, {'source':'Material_Definition','target':'Lot11','value':10,'type':'A'}, {'source':'Material_Definition','target':'Lot12','value':1,'type':'A'}, {'source':'Material_Definition','target':'Lot13','value':1,'type':'A'}, {'source':'Material_Definition','target':'Lot14','value':1,'type':'A'}, {'source':'Material_Definition','target':'Lot15','value':1,'type':'A'}, {'source':'Material_Definition','target':'Lot16','value':2,'type':'A'}, {'source':'Material_Definition','target':'Lot17','value':1,'type':'A'}, {'source':'Material_Definition','target':'Lot18','value':1,'type':'A'}, {'source':'Material_Definition','target':'Lot19','value':2,'type':'A'}, {'source':'Material_Definition','target':'Lot20','value':1,'type':'A'}, /* Lot1 is linked to Sublots */ {'source':'Lot1','target':'SubLot1_Lot1','value':2,'type':'A'}, {'source':'Lot1','target':'SubLot2_Lot1','value':1,'type':'A'}, {'source':'Lot1','target':'SubLot3_Lot1','value':2,'type':'A'}, {'source':'Lot1','target':'SubLot4_Lot1','value':1,'type':'A'}, {'source':'Lot1','target':'SubLot5_Lot1','value':2,'type':'A'}, {'source':'Lot1','target':'SubLot6_Lot1','value':1,'type':'A'}, /* Lot2 is linked to Sublots */ {'source':'Lot2','target':'SubLot1_Lot2','value':2,'type':'A'}, {'source':'Lot2','target':'SubLot2_Lot2','value':1,'type':'A'}, {'source':'Lot2','target':'SubLot3_Lot2','value':2,'type':'A'}, {'source':'Lot2','target':'SubLot4_Lot2','value':1,'type':'A'}, {'source':'Lot2','target':'SubLot5_Lot2','value':2,'type':'A'}, {'source':'Lot2','target':'SubLot6_Lot2','value':1,'type':'A'}, /* Interconnected Lots */ {'source':'Lot10','target':'Lot18','value':2,'type':'A'}, {'source':'Lot10','target':'Lot19','value':1,'type':'A'}, {'source':'Lot10','target':'Lot20','value':2,'type':'A'}, {'source':'Lot7','target':'Lot8','value':1,'type':'A'}, {'source':'Lot7','target':'Lot9','value':2,'type':'A'}, {'source':'Lot7','target':'Lot10','value':1,'type':'A'}, {'source':'Lot12','target':'Lot4','value':2,'type':'A'}, {'source':'Lot12','target':'Lot3','value':1,'type':'A'}, {'source':'Lot12','target':'Lot2','value':2,'type':'A'}, {'source':'Lot16','target':'Lot1','value':1,'type':'A'}, {'source':'Lot16','target':'Lot9','value':2,'type':'A'}, {'source':'Lot16','target':'Lot12','value':1,'type':'A'} ]}; var svg = d3.select("svg"), width = +svg.attr("width"), height = +svg.attr("height"); var color = d3.scaleOrdinal(d3.schemeCategory10); var zoom_handler = d3.zoom().on("zoom", zoom_actions); // zoom_handler(svg); var simulation = d3.forceSimulation() .force("link", d3.forceLink().distance(300).id(function(d) { return d.id; })) .force("charge", d3.forceManyBody().strength(-300)) .force("center", d3.forceCenter(width / 2, height / 2)); var g = svg.append("g") .attr("class", "everything"); svg.call(zoom_handler) .call(zoom_handler.transform, d3.zoomIdentity.translate(200, 150).scale(0.2)); var linkElements = g.append("g") .attr("class", "links") .selectAll("line") .data(graph.links) .enter().append("line") .style("stroke-width",5.5) .style("stroke",'black'); var nodeElements = g.append("g") .attr("class", "nodes") .selectAll("circle") .data(graph.nodes) .enter().append("circle") .attr("r", 40) .attr('class', 'nodecircles') .attr("fill", function(d) { return color(d.id); }) .attr("stroke", "#fff") .attr('stroke-width', 21) .attr("id", function(d) { return d.id }) .on('mouseover', selectNode) .on('mouseout', releaseNode) .call(d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended)); function releaseNode(d) { nodeElements.transition().duration(500) .attr("fill", function(d) { return color(d.id) }) .attr('r', 40); } var textElements = g.append("g") // use g.append instead of svg.append to enable zoom .attr("class", "texts") .selectAll("text") .data(graph.nodes) .enter().append("text") .text(function(node) { return node.id }) .attr("font-size", 55) .attr("font-family", "sans-serif") .attr("text-anchor", "middle") .attr("fill", "black") .attr("style", "font-weight:bold; text-stroke: 1px #fff;") .attr("dx", 0) .attr("dy", 20) function ticked() { linkElements .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; }); nodeElements .attr("cx", function(d) { return dx; }) .attr("cy", function(d) { return dy; }) .each(d => { d3.select('#t_' + d.id).attr('x', dx + 10).attr('y', dy + 3); }); textElements .attr('x', function(d) { return dx }) .attr('y', function(d) { return dy }); } simulation .nodes(graph.nodes) .on("tick", ticked); simulation.force("link") .links(graph.links); function zoom_actions() { g.attr("transform", d3.event.transform) } function dragstarted(d) { if (!d3.event.active) simulation.alphaTarget(0.3).restart(); d.fx = dx; d.fy = dy; } function dragged(d) { d.fx = d3.event.x; d.fy = d3.event.y; } function dragended(d) { if (!d3.event.active) simulation.alphaTarget(0); d.fx = null; d.fy = null; } function selectNode(selectedNode) { var neighbors = getNeighbors(selectedNode) nodeElements.transition() .duration(500) .attr('fill', function(node) { return getNodeColor(node, neighbors) }) .attr('r', function(node) { return getNodeRadius(node,neighbors); }) } function getNeighbors(node) { return graph.links.reduce(function(neighbors, link) { if (link.target.id === node.id) { neighbors.push(link.source.id) } else if (link.source.id === node.id) { neighbors.push(link.target.id) } return neighbors }, [node.id]) } function getNodeColor(node, neighbors) { // If is neighbor if ( neighbors.indexOf(node.id) > -1) { return 'rgba(251, 130, 30, 1)' } else { return color(node.id); } } function getNodeRadius(node, neighbors) { // If is neighbor if ( neighbors.indexOf(node.id) > -1) { return '60' } else { return '40' } }
 .links line { stroke: #999; stroke-opacity: 0.6; } .nodes circle { stroke: #000; stroke-width: 1.5px; } text { font-size: 10px; }
 <!DOCTYPE html> <meta charset="utf-8"> <link rel="shortcut icon" href="//#" /> <html> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css"> </html> <svg width="798" height="400"></svg> <script src="https://d3js.org/d3.v4.min.js"></script>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM