Удалите выпуклую оболочку при событии щелчка узла - PullRequest
0 голосов
/ 24 февраля 2020

Я пытаюсь удалить оболочку вокруг построенного сетевого графика D3. Моя сеть основана на этом JSFiddle . Мое требование - показать все дочерние узлы в группе, окружив их заштрихованным цветом. Мой график начинается с одного родительского узла, при событии щелчка он расширяется, чтобы показать дочерние узлы. Кроме того, если дочерний узел имеет вложенный дочерний узел, то при щелчке он снова развернется и покажет эти внутренние дочерние узлы. Узлы имеют свойство переключения. Событие щелчка на развернутом узле скрывает дочерний узел. Прямо сейчас я застрял на удалении корпуса, когда я хочу скрыть дочерний узел. Ниже приведены снимки. 1. Родительский узел Родительский узел

Расширенные узлы (нажмите на родительский узел). Родительский и дочерний узел. расширенная сеть

Снова нажмите на root родительский узел. изображение после скрытия дочернего узла .

Здесь я хочу удалить область корпуса, когда скрываю дочерний узел при событии щелчка. Я попытался удалить разметку 'path' для оболочки внутри элемента тега SVG в функции щелчка, но она не работает. Любая помощь будет высоко оценена.

var width = 700,
    height = 300,
    root;

var force = d3.layout.force()
    .gravity(.02)
    .charge(function(d) { return d._children ? -d.size / 160 : -30; })
    .linkDistance(function(d) { return d.target._children ? 120 : 80; })
    .size([width, height])
    .on("tick", tick);

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

var link = svg.selectAll(".link"),
    node = svg.selectAll(".node");
    
var fill = d3.scale.category10();

function getDepth(n) { return n.depth; }

//var color = d3.scale.linear().domain([-2, 4]).range(["#252525", "#cccccc"]), //This is used to scale the gray color based on the propertyValue
 var groupHullColor = "#e7cb94",  //d3.scale.category10(),
    subgroupHullColor = " #9ecae1",
    subsubgroupHullColor = "#ff9896";
 
 var groups = [[14,17]];
 var subgroups = [[15,16,17],[14,5,11,13]];
 var subsubgroups = [[14,13,12],[14,5,1,2,3,4],[14,11,6,7,8,9,10]]; 

var minNodeSize = 2
//function radiusOf(element) {return (minNodeSize + (8 * Math.sqrt(element.depth))) };
function radiusOf(element) {return (minNodeSize + (8 * Math.sqrt(2))) };

var groupPath = function(d) {
    var fakePoints = [];     
    d.forEach(function(element) { fakePoints = fakePoints.concat([   // "0.7071" is the sine and cosine of 45 degree for corner points.
           [(element.x), (element.y + (radiusOf(element) - minNodeSize))],
           [(element.x + (0.7071 * (radiusOf(element) - minNodeSize))), (element.y + (0.7071 * (radiusOf(element) - minNodeSize)))],
           [(element.x + (radiusOf(element) - minNodeSize)), (element.y)],
           [(element.x + (0.7071 * (radiusOf(element) - minNodeSize))), (element.y - (0.7071 * (radiusOf(element) - minNodeSize)))],
           [(element.x), (element.y - (radiusOf(element) - minNodeSize))],
           [(element.x - (0.7071 * (radiusOf(element) - minNodeSize))), (element.y - (0.7071 * (radiusOf(element) - minNodeSize)))],
           [(element.x - (radiusOf(element) - minNodeSize)), (element.y)],
           [(element.x - (0.7071 * (radiusOf(element) - minNodeSize))), (element.y + (0.7071 * (radiusOf(element) - minNodeSize)))]
    ]); })
    return "M" + d3.geom.hull( fakePoints ).join("L") + "Z";
};

var groupHullFill = function(d, i) { return groupHullColor; };
var subgroupHullFill = function(d, i) { return subgroupHullColor; };
var subsubgroupHullFill = function(d, i) { return subsubgroupHullColor; };

var groupNodes,subgroupNodes,subsubgroupNodes;


