d3.js保持可缩放的y轴不低于零

时间:2013-03-05 17:42:21

标签: svg d3.js zoom scale

我有一个带缩放功能的图表。我的主要观察是x轴根据我当前的缩放级别更新了它的比例。我希望y轴也这样做,所以启用zoom.y(y),不受欢迎的一面会影响现在用户可以在所有方向上缩小,甚至可以在图形“下方”的负值下缩小。

http://jsfiddle.net/ericps/xJ3Ke/5/

var zoom = d3.behavior.zoom().scaleExtent([0.2, 5]) .on("zoom", draw);似乎并未真正考虑y轴。并且用户仍然可以将图表在任何方向上拖动到无限远。

我想到的一个想法与启用zoom.y(y)无关,只需要根据当前可见范围内的内容重新绘制y轴。像某种基于X轴位置的重绘一样。我现在不想上下滚动,只有左右滚动

除了评论//zoom.y(y)这将如何做?洞察力很高兴。

1 个答案:

答案 0 :(得分:12)

您需要做的就是在draw方法中更新y scale域。

缩放功能将修改关联的比例并设置其域以模拟缩放。因此,您可以通过执行x.invert(0)和x.invert(width)来获取x可见数据边界。如果您将数据转换为使用日期而不是字符串,那么这就是我建议您用来过滤的内容,它可能会更有效率。

尽管如此,您仍然可以使用x比例过滤到可见数据,找到这些值的y轴范围,并将y比例域设置为相应匹配。事实上,您可以在几行中完成所有这些操作(在缩放更新回调中):

var yExtent = d3.extent(data.filter(function(d) { 
    var dt = x(d.date);
    return dt > 0 && dt < width;
}), function(d) { return d.value; });
y.domain(yExtent).nice(); 

您可以尝试here

为了更好地解释发生了什么:

缩放行为侦听鼠标事件并修改关联比例的范围。

轴使用刻度线将它们绘制为带刻度的线条,并且当​​您在回调中设置它们时,与您的路径和区域相关联的数据也会使用刻度。

因此,当缩放发生变化时,它会触发回调,基本方法就是你所拥有的:

svg.select("g.x.axis").call(xAxis);
svg.select("g.y.axis").call(yAxis);
svg.select("path.area").attr("d", area);
svg.select("path.line").attr("d", line);

我们使用新更新的域重新绘制x轴和y轴,然后重新绘制(重新计算)区域和线 - 同时使用新分析的x和y标度。

因此,要获得您想要的行为,我们会删除y刻度上的默认缩放行为,而是每当我们获得缩放或平移时,我们将自己修改y scale域:方便地,我们已经对这些操作进行了回调,因为缩放行为。

计算y比例域的第一步是确定哪些数据值是可见的。 x轴已配置为输出到0到宽度的范围,并且缩放行为已更新x缩放的域,使得仅原始域的子集输出到此范围。因此,我们使用javascript数组的过滤器方法仅提取那些映射将它们放在可见范围内的数据对象:

data.filter(function(d) { 
    var dt = x(d.date);
    return dt > 0 && dt < width;
}

然后我们使用方便的d3范围方法返回数组中的最小值和最大值。但是因为我们的数组是所有对象,所以我们需要一个访问器函数,因此extents方法有一些数字可以实际比较(这是D3中的常见模式)

d3.extents(filteredData, function(d) { return d.value; });

现在我们知道在给定当前x标度的情况下绘制的所有数据点的最小值和最大值。最后一点是设置y比例域并继续正常!

y.domain(yExtent).nice(); 

我在api找到了一个很好的方法,因为它是你想要做比例的事情,d3经常为你做你想做的事。

找出其中一些内容的好教程是:http://alignedleft.com/tutorials/ 即使是你认为已经知道的部分也值得一试。