This question already has answers here:
How to disable double click zoom for d3.behavior.zoom?
(3 answers)
Closed 8 years ago.
I have a D3 Network Graph and I am trying to disable the Double Click zoom function.
I have it zooming using:
var zoom = d3.behavior.zoom().scaleExtent([minZoom, maxZoom]);
zoom.on("zoom", function() {
g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
});
svg.call(zoom)
However I cant seem to be able to disable just the Double click zoom. When I use the code below it disables the zoom altogether.
var zoom = d3.behavior.zoom().scaleExtent([minZoom, maxZoom]);
zoom.on("zoom", function() {
g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")").on("dblclick.zoom", null);
});
svg.call(zoom)
I have also tried calling
.on("dblclick.zoom", null)
on the svg element by itself and that doesnt work either.
Any help would be much appreciated.
You need to call
.on("dblclick.zoom", null)
after
svg.call(zoom)
i.e.
svg.call(zoom).on("dblclick.zoom", null);
Related
I've built a D3 force graph largely based on these really helpful examples.
I wanted to add pan and zoom functionality, which I tried to do using another example (looks like I can only include two links, but Google "d3 force zoom eyaler" to find it).
Unfortunately, when I zoom out on a graph that is larger than the initial SVG, I get something like this:
Result of dragging and dropping
Here's the relevant code:
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.call(d3.behavior.zoom().scaleExtent([0.5,2]).on("zoom", redraw));
function redraw() {
svg.attr("transform",
"translate(" + d3.event.translate + ")"
+ " scale(" + d3.event.scale + ")");
}
How can I change the pan and zoom behaviour so that it scrolls and makes it possible to see the rest of the graph, rather than just allowing me to move the square that was originally visible?
OK, looks like I worked it out... you need to perform the transform on a <g> rather than on the SVG itself. So:
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.call(d3.behavior.zoom().scaleExtent([0.5,2]).on("zoom", redraw));
var g = svg.append("g"); // add <g>
function redraw() {
g.attr("transform", // perform transform on g, not svg
"translate(" + d3.event.translate + ")"
+ " scale(" + d3.event.scale + ")");
}
Just putting this here in case anyone else made the same mistake!
Edit
I have found a solution involving using a slightly older version of the dagre-d3 library (4.11). If anyone can find the problem with the latest version, that would help too. Thank you
I'm using Dagre d3 to draw some graphs.
When I initially render my graph, I do
g = new dagreD3.graphlib.Graph()
.setGraph({})
.setDefaultEdgeLabel(function() { return {}; });
var svg = d3.select("svg"),
inner = svg.select("g");
svgGroup = svg.append("g");
var render = new dagreD3.render();
render(d3.select("svg g"), g);
var zoom = d3.behavior.zoom().on("zoom", function() {
inner.attr("transform", "translate(" + d3.event.translate + ")" +
"scale(" + d3.event.scale + ")");
currentZoomScale = d3.event.scale;
currentPosition = d3.event.translate;
});
svg.call(zoom);
Then, when a user clicks on a certain node, I want to append HTML to that node's label. This doesn't show unless I re-render the graph, which I do with the following:
g.node(id).label += "<div>" + inputTemplate + "</div>";
var zoom = d3.behavior.zoom()
.scale(currentZoomScale)
.on("zoom", function() {
inner.attr("transform", "translate(" + d3.event.translate + ")" + "scale(" + d3.event.scale + ")")
});
svg.call(zoom);
d3.select("svg").on("dblclick.zoom", null);
inner.attr("transform", "translate(" + currentPosition + ")" + "scale(" + currentZoomScale + ")");
I thought that by maintaining currentPosition and currentZoomScale I would be able to make sure the graph stays well after zooming and re-rendering. But this is not the case. All my nodes become smaller if I zoom out, and larger if I zoom in.
I'm not crystal clear on the problem but could it be because you have included .scale(currentZoomScale) in the second line of
var zoom = d3.behavior.zoom()
.scale(currentZoomScale)
.on("zoom", function() {
inner.attr("transform", "translate(" + d3.event.translate + ")" + "scale(" + d3.event.scale + ")")
});
svg.call(zoom);
d3.select("svg").on("dblclick.zoom", null);
inner.attr("transform", "translate(" + currentPosition + ")" + "scale(" + currentZoomScale + ")");
and then you're scaling it again in the innner.attr()?
It seems to me that the problem lies here:
var svg = d3.select("svg"),
inner = svg.select("g");
svgGroup = svg.append("g");
If you look at the order of your code, there is no <g> when you define inner. So, at this point, inner is null. When you re-render the chart the group is now there, and inner is no more a null selection.
Thus, a possible solution is just changing the order:
var svg = d3.select("svg"),
svgGroup = svg.append("g");//we first append the <g>..
inner = svg.select("g");//and only after that we select it
I have implemented a zooming treemap using D3.js. The treemap can be zoomed and panned I have limited the zooming function but cant limit the pan of the map. I want the panning to be only be inside the map rather than outside of it.
This is the current working implementation of my treemap : http://www.advbizclan.com/treemapt/
I want it like the zooming function which is only limited to the map the panning should also be limited only to the map.
The problem with your fiddle was the LoadType was incorrect. To fix this just click the Javascript button at the top of the Javascript window, and select No wrap- in <body> in the LOAD TYPE.
As for your problem. It's fairly simple. At the moment, you have this for your panning and zooming of your treemap :
.call(d3.behavior.zoom().scaleExtent([1, 3]).on("zoom", function() {
console.log(d3.event.translate)
chart.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")")
This uses the d3.event.translate to translate your svg. But you only want to pan in the y direction yes ? As d3.event.translatereturns an array of x and y coordinates, and the translate takes an x and y coordinate to translate by, just pass 0 for the x and d3.event.translate[1] (i.e the y coordinate) to the translate like so :
.on("zoom", function() {
chart.attr("transform", function(d) {
console.log(d3.event.translate);
return "translate(" + [0, d3.event.translate[1]] + ")" + " scale(" + d3.event.scale + ")"
})
}))
Now for the extent. You need to add limits to this, for my example I have just done this (you can easily implement your own limits) :
if(d3.event.translate[1] > 0 && d3.event.translate[1] < chartHeight/2 ){
console.log('move')
return "translate(" + [0, d3.event.translate[1]] + ")" + " scale(" + d3.event.scale + ")";
}
Here, you cant drag the map up, but you can drag it down half way.
Updated fiddle : https://jsfiddle.net/thatoneguy/w7em39wj/
I tried to copy the behavior of the grid displayed here.
The code I have is here
Problem is, when I'm dragging or zooming, the grid is moving along with everything else, while it should not.
I suspect the problem is around this part :
function zoomed() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
Indeed, when I remove the last line, the grid works fine (more or less) :
function zoomed() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
}
However, in this case, my visualization (the lines) don't move anymore:
How can I make my lines and the grid move the right way?
I have corrected your code
Working example here: http://jsfiddle.net/cyril123/p4cmx1kj/3/
You will need to update the lines also on zoom along with axis.
function zoomed() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
lines.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
I'm currently using d3 transitions to animate graphs. Unfortunately these transitions make the page to redraw continuously, as a result cpu is always around 100%.
d3Element.attr("transform", "translate(" + this.someDistance + ")")
.attr("d", linePath)
.transition()
.ease("linear")
.duration(animationDuration)
.attr("transform", "translate(" + 0 + ")");
I have already found a simple solution to this problem and I will share it with you but I would like to know if there is any better way to do it with d3.
What I'm actually doing to reduce cpu usage is to limit the frames per second.
This is a part of the code :
var start = d3.transform( "translate(" + this.startPoint.x + "," + this.startPoint.y + ")");
var stop = d3.transform("translate(" + this.stopPoint.x + "," + this.stopPoint.y + ")");
var interpolate = d3.interpolateTransform(start,stop);
var animation_interval = window.setInterval(function(){
frame++;
// Get transform Value and aply it to the DOM
var transformValue = interpolate(frame/(self.fps * self.duration));
self.d3Selector.attr("transform", transformValue);
// Check if animation should stop
if(frame >= self.fps * self.duration || self.stopFlag){
window.clearInterval(animation_interval);
return;
}
},intervalTime);