JavaScript How to selectively zoom x and/or y in d3.js — dynamically?

I have a small JavaScript graphing/histogramming library which allows zooming/panning in either X or Y directions, or both, as declared when the plot is created. A simplified example is in this jsfiddle.

What I want to do instead is to allow the zoom behavior to change when, e.g., the shift key is pressed.

The core of the zoom logic in my example currently looks like this:

 function draw() {
     // handle rendering of plot
 }

 // zoom behavior:
 var zoom = d3.behavior.zoom();
 zoom.x(xscale);
 //zoom.y(yscale);   <-- add this in if y-scrolling is to be allowed

 zoom.on("zoom", draw);

 // Restrict zoom action to display box (non-axis part) only:
 svg.append("svg:rect")
     .attr("class", "pane")
     .attr("width", w - (padding_left + padding_right))
     .attr("height", h - (padding_top + padding_bottom))
     .attr("cursor", "move")
     .attr("fill", "none")
     .attr("pointer-events", "all")
     .attr("x", padding_left)
     .attr("y", padding_top)
     .call(zoom);

 function keydown() {
     if(d3.event.shiftKey) {
         // turn on y-zoom behavior, turn off x...
     }
 }

 function keyup() {
     // revert to old behavior
 }

 d3.select("body").on("keydown", keydown);
 d3.select("body").on("keyup", keyup);

I can turn on X or Y zooming selectively when the plot is set up; but I want to do this intermittently, when the shift key is pressed, i.e. in keydown and keyup. Since the zoom behavior is wired in to my "pane" div once, it's not clear to me how to make this dynamic.

Thanks!

Answer:1

The easiest way to do this would be to handle this in your zoom function. That is, instead of modifying what events are generated, you just modify how to handle them. So if x zoom is enabled, you only specify the x scale. The code would look something like this.

var zoom = d3.behaviour.zoom().on("zoom", onZoom);
var svg = d3.select("body").append("svg").call(zoom);

function onZoom() {
  if(x_zoom) {
    svg.attr("transform", "scale(" + d3.event.scale + ", 1)");
  }
  else if(y_zoom) {
    svg.attr("transform", "scale(1, " + d3.event.scale + ")");
  }
}
Answer:2

I've written a plugin that modifies d3's default zoom behavior to allow for this:

enter image description here

https://github.com/mathisonian/d3-multiaxis-zoom

Answer:3

It turns out that if you call zoom.x or .y again with a new d3.scale.linear() argument, it will disable that axis's pan/zoom behavior, and if you call it again with the original xscale or yscale, it will reenable it.

However, one problem I ran into is that, unlike mouseover events, I could not tie keydown and keyup events to an individual div or svg; they are fired for the page as a whole (see this related question). This meant that, in order to support multiple graphs in i3d3, I had to save separate zoom and scale behaviors for each plot; otherwise, only the last plot on the page would have the correct behavior.

I'll keep this question unanswered for a while to see if other people have additional suggestions.

Answer:4

I want to add a transition time to my pure javascript toggle class function I knew how to code it but i forgot and now need some advice <!DOCTYPE html> <html> <head> <style ...

I want to add a transition time to my pure javascript toggle class function I knew how to code it but i forgot and now need some advice <!DOCTYPE html> <html> <head> <style ...

I'm trying to make a countdown that is counting down in milliseconds; however, the countdown actually takes much longer than 7 seconds. Any idea as to why? function countDown(time){ var i = 0; ...

I'm trying to make a countdown that is counting down in milliseconds; however, the countdown actually takes much longer than 7 seconds. Any idea as to why? function countDown(time){ var i = 0; ...

<div class="foo"> <input name="moobar" /> <input name="foobar" /> </div> How do I replace all "oo" in the names found in $('.foo');? e.g. div.replace('oo', 'aa') => moobar ...

<div class="foo"> <input name="moobar" /> <input name="foobar" /> </div> How do I replace all "oo" in the names found in $('.foo');? e.g. div.replace('oo', 'aa') => moobar ...

  1. find replace name manager excel
  2. find replace name
  3. search and replace name
  4. find and replace name of files
  5. find replace file name windows
  6. find and replace name of files linux
  7. find and replace sheet name in excel formula
  8. maya find and replace name
  9. find and replace class name in jquery
  10. find and replace sheet name in excel
  11. bash find replace file name
  12. find and replace folder name
  13. autocad find replace layer name
  14. find and replace file name in unix
  15. find and replace file name mac
  16. find and replace in name manager
  17. intellij find replace file name
  18. find and replace file name in folder
  19. applescript find replace file name
  20. excel find replace file name

I am writing a javascript program with a very long-running foreach loop like the following: for (property in object) { difficultTask(); } I've seen that you can do some things with setTimeout ...

I am writing a javascript program with a very long-running foreach loop like the following: for (property in object) { difficultTask(); } I've seen that you can do some things with setTimeout ...