I've implemented zoom on force-directed graph
svg.call(d3.behavior.zoom().on("zoom", rescale))
function rescale() {
var trans = d3.event.translate;
var scale = d3.event.scale;
svg.attr("transform",
"translate(" + trans + ")"
+ " scale(" + scale + ")");
}
Graph can be zoomed in either using mouse wheel or double click on it. I need some advice how to implement zooming out without using mouse wheel.
Shift-double click should zoom out.
If you are on a trackpad-equipped Mac, the zooming gestures are actually the Mac scrolling gestures: Scrolling up with two fingers zooms in, scrolling down with two fingers zooms out - Assuming that the Scroll direction in the Preferences is set to unnatural.
Related
How do you add interactivity to d3 maps?
I want to add functionality to query my dataset when you zoom into and out of a d3 map. Is there a callback or something that will enable me to do this?
2.1 I also want the transition to the new data displayed once you zoom to be fairly seamless.
d3.behavior.zoom has 3 event handlers:
1.) zoomstart - at the start of a zoom gesture (e.g., touchstart).
2.) zoom - when the view changes (e.g., touchmove).
3.) zoomend - at the end of the current zoom gesture (e.g., touchend).
So, it seems to be your case fits the zoomend scenerio:
var zoom = d3.behavior.zoom()
.on("zoom", zoomed)
.on("zoomend", zoomend);
function zoomed() {
features.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
function zoomend(){
// query dataset and do awesome stuff!!
}
I want to make chart, that you can not drag out of its svg element.
I'm doing this at the moment like this jsfiddle
As you can see, you can zoom and drag this freely. What i want is this:
If you drag it for example to the right and the y axis hits the edge of your screen on the left it should stop and not be able to be dragged anymore to the right.
Which also means, that you can't drag it around while not zoomed in, because it already fills its svg area.
I guess i have to somehow restrict my redraw method. At the moment it's just this
function redraw() {
plotChart.attr("transform",
"translate(" + d3.event.translate + ")"
+ " scale(" + d3.event.scale + ")");
};
It probably has to check if for example the left edge of the chart hits coordinate [0][x] and then somehow stop drawing it any further out.
To know the axis point on scaling and on translation you need to get the CTM and then transform to get the real points.
//gets CTM on the first y line that is the group
var ctm = d3.select(".x").select(".tick")[0][0].getCTM();
//the first y line
var k = d3.select("svg")[0][0].createSVGPoint();
//current point without transform
k.x = d3.select(".x").select("line").attr("x2");
k.y = d3.select(".x").select("line").attr("y2")
j = k.matrixTransform(ctm)
//j is the real point of the line post transform.
//your code to zoom or pan depending on the value of j
I have a JavaFX Webview which renders a graph (using D3). I want to implement the 'zoom on mouse scroll' on this graph in the JavaFX application (when the mouse is hovered on top of the webview). I was able to do it successfully on a web-browser using the following d3 js code
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.call(d3.behavior.zoom().on("zoom", zoomHandler))
.append('g');
function zoomHandler() {
svg.attr("transform",
"translate(" + d3.event.translate + ")"
+ " scale(" + d3.event.scale + ")");
}
but if I do something similar inside the JavaFX application's WebView, the graph is rendered initially in the WebView but on scroll, just disappears and only reappears if I bring back the mouse scroll to the initial position (when the application was started)
The following code is how I use WebView to render the graph
final URL urlLoadMainGraph = getClass().getResource("html/MainGraph.html");
weMainGraph.load(urlLoadMainGraph.toExternalForm());
Is there something wrong on what is being done ?
Thanks
I cannot provide a solution, but i have the same problem.
The problem is, that you have not specified any scale.
JavaFX is just jumping from the minimum to the maximum scale of the zoom with one "tip" on the mousewheel :(. if you specify it in a certain range, it could work out for you. Use this for example to zoom a little bit outside.
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height).call(d3.behavior.zoom().scaleExtent([0.75, 1]);
best so far... hoping for anwsers!
(PS: i couldnt comment... thats why this kind of answer.
There seems to be a bug in your zoomhandler code example. You might want to start with a handler like the following and go on from there:
function zoomHandler() {
alert('zoom');
}
Here is a more detailed d3 zoom example:
http://bl.ocks.org/mbostock/3892919
And here is a JavaFx wrapper for D3 that also contains a working zoom example:
https://github.com/stefaneidelloth/javafx-d3
https://github.com/stefaneidelloth/javafx-d3/blob/master/javafx-d3-demo/src/main/java/com/github/javafxd3/demo/client/democases/behaviors/ZoomDemo.java
I wish to set a boundary for two rectangles in my SVG.
I found this example: http://bl.ocks.org/mbostock/1557377
In the example the boundaries get worked out from the position of the object that is dragged. Every circle in the example can only move a certain distance from where it started. What I wish to do is to create one drag function and use it on multiple shapes. This drag function will stop the shapes from going out of a certain area.
For example: I have a rectangle on the left side of the screen and one on the right but I don't want any of them to be able to go off screen. I started working on this but figured out this worked with regards to the position of the object getting dragged. So this works for the left hand rectangle but the right hand rectangle can go offscreen to the right but only so far to the left
.on("drag", function(d) {
g = this;
translate = d3.transform(g.getAttribute("transform")).translate;
x = d3.event.dx + translate[0],
y = d3.event.dy + translate[1];
if(x<-10){x=-10}
if(x>width-10){width-10}
if(y<-10){y=-10}
if(y>height-10){y=height-10}
d3.select(g).attr("transform", "translate(" + x + "," + y + ")");
d3.event.sourceEvent.stopPropagation();
My question is: how do I impose the same boundary on anything that is dragged? i.e I don't want it to go off screen. I have variables width and height which are screen width and screen height respectively
I'm trying to implement an image zoom effect, a bit like how the zoom works with Google Maps, but with a grid of fix position images.
I've uploaded an example of what I have so far here:
http://www.dominicpettifer.co.uk/Files/MosaicZoom.html
(uses CSS3 transforms so only works with Firefox, Opera, Chrome or Safari)
Use your mouse wheel to zoom in/out. The HTML source is basically an outer div with an inner-div, and that inner-div contains 16 images arranged using absolute position. It's going to be a Photo Mosaic basically.
I've got the zoom bit working using CSS3 transforms:
$(this).find('div').css('-moz-transform', 'scale(' + scale + ')');
...however, I'm relying on the mouse X/Y position on the outer div to zoom in on where the mouse cursor is, similar to how Google Maps functions. The problem is that if you zoom right in on an image, move the cursor to the bottom/left corner and zoom again, instead of zooming to the bottom/left corner of the image, it zooms to the bottom/left of the entire mosaic. This has the effect of appearing to jump about the mosaic as you zoom in closer while moving the mouse around, even slightly.
That's basically the problem, I want the zoom to work exactly like Google Maps where it zooms exactly to where your mouse cursor position is, but I can't get my head around the Maths to calculate the transform-origin: X/Y values correctly. Please help, been stuck on this for 3 days now.
Here is the full code listing for the mouse wheel event:
var scale = 1;
$("#mosaicContainer").mousewheel(function(e, delta)
{
if (delta > 0)
{
scale += 1;
}
else
{
scale -= 1;
}
scale = scale < 1 ? 1 : (scale > 40 ? 40 : scale);
var x = e.pageX - $(this).offset().left;
var y = e.pageY - $(this).offset().top;
$(this).find('div').css('-moz-transform', 'scale(' + scale + ')')
.css('-moz-transform-origin', x + 'px ' + y + 'px');
return false;
});
Finally figured it out, check it out here:
http://www.dominicpettifer.co.uk/Files/Mosaic/MosaicTest.html
Use the mouse wheel to zoom, you can also drag the image about, only works properly on latest Safari, Opera and Firefox (images are blurry on Chrome for some reason). Also a bit buggy in certain areas. Got a lot of help someone at DocType http://doctype.com/javascript-image-zoom-css3-transforms-calculate-origin-example