By default, when you create a new zoom behavior in D3, it maps the mousewheel to control zoom level. You can also click and drag to pan the chart if it\'s larger than the c
Ok, here we go:
Based on Lars' comment, we can specify event handler for mousewheel event. As shown in the answer, we start by mapping wheel.zoom
event to a custom handler pan
selection.call(zoomer)
.on("wheel.zoom",pan) // handler function for mousewheel zoom
Second, we need to define the pan gesture, which is basically a translate
in x and/or y direction.
function pan() {
svg.attr("transform", "translate(" + [dx,dy] + ")");
}
We also need to quantify the movement in both directions, and relate it to mousewheel movement. By inspecting the details of MouseWheel
event, we find two useful attributes deltaX and deltaY, indicating how much the mousewheel moved in each direction.
The final pan
function is as follows
function pan() {
current_translate = d3.transform(svg.attr("transform")).translate;
dx = d3.event.wheelDeltaX + current_translate[0];
dy = d3.event.wheelDeltaY + current_translate[1];
svg.attr("transform", "translate(" + [dx,dy] + ")");
d3.event.stopPropagation();
}
Here is a working fiddle and bl.ock also modifying Mike's geometric zoom example.
It seems that mousewheel events differs between browsers. For Safari and Firefox support, you need to add the following:
selection.call(zoomer)
.on("wheel.zoom",pan)
.on("mousewheel.zoom", pan)
.on("DOMMouseScroll.zoom", pan)
Also, the interpretation of wheelDelta
is reversed in Firefox. wheelDelta
can be fixed by this function
function crossWheelDelta()
// cross-browser wheel delta
var e = window.event || e; // old IE support
return Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
}
You can also intercept wheel events in the function you create with d3.behavior.zoom(). "Zoom" events are triggered on both wheel scroll and mouse drag by default, so one potential strategy is to just wait for zoom events and intercept the wheel events within the zoom function.
For example, here's an approach to doing Y translations with both wheel scroll and mouse drag:
var panYOnScrollAndDrag = d3.behavior.zoom()
.scaleExtent([1, 1]) // prevents wheel events (or anything) from changing the scale
.on("zoom", function() {
if (d3.event.sourceEvent.type === "wheel") {
// use the `d3.event.sourceEvent.deltaY` value to translate
// e.g., yTranslation += yTranslationDelta;
} else if (d3.event.sourceEvent.type === "mousemove") {
// use the normal d3.event.translate array to translate
// e.g., yTranslation = d3.event.translate[1];
}
container.attr("transform", "translate(0," + yTranslation + ")");
});
Then you can throw this function at the relevant d3 container like so, selection.call(panYOnScrollAndDrag)
, and all the logic is contained in that one function.