D3 ma tutaj układ ukierunkowany na siłę . Czy istnieje sposób na dodanie powiększenia do tego wykresu? Obecnie udało mi się uchwycić zdarzenie kółka myszy, ale nie jestem pewien, jak napisać samą funkcję przerysowywania. Jakieś sugestie?
var vis = d3.select("#graph")
.append("svg:svg")
.call(d3.behavior.zoom().on("zoom", redraw)) // <-- redraw function
.attr("width", w)
.attr("height", h);
javascript
jquery
d3.js
zoom
force-layout
Legenda
źródło
źródło
Odpowiedzi:
Aktualizacja 6/4/14
Zobacz także odpowiedź Mike'a Bostocka na zmiany w D3 v.3 i powiązany przykład . Myślę, że to prawdopodobnie zastępuje odpowiedź poniżej.
Aktualizacja 18.02.2014
Myślę, że odpowiedź @ ahaarnos jest lepsza, jeśli chcesz przesuwać i powiększać cały plik SVG. Zagnieżdżone
g
elementy w mojej odpowiedzi poniżej są naprawdę konieczne tylko wtedy, gdy masz elementy nie powiększające się w tym samym SVG (nie tak w oryginalnym pytaniu). Jeśli zrobić zastosować zachowanie dog
elementu, to tłorect
jest wymagane lub podobny element, który zapewnia, żeg
reaguje na zdarzenia wskaźnika.Oryginalna odpowiedź
Mam to działające w oparciu o przykład zoom-pan-transform - możesz zobaczyć moje jsFiddle tutaj: http://jsfiddle.net/nrabinowitz/QMKm3/
Było to trochę bardziej złożone, niż się spodziewałem - musisz zagnieżdżać kilka
g
elementów, aby działał, ustawićpointer-events
atrybut SVG naall
, a następnie dołączyć prostokąt tła, aby otrzymać zdarzenia wskaźnika (w przeciwnym razie działa tylko wtedy, gdy wskaźnik jest nad węzeł lub łącze).redraw
Funkcja ta jest stosunkowo prosta, wystarczy ustawienie transformacji na głębsząg
:var vis = d3.select("#chart") .append("svg:svg") .attr("width", w) .attr("height", h) .attr("pointer-events", "all") .append('svg:g') .call(d3.behavior.zoom().on("zoom", redraw)) .append('svg:g'); vis.append('svg:rect') .attr('width', w) .attr('height', h) .attr('fill', 'white'); function redraw() { console.log("here", d3.event.translate, d3.event.scale); vis.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")"); }
To skutecznie skaluje cały plik SVG, a więc skaluje również szerokość obrysu, podobnie jak powiększanie obrazu.
Jest inny przykład ilustrujący podobną technikę.
źródło
body
tag, więc polecam zajrzeć do źródła ramki i zobaczyć, czego brakuje.zoom.scaleExtent()
Dlaczego zagnieżdżone
<g>
?Poniższy kod działał dobrze dla mnie (tylko jeden
<g>
, bez losowego dużego białego<rect>
:var svg = d3.select("body") .append("svg") .attr({ "width": "100%", "height": "100%" }) .attr("viewBox", "0 0 " + width + " " + height ) .attr("preserveAspectRatio", "xMidYMid meet") .attr("pointer-events", "all") .call(d3.behavior.zoom().on("zoom", redraw)); var vis = svg .append('svg:g'); function redraw() { vis.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")"); }
Gdzie wszystkie elementy w svg są następnie dołączane do
vis
elementu.źródło
transformation
atrybutu dog
elementu, a nie dosvg
elementu.Podane odpowiedzi działają w D3 v2, ale nie w v3. Zsyntetyzowałem odpowiedzi w czyste rozwiązanie i rozwiązałem problem z wersją 3, korzystając z odpowiedzi podanej tutaj: Dlaczego d3.js v3 przerywa mój wykres siły podczas wdrażania powiększania, a wersja 2 nie?
Najpierw główny kod. To jest poprawiona wersja odpowiedzi @ahaarnos:
var svg = d3.select("body") .append("svg") .attr("width", width) .attr("height", height) .call(d3.behavior.zoom().on("zoom", redraw)) .append('g'); function redraw() { svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")"); }
Teraz możesz przesuwać i powiększać, ale nie będziesz w stanie przeciągać węzłów, ponieważ funkcja przesuwania zastąpi funkcję przeciągania. Więc musimy to zrobić:
var drag = force.stop().drag() .on("dragstart", function(d) { d3.event.sourceEvent.stopPropagation(); // to prevent pan functionality from //overriding node drag functionality. // put any other 'dragstart' actions here });
Oto skrzypce @nrabinowitz zmodyfikowane tak, aby korzystały z tej czystszej implementacji powiększenia, ale ilustrują, jak D3v3 przerywa przeciąganie węzłów: http://jsfiddle.net/QMKm3/718/
A oto te same skrzypce zmodyfikowane do pracy z D3v3: http://jsfiddle.net/QMKm3/719/
źródło
Mój wykres działał bez drugiego dodania „svg: g”.
[...].attr("pointer-events", "all") .attr("width", width2) .attr("height", height2) .append('svg:g') .call(d3.behavior.zoom().on("zoom", redraw));
Reszta jest taka sama.
źródło
Dostałem rozwiązanie dla wykresu zorientowanego siłą D3 z opcją powiększania.
var m = [40, 240, 40, 240], width = 960, height = 700, root; var svg = d3.select("body").append("svg") .attr("class", "svg_container") .attr("width", width) .attr("height", height) .style("overflow", "scroll") .style("background-color", "#EEEEEE") .append("svg:g") .attr("class", "drawarea") .append("svg:g") .attr("transform", "translate(" + m[3] + "," + m[0] + ")"); //applying zoom in&out for svg d3.select("svg") .call(d3.behavior.zoom() .scaleExtent([0.5, 5]) .on("zoom", zoom)); //zooming function zoom() { //zoom in&out function var scale = d3.event.scale, translation = d3.event.translate, tbound = -height * scale, bbound = height * scale, lbound = (-width + m[1]) * scale, rbound = (width - m[3]) * scale; // limit translation to thresholds translation = [ Math.max(Math.min(translation[0], rbound), lbound), Math.max(Math.min(translation[1], bbound), tbound) ]; d3.select(".drawarea") .attr("transform", "translate(" + translation + ")" + " scale(" + scale + ")"); }
źródło
Jeśli chcesz powiększyć i przesunąć układ siły bez zmiany rozmiaru węzła, spróbuj poniżej. Możesz także przeciągać węzły bez drżenia. Ten kod jest oparty na oryginalnym przykładzie układu siły. Jeśli chodzi o dane dotyczące węzłów i łączy, zapoznaj się z oryginalnymi przykładowymi danymi. http://bl.ocks.org/mbostock/4062045
Proszę zwrócić uwagę na zmienne xScale i yScale, funkcje dragstarted (), dragged () i dragended (). Funkcja tick () również została zmieniona.
Możesz zobaczyć wynik na http://steelblue.tistory.com/9 Językiem na tej stronie jest koreański. Jednak wynik można łatwo znaleźć w trzecim przykładzie na stronie.
var graph = { "nodes": [ { "name": "Myriel", "group": 1 }, { "name": "Napoleon", "group": 1 }, // ...... { "name": "Mme.Hucheloup", "group": 8 } ], "links": [ { "source": 1, "target": 0, "value": 1 }, { "source": 2, "target": 0, "value": 8 }, // ....... { "source": 76, "target": 58, "value": 1 } ] }; var width = 640, height = 400; var color = d3.scale.category20(); var xScale = d3.scale.linear() .domain([0, width]) .range([0, width]); var yScale = d3.scale.linear() .domain([0, height]) .range([0, height]); var zoomer = d3.behavior.zoom().x(xScale).y(yScale).scaleExtent([0.1, 8]).on("zoom", zoom); function zoom() { tick(); }; var drag = d3.behavior.drag() .origin(function (d) { return d; }) .on("dragstart", dragstarted) .on("drag", dragged) .on("dragend", dragended); function dragstarted(d) { d3.event.sourceEvent.stopPropagation(); d.fixed |= 2; } function dragged(d) { var mouse = d3.mouse(svg.node()); d.x = xScale.invert(mouse[0]); d.y = yScale.invert(mouse[1]); d.px = d.x; d.py = d.y; force.resume(); } function dragended(d) { d.fixed &= ~6; } var force = d3.layout.force() .charge(-120) .linkDistance(30) .size([width, height]); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); svg.call(zoomer); force .nodes(graph.nodes) .links(graph.links) .start(); var link = svg.selectAll(".link") .data(graph.links) .enter().append("line") .attr("class", "link") .style("stroke-width", function (d) { return Math.sqrt(d.value); }); var node = svg.selectAll(".node") .data(graph.nodes) .enter().append("circle") .attr("class", "node") .attr("r", 5) .style("fill", function (d) { return color(d.group); }) .call(drag); node.append("title") .text(function (d) { return d.name; }); force.on("tick",tick); function tick(){ link.attr("x1", function (d) { return xScale(d.source.x); }) .attr("y1", function (d) { return yScale(d.source.y); }) .attr("x2", function (d) { return xScale(d.target.x); }) .attr("y2", function (d) { return yScale(d.target.y); }); node.attr("transform", function (d) { return "translate(" + xScale(d.x) + "," + yScale(d.y) + ")"; }); };
źródło