如何有选择地在d3.js中动态缩放x和/或y?

时间:2013-11-20 19:23:46

标签: javascript d3.js

我有a small JavaScript graphing/histogramming library允许在创建绘图时声明的X或Y方向或两者的缩放/平移。一个简化的例子是this jsfiddle

我想要做的是允许在例如按下shift键时改变缩放行为。

我示例中缩放逻辑的核心目前如下所示:

 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);

设置绘图时,我可以选择性地打开X或Y缩放;但是我想在按下shift键时间歇地这样做,即在keydownkeyup。由于缩放行为已连接到我的“pane”div一次,因此我不清楚如何使其动态化。

谢谢!

4 个答案:

答案 0 :(得分:2)

最简单的方法是在zoom函数中处理此问题。也就是说,您只需修改处理它们的方式,而不是修改生成的事件。因此,如果启用了x缩放,则只指定x比例。代码看起来像这样。

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 + ")");
  }
}

答案 1 :(得分:2)

我已经编写了一个插件来修改d3的默认缩放行为以允许这样做:

enter image description here

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

答案 2 :(得分:1)

事实证明,如果您使用新的zoom.x参数再次调用.yd3.scale.linear(),它将禁用该轴的平移/缩放行为,如果您再次使用原始xscaleyscale,它会重新启用它。

但是,我遇到的一个问题是,与mouseover事件不同,我无法将keydownkeyup个事件与个人div或{{1}绑定};他们被整个页面解雇(见this related question)。这意味着,为了支持i3d3中的多个图表,我必须为每个图表保存单独的svgzoom行为;否则,只有页面上的最后一个图表具有正确的行为。

我会暂时不回答这个问题,看看其他人是否有其他建议。

答案 3 :(得分:1)

我将在Lars Kotthoff回答中添加一些内容。

如果我们添加翻译也会好得多 即

//For X-Zoom
svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + " ,1)");
//For Y-Zoom
svg.attr("transform", "translate(" + d3.event.translate + ")scale(1, " + d3.event.scale + ")");

即使您的绘图svg位于不同的容器中,此解决方案仍然有效,并且svg位于不同的容器中。