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
- How to pass values between drag.start and drag.end in d3
- D3.js double pendulum odd behavior
- Appending and arc to svg element in d3.js
- d3 show labels only for ticks with data in a bar chart
- "d3.select(...) is not a function"
- d3 - how to add x-axis labels for only years on a monthly chart?
- d3.js insert line path by "datum" or line (data)
- Can d3.js graph put inside a table?
- How to externally trigger d3 events
- D3 multiplying datapoints in stackedAreaChart
- When adding d3.behavior.zoom, the .on("zoom", zoom), zoom undefined
- D3 ... Best (recommended) way to load array of dictionaries with multiple Y values
- d3 force layout nodes in predictable order
- Creating animation to the D3 and SVG elements
- Vue, Webpack, DC.js, and Finally Crossfilter
- Create node cluster's focal points by data attribute in d3?
- Convertion from CSV to JSON in d3.js
- How do I flip the text in my D3 collapsible radial tree?
- d3js selection.each() callback group argument
- dc.js multi line series chart filtering
- D3 SelectAll except one class to modify opacity
- How to modify and copy observablehq zoomable sunburst to a local machine and run?
- NVD3: how to unset brush on default load?
- Get D3.js sums before next key
- D3 Bar Chart Axis quirk
- Adjusting rectangle size according to updated data (d3,js)
- Neat solution to convert flat data to nested JSON
- Pagination in d3js stacked bar chart
- D3 - mouse event handling on a map
- Access scale factor in d3's pack layout