//d3.json("readme.json", function(error, json) {
//  if (error) throw error;

  //root = json;
 // update();
 
 root = {
		 "name": "flare",
		 "depth": 1,
		 "size": 45000,
		 "children": [
		  {
		   "name": "analytics",
		   "depth": 2,
		   "size": 33700,
		   "children": [
		    {
		     "name": "cluster",
		     "depth": 3,
		     "size": 9700,
		     "children": [
		      {"name": "AgglomerativeCluster", "size": 4000, "depth": 4},
		      {"name": "CommunityStructure", "size": 2000, "depth": 4},
		      {"name": "HierarchicalCluster", "size": 3000, "depth": 4},
		      {"name": "MergeEdge", "size": 700, "depth": 4}
		     ]
		    },
		    {
		     "name": "graph",
		     "depth": 3,
		     "size": 21000,
		     "children": [
		      {"name": "BetweennessCentrality", "size": 4000,"depth": 4},
		      {"name": "LinkDistance", "size": 5000,"depth": 4},
		      {"name": "MaxFlowMinCut", "size": 7000,"depth": 4},
		      {"name": "ShortestPaths", "size": 3000,"depth": 4},
		      {"name": "SpanningTree", "size": 2000,"depth": 4}
		     ]
		    },
		    {
		     "name": "optimization",
		     "depth": 3,
		     "size": 3000,
		     "children": [
		      {"name": "AspectRatioBanker", "size": 3000,"depth": 4}
		     ]
		    }
		   ]
		  },
		  {
		  "name": "anamyers",
		   "depth": 2,
		   "size": 12000,
		   "children": [
		     {"name": "AspectRatio1", "size": 3000,"depth": 3},
		     {"name": "Aspect2", "size": 9000,"depth": 3}
		   ]
		  }
		 ]
		}
 
  var nd = flatten(root); //to set ids
  // This takes the list of group members and converts into lists lof lists of nodes
  groupNodes = groups.map(function(group,index){
      	return group.map(function(member){return nd[member-1] });
  	});
  subgroupNodes = subgroups.map(function(group,index){
      	return group.map(function(member){return nd[member-1] });
  	});
  subsubgroupNodes = subsubgroups.map(function(group,index){
      	return group.map(function(member){return nd[member-1] });
  	});
  //console.log("groupNodes : " + groupNodes);
  setParents(root, null);
  collapseAll(root);
  //root.children = root._children;
 // root._children = null;
  update();
  
//});

