score:97
Update 6/4/14
See also Mike Bostock's answer here for changes in D3 v.3 and the related example. I think this probably supersedes the answer below.
Update 2/18/2014
I think @ahaarnos's answer is preferable if you want the entire SVG to pan and zoom. The nested g
elements in my answer below are really only necessary if you have non-zooming elements in the same SVG (not the case in the original question). If you do apply the behavior to a g
element, then a background rect
or similar element is required to ensure that the g
receives pointer events.
Original Answer
I got this working based on the zoom-pan-transform example - you can see my jsFiddle here: http://jsfiddle.net/nrabinowitz/QMKm3/
It was a bit more complex than I had hoped - you have to nest several g
elements to get it to work, set the SVG's pointer-events
attribute to all
, and then append a background rectangle to receive the pointer events (otherwise it only works when the pointer is over a node or link). The redraw
function is comparatively simple, just setting a transform on the innermost 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 + ")");
}
This effectively scales the entire SVG, so it scales stroke width as well, like zooming in on an image.
There is another example that illustrates a similar technique.
score:0
I got a solution for D3 force directed graph with zooming option.
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 + ")");
}
score:0
If you want to zoom and pan force layout without changing node-size, try below. You can also drag nodes without trembling. This code is based on original force layout example. As for nodes and links data, please refer to original sample data. http://bl.ocks.org/mbostock/4062045
Plz note the variables xScale and yScale, the functions dragstarted(), dragged(), and dragended(). Function tick() was changed as well.
You can see the result at http://steelblue.tistory.com/9 The language on the site is Korean. However you can easily find the result at the third example on the page.
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) + ")";
});
};
score:2
I got my graph to work without the second "svg:g" append.
[...].attr("pointer-events", "all")
.attr("width", width2)
.attr("height", height2)
.append('svg:g')
.call(d3.behavior.zoom().on("zoom", redraw));
The rest is the same.
score:14
The provided answers work in D3 v2 but not in v3. I've synthesized the responses into a clean solution and resolved the v3 issue using the answer provided here: Why does d3.js v3 break my force graph when implementing zooming when v2 doesn't?
First the main code. This is a cleaned up version of @ahaarnos' answer:
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 + ")");
}
Now you have pan and zoom, but you won't be able to drag nodes because the pan functionality will override the drag functionality. So we need to do this:
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
});
Here's @nrabinowitz' fiddle modified to use this cleaner zoom implementation, but illustrating how D3v3 breaks node drag: http://jsfiddle.net/QMKm3/718/
And here's the same fiddle modified to work with D3v3: http://jsfiddle.net/QMKm3/719/
score:18
Why the nested <g>
's?
This code below worked well for me (only one <g>
, with no random large white <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 + ")");
}
Where all the elements in your svg are then appended to the vis
element.
Source: stackoverflow.com
Related Query
- Is there a way to zoom into a D3 force layout graph?
- Is there a way to make a D3 force layout continually move?
- Graph won't reload properly into D3 force layout
- D3 force layout graph zoom functionality
- how to implement zoom in d3 graph of force directed layout and position the nodes
- How to make force layout graph in D3.js responsive to screen/browser size
- Simple graph of nodes and links without using force layout
- Is there a way to convert CSV columns into hierarchical relationships?
- Is there a tap and double tap event in d3.js force directed graph
- D3 Force Layout Graph - Self linking node
- How can I show a graph using d3 force layout with initial positions set and no movement at all?
- Place pie charts on nodes of force directed layout graph in D3
- Having trouble converting a D3 v3 Force Directed graph into D3 v4 library implementation?
- D3 force layout graph with nodes positioned in a grid
- How to get the same node positions in d3's force layout graph
- How to stop a d3 force graph layout simulation?
- d3.js: Drag is disabled when use zoom with force layout
- Is there any way to capture zoomed/brushed d3.js multi-line graph position?
- how to generate a network graph with edge weight using D3.js force layout
- Automatic zoom on object in D3 force layout
- Nodes drawn randomly in Force Layout graph
- Changing nodes for images in d3.js force layout graph
- D3.js Force Layout - showing only part of a graph
- Breaking text from json into several lines for displaying labels in a D3 force layout
- How can I resize my d3.js script? is there a way to put this into a div tag where I can resize my bar chart smaller?
- Why are my D3 force layout diagram lines extending into circles?
- D3 JS - Force Graph - Doesn't restart layout after removing Node
- Adding OnClick event to D3 force layout graph
- d3.js force layout graph : how to build the nodes object from scratch?
- Using data(...) in D3 force layout to update the graph
More Query from same tag
- failed to use d3 to update legend data, entering is empty for changed data
- d3.js: Updating a pie with lables
- Shiny app not Rendering a Dimple.js Population Pyramid
- Comparison of D3 and Dojo GFX
- d3.js -- stacked bar with color categories
- d3: Append caption/title to table
- Querying MongoDB from browser using a flask backend
- How can I add links to dendrogram texts?
- How to change other segments of pie chart on mouseover in D3.js?
- Running D3.js in clojure
- Rotating text paths in d3.js chord diagram without usual svg:text
- Trying to add a second parent node to a child node using d3 tree chart library
- inexplicable inability to render city name labels on a d3.js map: out of scope NAME?
- Adding mouseover popups to d3 tree leaves
- Fitting data for D3 graph to create legend
- variable declaration conditional syntax
- Getting text area using getBBox()
- D3 click event with multiple svg on one page
- How to drag and drop a rectangle
- D3 Scale doesn't match graph
- How to fix the configuration of the nodes that are returned? (D3, Javascript, Neo4j)
- Render a d3 pie chart in angular with angular-nvd3
- Error: <rect> attribute and Expected length d3.js
- How to set range of year in x axis in d3
- Getting error on applying transition in d3
- D3.js: rotate coordinates, not an entire element?
- Coordinating views/dispatching events
- d3: why is variable set inside d3.json not accesible outside?
- SVG links not working after transition executed in d3.js
- D3 different behavior when using method chaining