Zoom extent issue in d3 axis - javascript

I am using d3 axis to show the bar graph and i have added zoom interaction to it.
I am adding zoom interaction like this,
d3.zoom(xScale).on("zoom", jQuery.proxy(function(){
//Do somthing on zooming.
},this));
},this));
On Zooming the axis i have to get the at what level the axis is zoomed,
suppose consider i have time axis on zooming it will show the labels in day level, after zooming again it will show the axis in hour level. So how to get whether it is zoomed in day level or hour level after zooming?

Assuming you are targeting d3 version 4, the best way to handle this is with the zoom functionality's rescaleX. Say we have the following zoom handler where x is the scale tied to the x-axis:
function zoomed() {
var newScale = d3.event.transform.rescaleX(x));
console.log(newScale.domain());
}
Would log the bounds (min/max) of your zoomed axis.

Related

D3: Use brush to zoom to specific interval

please see the following D3 example:
https://bl.ocks.org/mbostock/f48fcdb929a620ed97877e4678ab15e6
In this example, the user is able to draw a brush on the screen and then the graph zooms to the region encapsulated by the brush. The way this example works is by updating the x and y scale domains based on the brush extent. You can see that in the brushended() function.
I am looking to achieve this same functionality. However, I do not want to update the x and y scale domains but want to update the zoom scale and translate. The following example achieves this for a map:
https://bl.ocks.org/mmazanec22/586ee6674f52840492c16cc194aacb1f
You can see this is the brushend() function. Here the writer calculates a scale and translation based on the brush extent and then uses them to set a new scale and translate for the zoom behaviour. I am looking to achieve this however for a scatter plot.
I have a written an example of what I have tried in this jsfiddle: https://jsfiddle.net/SSS123/uxdd760k/1/ - see the part where I do my scale and translate calculations below:
var extent = brush.extent();
// Get box coordinates
var lowerX = d3.min([extent[0][0], extent[1][0]]);
var upperX = d3.max([extent[0][0], extent[1][0]]);
var lowerY = d3.min([extent[0][1], extent[1][1]]);
var upperY = d3.max([extent[0][1], extent[1][1]]);
var scale = Math.max( ( width / (x(upperX) - x(lowerX)) ), ( height / (y(upperY) - y(lowerY)) ) );
graphContainer.transition()
.duration(750)
.call(zoom.scale(scale).translate([-x(lowerX), -y(upperY)]).event);
I believe this now works fine for the case when you draw a brush with a width the same size as the height i.e. if you try drawing a box that stretches from 0 to 5 on the xAxis and 0 to 5 on the yAxis then this will zoom in quite well.
However, if you draw a box with 0 - 5 on the xAxis but 0 - 30 on the yAxis then this will no longer calculate a sensible zoom scale.
Has anyone any advise on how to solve this?

NVD3: Have labels at certain tick values at the top of the graph

I am using NVD3 to draw a graph that uses an ordinal scale on the x axis for dates. I also have a "focus graph" under it to highlight a specific region to display. To automatically update the ticks that are displayed, I use the tickValues() property.
I want to have label on specific dates at the top of the graph. My solution for this was to create another x axis, but above the the graph, plot the same data, but with a 0 height, and then use tickValues() to set the position of the labels. However, the labels don't show up on the top axis. Is there a solution or alternative?
I guess using a secondary x axis is fine. I forgot to remove the line setting the domain property for my secondary axis. When I removed that, it scaled just like my primary axis :)

d3.js: pan with limits

I'm working on a basic linear chart with pan functionality.
I managed to limit the extent to which the chart elements can be dragged by limiting the d3.event.translate values:
var tx = Math.max(0, d3.event.translate[0]),
ty = Math.min(0, d3.event.translate[1]);
All I need now is to limit the x and y axes accordingly. See the example:
http://jsfiddle.net/Q2SWV/
The bars on the chart are limited by 0 when dragging down or to the left. The x and y axes aren't. Any ideas on how to fix the axis problem?
You're very close, but you're missing the final step of updating the zoom behavior with your updated translation coordinates. This will fix your problem since both axes are updated using the zoom. Add the following right after determining tx and ty:
zoom.translate([tx, ty]);
This will apply the limits to your axes. See updated fiddle here: http://jsfiddle.net/mdml/nZD3E/.

D3 Zoom resets scales selected via brushing.

I've made zooming and brushing working together. The only problem is, when I've set the particular period on X axis via brushing and then trying to use zoom (on mouse drag or mouse wheel), it resets previous selected scales, so zoom doesn't store x axis domain that was set via brushing before.
zoomRight = d3.behavior.zoom()
.x(xScale)
.y(yRightScale)
.scaleExtent([1,20])
zoomed = ->
zoomRight.scale(zoom.scale()).translate(zoom.translate())
canvas.select("._x._axis").call xAxis
canvas.select(".axisLeft").call yLeftAxis
canvas.select(".axisRight").call yRightAxis
canvas.select(".y.grid").call make_y_axis().tickSize(-width, 0, 0).tickFormat("")
canvas.select(".line1").attr("d", line1(data))
canvas.select(".line2").attr("d", line2(data))
brush.extent(xScale.domain())
canvas.select(".brush").call(brush)
zoom = d3.behavior.zoom()
.x(xScale)
.y(yLeftScale)
.scaleExtent([1,20]) # 20x times zoom
.on("zoom", zoomed)
Full code is here fiddle. How can I force zoom to remember the previous brushing selection(position)?
Solved the problem by adding the following lines on brush:
zoom.x(xScale)
zoom.translate()
Working example is here.

Pinch zoom on touch devices

I have a graph rendered within the HTML5 canvas. The working is good till this point. Now I need to implement pinch zoom on the graph for touch devices. The logic is as the two finger stretches apart the graph zooms in and as the finger moves together the graph zooms out. In this case we need to constantly update the axis value. The problem here is how do we get the individual X and Y axis value of both the fingers and then calculate the amount of zoom to be done. As for example, for zooming using mouse we can get the start X and Y value on mouse down and on mouse up we get the end X and Y axis value. Using this start and end value of X and Y axis the graph can be zoomed accordingly. The canvas should not zoom in/out. The zoom in can be infinite but the zoom out will be till the default plotting of the graph. Any idea or help would be really appreciable. I am not getting the proper calculation.
I have implemented it in the following way. Any suggestions are welcome.
First I have taken the screen co-ordinates of the two fingers touch on start and converted it to its corresponding view co-ordinates by calculating its distance from the topmost and leftmost position. After that I have calculated the scale and new co-ordinates for X-axis in the following way.
Let
d1 and d2 be the dataspace coordinates of the initial/starting touches.
newx1 and newx2 are the x positions of the new touches.
screenW is the current screen width (i.e. width of plot in screen space).
Then
scale = (d2 - d1) / (newx2 - newx1)
If we use newd1, newd2 to denote the new datarange min and max values that we're trying to compute:
newd1 = d1 - newx1 * scale
newd2 = newd1 + screenW * scale
Similarly, we can do the calculation for new datarange min and max values of Y-axis.
Variant A:
Take a JavaScript library like Hammer.js which abstracts away all then event handling and gives you an event in case of a pinch. This should look like this:
var element = document.getElementById('test_el');
var hammertime = Hammer(element).on("pinchout", function(event) {
console.log("Zoom out!!");
// event.scale should contain the scaling factor for the zoom
});
Variant B:
Read about the touch events and how to identify if it is a multitouch. Figure out when it is a pinch and if how far the fingers have moved. There is nice write up here.

Categories