2017-01-29 5 views
2

Ich habe Probleme mit der Zoom-Funktion in D3 während der Verwendung von v4. Es gibt einen Fehler, der besagt, dass zoom.translate nicht definiert ist. Ich verwende meistens den folgenden Code aus dieser Antwort d3 focus on node on click, die perfekt für v3 funktionierte. Da ich jedoch Probleme mit v3 hatte, da es Einschränkungen bei Daten gibt, bei denen die Quelle und die Knoten in Form von Strings (anstelle von Indizes) D3 JSON file with source and index as strings rather than indices sind, wechselte ich zu v4.d3 Zoom Funktion Probleme in v4

<!DOCTYPE html> 
<meta charset="utf-8"> 
<style> 

.links line { 
    stroke: #999; 
    stroke-opacity: 0.6; 
} 

.nodes circle { 
    stroke: #fff; 
    stroke-width: 1.5px; 
} 

</style> 
<svg width="960" height="600"></svg> 
<script src="https://d3js.org/d3.v4.min.js"></script> 
<script> 


var svg = d3.select("svg"), 
    width = +svg.attr("width"), 
    height = +svg.attr("height") 
    active = d3.select(null); 

var zoom = d3.zoom() 
    .scaleExtent([1, 8]) 
    .on("zoom", zoomed);  

var color = d3.scaleOrdinal(d3.schemeCategory20); 

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

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

    var link = svg.append("g") 
     .attr("class", "links") 
    .selectAll("line") 
    .data(graph.links) 
    .enter().append("line") 
     .attr("stroke-width", function(d) { return Math.sqrt(d.value); }); 

    var node = svg.append("g") 
     .attr("class", "nodes") 
    .selectAll("circle") 
    .data(graph.nodes) 
    .enter().append("circle") 
     .attr("r", 5) 
     .attr("fill", function(d) { return color(d.group); }) 
     .call(d3.drag() 
      .on("start", dragstarted) 
      .on("drag", dragged) 
      .on("end", dragended)) 
      .on("click", clicked); 

    node.append("title") 
     .text(function(d) { return d.id; }); 

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

    simulation.force("link") 
     .links(graph.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; }); 
    } 
}); 

function dragstarted(d) { 
    if (!d3.event.active) simulation.alphaTarget(0.3).restart(); 
    d.fx = d.x; 
    d.fy = d.y; 
} 

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 clicked(d){ 
    if (active.node() === this) return reset(); 
    active.classed("active", false); 
    active = d3.select(this).classed("active", true); 

    var bbox = active.node().getBBox(), 
     bounds = [[bbox.x, bbox.y],[bbox.x + bbox.width, bbox.y + bbox.height]]; 

    var dx = bounds[1][0] - bounds[0][0], 
     dy = bounds[1][1] - bounds[0][1], 
     x = (bounds[0][0] + bounds[1][0])/2, 
     y = (bounds[0][1] + bounds[1][1])/2, 
     scale = Math.max(1, Math.min(8, 0.9/Math.max(dx/width, dy/height))), 
     translate = [width/2 - scale * x, height/2 - scale * y]; 

    svg.transition() 
     .duration(750) 
     .call(zoom.translate(translate).scale(scale).event); 
} 

function reset() { 
    active.classed("active", false); 
    active = d3.select(null); 

    svg.transition() 
     .duration(750) 
     .call(zoom.translate([0, 0]).scale(1).event); 
} 

function zoomed() { 
    console.log(d3.event) 
    g.style("stroke-width", 1.5/d3.event.scale + "px"); 
    g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"); 
}   

</script> 

Ich änderte d3.behaviour.zoom() zu d3.zoom() und sogar verändert

.call(zoom.translate(translate).scale(scale).event); 

zu

.call(d3.zoom().on("zoom", function() { 
     svg.attr("transform", d3.event.transform) 
})); 

, die einen seltsamen Fehler wirft, Fehler: unbekannt Typ: Rad

Was wäre der beste Weg zur Überwindung dieser Situation?

+0