function update() {

  var nodes = flatten(root),
      links = d3.layout.tree().links(nodes);

  // Restart the force layout.
  force
      .nodes(nodes)
      .links(links)
      .start();
  
//Update the links…
  link = svg.selectAll("line.link")
      .data(links, function(d) { return d.target.id; });

  // Exit any old links.
  link.exit().remove();

  // Enter any new links.
  link.enter().insert("line", ".node")
      .attr("class", "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; });

  // Update the nodes…
  node = node.data(nodes, function(d) { return d.id; })
  			.style("fill", color)

  // Exit any old nodes.
  node.exit().remove();
  			
  //new code
  node.transition()
     .attr("r", function(d) { return d.children ? 8.5 : Math.sqrt(d.size) / 10; })
     .style("stroke", function(d) { return 'steelblue'})
     .style("stroke-width", function(d) { if (d.children) { return 2.5 } else { return 0.5 }})
	 .style("stroke-dasharray",  function(d) { if (d.children) { return "10,3" } else { return "0,0" }});// make the stroke dashed

  // Enter any new nodes.
  node.enter().append("circle")
      .attr("class", "node")
      .attr("cx", function(d) { return d.x; })
      .attr("cy", function(d) { return d.y; })
      .attr("r", function(d) { return d.children ? 8.5 : Math.sqrt(d.size) / 10;})
    // .style("fill", color)
      .on("click", click)
      .call(force.drag);
  
  node.append("title")
  .text(function(d) { return d.name });
  
}

function tick() {
	
	var flag = true;
	
  var nodes = flatten(root),
      links = d3.layout.tree().links(nodes);
  
	
  // this updates the convex hulls
  svg.selectAll("path").remove();
  
  
  svg.selectAll("path#group")
    .data(groupNodes)
    //  .attr("d", drawCluster)
      .enter().insert("path", "circle")
       .attr("class", "group")
       .style("fill", groupHullFill)
     .style("stroke", groupHullFill)
      .style("stroke-width", 45)
      .style("stroke-linejoin", "round")
      .style("opacity", .5) 
  	.attr("ID","group")
      .attr("d", groupPath);
  
  svg.selectAll("path#subgroup")
  .data(subgroupNodes)
  .enter().insert("path", "circle")
    .style("fill", subgroupHullFill)
    .style("stroke", subgroupHullFill)
    .style("stroke-width", 25)
    .style("stroke-linejoin", "round")
    .style("opacity", .2)
	.attr("ID","subgroup")
    .attr("d", groupPath);

svg.selectAll("path#subsubgroup")
  .data(subsubgroupNodes)
  .enter().insert("path", "circle")
    .style("fill", subsubgroupHullFill)
    .style("stroke", subsubgroupHullFill)
    .style("stroke-width", 15)
    .style("stroke-linejoin", "round")
    .style("opacity", 0.2)
	.attr("ID","subsubgroup")
    .attr("d", groupPath);
    
// this redraws the links on top of the convex hulls
 link = svg.selectAll("line.link")
      .data(links, function(d) { return d.target.id; });

  // Exit any old links.
  link.exit().remove();

  // Enter any new links.
  link.enter().insert("line", ".node")
      .attr("class", "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; });

  // Update the nodes…
  node = node.data(nodes, function(d) { return d.id; })
  			.style("fill", color);

  // Exit any old nodes.
  node.exit().remove();

  // Enter any new nodes.
  node.enter().append("circle")
      .attr("class", "node")
      .attr("cx", function(d) { return d.x; })
      .attr("cy", function(d) { return d.y; })
      .attr("r", function(d) { return d.children ? 8.5 : Math.sqrt(d.size) / 10;})
     //.style("fill", color)
      .on("click", click)
      .call(force.drag);
  
  node.append("title")
  .text(function(d) { return d.name });
  

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

// Color leaf nodes orange, and packages white or blue.
function color(d) {
  return d._children ? "#3182bd" : d.children ? "#c6dbef" : "#fd8d3c";
}

// Toggle children on click.
function click(d) {
	 
  if (!d3.event.defaultPrevented) {
    if (d.children) {
      d._children = d.children;
      d.children = null;
    } else {
      d.children = d._children;
      d._children = null;
    }
    update();
  }
}


//Returns a list of all nodes under the root.
function flatten(root) {
  var nodes = [], i = 0;

  function recurse(node) {
    //if (node.children) node.size = node.children.reduce(function(p, v) { return p + recurse(v); }, 0);
    if (node.children) node.children.forEach(recurse);
    if (!node.id) node.id = ++i;
    nodes.push(node);
    return node.size;
  }

  root.size = recurse(root);
  console.log("nodes : - : " + nodes);
  return nodes;
}


function collapseAll(d){
	//svg.selectAll("path").remove();
	if (d.children){
        d.children.forEach(collapseAll);
        d._children = d.children;
        d.children = null;
    }
    else if (d._children){
        d._children.forEach(collapseAll);
        d.children = d._children;
        d._children = null;
    }
	
}

function setParents(d, p){
  d._parent = p;
  if (d.children) {
      d.children.forEach(function(e){ setParents(e,d);});
  } else if (d._children) {
      d._children.forEach(function(e){ setParents(e,d);});
  }
}
.node {
  cursor: pointer;
  stroke: #000;
  stroke-width: .5px;
}

.link {
  fill: none;
  stroke: #9ecae1;
  stroke-width: 1.5px;
}
<!DOCTYPE html>
<html>
  <head>
	<title>Force-Directed Graph</title>

<script src="https://d3js.org/d3.v3.min.js"></script>
 </head>
  <body>
  </body>
  </html>
...