D3.js Zoomen und schwenken einer reduzierbaren Struktur-Diagramm
Ich bin mit D3.js in den plot ein aufklappbares Baum-Diagramm wie in der Beispiel. Es funktioniert meist gut, aber das Diagramm könnte sich dramatisch ändern, in der Größe, wenn es in seiner normalen Funktion (also statt die paar Knoten, die ich jetzt habe, werde ich einen viel mehr).
Ich wollte die SVG-Bereich scrollen, ich habe versucht, alles, was ich online gefunden, es zu schaffen, aber ohne Erfolg. Die besten, die ich gearbeitet haben, war mit der d3.behaviour.drag
, in die ich ziehen das ganze Diagramm um. Es ist bei weitem nicht optimal und glitches viel, aber es ist irgendwie brauchbar.
Auch so, bin ich versucht zu reinigen es ein wenig und ich merkte, dass die d3.behaviour.zoom
können auch verwendet werden, um pan der SVG-Bereich, nach den API-docs.
Frage: Kann mir jemand erklären, wie man zum anpassen an meinen code?
Ich würde gerne in der Lage sein, um pan der SVG-Bereich mit der Grafik, wenn möglich so dass es zu reagieren, um einige Missbrauch, nämlich, versuchen zu schwenken, ein Diagramm aus der Ansicht, und aktivieren der zoom zu der maximalen viewport-Dimensionen...
Dies ist mein code bisher:
var realWidth = window.innerWidth;
var realHeight = window.innerHeight;
function load(){
callD3();
}
var m = [40, 240, 40, 240],
w = realWidth -m[0] -m[0],
h = realHeight -m[0] -m[2],
i = 0,
root;
var tree = d3.layout.tree()
.size([h, w]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
var vis = d3.select("#box").append("svg:svg")
.attr("class","svg_container")
.attr("width", w)
.attr("height", h)
.style("overflow", "scroll")
.style("background-color","#EEEEEE")
.append("svg:g")
.attr("class","drawarea")
.attr("transform", "translate(" + m[3] + "," + m[0] + ")")
;
var botao = d3.select("#form #button");
function callD3() {
//d3.json(filename, function(json) {
d3.json("D3_NEWCO_tree.json", function(json) {
root = json;
d3.select("#processName").html(root.text);
root.x0 = h / 2;
root.y0 = 0;
botao.on("click", function(){toggle(root); update(root);});
update(root);
});
function update(source) {
var duration = d3.event && d3.event.altKey ? 5000 : 500;
//Compute the new tree layout.
var nodes = tree.nodes(root).reverse();
//Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 50; });
//Update the nodes…
var node = vis.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
//Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("svg:g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", function(d) { toggle(d); update(d); });
nodeEnter.append("svg:circle")
.attr("r", function(d){
return Math.sqrt((d.part_cc_p*1))+4;
})
.attr("class", function(d) { return "level"+d.part_level; })
.style("stroke", function(d){
if(d._children){return "blue";}
})
;
nodeEnter.append("svg:text")
.attr("x", function(d) { return d.children || d._children ? -((Math.sqrt((d.part_cc_p*1))+6)+this.getComputedTextLength() ) : Math.sqrt((d.part_cc_p*1))+6; })
.attr("y", function(d) { return d.children || d._children ? -7 : 0; })
.attr("dy", ".35em")
.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
.text(function(d) {
if(d.part_level>0){return d.name;}
else
if(d.part_multi>1){return "Part " + d.name+ " ["+d.part_multi+"]";}
else{return "Part " + d.name;}
})
.attr("title",
function(d){
var node_type_desc;
if(d.part_level!=0){node_type_desc = "Labour";}else{node_type_desc = "Component";}
return ("Part Name: "+d.text+"<br/>Part type: "+d.part_type+"<br/>Cost so far: "+d3.round(d.part_cc, 2)+"€<br/>"+"<br/>"+node_type_desc+" cost at this node: "+d3.round(d.part_cost, 2)+"€<br/>"+"Total cost added by this node: "+d3.round(d.part_cost*d.part_multi, 2)+"€<br/>"+"Node multiplicity: "+d.part_multi);
})
.style("fill-opacity", 1e-6);
//Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
nodeUpdate.select("circle")
.attr("r", function(d){
return Math.sqrt((d.part_cc_p*1))+4;
})
.attr("class", function(d) { return "level"+d.part_level; })
.style("stroke", function(d){
if(d._children){return "blue";}else{return null;}
})
;
nodeUpdate.select("text")
.style("fill-opacity", 1);
//Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
.remove();
nodeExit.select("circle")
.attr("r", function(d){
return Math.sqrt((d.part_cc_p*1))+4;
});
nodeExit.select("text")
.style("fill-opacity", 1e-6);
//Update the links…
var link = vis.selectAll("path.link")
.data(tree.links(nodes), function(d) { return d.target.id; });
//Enter any new links at the parent's previous position.
link.enter().insert("svg:path", "g")
.attr("class", "link")
.attr("d", function(d) {
var o = {x: source.x0, y: source.y0};
return diagonal({source: o, target: o});
})
.transition()
.duration(duration)
.attr("d", diagonal);
//Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
//Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function(d) {
var o = {x: source.x, y: source.y};
return diagonal({source: o, target: o});
})
.remove();
$('svg text').tipsy({
fade:true,
gravity: 'nw',
html:true
});
//Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
var drag = d3.behavior.drag()
.origin(function() {
var t = d3.select(this);
return {x: t.attr("x"), y: t.attr("y")};
})
.on("drag", dragmove);
d3.select(".drawarea").call(drag);
}
//Toggle children.
function toggle(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
}
function dragmove(){
d3.transition(d3.select(".drawarea"))
.attr("transform", "translate(" + d3.event.x +"," + d3.event.y + ")");
}
}
InformationsquelleAutor Joum | 2013-07-01
Du musst angemeldet sein, um einen Kommentar abzugeben.
Können Sie sehen, (die meisten) eine funktionierende Implementierung hier: http://jsfiddle.net/nrabinowitz/fF4L4/2/
Den key-pieces hier:
Call
d3.behavior.zoom()
auf diesvg
element. Dies erfordert diesvg
element, umpointer-events: all
gesetzt. Sie können auch rufen Sie diese auf ein Unterelement, aber ich sehe nicht einen Grund, wenn Sie wollen, dass die ganze Sache zu schwenken und zu Zoomen, denn Sie wollen im Grunde den gesamten SVG-Bereich zu reagieren, um die Schwenk - /zoom-Aktionen.Einstellung
scaleExtent
hier gibt Ihnen die Fähigkeit zu beschränken, den zoom-Maßstab. Sie können[1, 1]
zu deaktivieren, Zoomen ganz, oder legen Sie programmgesteuert die max Größe Ihrer Inhalte, wenn es das ist, was Sie wollen (ich war nicht sicher, genau das, was gewünscht war hier).Den
zoom
Funktion ist ähnlich zu Ihremdragmove
Funktion, aber auch die Skala Faktor und setzt Grenzen für die pan offset (soweit ich das beurteilen kann, die d3 hat keinen eingebautenpanExtent
support):(Um ehrlich zu sein, ich glaube nicht, dass ich die Logik ganz Recht, hier die richtigen Links und rechts schwellen - scheint dies nicht zu begrenzen, ziehen Sie richtig, wenn gezoomt in. Links als übung für den Leser :).)
Dinge einfacher machen hier, es hilft, die
g.drawarea
element nicht das erste transformieren - so dass ich fügte hinzu, ein anderesg
element, um den äußeren Wrapper um den Rand versetzt:Den rest der änderungen, die hier sind, nur um Ihren code besser arbeiten in JSFiddle. Es gibt ein paar fehlende details hier, aber hoffentlich ist das genug, um Ihnen den Einstieg.
d3.behavior.zoom
an den falschen wrapper - es hielt nur auslassen wie verrückt... Aber das funktioniert wirklich gut (wenn auch etwas langsamer/schwerer auf den browser)...Sehr nützlich, abgesehen von den Rand-array, ist unklar
InformationsquelleAutor nrabinowitz