In [meine Antwort] (http://stackoverflow.com/a/41917020/5768908) zu Ihrer vorherigen Frage, I didn‘ t sagen, dass Sie auf v4 aktualisieren sollten. Eigentlich habe ich dir gezeigt, wie man es mit v3 macht. –

+0

Leider habe ich die Daten nicht in einem Array, sondern in einer JSON-Datei. Kann es noch getan werden? – VerletIntegrator

+0

Ja, kann es. JSON ist nur eine Syntax zum Speichern von Daten: Ihr JSON enthält wahrscheinlich ein Array. –

Antwort

3

In d3 Version 4 der richtige Weg, dies zu tun ist:

function clicked(d) { 

    if (active.node() === this){ 
     active.classed("active", false); 
     return reset(); 
    } 

    active = d3.select(this).classed("active", true); 

    svg.transition() 
     .duration(750) 
     .call(zoom.transform, 
     d3.zoomIdentity 
     .translate(width/2, height/2) 
     .scale(8) 
     .translate(-(+active.attr('cx')), -(+active.attr('cy'))) 
    ); 
    } 

Wo Ihr Zoom-Handler:

Hinweis ich die Berechnung von meiner vorherigen Antwort Transformation vereinfacht. Die Grenzberechnungen dort waren nicht wirklich notwendig.


Voll Code:

<!DOCTYPE html> 
 
<meta charset="utf-8"> 
 
<style> 
 
    .links line { 
 
    stroke: #aaa; 
 
    } 
 
    
 
    .nodes circle { 
 
    pointer-events: all; 
 
    stroke: none; 
 
    stroke-width: 40px; 
 
    } 
 
    
 
    .active { 
 
    fill: yellow; 
 
    } 
 
</style> 
 
<svg width="960" height="600"></svg> 
 
<script src="https://d3js.org/d3.v4.min.js"></script> 
 
<script> 
 
    var svg = d3.select("svg"), 
 
    width = +svg.attr("width"), 
 
    height = +svg.attr("height"); 
 

 
    var zoom = d3.zoom() 
 
    .scaleExtent([1/2, 4]) 
 
    .on("zoom", zoomed); 
 

 
    var g = svg.append("g"); 
 

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

 
    var graph = { 
 
    "nodes": [{ 
 
     "id": "Myriel", 
 
     "group": 1 
 
    }, { 
 
     "id": "Napoleon", 
 
     "group": 1 
 
    }, { 
 
     "id": "Mlle.Baptistine", 
 
     "group": 1 
 
    }, { 
 
     "id": "Mme.Magloire", 
 
     "group": 1 
 
    }, { 
 
     "id": "CountessdeLo", 
 
     "group": 1 
 
    }, { 
 
     "id": "Geborand", 
 
     "group": 1 
 
    }, { 
 
     "id": "Champtercier", 
 
     "group": 1 
 
    }, { 
 
     "id": "Cravatte", 
 
     "group": 1 
 
    }, { 
 
     "id": "Count", 
 
     "group": 1 
 
    }, { 
 
     "id": "OldMan", 
 
     "group": 1 
 
    }, { 
 
     "id": "Labarre", 
 
     "group": 2 
 
    }, { 
 
     "id": "Valjean", 
 
     "group": 2 
 
    }, { 
 
     "id": "Marguerite", 
 
     "group": 3 
 
    }, { 
 
     "id": "Mme.deR", 
 
     "group": 2 
 
    }, { 
 
     "id": "Isabeau", 
 
     "group": 2 
 
    }, { 
 
     "id": "Gervais", 
 
     "group": 2 
 
    }, { 
 
     "id": "Tholomyes", 
 
     "group": 3 
 
    }, { 
 
     "id": "Listolier", 
 
     "group": 3 
 
    }, { 
 
     "id": "Fameuil", 
 
     "group": 3 
 
    }, { 
 
     "id": "Blacheville", 
 
     "group": 3 
 
    }, { 
 
     "id": "Favourite", 
 
     "group": 3 
 
    }, { 
 
     "id": "Dahlia", 
 
     "group": 3 
 
    }, { 
 
     "id": "Zephine", 
 
     "group": 3 
 
    }, { 
 
     "id": "Fantine", 
 
     "group": 3 
 
    }, { 
 
     "id": "Mme.Thenardier", 
 
     "group": 4 
 
    }, { 
 
     "id": "Thenardier", 
 
     "group": 4 
 
    }, { 
 
     "id": "Cosette", 
 
     "group": 5 
 
    }, { 
 
     "id": "Javert", 
 
     "group": 4 
 
    }, { 
 
     "id": "Fauchelevent", 
 
     "group": 0 
 
    }, { 
 
     "id": "Bamatabois", 
 
     "group": 2 
 
    }, { 
 
     "id": "Perpetue", 
 
     "group": 3 
 
    }, { 
 
     "id": "Simplice", 
 
     "group": 2 
 
    }, { 
 
     "id": "Scaufflaire", 
 
     "group": 2 
 
    }, { 
 
     "id": "Woman1", 
 
     "group": 2 
 
    }, { 
 
     "id": "Judge", 
 
     "group": 2 
 
    }, { 
 
     "id": "Champmathieu", 
 
     "group": 2 
 
    }, { 
 
     "id": "Brevet", 
 
     "group": 2 
 
    }, { 
 
     "id": "Chenildieu", 
 
     "group": 2 
 
    }, { 
 
     "id": "Cochepaille", 
 
     "group": 2 
 
    }, { 
 
     "id": "Pontmercy", 
 
     "group": 4 
 
    }, { 
 
     "id": "Boulatruelle", 
 
     "group": 6 
 
    }, { 
 
     "id": "Eponine", 
 
     "group": 4 
 
    }, { 
 
     "id": "Anzelma", 
 
     "group": 4 
 
    }, { 
 
     "id": "Woman2", 
 
     "group": 5 
 
    }, { 
 
     "id": "MotherInnocent", 
 
     "group": 0 
 
    }, { 
 
     "id": "Gribier", 
 
     "group": 0 
 
    }, { 
 
     "id": "Jondrette", 
 
     "group": 7 
 
    }, { 
 
     "id": "Mme.Burgon", 
 
     "group": 7 
 
    }, { 
 
     "id": "Gavroche", 
 
     "group": 8 
 
    }, { 
 
     "id": "Gillenormand", 
 
     "group": 5 
 
    }, { 
 
     "id": "Magnon", 
 
     "group": 5 
 
    }, { 
 
     "id": "Mlle.Gillenormand", 
 
     "group": 5 
 
    }, { 
 
     "id": "Mme.Pontmercy", 
 
     "group": 5 
 
    }, { 
 
     "id": "Mlle.Vaubois", 
 
     "group": 5 
 
    }, { 
 
     "id": "Lt.Gillenormand", 
 
     "group": 5 
 
    }, { 
 
     "id": "Marius", 
 
     "group": 8 
 
    }, { 
 
     "id": "BaronessT", 
 
     "group": 5 
 
    }, { 
 
     "id": "Mabeuf", 
 
     "group": 8 
 
    }, { 
 
     "id": "Enjolras", 
 
     "group": 8 
 
    }, { 
 
     "id": "Combeferre", 
 
     "group": 8 
 
    }, { 
 
     "id": "Prouvaire", 
 
     "group": 8 
 
    }, { 
 
     "id": "Feuilly", 
 
     "group": 8 
 
    }, { 
 
     "id": "Courfeyrac", 
 
     "group": 8 
 
    }, { 
 
     "id": "Bahorel", 
 
     "group": 8 
 
    }, { 
 
     "id": "Bossuet", 
 
     "group": 8 
 
    }, { 
 
     "id": "Joly", 
 
     "group": 8 
 
    }, { 
 
     "id": "Grantaire", 
 
     "group": 8 
 
    }, { 
 
     "id": "MotherPlutarch", 
 
     "group": 9 
 
    }, { 
 
     "id": "Gueulemer", 
 
     "group": 4 
 
    }, { 
 
     "id": "Babet", 
 
     "group": 4 
 
    }, { 
 
     "id": "Claquesous", 
 
     "group": 4 
 
    }, { 
 
     "id": "Montparnasse", 
 
     "group": 4 
 
    }, { 
 
     "id": "Toussaint", 
 
     "group": 5 
 
    }, { 
 
     "id": "Child1", 
 
     "group": 10 
 
    }, { 
 
     "id": "Child2", 
 
     "group": 10 
 
    }, { 
 
     "id": "Brujon", 
 
     "group": 4 
 
    }, { 
 
     "id": "Mme.Hucheloup", 
 
     "group": 8 
 
    }], 
 
    "links": [{ 
 
     "source": "Napoleon", 
 
     "target": "Myriel", 
 
     "value": 1 
 
    }, { 
 
     "source": "Mlle.Baptistine", 
 
     "target": "Myriel", 
 
     "value": 8 
 
    }, { 
 
     "source": "Mme.Magloire", 
 
     "target": "Myriel", 
 
     "value": 10 
 
    }] 
 
    } 
 

 
    var link = g.append("g") 
 
    .attr("class", "links") 
 
    .selectAll("line") 
 
    .data(graph.links) 
 
    .enter().append("line"); 
 

 
    var node = g.append("g") 
 
    .attr("class", "nodes") 
 
    .selectAll("circle") 
 
    .data(graph.nodes) 
 
    .enter().append("circle") 
 
    .attr("r", 2.5) 
 
    .on('click', clicked); 
 

 
    node.append("title") 
 
    .text(function(d) { 
 
     return d.id; 
 
    }); 
 

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

 
    simulation.force("link") 
 
    .links(graph.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; 
 
     }); 
 
    } 
 

 
    var active = d3.select(null); 
 

 
    function clicked(d) { 
 

 
    if (active.node() === this){ 
 
     active.classed("active", false); 
 
     return reset(); 
 
    } 
 
    
 
    active = d3.select(this).classed("active", true); 
 

 
    svg.transition() 
 
     .duration(750) 
 
     .call(zoom.transform, 
 
     d3.zoomIdentity 
 
     .translate(width/2, height/2) 
 
     .scale(8) 
 
     .translate(-(+active.attr('cx')), -(+active.attr('cy'))) 
 
    ); 
 
    } 
 

 
    function reset() { 
 
    svg.transition() 
 
     .duration(750) 
 
     .call(zoom.transform, 
 
     d3.zoomIdentity 
 
     .translate(0, 0) 
 
     .scale(1) 
 
    ); 
 
    } 
 

 
    function zoomed() { 
 
    g.attr("transform", d3.event.transform); 
 
    } 
 
</script>