2016-08-26 2 views
1

Ziel: Zentrum ein Knoten im Sichtbereich folgenden Suchd3.js Knoten Position in Kraft Directed Graph folgende Suche

Ich habe eine Kraft gerichteten Graphen, die einen Benutzer für einen Knoten nach Namen suchen können. Wenn ein Knoten durchsucht wird, bleibt der ausgewählte Knoten sichtbar, während alle anderen Knoten die Opazität vorübergehend reduzieren, um den gesuchten Knoten hervorzuheben. Jetzt möchte ich auch den gesuchten Knoten im Ansichtsbereich zentrieren. Ich habe zahlreiche Methoden versucht, aber es ist mir nicht gelungen, den gesamten Graph einschließlich der Knotenbeschriftungen zu übersetzen. Jede Hilfe würde sehr geschätzt werden.

jsfiddle (Anmerkung: die automatische Vervollständigung Such perfekt funktioniert, wenn von meinem Skript laufen, aber scheint in jsfiddle zum Scheitern verurteilt): https://jsfiddle.net/dereksmith5822/73j63nn0/

<script> 

var width = 900, 
    height = 590; 

var svg = d3.select("body") 
     .append("svg") 
     .attr("width", width) 
     .attr("height", height) 
     .call(d3.behavior.zoom().scaleExtent([0.1,5]).on("zoom", redraw)).on("dblclick.zoom", null) 
     .append('g'); 

//INPUT DATA 
var links = [ 
    {source: 'N1', target: 'N2'}, 
    {source: 'N1', target: 'N3'}, 
    {source: 'N2', target: 'N3'}, 
    {source: 'N3', target: 'N4'}, 
]; 

var nodes = [ 
    {id: 'N1', name: 'A'}, 
    {id: 'N2', name: 'B'}, 
    {id: 'N3', name: 'C'}, 
    {id: 'N4', name: 'D'}, 
]; 

//CONNECTIONS 
var hash_lookup = []; 
nodes.forEach(function(d, i) { 
    hash_lookup[d.id] = d; 
}); 
links.forEach(function(d, i) { 
    d.source = hash_lookup[d.source]; 
    d.target = hash_lookup[d.target]; 
}); 

//FORCE LAYOUT 
var force = d3.layout.force() 
    .size([width, height]) 
    .nodes(d3.values(nodes)) 
    .links(links) 
    .on('tick', tick) 
    .linkDistance(100) 
    .gravity(.15) 
    .friction(.8) 
    .linkStrength(1) 
    .charge(-425) 
    .chargeDistance(600) 
    .start(); 

//LINKS 
var link = svg.selectAll('.link') 
    .data(links) 
    .enter().append('line') 
    .attr('class', 'link'); 

//NODES 
var node = svg.selectAll('.node') 
    .data(force.nodes()) 
    .enter().append('circle') 
    .attr('class', 'node') 
    .attr('r', width * 0.01) 

//LABELS 
var text_center = false; 
var nominal_text_size = 12; 
var max_text_size = 22; 
var nominal_base_node_size = 8; 
var max_base_node_size = 36;  
var size = d3.scale.pow().exponent(1) 
    .domain([1,100]) 
    .range([8,24]); 

var text = svg.selectAll(".text") 
    .data(nodes) 
    .enter().append("text") 
    .attr("dy", ".35em") 
    .style("font-size", nominal_text_size + "px") 

    if (text_center) 
    text.text(function(d) { return d.name; }) 
    .style("text-anchor", "middle"); 

    else 
    text.attr("dx", function(d) {return (size(d.size)|| nominal_base_node_size);}) 
    .text(function(d) { return '\u2002'+d.name; }); 

//ZOOM AND PAN 
function redraw() { 
    svg.attr("transform", 
     "translate(" + d3.event.translate + ")" 
     + " scale(" + d3.event.scale + ")"); 
    } 

var drag = force.drag() 
     .on("dragstart", function(d) { 
     d3.event.sourceEvent.stopPropagation(); 
     }); 

//NODES IN SPACE 
function tick(e) { 

    text.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); 

    node.attr('cx', function(d) { return d.x; }) 
     .attr('cy', function(d) { return d.y; }) 
     .call(force.drag); 

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

}; 

//AUTOCOMPLETE SEARCH 
var optArray = []; 
for (var i = 0; i < nodes.length - 1; i++) { 
    optArray.push(nodes[i].name); 
} 
optArray = optArray.sort(); 

$(function() { 
    $("#search").autocomplete({ 
     source: optArray 
    }); 
}); 

function searchNode() { 
    var selectedVal = document.getElementById('search').value; 
    if (selectedVal == 'none') {} 
    else { 
     var selected = node.filter(function (d, i) { 
      return d.name != selectedVal; 
     }); 
     var selectedText = text.filter(function (d, i) { 
      return d.name != selectedVal; 
     }); 
     selected.style("opacity", "0"); 
     selectedText.style("opacity", "0"); 
     var link = svg.selectAll(".link") 
      link.style("opacity", "0"); 
     d3.selectAll(".node, .link, .text").transition() 
      .duration(3000) 
      .style("opacity", '1'); 
    } 
} 
    </script> 

Antwort

2

Hier ist eine Idee, wie Sie es tun können:

Speichern Sie Ihre zoom Verhalten:

var zoom = d3.behavior.zoom().scaleExtent([0.1,5]).on("zoom", redraw); 
var svg = d3.select("body") 
    .append("svg") 
    .attr("width", width) 
    .attr("height", height) 
    .call(zoom).on("dblclick.zoom", null) 
    .append('g'); 

In searchNode Funktion:

var selectedNode = node 
    .filter(function (d, i) { return d.name == selectedVal; }) 
    .datum(); 
var desiredPosition = { x: 100, y: 100 }; // constants, set to svg center point 
zoom.translate([desiredPosition.x - selectedNode.x, desiredPosition.y - selectedNode.y]); 
zoom.event(svg); 

Dieser Code berücksichtigt nicht die Zoomskala. Ich denke, Sie können einfach zoom.scale() bekommen und selektierteNode-Koordinaten damit multiplizieren.

+0

Danke für diese Idee. Der Code funktioniert, um den ausgewählten Knoten in der Mitte des Felds zu positionieren. Beim Schwenken oder Zoomen kehrt die Grafik jedoch zu den ursprünglichen Positionen zurück. Das Ändern von ".call (zoom) .on (" dblclick.zoom ", null)" führt zu dem Fehler "Uncaught TypeError: Eigenschaft kann nicht gelesen werden" "von undefined anwenden". Kennen Sie den Grund für diesen Fehler? Vielen Dank. –

+0

Es funktioniert für mich ohne Fehler in Firefox 48. Meine Gabel deiner Geige: https://jsfiddle.net/v71d1ha8/ –

+0

Ich benutze Chrom. Ich habe den Fehler behoben, aber wenn ich schwenken oder zoomen lasse, nachdem der Knoten zentriert wurde, kehrt der Graph vor der Zentrierung in die ursprüngliche Position zurück. Haben Sie einen Weg gefunden, um Pan und Zoom von der neuen Knotenposition aus zu implementieren? Danke –

Verwandte Themen